Merge branch 'abstract_i2c' into abstract_buses

Conflicts:
	firmware/common/hackrf_core.c
	firmware/common/hackrf_core.h
	firmware/hackrf-common.cmake
This commit is contained in:
Jared Boone
2014-11-13 11:26:41 -08:00
12 changed files with 336 additions and 121 deletions

View File

@ -34,7 +34,8 @@
#include "w25q80bv_target.h" #include "w25q80bv_target.h"
#include "sgpio.h" #include "sgpio.h"
#include "rf_path.h" #include "rf_path.h"
#include <libopencm3/lpc43xx/i2c.h> #include "i2c_bus.h"
#include "i2c_lpc.h"
#include <libopencm3/lpc43xx/cgu.h> #include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/lpc43xx/gpio.h> #include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h> #include <libopencm3/lpc43xx/scu.h>
@ -42,6 +43,33 @@
#define WAIT_CPU_CLOCK_INIT_DELAY (10000) #define WAIT_CPU_CLOCK_INIT_DELAY (10000)
i2c_bus_t i2c0 = {
.obj = (void*)I2C0_BASE,
.start = i2c_lpc_start,
.stop = i2c_lpc_stop,
.transfer = i2c_lpc_transfer,
};
i2c_bus_t i2c1 = {
.obj = (void*)I2C1_BASE,
.start = i2c_lpc_start,
.stop = i2c_lpc_stop,
.transfer = i2c_lpc_transfer,
};
const i2c_lpc_config_t i2c_config_si5351c_slow_clock = {
.duty_cycle_count = 15,
};
const i2c_lpc_config_t i2c_config_si5351c_fast_clock = {
.duty_cycle_count = 255,
};
si5351c_driver_t clock_gen = {
.bus = &i2c0,
.i2c_address = 0x60,
};
const ssp_config_t ssp_config_max2837 = { const ssp_config_t ssp_config_max2837 = {
/* FIXME speed up once everything is working reliably */ /* FIXME speed up once everything is working reliably */
/* /*
@ -209,9 +237,9 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
/* Can we enable integer mode ? */ /* Can we enable integer mode ? */
if (a & 0x1 || b) if (a & 0x1 || b)
si5351c_set_int_mode(0, 0); si5351c_set_int_mode(&clock_gen, 0, 0);
else else
si5351c_set_int_mode(0, 1); si5351c_set_int_mode(&clock_gen, 0, 1);
/* Final MS values */ /* Final MS values */
MSx_P1 = 128*a + (128 * b/c) - 512; MSx_P1 = 128*a + (128 * b/c) - 512;
@ -219,13 +247,13 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
MSx_P3 = c; MSx_P3 = c;
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(0, MSx_P1, MSx_P2, MSx_P3, 1); si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(1, 0, 0, 0, 0);//p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0);//p1 doesn't matter
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(2, 0, 0, 0, 0);//p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0);//p1 doesn't matter
return true; return true;
} }
@ -265,13 +293,13 @@ bool sample_rate_set(const uint32_t sample_rate_hz) {
* values are irrelevant. */ * values are irrelevant. */
/* MS0/CLK1 is the source for the MAX5864 codec. */ /* MS0/CLK1 is the source for the MAX5864 codec. */
si5351c_configure_multisynth(1, 4608, 0, 1, r_div_sample); si5351c_configure_multisynth(&clock_gen, 1, 4608, 0, 1, r_div_sample);
/* MS0/CLK2 is the source for the CPLD codec clock (same as CLK1). */ /* MS0/CLK2 is the source for the CPLD codec clock (same as CLK1). */
si5351c_configure_multisynth(2, 4608, 0, 1, r_div_sample); si5351c_configure_multisynth(&clock_gen, 2, 4608, 0, 1, r_div_sample);
/* MS0/CLK3 is the source for the SGPIO clock. */ /* MS0/CLK3 is the source for the SGPIO clock. */
si5351c_configure_multisynth(3, 4608, 0, 1, r_div_sgpio); si5351c_configure_multisynth(&clock_gen, 3, 4608, 0, 1, r_div_sgpio);
return true; return true;
#endif #endif
@ -328,13 +356,13 @@ bool sample_rate_set(const uint32_t sample_rate_hz) {
} }
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(0, p1, p2, p3, 1); si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(1, p1, 0, 1, 0);//p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 1, p1, 0, 1, 0);//p1 doesn't matter
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(2, p1, 0, 1, 0);//p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 2, p1, 0, 1, 0);//p1 doesn't matter
return true; return true;
#endif #endif
@ -355,15 +383,15 @@ void cpu_clock_init(void)
/* use IRC as clock source for APB3 */ /* use IRC as clock source for APB3 */
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC); CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC);
i2c0_init(15); i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_slow_clock);
si5351c_disable_all_outputs(); si5351c_disable_all_outputs(&clock_gen);
si5351c_disable_oeb_pin_control(); si5351c_disable_oeb_pin_control(&clock_gen);
si5351c_power_down_all_clocks(); si5351c_power_down_all_clocks(&clock_gen);
si5351c_set_crystal_configuration(); si5351c_set_crystal_configuration(&clock_gen);
si5351c_enable_xo_and_ms_fanout(); si5351c_enable_xo_and_ms_fanout(&clock_gen);
si5351c_configure_pll_sources(); si5351c_configure_pll_sources(&clock_gen);
si5351c_configure_pll_multisynth(); si5351c_configure_pll_multisynth(&clock_gen);
#ifdef JELLYBEAN #ifdef JELLYBEAN
/* /*
@ -379,13 +407,13 @@ void cpu_clock_init(void)
*/ */
/* MS0/CLK0 is the source for the MAX2837 clock input. */ /* MS0/CLK0 is the source for the MAX2837 clock input. */
si5351c_configure_multisynth(0, 2048, 0, 1, 0); /* 40MHz */ si5351c_configure_multisynth(&clock_gen, 0, 2048, 0, 1, 0); /* 40MHz */
/* MS4/CLK4 is the source for the LPC43xx microcontroller. */ /* MS4/CLK4 is the source for the LPC43xx microcontroller. */
si5351c_configure_multisynth(4, 8021, 0, 3, 0); /* 12MHz */ si5351c_configure_multisynth(&clock_gen, 4, 8021, 0, 3, 0); /* 12MHz */
/* MS5/CLK5 is the source for the RFFC5071 mixer. */ /* MS5/CLK5 is the source for the RFFC5071 mixer. */
si5351c_configure_multisynth(5, 1536, 0, 1, 0); /* 50MHz */ si5351c_configure_multisynth(&clock_gen, 5, 1536, 0, 1, 0); /* 50MHz */
#endif #endif
#if (defined JAWBREAKER || defined HACKRF_ONE) #if (defined JAWBREAKER || defined HACKRF_ONE)
@ -402,32 +430,32 @@ void cpu_clock_init(void)
*/ */
/* MS3/CLK3 is the source for the external clock output. */ /* MS3/CLK3 is the source for the external clock output. */
si5351c_configure_multisynth(3, 80*128-512, 0, 1, 0); /* 800/80 = 10MHz */ si5351c_configure_multisynth(&clock_gen, 3, 80*128-512, 0, 1, 0); /* 800/80 = 10MHz */
/* MS4/CLK4 is the source for the RFFC5071 mixer. */ /* MS4/CLK4 is the source for the RFFC5071 mixer. */
si5351c_configure_multisynth(4, 16*128-512, 0, 1, 0); /* 800/16 = 50MHz */ si5351c_configure_multisynth(&clock_gen, 4, 16*128-512, 0, 1, 0); /* 800/16 = 50MHz */
/* MS5/CLK5 is the source for the MAX2837 clock input. */ /* MS5/CLK5 is the source for the MAX2837 clock input. */
si5351c_configure_multisynth(5, 20*128-512, 0, 1, 0); /* 800/20 = 40MHz */ si5351c_configure_multisynth(&clock_gen, 5, 20*128-512, 0, 1, 0); /* 800/20 = 40MHz */
/* MS6/CLK6 is unused. */ /* MS6/CLK6 is unused. */
/* MS7/CLK7 is the source for the LPC43xx microcontroller. */ /* MS7/CLK7 is the source for the LPC43xx microcontroller. */
uint8_t ms7data[] = { 90, 255, 20, 0 }; uint8_t ms7data[] = { 90, 255, 20, 0 };
si5351c_write(ms7data, sizeof(ms7data)); si5351c_write(&clock_gen, ms7data, sizeof(ms7data));
#endif #endif
/* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */ /* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */
sample_rate_set(10000000); sample_rate_set(10000000);
si5351c_set_clock_source(PLL_SOURCE_XTAL); si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL);
// soft reset // soft reset
uint8_t resetdata[] = { 177, 0xac }; uint8_t resetdata[] = { 177, 0xac };
si5351c_write(resetdata, sizeof(resetdata)); si5351c_write(&clock_gen, resetdata, sizeof(resetdata));
si5351c_enable_clock_outputs(); si5351c_enable_clock_outputs(&clock_gen);
//FIXME disable I2C //FIXME disable I2C
/* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */
i2c0_init(255); i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock);
/* /*
* 12MHz clock is entering LPC XTAL1/OSC input now. On * 12MHz clock is entering LPC XTAL1/OSC input now. On
@ -652,6 +680,9 @@ void pin_setup(void) {
/* GPIO3[6] on P6_10 as output. */ /* GPIO3[6] on P6_10 as output. */
GPIO3_DIR |= PIN_EN1V8; GPIO3_DIR |= PIN_EN1V8;
/* enable input on SCL and SDA pins */
SCU_SFSI2C0 = SCU_I2C0_NOMINAL;
spi_bus_start(&spi_bus_ssp1, &ssp_config_max2837); spi_bus_start(&spi_bus_ssp1, &ssp_config_max2837);
spi_bus_start(&spi_bus_rffc5071, NULL); spi_bus_start(&spi_bus_rffc5071, NULL);

