From 0bf84d974e94d4f612a1287b0a8901af4f729503 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Nov 2014 09:58:31 -0800 Subject: [PATCH 1/9] Si5351C: Extract low-level driver code. --- firmware/common/hackrf_core.c | 1 + firmware/common/si5351c.c | 50 +---------------- firmware/common/si5351c.h | 5 -- firmware/common/si5351c_drv.c | 74 ++++++++++++++++++++++++++ firmware/common/si5351c_drv.h | 41 ++++++++++++++ firmware/hackrf-common.cmake | 1 + firmware/hackrf_usb/usb_api_register.c | 2 +- 7 files changed, 120 insertions(+), 54 deletions(-) create mode 100644 firmware/common/si5351c_drv.c create mode 100644 firmware/common/si5351c_drv.h diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index b862ba4f..cd1c8005 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -23,6 +23,7 @@ #include "hackrf_core.h" #include "si5351c.h" +#include "si5351c_drv.h" #include "max2837.h" #include "rffc5071.h" #include "sgpio.h" diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 58b614dc..3be5041a 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -21,57 +21,11 @@ */ #include "si5351c.h" -#include + +#include "si5351c_drv.h" 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) -{ - i2c0_tx_start(); - i2c0_tx_byte(SI5351C_I2C_ADDR | 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 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; -} - -/* - * 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) -{ - 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(); -} - /* Disable all CLKx outputs. */ void si5351c_disable_all_outputs() { diff --git a/firmware/common/si5351c.h b/firmware/common/si5351c.h index b62279d7..fcc2d2b8 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -31,7 +31,6 @@ extern "C" #include #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) @@ -76,10 +75,6 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number, 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_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); diff --git a/firmware/common/si5351c_drv.c b/firmware/common/si5351c_drv.c new file mode 100644 index 00000000..e63912c1 --- /dev/null +++ b/firmware/common/si5351c_drv.c @@ -0,0 +1,74 @@ +/* + * 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 "si5351c_drv.h" + +#include + +#define SI5351C_I2C_ADDR (0x60 << 1) + +/* FIXME return i2c0 status from each function */ + +/* write to single register */ +void si5351c_write_single(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(); +} + +/* read single register */ +uint8_t si5351c_read_single(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; +} + +/* + * 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) +{ + 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(); +} diff --git a/firmware/common/si5351c_drv.h b/firmware/common/si5351c_drv.h new file mode 100644 index 00000000..501b221e --- /dev/null +++ b/firmware/common/si5351c_drv.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef __SI5351C_DRV_H +#define __SI5351C_DRV_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#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); + +#ifdef __cplusplus +} +#endif + +#endif /* __SI5351C_DRV_H */ diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index df5d5c96..9b4fb9a9 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -134,6 +134,7 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/sgpio.c ${PATH_HACKRF_FIRMWARE_COMMON}/rf_path.c ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.c + ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c_drv.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2837.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071.c diff --git a/firmware/hackrf_usb/usb_api_register.c b/firmware/hackrf_usb/usb_api_register.c index d822c924..9478e7c1 100644 --- a/firmware/hackrf_usb/usb_api_register.c +++ b/firmware/hackrf_usb/usb_api_register.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include From 3bc41f1480401ea09b49bd1c06bfb28865b8b148 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Nov 2014 10:45:24 -0800 Subject: [PATCH 2/9] Si5351C: Un-singleton the high- and low-level drivers. Proper. --- firmware/common/hackrf_core.c | 61 ++++++++++++----------- firmware/common/hackrf_core.h | 4 ++ firmware/common/si5351c.c | 69 +++++++++++++------------- firmware/common/si5351c.h | 31 ++++++------ firmware/common/si5351c_drv.c | 14 +++--- firmware/common/si5351c_drv.h | 10 ++-- firmware/hackrf_usb/hackrf_usb.c | 2 +- firmware/hackrf_usb/usb_api_register.c | 6 +-- 8 files changed, 106 insertions(+), 91 deletions(-) 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); From 721f74867779291e11dcf69ffe313b45213f84cf Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 12 Nov 2014 10:21:34 -0800 Subject: [PATCH 3/9] Si5351C: Change write data arg to be const. --- firmware/common/si5351c_drv.c | 2 +- firmware/common/si5351c_drv.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/common/si5351c_drv.c b/firmware/common/si5351c_drv.c index 4cb58cd6..4c17ae45 100644 --- a/firmware/common/si5351c_drv.c +++ b/firmware/common/si5351c_drv.c @@ -61,7 +61,7 @@ uint8_t si5351c_read_single(si5351c_driver_t* const drv, 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(si5351c_driver_t* const drv, uint8_t* const data, const uint_fast8_t data_count) +void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const uint_fast8_t data_count) { uint_fast8_t i; diff --git a/firmware/common/si5351c_drv.h b/firmware/common/si5351c_drv.h index 61c6f374..2e94e0bd 100644 --- a/firmware/common/si5351c_drv.h +++ b/firmware/common/si5351c_drv.h @@ -36,7 +36,7 @@ typedef struct { 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); +void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const uint_fast8_t data_count); #ifdef __cplusplus } From 4ea0f28d14a086c64c7e9f04707910b8776b4f02 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 12 Nov 2014 10:23:00 -0800 Subject: [PATCH 4/9] SI5351C: Rewrite si5351c_write_single() to use si5351c_write(). --- firmware/common/si5351c_drv.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/firmware/common/si5351c_drv.c b/firmware/common/si5351c_drv.c index 4c17ae45..207269d6 100644 --- a/firmware/common/si5351c_drv.c +++ b/firmware/common/si5351c_drv.c @@ -31,11 +31,8 @@ /* write to single register */ void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val) { - i2c0_tx_start(); - i2c0_tx_byte((drv->i2c_address << 1) | 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 */ From 35b549816a387d2c579a5d106720636f8ee78cbf Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 12 Nov 2014 10:37:58 -0800 Subject: [PATCH 5/9] Si5351C: Widen write() data_count argument type to size_t. --- firmware/common/si5351c_drv.c | 2 +- firmware/common/si5351c_drv.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/firmware/common/si5351c_drv.c b/firmware/common/si5351c_drv.c index 207269d6..85596839 100644 --- a/firmware/common/si5351c_drv.c +++ b/firmware/common/si5351c_drv.c @@ -58,7 +58,7 @@ uint8_t si5351c_read_single(si5351c_driver_t* const drv, 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(si5351c_driver_t* const drv, const 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; diff --git a/firmware/common/si5351c_drv.h b/firmware/common/si5351c_drv.h index 2e94e0bd..147e91fa 100644 --- a/firmware/common/si5351c_drv.h +++ b/firmware/common/si5351c_drv.h @@ -29,6 +29,7 @@ extern "C" #endif #include +#include typedef struct { uint8_t i2c_address; @@ -36,7 +37,7 @@ typedef struct { 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 uint_fast8_t data_count); +void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count); #ifdef __cplusplus } From 080a1ba9ac97ef5817d0302f0a408d95403c058a Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 12 Nov 2014 10:45:26 -0800 Subject: [PATCH 6/9] Si5351C: Extract I2C code into single transfer function. --- firmware/common/si5351c_drv.c | 51 ++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/firmware/common/si5351c_drv.c b/firmware/common/si5351c_drv.c index 85596839..e2c87eff 100644 --- a/firmware/common/si5351c_drv.c +++ b/firmware/common/si5351c_drv.c @@ -28,6 +28,30 @@ /* FIXME return i2c0 status from each function */ +static void i2c0_transfer(si5351c_driver_t* const drv, + const uint_fast8_t address, + const uint8_t* const data_tx, const size_t count_tx, + uint8_t* const data_rx, const size_t count_rx +) { + (void)drv; + + i2c0_tx_start(); + i2c0_tx_byte((address << 1) | I2C_WRITE); + for(size_t i=0; ii2c_address << 1) | I2C_WRITE); - i2c0_tx_byte(reg); - - /* read the value */ - i2c0_tx_start(); - i2c0_tx_byte((drv->i2c_address << 1) | I2C_READ); - val = i2c0_rx_byte(); - i2c0_stop(); - - return val; + const uint8_t data_tx[] = { reg }; + uint8_t data_rx[] = { 0x00 }; + i2c0_transfer(drv, drv->i2c_address, data_tx, 1, data_rx, 1); + return data_rx[0]; } /* @@ -60,12 +74,5 @@ 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) { - uint_fast8_t i; - - i2c0_tx_start(); - i2c0_tx_byte((drv->i2c_address << 1) | I2C_WRITE); - - for (i = 0; i < data_count; i++) - i2c0_tx_byte(data[i]); - i2c0_stop(); + i2c0_transfer(drv, drv->i2c_address, data, data_count, NULL, 0); } From eb0dea483fa120fc8c4252ba0c7331879fe3d189 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 12 Nov 2014 13:56:58 -0800 Subject: [PATCH 7/9] I2C: Finish extracting from Si5351C code. --- firmware/common/hackrf_core.c | 31 +++++++++++++++++-- firmware/common/i2c_bus.c | 35 +++++++++++++++++++++ firmware/common/i2c_bus.h | 50 ++++++++++++++++++++++++++++++ firmware/common/i2c_lpc.c | 57 +++++++++++++++++++++++++++++++++++ firmware/common/i2c_lpc.h | 41 +++++++++++++++++++++++++ firmware/common/si5351c_drv.c | 34 ++------------------- firmware/common/si5351c_drv.h | 3 ++ firmware/hackrf-common.cmake | 2 ++ firmware/libopencm3 | 2 +- 9 files changed, 219 insertions(+), 36 deletions(-) create mode 100644 firmware/common/i2c_bus.c create mode 100644 firmware/common/i2c_bus.h create mode 100644 firmware/common/i2c_lpc.c create mode 100644 firmware/common/i2c_lpc.h diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 792beec3..a562f7c6 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -27,7 +27,8 @@ #include "rffc5071.h" #include "sgpio.h" #include "rf_path.h" -#include +#include "i2c_bus.h" +#include "i2c_lpc.h" #include #include #include @@ -35,7 +36,28 @@ #define WAIT_CPU_CLOCK_INIT_DELAY (10000) +i2c_bus_t i2c0 = { + .obj = (void*)I2C0_BASE, + .init = i2c_lpc_init, + .transfer = i2c_lpc_transfer, +}; + +i2c_bus_t i2c1 = { + .obj = (void*)I2C1_BASE, + .init = i2c_lpc_init, + .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, }; @@ -268,7 +290,7 @@ 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_init(clock_gen.bus, &i2c_config_si5351c_slow_clock); si5351c_disable_all_outputs(&clock_gen); si5351c_disable_oeb_pin_control(&clock_gen); @@ -340,7 +362,7 @@ void cpu_clock_init(void) //FIXME disable I2C /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ - i2c0_init(255); + i2c_bus_init(clock_gen.bus, &i2c_config_si5351c_fast_clock); /* * 12MHz clock is entering LPC XTAL1/OSC input now. On @@ -615,6 +637,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; + rf_path_pin_setup(); /* Configure SSP1 Peripheral (to be moved later in SSP driver) */ diff --git a/firmware/common/i2c_bus.c b/firmware/common/i2c_bus.c new file mode 100644 index 00000000..6b60455a --- /dev/null +++ b/firmware/common/i2c_bus.c @@ -0,0 +1,35 @@ +/* + * 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_init(i2c_bus_t* const bus, const void* const config) { + bus->init(bus, config); +} + +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..784fb602 --- /dev/null +++ b/firmware/common/i2c_bus.h @@ -0,0 +1,50 @@ +/* + * 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 (*init)(i2c_bus_t* const bus, const void* const config); + 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_init(i2c_bus_t* const bus, const void* const config); +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..73c3e92c --- /dev/null +++ b/firmware/common/i2c_lpc.c @@ -0,0 +1,57 @@ +/* + * 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_init(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_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_init(i2c_bus_t* const bus, const void* const config); +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_drv.c b/firmware/common/si5351c_drv.c index e2c87eff..2b788842 100644 --- a/firmware/common/si5351c_drv.c +++ b/firmware/common/si5351c_drv.c @@ -22,36 +22,6 @@ #include "si5351c_drv.h" -#include - -#define SI5351C_I2C_ADDR (0x60 << 1) - -/* FIXME return i2c0 status from each function */ - -static void i2c0_transfer(si5351c_driver_t* const drv, - const uint_fast8_t address, - const uint8_t* const data_tx, const size_t count_tx, - uint8_t* const data_rx, const size_t count_rx -) { - (void)drv; - - i2c0_tx_start(); - i2c0_tx_byte((address << 1) | I2C_WRITE); - for(size_t i=0; ii2c_address, data_tx, 1, data_rx, 1); + i2c_bus_transfer(drv->bus, drv->i2c_address, data_tx, 1, data_rx, 1); return data_rx[0]; } @@ -74,5 +44,5 @@ 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) { - i2c0_transfer(drv, drv->i2c_address, data, data_count, NULL, 0); + i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0); } diff --git a/firmware/common/si5351c_drv.h b/firmware/common/si5351c_drv.h index 147e91fa..acb71459 100644 --- a/firmware/common/si5351c_drv.h +++ b/firmware/common/si5351c_drv.h @@ -31,7 +31,10 @@ extern "C" #include #include +#include "i2c_bus.h" + typedef struct { + i2c_bus_t* const bus; uint8_t i2c_address; } si5351c_driver_t; diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index 9b4fb9a9..decd2bed 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -138,6 +138,8 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/max2837.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071.c + ${PATH_HACKRF_FIRMWARE_COMMON}/i2c_bus.c + ${PATH_HACKRF_FIRMWARE_COMMON}/i2c_lpc.c m0_bin.s ) diff --git a/firmware/libopencm3 b/firmware/libopencm3 index 854c112a..aec04e96 160000 --- a/firmware/libopencm3 +++ b/firmware/libopencm3 @@ -1 +1 @@ -Subproject commit 854c112a0ea7b27e85a15345507c8a2e13e76607 +Subproject commit aec04e962c2264877580be30fe1e1178ce3f568c From 28d629e0993985430284e2c4625af4c45d55ac0e Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 12 Nov 2014 18:32:00 -0800 Subject: [PATCH 8/9] Si5351C: Bring I2C wrapper into main driver. --- firmware/common/hackrf_core.h | 2 +- firmware/common/si5351c.c | 27 +++++++++++++++++-- firmware/common/si5351c.h | 11 +++++++- firmware/common/si5351c_drv.c | 48 ---------------------------------- firmware/common/si5351c_drv.h | 49 ----------------------------------- firmware/hackrf-common.cmake | 1 - 6 files changed, 36 insertions(+), 102 deletions(-) delete mode 100644 firmware/common/si5351c_drv.c delete mode 100644 firmware/common/si5351c_drv.h diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 7ad1ad50..ae7c7a2d 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -32,7 +32,7 @@ extern "C" #include #include -#include "si5351c_drv.h" +#include "si5351c.h" /* hardware identification number */ #define BOARD_ID_JELLYBEAN 0 diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index f6b4483a..36730930 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -22,10 +22,33 @@ #include "si5351c.h" -#include "si5351c_drv.h" - enum pll_sources active_clock_source; +/* write to single register */ +void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val) +{ + const uint8_t data_tx[] = { reg, val }; + si5351c_write(drv, data_tx, 2); +} + +/* read single register */ +uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg) +{ + 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(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count) +{ + i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0); +} + /* Disable all CLKx outputs. */ void si5351c_disable_all_outputs(si5351c_driver_t* const drv) { diff --git a/firmware/common/si5351c.h b/firmware/common/si5351c.h index 7151f990..d10a0a93 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -30,7 +30,7 @@ extern "C" #include -#include "si5351c_drv.h" +#include "i2c_bus.h" #define SI_INTDIV(x) (x*128-512) @@ -63,6 +63,11 @@ enum pll_sources { PLL_SOURCE_CLKIN = 1, }; +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); @@ -81,6 +86,10 @@ void si5351c_set_int_mode(si5351c_driver_t* const drv, const uint_fast8_t ms_num 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(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 } #endif diff --git a/firmware/common/si5351c_drv.c b/firmware/common/si5351c_drv.c deleted file mode 100644 index 2b788842..00000000 --- a/firmware/common/si5351c_drv.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 "si5351c_drv.h" - -/* write to single register */ -void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val) -{ - const uint8_t data_tx[] = { reg, val }; - si5351c_write(drv, data_tx, 2); -} - -/* read single register */ -uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg) -{ - 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(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count) -{ - i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0); -} diff --git a/firmware/common/si5351c_drv.h b/firmware/common/si5351c_drv.h deleted file mode 100644 index acb71459..00000000 --- a/firmware/common/si5351c_drv.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#ifndef __SI5351C_DRV_H -#define __SI5351C_DRV_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include -#include - -#include "i2c_bus.h" - -typedef struct { - i2c_bus_t* const bus; - 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, const uint8_t* const data, const size_t data_count); - -#ifdef __cplusplus -} -#endif - -#endif /* __SI5351C_DRV_H */ diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index decd2bed..b7a0ec91 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -134,7 +134,6 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/sgpio.c ${PATH_HACKRF_FIRMWARE_COMMON}/rf_path.c ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.c - ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c_drv.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2837.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071.c From 02cc5814b15dfc666d6a0bcdedaec4583a659550 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 13 Nov 2014 10:32:38 -0800 Subject: [PATCH 9/9] I2C: Interface: Rename init()->start(), add stop(). --- firmware/common/hackrf_core.c | 10 ++++++---- firmware/common/i2c_bus.c | 8 ++++++-- firmware/common/i2c_bus.h | 6 ++++-- firmware/common/i2c_lpc.c | 7 ++++++- firmware/common/i2c_lpc.h | 3 ++- firmware/libopencm3 | 2 +- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index a562f7c6..1af5e823 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -38,13 +38,15 @@ i2c_bus_t i2c0 = { .obj = (void*)I2C0_BASE, - .init = i2c_lpc_init, + .start = i2c_lpc_start, + .stop = i2c_lpc_stop, .transfer = i2c_lpc_transfer, }; i2c_bus_t i2c1 = { .obj = (void*)I2C1_BASE, - .init = i2c_lpc_init, + .start = i2c_lpc_start, + .stop = i2c_lpc_stop, .transfer = i2c_lpc_transfer, }; @@ -290,7 +292,7 @@ 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); - i2c_bus_init(clock_gen.bus, &i2c_config_si5351c_slow_clock); + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_slow_clock); si5351c_disable_all_outputs(&clock_gen); si5351c_disable_oeb_pin_control(&clock_gen); @@ -362,7 +364,7 @@ void cpu_clock_init(void) //FIXME disable I2C /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ - i2c_bus_init(clock_gen.bus, &i2c_config_si5351c_fast_clock); + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); /* * 12MHz clock is entering LPC XTAL1/OSC input now. On diff --git a/firmware/common/i2c_bus.c b/firmware/common/i2c_bus.c index 6b60455a..7b5497e0 100644 --- a/firmware/common/i2c_bus.c +++ b/firmware/common/i2c_bus.c @@ -21,8 +21,12 @@ #include "i2c_bus.h" -void i2c_bus_init(i2c_bus_t* const bus, const void* const config) { - bus->init(bus, config); +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( diff --git a/firmware/common/i2c_bus.h b/firmware/common/i2c_bus.h index 784fb602..04b83499 100644 --- a/firmware/common/i2c_bus.h +++ b/firmware/common/i2c_bus.h @@ -30,7 +30,8 @@ typedef struct i2c_bus_t i2c_bus_t; struct i2c_bus_t { void* const obj; - void (*init)(i2c_bus_t* const bus, const void* const config); + 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, @@ -39,7 +40,8 @@ struct i2c_bus_t { ); }; -void i2c_bus_init(i2c_bus_t* const bus, const void* const config); +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, diff --git a/firmware/common/i2c_lpc.c b/firmware/common/i2c_lpc.c index 73c3e92c..f7bf4393 100644 --- a/firmware/common/i2c_lpc.c +++ b/firmware/common/i2c_lpc.c @@ -26,13 +26,18 @@ /* FIXME return i2c0 status from each function */ -void i2c_lpc_init(i2c_bus_t* const bus, const void* const _config) { +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, diff --git a/firmware/common/i2c_lpc.h b/firmware/common/i2c_lpc.h index 16c04a22..32c79fcd 100644 --- a/firmware/common/i2c_lpc.h +++ b/firmware/common/i2c_lpc.h @@ -31,7 +31,8 @@ typedef struct i2c_lpc_config_t { const uint16_t duty_cycle_count; } i2c_lpc_config_t; -void i2c_lpc_init(i2c_bus_t* const bus, const void* const config); +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, diff --git a/firmware/libopencm3 b/firmware/libopencm3 index aec04e96..10503c7c 160000 --- a/firmware/libopencm3 +++ b/firmware/libopencm3 @@ -1 +1 @@ -Subproject commit aec04e962c2264877580be30fe1e1178ce3f568c +Subproject commit 10503c7cc19647393d98cc66c3dbaf20bd634494