diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index a1ad6008..f5f025ef 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -34,7 +34,8 @@ #include "w25q80bv_target.h" #include "sgpio.h" #include "rf_path.h" -#include +#include "i2c_bus.h" +#include "i2c_lpc.h" #include #include #include @@ -42,6 +43,33 @@ #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 = { /* 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 ? */ 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; @@ -219,13 +247,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; } @@ -265,13 +293,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 @@ -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). */ - 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 @@ -355,15 +383,15 @@ void cpu_clock_init(void) /* use IRC as clock source for APB3 */ 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_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 /* @@ -379,13 +407,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) @@ -402,32 +430,32 @@ 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 */ - i2c0_init(255); + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); /* * 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_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_rffc5071, NULL); diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 2bda7e4c..c41fd83b 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -32,6 +32,7 @@ extern "C" #include #include +#include "si5351c.h" #include "spi_ssp.h" #include "max2837.h" @@ -358,6 +359,7 @@ typedef enum { void delay(uint32_t duration); /* 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_max2837; extern const ssp_config_t ssp_config_max5864; diff --git a/firmware/common/i2c_bus.c b/firmware/common/i2c_bus.c new file mode 100644 index 00000000..7b5497e0 --- /dev/null +++ b/firmware/common/i2c_bus.c @@ -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); +} diff --git a/firmware/common/i2c_bus.h b/firmware/common/i2c_bus.h new file mode 100644 index 00000000..04b83499 --- /dev/null +++ b/firmware/common/i2c_bus.h @@ -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 +#include + +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__*/ diff --git a/firmware/common/i2c_lpc.c b/firmware/common/i2c_lpc.c new file mode 100644 index 00000000..f7bf4393 --- /dev/null +++ b/firmware/common/i2c_lpc.c @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Michael Ossmann + * Copyright 2012 Jared Boone + * + * 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 + +/* 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 +#include + +#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__*/ diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 58b614dc..36730930 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -21,73 +21,50 @@ */ #include "si5351c.h" -#include enum pll_sources active_clock_source; -/* 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(reg); - i2c0_tx_byte(val); - i2c0_stop(); + const uint8_t data_tx[] = { reg, val }; + si5351c_write(drv, data_tx, 2); } /* 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(reg); - - /* read the value */ - i2c0_tx_start(); - i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_READ); - val = i2c0_rx_byte(); - i2c0_stop(); - - return val; + const uint8_t data_tx[] = { reg }; + uint8_t data_rx[] = { 0x00 }; + i2c_bus_transfer(drv->bus, drv->i2c_address, data_tx, 1, data_rx, 1); + return data_rx[0]; } /* * 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, const uint8_t* const data, const size_t data_count) { - uint_fast8_t i; - - 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(); + i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0); } /* 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 @@ -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_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 * 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)); } /* @@ -129,34 +106,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) { @@ -183,7 +161,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 @@ -232,15 +210,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; @@ -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_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 b62279d7..d10a0a93 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -30,8 +30,9 @@ extern "C" #include +#include "i2c_bus.h" + #define SI_INTDIV(x) (x*128-512) -#define SI5351C_I2C_ADDR (0x60 << 1) #define SI5351C_CLK_POWERDOWN (1<<7) #define SI5351C_CLK_INT_MODE (1<<6) @@ -62,26 +63,32 @@ 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, +typedef struct { + i2c_bus_t* const bus; + uint8_t i2c_address; +} si5351c_driver_t; + +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_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); -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); -void si5351c_set_clock_source(const enum pll_sources source); -void si5351c_activate_best_clock_source(void); +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, const uint8_t* const data, const size_t data_count); #ifdef __cplusplus } diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index f585181a..e39343f6 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -139,6 +139,8 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864_target.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}/w25q80bv.c ${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv_target.c diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 2e6a4140..2573b37a 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 c8b8678a..373354d9 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 @@ -77,7 +77,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; } @@ -94,7 +94,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); diff --git a/firmware/libopencm3 b/firmware/libopencm3 index 854c112a..10503c7c 160000 --- a/firmware/libopencm3 +++ b/firmware/libopencm3 @@ -1 +1 @@ -Subproject commit 854c112a0ea7b27e85a15345507c8a2e13e76607 +Subproject commit 10503c7cc19647393d98cc66c3dbaf20bd634494