diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index cd1c8005..792beec3 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -23,7 +23,6 @@ #include "hackrf_core.h" #include "si5351c.h" -#include "si5351c_drv.h" #include "max2837.h" #include "rffc5071.h" #include "sgpio.h" @@ -36,6 +35,10 @@ #define WAIT_CPU_CLOCK_INIT_DELAY (10000) +si5351c_driver_t clock_gen = { + .i2c_address = 0x60, +}; + void delay(uint32_t duration) { uint32_t i; @@ -119,9 +122,9 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom) /* Can we enable integer mode ? */ if (a & 0x1 || b) - si5351c_set_int_mode(0, 0); + si5351c_set_int_mode(&clock_gen, 0, 0); else - si5351c_set_int_mode(0, 1); + si5351c_set_int_mode(&clock_gen, 0, 1); /* Final MS values */ MSx_P1 = 128*a + (128 * b/c) - 512; @@ -129,13 +132,13 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom) MSx_P3 = c; /* 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). */ - 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) */ - 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; } @@ -175,13 +178,13 @@ bool sample_rate_set(const uint32_t sample_rate_hz) { * values are irrelevant. */ /* 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). */ - 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. */ - si5351c_configure_multisynth(3, 4608, 0, 1, r_div_sgpio); + si5351c_configure_multisynth(&clock_gen, 3, 4608, 0, 1, r_div_sgpio); return true; #endif @@ -238,13 +241,13 @@ bool sample_rate_set(const uint32_t sample_rate_hz) { } /* 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). */ - 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) */ - 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; #endif @@ -267,13 +270,13 @@ void cpu_clock_init(void) i2c0_init(15); - si5351c_disable_all_outputs(); - si5351c_disable_oeb_pin_control(); - si5351c_power_down_all_clocks(); - si5351c_set_crystal_configuration(); - si5351c_enable_xo_and_ms_fanout(); - si5351c_configure_pll_sources(); - si5351c_configure_pll_multisynth(); + si5351c_disable_all_outputs(&clock_gen); + si5351c_disable_oeb_pin_control(&clock_gen); + si5351c_power_down_all_clocks(&clock_gen); + si5351c_set_crystal_configuration(&clock_gen); + si5351c_enable_xo_and_ms_fanout(&clock_gen); + si5351c_configure_pll_sources(&clock_gen); + si5351c_configure_pll_multisynth(&clock_gen); #ifdef JELLYBEAN /* @@ -289,13 +292,13 @@ void cpu_clock_init(void) */ /* 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. */ - 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. */ - si5351c_configure_multisynth(5, 1536, 0, 1, 0); /* 50MHz */ + si5351c_configure_multisynth(&clock_gen, 5, 1536, 0, 1, 0); /* 50MHz */ #endif #if (defined JAWBREAKER || defined HACKRF_ONE) @@ -312,28 +315,28 @@ void cpu_clock_init(void) */ /* 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. */ - 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. */ - 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. */ /* MS7/CLK7 is the source for the LPC43xx microcontroller. */ uint8_t ms7data[] = { 90, 255, 20, 0 }; - si5351c_write(ms7data, sizeof(ms7data)); + si5351c_write(&clock_gen, ms7data, sizeof(ms7data)); #endif /* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */ sample_rate_set(10000000); - si5351c_set_clock_source(PLL_SOURCE_XTAL); + si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL); // soft reset uint8_t resetdata[] = { 177, 0xac }; - si5351c_write(resetdata, sizeof(resetdata)); - si5351c_enable_clock_outputs(); + si5351c_write(&clock_gen, resetdata, sizeof(resetdata)); + si5351c_enable_clock_outputs(&clock_gen); //FIXME disable I2C /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 8ce6c943..7ad1ad50 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -32,6 +32,8 @@ extern "C" #include #include +#include "si5351c_drv.h" + /* hardware identification number */ #define BOARD_ID_JELLYBEAN 0 #define BOARD_ID_JAWBREAKER 1 @@ -350,6 +352,8 @@ typedef enum { void delay(uint32_t duration); +extern si5351c_driver_t clock_gen; + void cpu_clock_init(void); void cpu_clock_pll1_low_speed(void); void cpu_clock_pll1_max_speed(void); diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 3be5041a..f6b4483a 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -27,21 +27,21 @@ enum pll_sources active_clock_source; /* Disable all CLKx outputs. */ -void si5351c_disable_all_outputs() +void si5351c_disable_all_outputs(si5351c_driver_t* const drv) { uint8_t data[] = { 3, 0xFF }; - si5351c_write(data, sizeof(data)); + si5351c_write(drv, data, sizeof(data)); } /* 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 }; - si5351c_write(data, sizeof(data)); + si5351c_write(drv, data, sizeof(data)); } /* 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 , SI5351C_CLK_POWERDOWN @@ -53,7 +53,7 @@ void si5351c_power_down_all_clocks() , 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)); } /* @@ -61,20 +61,20 @@ void si5351c_power_down_all_clocks() * Reads as 0xE4 on power-up * 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 }; - si5351c_write(data, sizeof(data)); + si5351c_write(drv, data, sizeof(data)); } /* * Register 187: Fanout Enable * 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 }; - si5351c_write(data, sizeof(data)); + si5351c_write(drv, data, sizeof(data)); } /* @@ -83,34 +83,35 @@ void si5351c_enable_xo_and_ms_fanout() * PLLA_SRC=0 (XTAL) * 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 }; - si5351c_write(data, sizeof(data)); + si5351c_write(drv, data, sizeof(data)); } /* 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 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 */ data[0] = 34; 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 */ 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 uint_fast8_t r_div) { @@ -137,7 +138,7 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number, (((p3 >> 16) & 0xF) << 4) | (((p2 >> 16) & 0xF) << 0), (p2 >> 8) & 0xFF, (p2 >> 0) & 0xFF }; - si5351c_write(data, sizeof(data)); + si5351c_write(drv, data, sizeof(data)); } #ifdef JELLYBEAN @@ -186,15 +187,15 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number, * CLK5_SRC=3 (MS5 as input source) * 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 }; - si5351c_write(data, sizeof(data)); + si5351c_write(drv, data, sizeof(data)); } #endif #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; @@ -215,54 +216,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_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 /* 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 }; - 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}; if(ms_number < 8){ data[0] = 16 + ms_number; - data[1] = si5351c_read_single(data[0]); + data[1] = si5351c_read_single(drv, data[0]); if(on) data[1] |= SI5351C_CLK_INT_MODE; else 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; } -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) { /* CLKIN not detected */ if (active_clock_source == PLL_SOURCE_CLKIN) { - si5351c_set_clock_source(PLL_SOURCE_XTAL); + si5351c_set_clock_source(drv, PLL_SOURCE_XTAL); } } else { /* CLKIN detected */ if (active_clock_source == PLL_SOURCE_XTAL) { - si5351c_set_clock_source(PLL_SOURCE_CLKIN); + si5351c_set_clock_source(drv, PLL_SOURCE_CLKIN); } } } diff --git a/firmware/common/si5351c.h b/firmware/common/si5351c.h index fcc2d2b8..7151f990 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -30,6 +30,8 @@ extern "C" #include +#include "si5351c_drv.h" + #define SI_INTDIV(x) (x*128-512) #define SI5351C_CLK_POWERDOWN (1<<7) @@ -61,22 +63,23 @@ enum pll_sources { PLL_SOURCE_CLKIN = 1, }; -void si5351c_disable_all_outputs(); -void si5351c_disable_oeb_pin_control(); -void si5351c_power_down_all_clocks(); -void si5351c_set_crystal_configuration(); -void si5351c_enable_xo_and_ms_fanout(); -void si5351c_configure_pll_sources(void); -void si5351c_configure_pll_multisynth(void); -void si5351c_reset_pll(void); -void si5351c_configure_multisynth(const uint_fast8_t ms_number, +void si5351c_disable_all_outputs(si5351c_driver_t* const drv); +void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv); +void si5351c_power_down_all_clocks(si5351c_driver_t* const drv); +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 uint_fast8_t r_div); -void si5351c_configure_clock_control(const enum pll_sources source); -void si5351c_enable_clock_outputs(); -void si5351c_set_int_mode(const uint_fast8_t ms_number, const uint_fast8_t on); -void si5351c_set_clock_source(const enum pll_sources source); -void si5351c_activate_best_clock_source(void); +void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll_sources source); +void si5351c_enable_clock_outputs(si5351c_driver_t* const drv); +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); #ifdef __cplusplus } diff --git a/firmware/common/si5351c_drv.c b/firmware/common/si5351c_drv.c index e63912c1..4cb58cd6 100644 --- a/firmware/common/si5351c_drv.c +++ b/firmware/common/si5351c_drv.c @@ -29,28 +29,28 @@ /* FIXME return i2c0 status from each function */ /* 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(); - i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE); + i2c0_tx_byte((drv->i2c_address << 1) | I2C_WRITE); i2c0_tx_byte(reg); i2c0_tx_byte(val); i2c0_stop(); } /* 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; /* set register address with write */ i2c0_tx_start(); - i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE); + i2c0_tx_byte((drv->i2c_address << 1) | I2C_WRITE); i2c0_tx_byte(reg); /* read the value */ i2c0_tx_start(); - i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_READ); + i2c0_tx_byte((drv->i2c_address << 1) | I2C_READ); val = i2c0_rx_byte(); i2c0_stop(); @@ -61,12 +61,12 @@ uint8_t si5351c_read_single(uint8_t reg) * Write to one or more contiguous registers. data[0] should be the first * 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, uint8_t* const data, const uint_fast8_t data_count) { uint_fast8_t i; i2c0_tx_start(); - i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE); + i2c0_tx_byte((drv->i2c_address << 1) | I2C_WRITE); for (i = 0; i < data_count; i++) i2c0_tx_byte(data[i]); diff --git a/firmware/common/si5351c_drv.h b/firmware/common/si5351c_drv.h index 501b221e..61c6f374 100644 --- a/firmware/common/si5351c_drv.h +++ b/firmware/common/si5351c_drv.h @@ -30,9 +30,13 @@ extern "C" #include -void si5351c_write_single(uint8_t reg, uint8_t val); -uint8_t si5351c_read_single(uint8_t reg); -void si5351c_write(uint8_t* const data, const uint_fast8_t data_count); +typedef struct { + uint8_t i2c_address; +} si5351c_driver_t; + +void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val); +uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg); +void si5351c_write(si5351c_driver_t* const drv, uint8_t* const data, const uint_fast8_t data_count); #ifdef __cplusplus } diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 42fc4482..0ed260c5 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -75,7 +75,7 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) { } if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) { - si5351c_activate_best_clock_source(); + si5351c_activate_best_clock_source(&clock_gen); baseband_streaming_enable(); } } diff --git a/firmware/hackrf_usb/usb_api_register.c b/firmware/hackrf_usb/usb_api_register.c index 9478e7c1..35b9e012 100644 --- a/firmware/hackrf_usb/usb_api_register.c +++ b/firmware/hackrf_usb/usb_api_register.c @@ -22,9 +22,9 @@ #include "usb_api_register.h" +#include #include #include -#include #include #include @@ -75,7 +75,7 @@ usb_request_status_t usb_vendor_request_write_si5351c( if( stage == USB_TRANSFER_STAGE_SETUP ) { if( endpoint->setup.index < 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); return USB_REQUEST_STATUS_OK; } @@ -92,7 +92,7 @@ usb_request_status_t usb_vendor_request_read_si5351c( ) { if( stage == USB_TRANSFER_STAGE_SETUP ) { 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; usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL);