Si5351C: Un-singleton the high- and low-level drivers. Proper.

This commit is contained in:
Jared Boone
2014-11-04 10:45:24 -08:00
parent 0bf84d974e
commit 3bc41f1480
8 changed files with 106 additions and 91 deletions

View File

@ -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 */

View File

@ -32,6 +32,8 @@ extern "C"
#include <stdint.h>
#include <stdbool.h>
#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);

View File

@ -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);
}
}
}

View File

@ -30,6 +30,8 @@ extern "C"
#include <stdint.h>
#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
}

View File

@ -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]);

View File

@ -30,9 +30,13 @@ extern "C"
#include <stdint.h>
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
}

View File

@ -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();
}
}

View File

@ -22,9 +22,9 @@
#include "usb_api_register.h"
#include <hackrf_core.h>
#include <usb_queue.h>
#include <max2837.h>
#include <si5351c_drv.h>
#include <rffc5071.h>
#include <stddef.h>
@ -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);