View File

@ -32,6 +32,7 @@ extern "C"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "si5351c.h"
#include "spi_ssp.h" #include "spi_ssp.h"
#include "max2837.h" #include "max2837.h"
@ -358,6 +359,7 @@ typedef enum {
void delay(uint32_t duration); void delay(uint32_t duration);
/* TODO: Hide these configurations */ /* TODO: Hide these configurations */
extern si5351c_driver_t clock_gen;
extern const ssp_config_t ssp_config_w25q80bv; extern const ssp_config_t ssp_config_w25q80bv;
extern const ssp_config_t ssp_config_max2837; extern const ssp_config_t ssp_config_max2837;
extern const ssp_config_t ssp_config_max5864; extern const ssp_config_t ssp_config_max5864;

39
firmware/common/i2c_bus.c Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "i2c_bus.h"
void i2c_bus_start(i2c_bus_t* const bus, const void* const config) {
bus->start(bus, config);
}
void i2c_bus_stop(i2c_bus_t* const bus) {
bus->stop(bus);
}
void i2c_bus_transfer(
i2c_bus_t* const bus,
const uint_fast8_t slave_address,
const uint8_t* const tx, const size_t tx_count,
uint8_t* const rx, const size_t rx_count
) {
bus->transfer(bus, slave_address, tx, tx_count, rx, rx_count);
}

52
firmware/common/i2c_bus.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __I2C_BUS_H__
#define __I2C_BUS_H__
#include <stdint.h>
#include <stddef.h>
struct i2c_bus_t;
typedef struct i2c_bus_t i2c_bus_t;
struct i2c_bus_t {
void* const obj;
void (*start)(i2c_bus_t* const bus, const void* const config);
void (*stop)(i2c_bus_t* const bus);
void (*transfer)(
i2c_bus_t* const bus,
const uint_fast8_t slave_address,
const uint8_t* const tx, const size_t tx_count,
uint8_t* const rx, const size_t rx_count
);
};
void i2c_bus_start(i2c_bus_t* const bus, const void* const config);
void i2c_bus_stop(i2c_bus_t* const bus);
void i2c_bus_transfer(
i2c_bus_t* const bus,
const uint_fast8_t slave_address,
const uint8_t* const tx, const size_t tx_count,
uint8_t* const rx, const size_t rx_count
);
#endif/*__I2C_BUS_H__*/

62
firmware/common/i2c_lpc.c Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "i2c_lpc.h"
#include <libopencm3/lpc43xx/i2c.h>
/* FIXME return i2c0 status from each function */
void i2c_lpc_start(i2c_bus_t* const bus, const void* const _config) {
const i2c_lpc_config_t* const config = _config;
const uint32_t port = (uint32_t)bus->obj;
i2c_init(port, config->duty_cycle_count);
}
void i2c_lpc_stop(i2c_bus_t* const bus) {
const uint32_t port = (uint32_t)bus->obj;
i2c_disable(port);
}
void i2c_lpc_transfer(i2c_bus_t* const bus,
const uint_fast8_t slave_address,
const uint8_t* const data_tx, const size_t count_tx,
uint8_t* const data_rx, const size_t count_rx
) {
const uint32_t port = (uint32_t)bus->obj;
i2c_tx_start(port);
i2c_tx_byte(port, (slave_address << 1) | I2C_WRITE);
for(size_t i=0; i<count_tx; i++) {
i2c_tx_byte(port, data_tx[i]);
}
if( data_rx ) {
i2c_tx_start(port);
i2c_tx_byte(port, (slave_address << 1) | I2C_READ);
for(size_t i=0; i<count_rx; i++) {
data_rx[i] = i2c_rx_byte(port);
}
}
i2c_stop(port);
}

42
firmware/common/i2c_lpc.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __I2C_LPC_H__
#define __I2C_LPC_H__
#include <stdint.h>
#include <stddef.h>
#include "i2c_bus.h"
typedef struct i2c_lpc_config_t {
const uint16_t duty_cycle_count;
} i2c_lpc_config_t;
void i2c_lpc_start(i2c_bus_t* const bus, const void* const config);
void i2c_lpc_stop(i2c_bus_t* const bus);
void i2c_lpc_transfer(i2c_bus_t* const bus,
const uint_fast8_t slave_address,
const uint8_t* const data_tx, const size_t count_tx,
uint8_t* const data_rx, const size_t count_rx
);
#endif/*__I2C_LPC_H__*/

View File

@ -21,73 +21,50 @@
*/ */
#include "si5351c.h" #include "si5351c.h"
#include <libopencm3/lpc43xx/i2c.h>
enum pll_sources active_clock_source; enum pll_sources active_clock_source;
/* FIXME return i2c0 status from each function */
/* write to single register */ /* write to single register */
void si5351c_write_single(uint8_t reg, uint8_t val) void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val)
{ {
i2c0_tx_start(); const uint8_t data_tx[] = { reg, val };
i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE); si5351c_write(drv, data_tx, 2);
i2c0_tx_byte(reg);
i2c0_tx_byte(val);
i2c0_stop();
} }
/* read single register */ /* read single register */
uint8_t si5351c_read_single(uint8_t reg) uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg)
{ {
uint8_t val; const uint8_t data_tx[] = { reg };
uint8_t data_rx[] = { 0x00 };
/* set register address with write */ i2c_bus_transfer(drv->bus, drv->i2c_address, data_tx, 1, data_rx, 1);
i2c0_tx_start(); return data_rx[0];
i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE);
i2c0_tx_byte(reg);
/* read the value */
i2c0_tx_start();
i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_READ);
val = i2c0_rx_byte();
i2c0_stop();
return val;
} }
/* /*
* Write to one or more contiguous registers. data[0] should be the first * Write to one or more contiguous registers. data[0] should be the first
* register number, one or more values follow. * register number, one or more values follow.
*/ */
void si5351c_write(uint8_t* const data, const uint_fast8_t data_count) void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count)
{ {
uint_fast8_t i; i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0);
i2c0_tx_start();
i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE);
for (i = 0; i < data_count; i++)
i2c0_tx_byte(data[i]);
i2c0_stop();
} }
/* Disable all CLKx outputs. */ /* Disable all CLKx outputs. */
void si5351c_disable_all_outputs() void si5351c_disable_all_outputs(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 3, 0xFF }; uint8_t data[] = { 3, 0xFF };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* Turn off OEB pin control for all CLKx */ /* Turn off OEB pin control for all CLKx */
void si5351c_disable_oeb_pin_control() void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 9, 0xFF }; uint8_t data[] = { 9, 0xFF };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* Power down all CLKx */ /* Power down all CLKx */
void si5351c_power_down_all_clocks() void si5351c_power_down_all_clocks(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 16 uint8_t data[] = { 16
, SI5351C_CLK_POWERDOWN , SI5351C_CLK_POWERDOWN
@ -99,7 +76,7 @@ void si5351c_power_down_all_clocks()
, SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE , SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE
, SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE , SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE
}; };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* /*
@ -107,20 +84,20 @@ void si5351c_power_down_all_clocks()
* Reads as 0xE4 on power-up * Reads as 0xE4 on power-up
* Set to 8pF based on crystal specs and HackRF One testing * Set to 8pF based on crystal specs and HackRF One testing
*/ */
void si5351c_set_crystal_configuration() void si5351c_set_crystal_configuration(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 183, 0x80 }; uint8_t data[] = { 183, 0x80 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* /*
* Register 187: Fanout Enable * Register 187: Fanout Enable
* Turn on XO and MultiSynth fanout only. * Turn on XO and MultiSynth fanout only.
*/ */
void si5351c_enable_xo_and_ms_fanout() void si5351c_enable_xo_and_ms_fanout(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 187, 0xD0 }; uint8_t data[] = { 187, 0xD0 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* /*
@ -129,34 +106,35 @@ void si5351c_enable_xo_and_ms_fanout()
* PLLA_SRC=0 (XTAL) * PLLA_SRC=0 (XTAL)
* PLLB_SRC=1 (CLKIN) * PLLB_SRC=1 (CLKIN)
*/ */
void si5351c_configure_pll_sources(void) void si5351c_configure_pll_sources(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 15, 0x08 }; uint8_t data[] = { 15, 0x08 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* MultiSynth NA (PLLA) and NB (PLLB) */ /* MultiSynth NA (PLLA) and NB (PLLB) */
void si5351c_configure_pll_multisynth(void) void si5351c_configure_pll_multisynth(si5351c_driver_t* const drv)
{ {
//init plla to (0x0e00+512)/128*25mhz xtal = 800mhz -> int mode //init plla to (0x0e00+512)/128*25mhz xtal = 800mhz -> int mode
uint8_t data[] = { 26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00 }; uint8_t data[] = { 26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
/* 10 MHz input on CLKIN for PLLB */ /* 10 MHz input on CLKIN for PLLB */
data[0] = 34; data[0] = 34;
data[4] = 0x26; data[4] = 0x26;
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
void si5351c_reset_pll(void) void si5351c_reset_pll(si5351c_driver_t* const drv)
{ {
/* reset PLLA and PLLB */ /* reset PLLA and PLLB */
uint8_t data[] = { 177, 0xA0 }; uint8_t data[] = { 177, 0xA0 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
void si5351c_configure_multisynth(const uint_fast8_t ms_number, void si5351c_configure_multisynth(si5351c_driver_t* const drv,
const uint_fast8_t ms_number,
const uint32_t p1, const uint32_t p2, const uint32_t p3, const uint32_t p1, const uint32_t p2, const uint32_t p3,
const uint_fast8_t r_div) const uint_fast8_t r_div)
{ {
@ -183,7 +161,7 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number,
(((p3 >> 16) & 0xF) << 4) | (((p2 >> 16) & 0xF) << 0), (((p3 >> 16) & 0xF) << 4) | (((p2 >> 16) & 0xF) << 0),
(p2 >> 8) & 0xFF, (p2 >> 8) & 0xFF,
(p2 >> 0) & 0xFF }; (p2 >> 0) & 0xFF };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
#ifdef JELLYBEAN #ifdef JELLYBEAN
@ -232,15 +210,15 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number,
* CLK5_SRC=3 (MS5 as input source) * CLK5_SRC=3 (MS5 as input source)
* CLK5_IDRV=3 (8mA) * CLK5_IDRV=3 (8mA)
*/ */
void si5351c_configure_clock_control() void si5351c_configure_clock_control(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 16, 0x4F, 0x4B, 0x4B, 0x4B, 0x0F, 0x4F, 0xC0, 0xC0 }; uint8_t data[] = { 16, 0x4F, 0x4B, 0x4B, 0x4B, 0x0F, 0x4F, 0xC0, 0xC0 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
#endif #endif
#if (defined JAWBREAKER || defined HACKRF_ONE) #if (defined JAWBREAKER || defined HACKRF_ONE)
void si5351c_configure_clock_control(const enum pll_sources source) void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll_sources source)
{ {
uint8_t pll; uint8_t pll;
@ -261,54 +239,54 @@ void si5351c_configure_clock_control(const enum pll_sources source)
,SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/ ,SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/
,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA)
}; };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
#endif #endif
/* Enable CLK outputs 0, 1, 2, 3, 4, 5, 7 only. */ /* Enable CLK outputs 0, 1, 2, 3, 4, 5, 7 only. */
void si5351c_enable_clock_outputs() void si5351c_enable_clock_outputs(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 3, 0x40 }; uint8_t data[] = { 3, 0x40 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
void si5351c_set_int_mode(const uint_fast8_t ms_number, const uint_fast8_t on){ void si5351c_set_int_mode(si5351c_driver_t* const drv, const uint_fast8_t ms_number, const uint_fast8_t on){
uint8_t data[] = {16, 0}; uint8_t data[] = {16, 0};
if(ms_number < 8){ if(ms_number < 8){
data[0] = 16 + ms_number; data[0] = 16 + ms_number;
data[1] = si5351c_read_single(data[0]); data[1] = si5351c_read_single(drv, data[0]);
if(on) if(on)
data[1] |= SI5351C_CLK_INT_MODE; data[1] |= SI5351C_CLK_INT_MODE;
else else
data[1] &= ~(SI5351C_CLK_INT_MODE); data[1] &= ~(SI5351C_CLK_INT_MODE);
si5351c_write(data, 2); si5351c_write(drv, data, 2);
} }
} }
void si5351c_set_clock_source(const enum pll_sources source) void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source)
{ {
si5351c_configure_clock_control(source); si5351c_configure_clock_control(drv, source);
active_clock_source = source; active_clock_source = source;
} }
void si5351c_activate_best_clock_source(void) void si5351c_activate_best_clock_source(si5351c_driver_t* const drv)
{ {
uint8_t device_status = si5351c_read_single(0); uint8_t device_status = si5351c_read_single(drv, 0);
if (device_status & SI5351C_LOS) { if (device_status & SI5351C_LOS) {
/* CLKIN not detected */ /* CLKIN not detected */
if (active_clock_source == PLL_SOURCE_CLKIN) { if (active_clock_source == PLL_SOURCE_CLKIN) {
si5351c_set_clock_source(PLL_SOURCE_XTAL); si5351c_set_clock_source(drv, PLL_SOURCE_XTAL);
} }
} else { } else {
/* CLKIN detected */ /* CLKIN detected */
if (active_clock_source == PLL_SOURCE_XTAL) { if (active_clock_source == PLL_SOURCE_XTAL) {
si5351c_set_clock_source(PLL_SOURCE_CLKIN); si5351c_set_clock_source(drv, PLL_SOURCE_CLKIN);
} }
} }
} }

View File

@ -30,8 +30,9 @@ extern "C"
#include <stdint.h> #include <stdint.h>
#include "i2c_bus.h"
#define SI_INTDIV(x) (x*128-512) #define SI_INTDIV(x) (x*128-512)
#define SI5351C_I2C_ADDR (0x60 << 1)
#define SI5351C_CLK_POWERDOWN (1<<7) #define SI5351C_CLK_POWERDOWN (1<<7)
#define SI5351C_CLK_INT_MODE (1<<6) #define SI5351C_CLK_INT_MODE (1<<6)
@ -62,26 +63,32 @@ enum pll_sources {
PLL_SOURCE_CLKIN = 1, PLL_SOURCE_CLKIN = 1,
}; };
void si5351c_disable_all_outputs(); typedef struct {
void si5351c_disable_oeb_pin_control(); i2c_bus_t* const bus;
void si5351c_power_down_all_clocks(); uint8_t i2c_address;
void si5351c_set_crystal_configuration(); } si5351c_driver_t;
void si5351c_enable_xo_and_ms_fanout();
void si5351c_configure_pll_sources(void); void si5351c_disable_all_outputs(si5351c_driver_t* const drv);
void si5351c_configure_pll_multisynth(void); void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv);
void si5351c_reset_pll(void); void si5351c_power_down_all_clocks(si5351c_driver_t* const drv);
void si5351c_configure_multisynth(const uint_fast8_t ms_number, void si5351c_set_crystal_configuration(si5351c_driver_t* const drv);
void si5351c_enable_xo_and_ms_fanout(si5351c_driver_t* const drv);
void si5351c_configure_pll_sources(si5351c_driver_t* const drv);
void si5351c_configure_pll_multisynth(si5351c_driver_t* const drv);
void si5351c_reset_pll(si5351c_driver_t* const drv);
void si5351c_configure_multisynth(si5351c_driver_t* const drv,
const uint_fast8_t ms_number,
const uint32_t p1, const uint32_t p2, const uint32_t p3, const uint32_t p1, const uint32_t p2, const uint32_t p3,
const uint_fast8_t r_div); const uint_fast8_t r_div);
void si5351c_configure_clock_control(const enum pll_sources source); void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll_sources source);
void si5351c_enable_clock_outputs(); void si5351c_enable_clock_outputs(si5351c_driver_t* const drv);
void si5351c_set_int_mode(const uint_fast8_t ms_number, const uint_fast8_t on); void si5351c_set_int_mode(si5351c_driver_t* const drv, const uint_fast8_t ms_number, const uint_fast8_t on);
void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source);
void si5351c_activate_best_clock_source(si5351c_driver_t* const drv);
void si5351c_write_single(uint8_t reg, uint8_t val); void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val);
uint8_t si5351c_read_single(uint8_t reg); uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg);
void si5351c_write(uint8_t* const data, const uint_fast8_t data_count); void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count);
void si5351c_set_clock_source(const enum pll_sources source);
void si5351c_activate_best_clock_source(void);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -139,6 +139,8 @@ macro(DeclareTargets)
${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c
${PATH_HACKRF_FIRMWARE_COMMON}/max5864_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864_target.c
${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071.c ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071.c
${PATH_HACKRF_FIRMWARE_COMMON}/i2c_bus.c
${PATH_HACKRF_FIRMWARE_COMMON}/i2c_lpc.c
${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071_spi.c ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071_spi.c
${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv.c ${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv.c
${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv_target.c

View File

@ -75,7 +75,7 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
} }
if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) { if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) {
si5351c_activate_best_clock_source(); si5351c_activate_best_clock_source(&clock_gen);
baseband_streaming_enable(); baseband_streaming_enable();
} }
} }

View File

@ -22,9 +22,9 @@
#include "usb_api_register.h" #include "usb_api_register.h"
#include <hackrf_core.h>
#include <usb_queue.h> #include <usb_queue.h>
#include <max2837.h> #include <max2837.h>
#include <si5351c.h>
#include <rffc5071.h> #include <rffc5071.h>
#include <stddef.h> #include <stddef.h>
@ -77,7 +77,7 @@ usb_request_status_t usb_vendor_request_write_si5351c(
if( stage == USB_TRANSFER_STAGE_SETUP ) { if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < 256 ) { if( endpoint->setup.index < 256 ) {
if( endpoint->setup.value < 256 ) { if( endpoint->setup.value < 256 ) {
si5351c_write_single(endpoint->setup.index, endpoint->setup.value); si5351c_write_single(&clock_gen, endpoint->setup.index, endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
} }
@ -94,7 +94,7 @@ usb_request_status_t usb_vendor_request_read_si5351c(
) { ) {
if( stage == USB_TRANSFER_STAGE_SETUP ) { if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < 256 ) { if( endpoint->setup.index < 256 ) {
const uint8_t value = si5351c_read_single(endpoint->setup.index); const uint8_t value = si5351c_read_single(&clock_gen, endpoint->setup.index);
endpoint->buffer[0] = value; endpoint->buffer[0] = value;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL); NULL, NULL);