Big work around si5351 generator

Improve sweep speed about 60%
Stop generation on pause sweep
Remove all hack for si5351
Reduce code size
Fix integer overflow on big freq values

Additional
Change I2C

Others:
 move marker_tracking variable to ui config
 move some definition to correct place
 reduce tlv320aic3204 code size
 Speedup marker move from lever (BUTTON_REPEAT_TICKS = 625)

Need test stability
This commit is contained in:
DiSlord 2020-03-05 22:36:44 +03:00
parent f1cc60e99e
commit b77e1d6680
7 changed files with 372 additions and 371 deletions

75
main.c
View file

@ -69,10 +69,6 @@ static void transform_domain(void);
static MUTEX_DECL(mutex); static MUTEX_DECL(mutex);
#define DRIVE_STRENGTH_AUTO (-1)
#define FREQ_HARMONICS (config.harmonic_freq_threshold)
#define IS_HARMONIC_MODE(f) ((f) > FREQ_HARMONICS)
int32_t frequency_offset = 5000; int32_t frequency_offset = 5000;
uint32_t frequency = 10000000; uint32_t frequency = 10000000;
int8_t drive_strength = DRIVE_STRENGTH_AUTO; int8_t drive_strength = DRIVE_STRENGTH_AUTO;
@ -101,6 +97,7 @@ static THD_FUNCTION(Thread1, arg)
sweep_once = FALSE; sweep_once = FALSE;
chMtxUnlock(&mutex); chMtxUnlock(&mutex);
} else { } else {
si5351_disable_output();
__WFI(); __WFI();
} }
@ -123,7 +120,7 @@ static THD_FUNCTION(Thread1, arg)
plot_into_index(measured); plot_into_index(measured);
redraw_request |= REDRAW_CELLS; redraw_request |= REDRAW_CELLS;
if (marker_tracking) { if (uistat.marker_tracking) {
int i = marker_search(); int i = marker_search();
if (i != -1 && active_marker != -1) { if (i != -1 && active_marker != -1) {
markers[active_marker].index = i; markers[active_marker].index = i;
@ -316,7 +313,7 @@ const int8_t gain_table[] = {
95 // 2400MHz ~ 95 // 2400MHz ~
}; };
#define DELAY_GAIN_CHANGE 10 #define DELAY_GAIN_CHANGE 2
static int static int
adjust_gain(int newfreq) adjust_gain(int newfreq)
@ -474,7 +471,7 @@ VNA_SHELL_FUNCTION(cmd_power)
#ifdef ENABLE_TIME_COMMAND #ifdef ENABLE_TIME_COMMAND
#if HAL_USE_RTC == FALSE #if HAL_USE_RTC == FALSE
#error "Error cmd_time require ENABLE_TIME_COMMAND = TRUE in halconf.h" #error "Error cmd_time require define HAL_USE_RTC = TRUE in halconf.h"
#endif #endif
VNA_SHELL_FUNCTION(cmd_time) VNA_SHELL_FUNCTION(cmd_time)
{ {
@ -745,7 +742,8 @@ static const marker_t def_markers[MARKERS_MAX] = {
// Load propeties default settings // Load propeties default settings
void loadDefaultProps(void){ void loadDefaultProps(void){
current_props.magic = CONFIG_MAGIC; //Magic add on caldata_save
//current_props.magic = CONFIG_MAGIC;
current_props._frequency0 = 50000; // start = 50kHz current_props._frequency0 = 50000; // start = 50kHz
current_props._frequency1 = 900000000; // end = 900MHz current_props._frequency1 = 900000000; // end = 900MHz
current_props._sweep_points = POINTS_COUNT; current_props._sweep_points = POINTS_COUNT;
@ -761,6 +759,8 @@ void loadDefaultProps(void){
current_props._active_marker = 0; current_props._active_marker = 0;
current_props._domain_mode = 0; current_props._domain_mode = 0;
current_props._marker_smith_format = MS_RLC; current_props._marker_smith_format = MS_RLC;
//Checksum add on caldata_save
//current_props.checksum = 0;
} }
void void
@ -775,7 +775,7 @@ ensure_edit_config(void)
cal_status = 0; cal_status = 0;
} }
#define DELAY_CHANNEL_CHANGE 3 #define DELAY_CHANNEL_CHANGE 2
// main loop for measurement // main loop for measurement
bool sweep(bool break_on_operation) bool sweep(bool break_on_operation)
@ -783,11 +783,17 @@ bool sweep(bool break_on_operation)
int i; int i;
// blink LED while scanning // blink LED while scanning
palClearPad(GPIOC, GPIOC_LED); palClearPad(GPIOC, GPIOC_LED);
systime_t time = chVTGetSystemTimeX();
systime_t sweep_t = 0;
si5351_enable_output();
// On CW set freq once, and run
for (i = 0; i < sweep_points; i++) { // 8365 for (i = 0; i < sweep_points; i++) { // 8365
sweep_t-= chVTGetSystemTimeX();
int delay = set_frequency(frequencies[i]); // 1560 int delay = set_frequency(frequencies[i]); // 1560
sweep_t+= chVTGetSystemTimeX();
tlv320aic3204_select(0); // 60 CH0:REFLECT tlv320aic3204_select(0); // 60 CH0:REFLECT
wait_dsp(delay); // 3270 wait_dsp(delay+(i==0 ? 1 :0)); // 3270
// calculate reflection coefficient // calculate reflection coefficient
(*sample_func)(measured[0][i]); // 60 (*sample_func)(measured[0][i]); // 60
@ -803,9 +809,11 @@ bool sweep(bool break_on_operation)
apply_edelay_at(i); apply_edelay_at(i);
// back to toplevel to handle ui operation // back to toplevel to handle ui operation
if (operation_requested && break_on_operation) if (operation_requested && break_on_operation){
return false; return false;
}
} }
{char string_buf[18];plot_printf(string_buf, sizeof string_buf, "T:%06d:%06d", chVTGetSystemTimeX() - time, sweep_t);ili9341_drawstringV(string_buf, 1, 90);}
// blink LED while scanning // blink LED while scanning
palSetPad(GPIOC, GPIOC_LED); palSetPad(GPIOC, GPIOC_LED);
return true; return true;
@ -912,7 +920,7 @@ update_frequencies(void)
} }
set_frequencies(start, stop, sweep_points); set_frequencies(start, stop, sweep_points);
operation_requested = OP_FREQCHANGE; // operation_requested|= OP_FREQCHANGE;
update_marker_index(); update_marker_index();
@ -1430,6 +1438,7 @@ VNA_SHELL_FUNCTION(cmd_cal)
shell_printf("\r\n"); shell_printf("\r\n");
return; return;
} }
redraw_request|=REDRAW_CAL_STATUS;
// 0 1 2 3 4 5 6 7 8 9 10 // 0 1 2 3 4 5 6 7 8 9 10
static const char cmd_cal_list[] = "load|open|short|thru|isoln|done|on|off|reset|data|in"; static const char cmd_cal_list[] = "load|open|short|thru|isoln|done|on|off|reset|data|in";
switch (getStringIndex(argv[0], cmd_cal_list)){ switch (getStringIndex(argv[0], cmd_cal_list)){
@ -1439,9 +1448,9 @@ VNA_SHELL_FUNCTION(cmd_cal)
case 3:cal_collect(CAL_THRU ); return; case 3:cal_collect(CAL_THRU ); return;
case 4:cal_collect(CAL_ISOLN); return; case 4:cal_collect(CAL_ISOLN); return;
case 5:cal_done(); return; case 5:cal_done(); return;
case 6:cal_status|= CALSTAT_APPLY;redraw_request|=REDRAW_CAL_STATUS; return; case 6:cal_status|= CALSTAT_APPLY;return;
case 7:cal_status&=~CALSTAT_APPLY;redraw_request|=REDRAW_CAL_STATUS; return; case 7:cal_status&=~CALSTAT_APPLY;return;
case 8:cal_status = 0; redraw_request|=REDRAW_CAL_STATUS; return; case 8:cal_status = 0; return;
case 9: case 9:
shell_printf("%f %f\r\n", cal_data[CAL_LOAD ][0][0], cal_data[CAL_LOAD ][0][1]); shell_printf("%f %f\r\n", cal_data[CAL_LOAD ][0][0], cal_data[CAL_LOAD ][0][1]);
shell_printf("%f %f\r\n", cal_data[CAL_OPEN ][0][0], cal_data[CAL_OPEN ][0][1]); shell_printf("%f %f\r\n", cal_data[CAL_OPEN ][0][0], cal_data[CAL_OPEN ][0][1]);
@ -1451,11 +1460,9 @@ VNA_SHELL_FUNCTION(cmd_cal)
return; return;
case 10: case 10:
cal_interpolate((argc > 1) ? my_atoi(argv[1]) : 0); cal_interpolate((argc > 1) ? my_atoi(argv[1]) : 0);
redraw_request|=REDRAW_CAL_STATUS;
return; return;
default:break; default:break;
} }
shell_printf("usage: cal [%s]\r\n", cmd_cal_list); shell_printf("usage: cal [%s]\r\n", cmd_cal_list);
} }
@ -1687,14 +1694,13 @@ VNA_SHELL_FUNCTION(cmd_marker)
} }
return; return;
} }
redraw_request |= REDRAW_MARKER;
if (strcmp(argv[0], "off") == 0) { if (strcmp(argv[0], "off") == 0) {
active_marker = -1; active_marker = -1;
for (t = 0; t < MARKERS_MAX; t++) for (t = 0; t < MARKERS_MAX; t++)
markers[t].enabled = FALSE; markers[t].enabled = FALSE;
redraw_request |= REDRAW_MARKER;
return; return;
} }
t = my_atoi(argv[0])-1; t = my_atoi(argv[0])-1;
if (t < 0 || t >= MARKERS_MAX) if (t < 0 || t >= MARKERS_MAX)
goto usage; goto usage;
@ -1703,13 +1709,12 @@ VNA_SHELL_FUNCTION(cmd_marker)
active_marker = t; active_marker = t;
// select active marker // select active marker
markers[t].enabled = TRUE; markers[t].enabled = TRUE;
redraw_request |= REDRAW_MARKER;
return; return;
} }
static const char cmd_marker_list[] = "on|off"; static const char cmd_marker_list[] = "on|off";
switch (getStringIndex(argv[1], cmd_marker_list)){ switch (getStringIndex(argv[1], cmd_marker_list)){
case 0: markers[t].enabled = TRUE; active_marker = t; redraw_request |= REDRAW_MARKER; return; case 0: markers[t].enabled = TRUE; active_marker = t; return;
case 1: markers[t].enabled =FALSE; if (active_marker == t) active_marker = -1; redraw_request|=REDRAW_MARKER; return; case 1: markers[t].enabled =FALSE; if (active_marker == t) active_marker = -1; return;
default: default:
// select active marker and move to index // select active marker and move to index
markers[t].enabled = TRUE; markers[t].enabled = TRUE;
@ -1717,7 +1722,6 @@ VNA_SHELL_FUNCTION(cmd_marker)
markers[t].index = index; markers[t].index = index;
markers[t].frequency = frequencies[index]; markers[t].frequency = frequencies[index];
active_marker = t; active_marker = t;
redraw_request |= REDRAW_MARKER;
return; return;
} }
usage: usage:
@ -1923,8 +1927,8 @@ VNA_SHELL_FUNCTION(cmd_stat)
//shell_printf("interval cycle: %d\r\n", stat.interval_cycles); //shell_printf("interval cycle: %d\r\n", stat.interval_cycles);
//shell_printf("busy cycle: %d\r\n", stat.busy_cycles); //shell_printf("busy cycle: %d\r\n", stat.busy_cycles);
//shell_printf("load: %d\r\n", stat.busy_cycles * 100 / stat.interval_cycles); //shell_printf("load: %d\r\n", stat.busy_cycles * 100 / stat.interval_cycles);
extern int awd_count; // extern int awd_count;
shell_printf("awd: %d\r\n", awd_count); // shell_printf("awd: %d\r\n", awd_count);
} }
@ -2160,10 +2164,25 @@ THD_FUNCTION(myshellThread, p) {
} }
#endif #endif
// I2C clock bus setting: depend from STM32_I2C1SW in mcuconf.h
// STM32_I2C1SW = STM32_I2C1SW_HSI (HSI=8MHz)
// STM32_I2C1SW = STM32_I2C1SW_SYSCLK (SYSCLK = 48MHz)
static const I2CConfig i2ccfg = { static const I2CConfig i2ccfg = {
0x00300506, //voodoo magic 400kHz @ HSI 8MHz // TIMINGR register initialization. (use I2C timing configuration tool for STM32F3xx and STM32F0xx microcontrollers (AN4235))
0, // 400kHz @ SYSCLK 48MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
0 // STM32_TIMINGR_PRESC(5U) |
// STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(3U) |
// STM32_TIMINGR_SCLH(3U) | STM32_TIMINGR_SCLL(9U),
// 400kHz @ HSI 8MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
STM32_TIMINGR_PRESC(0U) |
STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(1U) |
STM32_TIMINGR_SCLH(3U) | STM32_TIMINGR_SCLL(9U),
// Old values voodoo magic 400kHz @ HSI 8MHz
// STM32_TIMINGR_PRESC(0U) |
// STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(0U) |
// STM32_TIMINGR_SCLH(5U) | STM32_TIMINGR_SCLL(6U),
0, // CR1 register initialization.
0 // CR2 register initialization.
}; };
static DACConfig dac1cfg1 = { static DACConfig dac1cfg1 = {

View file

@ -88,30 +88,6 @@ void loadDefaultProps(void);
extern int8_t sweep_enabled; extern int8_t sweep_enabled;
/*
* flash.c
*/
#define SAVEAREA_MAX 5
// Begin addr 0x08018000
#define SAVE_CONFIG_AREA_SIZE 0x00008000
// config save area
#define SAVE_CONFIG_ADDR 0x08018000
// properties_t save area
#define SAVE_PROP_CONFIG_0_ADDR 0x08018800
#define SAVE_PROP_CONFIG_1_ADDR 0x0801a000
#define SAVE_PROP_CONFIG_2_ADDR 0x0801b800
#define SAVE_PROP_CONFIG_3_ADDR 0x0801d000
#define SAVE_PROP_CONFIG_4_ADDR 0x0801e800
/*
* ui.c
*/
extern void ui_init(void);
extern void ui_process(void);
enum opreq { OP_NONE = 0, OP_LEVER, OP_TOUCH, OP_FREQCHANGE };
extern uint8_t operation_requested;
/* /*
* dsp.c * dsp.c
*/ */
@ -134,9 +110,6 @@ void calculate_gamma(float *gamma);
void fetch_amplitude(float *gamma); void fetch_amplitude(float *gamma);
void fetch_amplitude_ref(float *gamma); void fetch_amplitude_ref(float *gamma);
int si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength);
/* /*
* tlv320aic3204.c * tlv320aic3204.c
*/ */
@ -250,6 +223,10 @@ typedef struct config {
extern config_t config; extern config_t config;
#define DRIVE_STRENGTH_AUTO (-1)
#define FREQ_HARMONICS (config.harmonic_freq_threshold)
#define IS_HARMONIC_MODE(f) ((f) > FREQ_HARMONICS)
//extern trace_t trace[TRACES_MAX]; //extern trace_t trace[TRACES_MAX];
void set_trace_type(int t, int type); void set_trace_type(int t, int type);
@ -366,6 +343,16 @@ void show_logo(void);
* flash.c * flash.c
*/ */
#define SAVEAREA_MAX 5 #define SAVEAREA_MAX 5
// Begin addr 0x08018000
#define SAVE_CONFIG_AREA_SIZE 0x00008000
// config save area
#define SAVE_CONFIG_ADDR 0x08018000
// properties_t save area
#define SAVE_PROP_CONFIG_0_ADDR 0x08018800
#define SAVE_PROP_CONFIG_1_ADDR 0x0801a000
#define SAVE_PROP_CONFIG_2_ADDR 0x0801b800
#define SAVE_PROP_CONFIG_3_ADDR 0x0801d000
#define SAVE_PROP_CONFIG_4_ADDR 0x0801e800
typedef struct properties { typedef struct properties {
uint32_t magic; uint32_t magic;
@ -432,6 +419,15 @@ void clear_all_config_prop_data(void);
/* /*
* ui.c * ui.c
*/ */
extern void ui_init(void);
extern void ui_process(void);
// Irq operation process set
#define OP_NONE 0x00
#define OP_LEVER 0x01
#define OP_TOUCH 0x02
//#define OP_FREQCHANGE 0x04
extern volatile uint8_t operation_requested;
// lever_mode // lever_mode
enum lever_mode { enum lever_mode {
@ -448,13 +444,13 @@ typedef struct uistat {
int8_t digit_mode; int8_t digit_mode;
int8_t current_trace; /* 0..3 */ int8_t current_trace; /* 0..3 */
uint32_t value; // for editing at numeric input area uint32_t value; // for editing at numeric input area
uint32_t previous_value; // uint32_t previous_value;
uint8_t lever_mode; uint8_t lever_mode;
bool marker_delta; uint8_t marker_delta;
uint8_t marker_tracking;
} uistat_t; } uistat_t;
extern uistat_t uistat; extern uistat_t uistat;
void ui_init(void); void ui_init(void);
void ui_show(void); void ui_show(void);
void ui_hide(void); void ui_hide(void);

1
plot.c
View file

@ -1056,7 +1056,6 @@ static int greater(int x, int y) { return x > y; }
static int lesser(int x, int y) { return x < y; } static int lesser(int x, int y) { return x < y; }
static int (*compare)(int x, int y) = lesser; static int (*compare)(int x, int y) = lesser;
int8_t marker_tracking = false;
int int
marker_search(void) marker_search(void)

353
si5351.c
View file

@ -21,17 +21,18 @@
#include "nanovna.h" #include "nanovna.h"
#include "si5351.h" #include "si5351.h"
#define XTALFREQ 26000000L
// MCLK (processor clock, audio codec) frequency clock
#define CLK2_FREQUENCY 8000000L
// Fixed PLL mode multiplier
#define PLL_N 32
//
#define SI5351_I2C_ADDR (0x60<<1) #define SI5351_I2C_ADDR (0x60<<1)
static void static uint8_t current_band = 0;
si5351_write(uint8_t reg, uint8_t dat) static uint32_t current_freq = 0;
{
int addr = SI5351_I2C_ADDR>>1;
uint8_t buf[] = { reg, dat };
i2cAcquireBus(&I2CD1);
(void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, 2, NULL, 0, 1000);
i2cReleaseBus(&I2CD1);
}
static void static void
si5351_bulk_write(const uint8_t *buf, int len) si5351_bulk_write(const uint8_t *buf, int len)
@ -41,6 +42,22 @@ si5351_bulk_write(const uint8_t *buf, int len)
(void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, len, NULL, 0, 1000); (void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, len, NULL, 0, 1000);
i2cReleaseBus(&I2CD1); i2cReleaseBus(&I2CD1);
} }
#if 0
static void si5351_bulk_read(uint8_t reg, uint8_t* buf, int len)
{
int addr = SI5351_I2C_ADDR>>1;
i2cAcquireBus(&I2CD1);
msg_t mr = i2cMasterTransmitTimeout(&I2CD1, addr, &reg, 1, buf, len, 1000);
i2cReleaseBus(&I2CD1);
}
#endif
static inline void
si5351_write(uint8_t reg, uint8_t dat)
{
uint8_t buf[] = { reg, dat };
si5351_bulk_write(buf, 2);
}
// register addr, length, data, ... // register addr, length, data, ...
const uint8_t si5351_configs[] = { const uint8_t si5351_configs[] = {
@ -48,13 +65,14 @@ const uint8_t si5351_configs[] = {
4, SI5351_REG_16_CLK0_CONTROL, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, 4, SI5351_REG_16_CLK0_CONTROL, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN,
2, SI5351_REG_183_CRYSTAL_LOAD, SI5351_CRYSTAL_LOAD_8PF, 2, SI5351_REG_183_CRYSTAL_LOAD, SI5351_CRYSTAL_LOAD_8PF,
// setup PLL (26MHz * 32 = 832MHz, 32/2-2=14) // setup PLL (26MHz * 32 = 832MHz, 32/2-2=14)
9, SI5351_REG_26_PLL_A, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0, // 9, SI5351_REG_PLL_A, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0,
// 9, SI5351_REG_PLL_B, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0,
// RESET PLL // RESET PLL
2, SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B, 2, SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B | 0x0C, //
// setup multisynth (832MHz / 104 = 8MHz, 104/2-2=50) // setup multisynth (832MHz / 104 = 8MHz, 104/2-2=50)
9, SI5351_REG_58_MULTISYNTH2, /*P3*/0, 1, /*P1*/0, 50, 0, /*P2|P3*/0, 0, 0, // 9, SI5351_REG_58_MULTISYNTH2, /*P3*/0, 1, /*P1*/0, 50, 0, /*P2|P3*/0, 0, 0,
2, SI5351_REG_18_CLK2_CONTROL, SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_INPUT_MULTISYNTH_N | SI5351_CLK_INTEGER_MODE, // 2, SI5351_REG_18_CLK2_CONTROL, SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_INPUT_MULTISYNTH_N | SI5351_CLK_INTEGER_MODE,
2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0, // 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0,
0 // sentinel 0 // sentinel
}; };
@ -71,26 +89,46 @@ si5351_init(void)
static const uint8_t disable_output[] = { static const uint8_t disable_output[] = {
SI5351_REG_16_CLK0_CONTROL, SI5351_REG_16_CLK0_CONTROL,
SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, // CLK 0
SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, // CLK 1
SI5351_CLK_POWERDOWN SI5351_CLK_POWERDOWN // CLK 2
}; };
/* Get the appropriate starting point for the PLL registers */
static const uint8_t msreg_base[] = {
SI5351_REG_42_MULTISYNTH0,
SI5351_REG_50_MULTISYNTH1,
SI5351_REG_58_MULTISYNTH2,
};
static const uint8_t clkctrl[] = {
SI5351_REG_16_CLK0_CONTROL,
SI5351_REG_17_CLK1_CONTROL,
SI5351_REG_18_CLK2_CONTROL
};
static void si5351_reset_pll(uint8_t mask)
{
// Writing a 1<<5 will reset PLLA, 1<<7 reset PLLB, this is a self clearing bits.
// !!! Need delay before reset PLL for apply PLL freq changes before
chThdSleepMicroseconds(200);
si5351_write(SI5351_REG_177_PLL_RESET, mask | 0x0C);
// chThdSleepMicroseconds(250);
}
void si5351_disable_output(void) void si5351_disable_output(void)
{ {
// si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, (SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN));
si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff); si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff);
si5351_bulk_write(disable_output, sizeof(disable_output)); si5351_bulk_write(disable_output, sizeof(disable_output));
} }
void si5351_enable_output(void) void si5351_enable_output(void)
{ {
si5351_reset_pll( SI5351_PLL_RESET_A | SI5351_PLL_RESET_B );
// si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, ~(SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN));
si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0x00); si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0x00);
} current_freq = 0;
current_band = 0;
static void si5351_reset_pll(void)
{
//si5351_write(SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B);
si5351_write(SI5351_REG_177_PLL_RESET, 0xAC);
} }
static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */ static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */
@ -98,11 +136,6 @@ static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */
uint32_t num, uint32_t num,
uint32_t denom) uint32_t denom)
{ {
/* Get the appropriate starting point for the PLL registers */
static const uint8_t pllreg_base[] = {
SI5351_REG_26_PLL_A,
SI5351_REG_34_PLL_B
};
uint32_t P1; uint32_t P1;
uint32_t P2; uint32_t P2;
uint32_t P3; uint32_t P3;
@ -134,10 +167,17 @@ static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */
P2 = 128 * num - denom * ((128 * num) / denom); P2 = 128 * num - denom * ((128 * num) / denom);
P3 = denom; P3 = denom;
} }
// Pll MSN(A|B) registers Datasheet
/* The datasheet is a nightmare of typos and inconsistencies here! */ // MSN_P3[15:8]
// MSN_P3[ 7:0]
// Reserved | MSN_P1[17:16]
// MSN_P1[15:8]
// MSN_P1[ 7:0]
// MSN_P3[19:16] | MSN_P2[19:16]
// MSN_P2[15:8]
// MSN_P2[ 7:0]
uint8_t reg[9]; uint8_t reg[9];
reg[0] = pllreg_base[pll]; reg[0] = pll;//reg_base[pll];
reg[1] = (P3 & 0x0000FF00) >> 8; reg[1] = (P3 & 0x0000FF00) >> 8;
reg[2] = (P3 & 0x000000FF); reg[2] = (P3 & 0x000000FF);
reg[3] = (P1 & 0x00030000) >> 16; reg[3] = (P1 & 0x00030000) >> 16;
@ -149,8 +189,9 @@ static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */
si5351_bulk_write(reg, 9); si5351_bulk_write(reg, 9);
} }
static void static void
si5351_setupMultisynth(uint8_t output, si5351_setupMultisynth(uint8_t channel,
uint8_t pllSource, uint8_t pllSource,
uint32_t div, // 4,6,8, 8+ ~ 900 uint32_t div, // 4,6,8, 8+ ~ 900
uint32_t num, uint32_t num,
@ -158,17 +199,6 @@ si5351_setupMultisynth(uint8_t output,
uint32_t rdiv, // SI5351_R_DIV_1~128 uint32_t rdiv, // SI5351_R_DIV_1~128
uint8_t drive_strength) uint8_t drive_strength)
{ {
/* Get the appropriate starting point for the PLL registers */
static const uint8_t msreg_base[] = {
SI5351_REG_42_MULTISYNTH0,
SI5351_REG_50_MULTISYNTH1,
SI5351_REG_58_MULTISYNTH2,
};
static const uint8_t clkctrl[] = {
SI5351_REG_16_CLK0_CONTROL,
SI5351_REG_17_CLK1_CONTROL,
SI5351_REG_18_CLK2_CONTROL
};
uint8_t dat; uint8_t dat;
uint32_t P1; uint32_t P1;
@ -204,7 +234,7 @@ si5351_setupMultisynth(uint8_t output,
/* Set the MSx config registers */ /* Set the MSx config registers */
uint8_t reg[9]; uint8_t reg[9];
reg[0] = msreg_base[output]; reg[0] = msreg_base[channel];
reg[1] = (P3 & 0x0000FF00) >> 8; reg[1] = (P3 & 0x0000FF00) >> 8;
reg[2] = (P3 & 0x000000FF); reg[2] = (P3 & 0x000000FF);
reg[3] = ((P1 & 0x00030000) >> 16) | div4 | rdiv; reg[3] = ((P1 & 0x00030000) >> 16) | div4 | rdiv;
@ -217,86 +247,80 @@ si5351_setupMultisynth(uint8_t output,
/* Configure the clk control and enable the output */ /* Configure the clk control and enable the output */
dat = drive_strength | SI5351_CLK_INPUT_MULTISYNTH_N; dat = drive_strength | SI5351_CLK_INPUT_MULTISYNTH_N;
if (pllSource == SI5351_PLL_B) if (pllSource == SI5351_REG_PLL_B)
dat |= SI5351_CLK_PLL_SELECT_B; dat |= SI5351_CLK_PLL_SELECT_B;
if (num == 0) if (num == 0)
dat |= SI5351_CLK_INTEGER_MODE; dat |= SI5351_CLK_INTEGER_MODE;
si5351_write(clkctrl[output], dat); si5351_write(clkctrl[channel], dat);
} }
#define XTALFREQ 26000000L
#define PLL_N 32
#define PLLFREQ (XTALFREQ * PLL_N)
static void static void
si5351_set_frequency_fixedpll(int channel, int pll, uint32_t pllfreq, uint32_t freq, si5351_set_frequency_fixedpll(uint8_t channel, uint32_t pllSource, uint64_t pllfreq, uint32_t freq, uint32_t rdiv, uint8_t drive_strength)
int rdiv, uint8_t drive_strength, int mul)
{ {
int denom = freq; uint32_t denom = freq;
int div = (pllfreq * mul) / denom; // range: 8 ~ 1800 uint32_t div = pllfreq / denom; // range: 8 ~ 1800
int num = (pllfreq * mul) - denom * div; uint32_t num = pllfreq % denom;
// cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227 // cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227
int max_denominator = (1 << 20) - 1; uint32_t max_denominator = (1 << 20) - 1;
if (denom > max_denominator) { if (denom > max_denominator) {
int p0 = 0, q0 = 1, p1 = 1, q1 = 0; uint32_t p0 = 0, q0 = 1, p1 = 1, q1 = 0;
while (denom != 0) { while (denom != 0) {
int a = num / denom; uint32_t a = num / denom;
int q2 = q0 + a*q1; uint32_t b = num % denom;
uint32_t q2 = q0 + a*q1;
if (q2 > max_denominator) if (q2 > max_denominator)
break; break;
int p2 = p0 + a*p1; uint32_t p2 = p0 + a*p1;
p0 = p1; q0 = q1; p1 = p2; q1 = q2; p0 = p1;
int new_denom = num - a * denom; q0 = q1;
num = denom; denom = new_denom; p1 = p2;
q1 = q2;
num = denom; denom = b;
} }
num = p1; num = p1;
denom = q1; denom = q1;
} }
si5351_setupMultisynth(channel, pllSource, div, num, denom, rdiv, drive_strength);
si5351_setupMultisynth(channel, pll, div, num, denom, rdiv, drive_strength);
} }
static void void si5351_setupPLL_freq(uint32_t pll, uint32_t freq, uint32_t div, uint32_t mul){
si5351_set_frequency_fixeddiv(int channel, int pll, uint32_t freq, int div, uint32_t denom = XTALFREQ * mul;
uint8_t drive_strength, int mul) uint64_t pllfreq = (uint64_t)freq * div;
{ uint32_t multi = pllfreq / denom;
int denom = XTALFREQ * mul; uint32_t num = pllfreq % denom;
int64_t pllfreq = (int64_t)freq * div;
int multi = pllfreq / denom;
int num = pllfreq - denom * multi;
// cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227 // cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227
int max_denominator = (1 << 20) - 1; uint32_t max_denominator = (1 << 20) - 1;
if (denom > max_denominator) { if (denom > max_denominator) {
int p0 = 0, q0 = 1, p1 = 1, q1 = 0; uint32_t p0 = 0, q0 = 1, p1 = 1, q1 = 0;
while (denom != 0) { while (denom != 0) {
int a = num / denom; uint32_t a = num / denom;
int q2 = q0 + a*q1; uint32_t b = num % denom;
if (q2 > max_denominator) uint32_t q2 = q0 + a*q1;
break; if (q2 > max_denominator)
int p2 = p0 + a*p1; break;
p0 = p1; q0 = q1; p1 = p2; q1 = q2; uint32_t p2 = p0 + a*p1;
int new_denom = num - a * denom; p0 = p1; q0 = q1; p1 = p2; q1 = q2;
num = denom; denom = new_denom; num = denom; denom = b;
}
num = p1;
denom = q1;
} }
num = p1;
si5351_setupPLL(pll, multi, num, denom); denom = q1;
si5351_setupMultisynth(channel, pll, div, 0, 1, SI5351_R_DIV_1, drive_strength); }
si5351_setupPLL(pll, multi, num, denom);
} }
/*
* 1~100MHz fixed PLL 900MHz, fractional divider
* 100~150MHz fractional PLL 600-900MHz, fixed divider 6
* 150~200MHz fractional PLL 600-900MHz, fixed divider 4
*/
#if 0 #if 0
void static void
si5351_set_frequency(int channel, int freq, uint8_t drive_strength) si5351_set_frequency_fixeddiv(uint8_t channel, uint32_t pll, uint32_t freq, uint32_t div,
uint8_t drive_strength, uint32_t mul)
{ {
si5351_setupPLL_freq(pll, freq, div, mul);
si5351_setupMultisynth(channel, pll, div, 0, 1, SI5351_R_DIV_1, drive_strength);
}
void
si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength){
if (freq <= 100000000) { if (freq <= 100000000) {
si5351_setupPLL(SI5351_PLL_B, 32, 0, 1); si5351_setupPLL(SI5351_PLL_B, 32, 0, 1);
si5351_set_frequency_fixedpll(channel, SI5351_PLL_B, PLLFREQ, freq, SI5351_R_DIV_1, drive_strength, 1); si5351_set_frequency_fixedpll(channel, SI5351_PLL_B, PLLFREQ, freq, SI5351_R_DIV_1, drive_strength, 1);
@ -308,11 +332,8 @@ si5351_set_frequency(int channel, int freq, uint8_t drive_strength)
} }
#endif #endif
int current_band = -1; #define DELAY_NORMAL 2
#define DELAY_BANDCHANGE 2
#define DELAY_NORMAL 3
#define DELAY_BANDCHANGE 1
#define DELAY_LOWBAND 1
/* /*
* configure output as follows: * configure output as follows:
@ -320,105 +341,89 @@ int current_band = -1;
* CLK1: frequency * CLK1: frequency
* CLK2: fixed 8MHz * CLK2: fixed 8MHz
*/ */
#define CLK2_FREQUENCY 8000000L
int int
si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength) si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength)
{ {
int band; uint8_t band;
int delay = DELAY_NORMAL; int delay = DELAY_NORMAL;
if (freq == current_freq)
return delay;
uint32_t ofreq = freq + offset; uint32_t ofreq = freq + offset;
uint32_t mul = 1, omul = 1; uint32_t mul = 1, omul = 1;
uint32_t rdiv = SI5351_R_DIV_1; uint32_t rdiv = SI5351_R_DIV_1;
if (freq >= config.harmonic_freq_threshold * 7U) { uint32_t fdiv;
current_freq = freq;
if (freq >= FREQ_HARMONICS * 7U) {
mul = 9; mul = 9;
omul = 11; omul = 11;
} else if (freq >= config.harmonic_freq_threshold * 5U) { } else if (freq >= FREQ_HARMONICS * 5U) {
mul = 7; mul = 7;
omul = 9; omul = 9;
} else if (freq >= config.harmonic_freq_threshold * 3U) { } else if (freq >= FREQ_HARMONICS * 3U) {
mul = 5; mul = 5;
omul = 7; omul = 7;
} else if (freq >= config.harmonic_freq_threshold) { } else if (freq >= FREQ_HARMONICS) {
mul = 3; mul = 3;
omul = 5; omul = 5;
} }
if ((freq / mul) < 100000000U) { else if (freq <= 500000U) {
band = 0;
} else if ((freq / mul) < 150000000U) {
band = 1;
} else {
band = 2;
}
if (freq <= 500000U) {
rdiv = SI5351_R_DIV_64; rdiv = SI5351_R_DIV_64;
freq *= 64;
ofreq *= 64;
} else if (freq <= 4000000U) { } else if (freq <= 4000000U) {
rdiv = SI5351_R_DIV_8; rdiv = SI5351_R_DIV_8;
freq *= 8;
ofreq *= 8;
}
/*
* Band 0
* 1~100MHz fixed PLL = XTALFREQ * PLL_N, fractional divider
* Band 1
* 100~150MHz fractional PLL = 600- 900MHz, fixed divider 6
* Band 2
* 150~300MHz fractional PLL = 600-1200MHz, fixed divider 4
*/
if ((freq / mul) < 100000000U) {
band = 1;
} else if ((freq / mul) < 150000000U) {
band = 2;
fdiv = 6;
} else {
band = 3;
fdiv = 4;
} }
#if 1
if (current_band != band)
si5351_disable_output();
#endif
switch (band) { switch (band) {
case 0:
// fractional divider mode. only PLL A is used.
if (current_band == 1 || current_band == 2)
si5351_setupPLL(SI5351_PLL_A, 32, 0, 1);
// Set PLL twice on changing from band 2
if (current_band == 2)
si5351_setupPLL(SI5351_PLL_A, 32, 0, 1);
if (rdiv == SI5351_R_DIV_8) {
freq *= 8;
ofreq *= 8;
} else if (rdiv == SI5351_R_DIV_64) {
freq *= 64;
ofreq *= 64;
}
si5351_set_frequency_fixedpll(0, SI5351_PLL_A, PLLFREQ, ofreq,
rdiv, drive_strength, omul);
si5351_set_frequency_fixedpll(1, SI5351_PLL_A, PLLFREQ, freq,
rdiv, drive_strength, mul);
//if (current_band != 0)
si5351_set_frequency_fixedpll(2, SI5351_PLL_A, PLLFREQ, CLK2_FREQUENCY,
SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1);
break;
case 1: case 1:
// Set PLL twice on changing from band 2 // Setup CH0 and CH1 constant PLL freq at band change, and set CH2 freq = CLK2_FREQUENCY
if (current_band == 2) { if (current_band != 1){
si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul); si5351_setupPLL(SI5351_REG_PLL_A, PLL_N, 0, 1);
si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul); si5351_setupPLL(SI5351_REG_PLL_B, PLL_N, 0, 1);
si5351_set_frequency_fixedpll(2, SI5351_REG_PLL_B, XTALFREQ * PLL_N, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
} }
// Calculate and set CH0 and CH1 divider
// div by 6 mode. both PLL A and B are dedicated for CLK0, CLK1 si5351_set_frequency_fixedpll(0, SI5351_REG_PLL_A, XTALFREQ * PLL_N * omul, ofreq, rdiv, drive_strength);
si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul); si5351_set_frequency_fixedpll(1, SI5351_REG_PLL_A, XTALFREQ * PLL_N * mul, freq, rdiv, drive_strength);
si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul);
si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq / mul * 6, CLK2_FREQUENCY,
SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1);
break; break;
case 2: case 2:
// div by 4 mode. both PLL A and B are dedicated for CLK0, CLK1 case 3:
si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 4, drive_strength, omul); // Setup CH0 and CH1 constant fdiv divider at change
si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 4, drive_strength, mul); if (current_band != band){
si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq / mul * 4, CLK2_FREQUENCY, si5351_setupMultisynth(0, SI5351_REG_PLL_A, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength);
SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1); si5351_setupMultisynth(1, SI5351_REG_PLL_B, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength);
}
// Calculate and set CH0 and CH1 PLL freq
si5351_setupPLL_freq(SI5351_REG_PLL_A, ofreq, fdiv, omul);// set PLLA freq = (ofreq/omul)*fdiv
si5351_setupPLL_freq(SI5351_REG_PLL_B, freq, fdiv, mul);// set PLLB freq = ( freq/ mul)*fdiv
// Calculate CH2 freq = CLK2_FREQUENCY, depend from calculated before CH1 PLLB = (freq/mul)*fdiv
si5351_set_frequency_fixedpll(2, SI5351_REG_PLL_B, (freq/mul)*fdiv, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
break; break;
} }
if (current_band != band) { if (current_band != band) {
si5351_reset_pll(); si5351_reset_pll(SI5351_PLL_RESET_A|SI5351_PLL_RESET_B);
#if 1 current_band = band;
si5351_enable_output(); delay+=DELAY_BANDCHANGE;
#endif
delay += DELAY_BANDCHANGE;
} }
if (band == 0)
delay += DELAY_LOWBAND;
current_band = band;
return delay; return delay;
} }

View file

@ -17,8 +17,8 @@
* the Free Software Foundation, Inc., 51 Franklin Street, * the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#define SI5351_PLL_A 0 //#define SI5351_PLL_A 0
#define SI5351_PLL_B 1 //#define SI5351_PLL_B 1
#define SI5351_MULTISYNTH_DIV_4 4 #define SI5351_MULTISYNTH_DIV_4 4
#define SI5351_MULTISYNTH_DIV_6 6 #define SI5351_MULTISYNTH_DIV_6 6
@ -33,12 +33,16 @@
#define SI5351_R_DIV_128 (7<<4) #define SI5351_R_DIV_128 (7<<4)
#define SI5351_DIVBY4 (3<<2) #define SI5351_DIVBY4 (3<<2)
#define SI5351_REG_3_OUTPUT_ENABLE_CONTROL 3 #define SI5351_REG_3_OUTPUT_ENABLE_CONTROL 3
#define SI5351_CLK0_EN (1<<0)
#define SI5351_CLK1_EN (1<<2)
#define SI5351_CLK2_EN (1<<3)
#define SI5351_REG_16_CLK0_CONTROL 16 #define SI5351_REG_16_CLK0_CONTROL 16
#define SI5351_REG_17_CLK1_CONTROL 17 #define SI5351_REG_17_CLK1_CONTROL 17
#define SI5351_REG_18_CLK2_CONTROL 18 #define SI5351_REG_18_CLK2_CONTROL 18
#define SI5351_REG_26_PLL_A 26 #define SI5351_REG_PLL_A 26
#define SI5351_REG_34_PLL_B 34 #define SI5351_REG_PLL_B 34
#define SI5351_REG_42_MULTISYNTH0 42 #define SI5351_REG_42_MULTISYNTH0 42
#define SI5351_REG_50_MULTISYNTH1 50 #define SI5351_REG_50_MULTISYNTH1 50
#define SI5351_REG_58_MULTISYNTH2 58 #define SI5351_REG_58_MULTISYNTH2 58
@ -74,4 +78,7 @@
void si5351_init(void); void si5351_init(void);
void si5351_set_frequency(int channel, int freq, uint8_t drive_strength); void si5351_disable_output(void);
void si5351_enable_output(void);
void si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength);
int si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength);

View file

@ -25,74 +25,78 @@
#define wait_ms(ms) chThdSleepMilliseconds(ms) #define wait_ms(ms) chThdSleepMilliseconds(ms)
static const uint8_t conf_data_pll[] = { static const uint8_t conf_data[] = {
// len, ( reg, data ), // reg, data,
2, 0x00, 0x00, /* Initialize to Page 0 */ // PLL clock config
2, 0x01, 0x01, /* Initialize the device through software reset */ 0x00, 0x00, /* Initialize to Page 0 */
2, 0x04, 0x43, /* PLL Clock High, MCLK, PLL */ 0x01, 0x01, /* Initialize the device through software reset */
0x04, 0x43, /* PLL Clock High, MCLK, PLL */
#ifdef REFCLK_8000KHZ #ifdef REFCLK_8000KHZ
/* 8.000MHz*10.7520 = 86.016MHz, 86.016MHz/(2*7*128) = 48kHz */ /* 8.000MHz*10.7520 = 86.016MHz, 86.016MHz/(2*7*128) = 48kHz */
2, 0x05, 0x91, /* Power up PLL, P=1,R=1 */ 0x05, 0x91, /* Power up PLL, P=1,R=1 */
2, 0x06, 0x0a, /* J=10 */ 0x06, 0x0a, /* J=10 */
2, 0x07, 29, /* D=7520 = (29<<8) + 96 */ 0x07, 29, /* D=7520 = (29<<8) + 96 */
2, 0x08, 96, 0x08, 96,
#endif #endif
0 // sentinel // Clock config, default fs=48kHz
0x0b, 0x82, /* Power up the NDAC divider with value 2 */
0x0c, 0x87, /* Power up the MDAC divider with value 7 */
0x0d, 0x00, /* Program the OSR of DAC to 128 */
0x0e, 0x80,
0x3c, 0x08, /* Set the DAC Mode to PRB_P8 */
//0x3c, 25, /* Set the DAC Mode to PRB_P25 */
0x1b, 0x0c, /* Set the BCLK,WCLK as output */
0x1e, 0x80 + 28, /* Enable the BCLKN divider with value 28 */
0x25, 0xee, /* DAC power up */
0x12, 0x82, /* Power up the NADC divider with value 2 */
0x13, 0x87, /* Power up the MADC divider with value 7 */
0x14, 0x80, /* Program the OSR of ADC to 128 */
0x3d, 0x01, /* Select ADC PRB_R1 */
// Data routing
0x00, 0x01, /* Select Page 1 */
0x01, 0x08, /* Disable Internal Crude AVdd in presence of external AVdd supply or before powering up internal AVdd LDO*/
0x02, 0x01, /* Enable Master Analog Power Control */
0x7b, 0x01, /* Set the REF charging time to 40ms */
0x14, 0x25, /* HP soft stepping settings for optimal pop performance at power up Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling capacitor. Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound. */
0x0a, 0x33, /* Set the Input Common Mode to 0.9V and Output Common Mode for Headphone to 1.65V */
0x3d, 0x00, /* Select ADC PTM_R4 */
0x47, 0x32, /* Set MicPGA startup delay to 3.1ms */
0x7b, 0x01, /* Set the REF charging time to 40ms */
0x34, 0x10, /* Route IN2L to LEFT_P with 10K */
0x36, 0x10, /* Route IN2R to LEFT_N with 10K */
//0x37, 0x04, /* Route IN3R to RIGHT_P with 10K */
//0x39, 0x04, /* Route IN3L to RIGHT_N with 10K */
//0x3b, 0x00, /* Unmute Left MICPGA, Gain selection of 32dB to make channel gain 0dB */
//0x3c, 0x00, /* Unmute Right MICPGA, Gain selection of 32dB to make channel gain 0dB */
}; };
// default fs=48kHz static const uint8_t conf_data_unmute[] = {
static const uint8_t conf_data_clk[] = { // reg, data,
2, 0x0b, 0x82, /* Power up the NDAC divider with value 2 */ 0x00, 0x00, /* Select Page 0 */
2, 0x0c, 0x87, /* Power up the MDAC divider with value 7 */ 0x51, 0xc0, /* Power up Left and Right ADC Channels */
2, 0x0d, 0x00, /* Program the OSR of DAC to 128 */ 0x52, 0x00, /* Unmute Left and Right ADC Digital Volume Control */
2, 0x0e, 0x80,
2, 0x3c, 0x08, /* Set the DAC Mode to PRB_P8 */
//2, 0x3c, 25, /* Set the DAC Mode to PRB_P25 */
2, 0x1b, 0x0c, /* Set the BCLK,WCLK as output */
2, 0x1e, 0x80 + 28, /* Enable the BCLKN divider with value 28 */
2, 0x25, 0xee, /* DAC power up */
2, 0x12, 0x82, /* Power up the NADC divider with value 2 */
2, 0x13, 0x87, /* Power up the MADC divider with value 7 */
2, 0x14, 0x80, /* Program the OSR of ADC to 128 */
2, 0x3d, 0x01, /* Select ADC PRB_R1 */
0 // sentinel
}; };
static const uint8_t conf_data_routing[] = { static const uint8_t conf_data_ch3_select[] = {
2, 0x00, 0x01, /* Select Page 1 */ // reg, data,
2, 0x01, 0x08, /* Disable Internal Crude AVdd in presence of external AVdd supply or before powering up internal AVdd LDO*/ 0x00, 0x01, /* Select Page 1 */
2, 0x02, 0x01, /* Enable Master Analog Power Control */ 0x37, 0x04, /* Route IN3R to RIGHT_P with input impedance of 10K */
2, 0x7b, 0x01, /* Set the REF charging time to 40ms */ 0x39, 0x04, /* Route IN3L to RIGHT_N with input impedance of 10K */
2, 0x14, 0x25, /* HP soft stepping settings for optimal pop performance at power up Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling capacitor. Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound. */
2, 0x0a, 0x33, /* Set the Input Common Mode to 0.9V and Output Common Mode for Headphone to 1.65V */
2, 0x3d, 0x00, /* Select ADC PTM_R4 */
2, 0x47, 0x32, /* Set MicPGA startup delay to 3.1ms */
2, 0x7b, 0x01, /* Set the REF charging time to 40ms */
2, 0x34, 0x10, /* Route IN2L to LEFT_P with 10K */
2, 0x36, 0x10, /* Route IN2R to LEFT_N with 10K */
2, 0x37, 0x04, /* Route IN3R to RIGHT_P with 10K */
2, 0x39, 0x04, /* Route IN3L to RIGHT_N with 10K */
2, 0x3b, 0, /* Unmute Left MICPGA, Gain selection of 32dB to make channel gain 0dB */
2, 0x3c, 0, /* Unmute Right MICPGA, Gain selection of 32dB to make channel gain 0dB */
0 // sentinel
}; };
const uint8_t conf_data_unmute[] = { static const uint8_t conf_data_ch1_select[] = {
2, 0x00, 0x00, /* Select Page 0 */ // reg, data,
2, 0x51, 0xc0, /* Power up Left and Right ADC Channels */ 0x00, 0x01, /* Select Page 1 */
2, 0x52, 0x00, /* Unmute Left and Right ADC Digital Volume Control */ 0x37, 0x40, /* Route IN1R to RIGHT_P with input impedance of 10K */
0 // sentinel 0x39, 0x10, /* Route IN1L to RIGHT_N with input impedance of 10K */
}; };
static void static inline void
tlv320aic3204_bulk_write(const uint8_t *buf, int len) tlv320aic3204_bulk_write(const uint8_t *buf, int len)
{ {
int addr = AIC3204_ADDR; (void)i2cMasterTransmitTimeout(&I2CD1, AIC3204_ADDR, buf, len, NULL, 0, 1000);
i2cAcquireBus(&I2CD1);
(void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, len, NULL, 0, 1000);
i2cReleaseBus(&I2CD1);
} }
#if 0 #if 0
@ -109,49 +113,32 @@ tlv320aic3204_read(uint8_t d0)
#endif #endif
static void static void
tlv320aic3204_config(const uint8_t *data) tlv320aic3204_config(const uint8_t *data, int len)
{ {
const uint8_t *p = data; i2cAcquireBus(&I2CD1);
while (*p) { for (;len--;data+=2)
uint8_t len = *p++; tlv320aic3204_bulk_write(data, 2);
tlv320aic3204_bulk_write(p, len); i2cReleaseBus(&I2CD1);
p += len;
}
} }
void tlv320aic3204_init(void) void tlv320aic3204_init(void)
{ {
tlv320aic3204_config(conf_data_pll); tlv320aic3204_config(conf_data, sizeof(conf_data)/2);
tlv320aic3204_config(conf_data_clk);
tlv320aic3204_config(conf_data_routing);
wait_ms(40); wait_ms(40);
tlv320aic3204_config(conf_data_unmute); tlv320aic3204_config(conf_data_unmute, sizeof(conf_data_unmute)/2);
} }
void tlv320aic3204_select(int channel) void tlv320aic3204_select(int channel)
{ {
const uint8_t ch3[] = { tlv320aic3204_config(channel ? conf_data_ch1_select : conf_data_ch3_select, sizeof(conf_data_ch3_select)/2);
2, 0x00, 0x01, /* Select Page 1 */
2, 0x37, 0x04, /* Route IN3R to RIGHT_P with input impedance of 10K */
2, 0x39, 0x04, /* Route IN3L to RIGHT_N with input impedance of 10K */
0 // sentinel
};
const uint8_t ch1[] = {
2, 0x00, 0x01, /* Select Page 1 */
2, 0x37, 0x40, /* Route IN1R to RIGHT_P with input impedance of 10K */
2, 0x39, 0x10, /* Route IN1L to RIGHT_N with input impedance of 10K */
0 // sentinel
};
tlv320aic3204_config(channel ? ch1 : ch3);
} }
void tlv320aic3204_set_gain(int lgain, int rgain) void tlv320aic3204_set_gain(int lgain, int rgain)
{ {
uint8_t data[] = { uint8_t data[] = {
2, 0x00, 0x01, /* Select Page 1 */ 0x00, 0x01, /* Select Page 1 */
2, 0x3b, lgain, /* Unmute Left MICPGA, set gain */ 0x3b, lgain, /* Unmute Left MICPGA, set gain */
2, 0x3c, rgain, /* Unmute Right MICPGA, set gain */ 0x3c, rgain, /* Unmute Right MICPGA, set gain */
0 // sentinel };
}; tlv320aic3204_config(data, sizeof(data)/2);
tlv320aic3204_config(data);
} }

80
ui.c
View file

@ -25,12 +25,12 @@
//#include <stdlib.h> //#include <stdlib.h>
#include <string.h> #include <string.h>
uistat_t uistat = { uistat_t uistat = {
digit: 6, digit: 6,
current_trace: 0, current_trace: 0,
lever_mode: LM_MARKER, lever_mode: LM_MARKER,
marker_delta: FALSE, marker_delta: FALSE,
marker_tracking : FALSE,
}; };
#define NO_EVENT 0 #define NO_EVENT 0
@ -41,9 +41,9 @@ uistat_t uistat = {
#define EVT_DOWN 0x20 #define EVT_DOWN 0x20
#define EVT_REPEAT 0x40 #define EVT_REPEAT 0x40
#define BUTTON_DOWN_LONG_TICKS 5000 /* 1sec */ #define BUTTON_DOWN_LONG_TICKS 5000 /* 1sec */
#define BUTTON_DOUBLE_TICKS 5000 /* 500ms */ #define BUTTON_DOUBLE_TICKS 2500 /* 500ms */
#define BUTTON_REPEAT_TICKS 1000 /* 100ms */ #define BUTTON_REPEAT_TICKS 625 /* 125ms */
#define BUTTON_DEBOUNCE_TICKS 200 #define BUTTON_DEBOUNCE_TICKS 200
/* lever switch assignment */ /* lever switch assignment */
@ -59,7 +59,7 @@ static uint32_t last_button_down_ticks;
static uint32_t last_button_repeat_ticks; static uint32_t last_button_repeat_ticks;
static int8_t inhibit_until_release = FALSE; static int8_t inhibit_until_release = FALSE;
uint8_t operation_requested = OP_NONE; volatile uint8_t operation_requested = OP_NONE;
int8_t previous_marker = -1; int8_t previous_marker = -1;
@ -71,8 +71,14 @@ enum {
KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_CW, KM_SCALE, KM_REFPOS, KM_EDELAY, KM_VELOCITY_FACTOR, KM_SCALEDELAY KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_CW, KM_SCALE, KM_REFPOS, KM_EDELAY, KM_VELOCITY_FACTOR, KM_SCALEDELAY
}; };
#define NUMINPUT_LEN 10
static uint8_t ui_mode = UI_NORMAL; static uint8_t ui_mode = UI_NORMAL;
static uint8_t keypad_mode; static uint8_t keypad_mode;
static uint8_t keypads_last_index;
static char kp_buf[NUMINPUT_LEN+1];
static int8_t kp_index = 0;
static uint8_t menu_current_level = 0;
static int8_t selection = 0; static int8_t selection = 0;
// Set structure align as WORD (save flash memory) // Set structure align as WORD (save flash memory)
@ -98,18 +104,13 @@ static int16_t last_touch_y;
//int16_t touch_cal[4] = { 1000, 1000, 10*16, 12*16 }; //int16_t touch_cal[4] = { 1000, 1000, 10*16, 12*16 };
//int16_t touch_cal[4] = { 620, 600, 130, 180 }; //int16_t touch_cal[4] = { 620, 600, 130, 180 };
int awd_count; //int awd_count;
//int touch_x, touch_y; //int touch_x, touch_y;
#define NUMINPUT_LEN 10
#define KP_CONTINUE 0 #define KP_CONTINUE 0
#define KP_DONE 1 #define KP_DONE 1
#define KP_CANCEL 2 #define KP_CANCEL 2
static char kp_buf[NUMINPUT_LEN+1];
static int8_t kp_index = 0;
static void ui_mode_normal(void); static void ui_mode_normal(void);
static void ui_mode_menu(void); static void ui_mode_menu(void);
static void ui_mode_numeric(int _keypad_mode); static void ui_mode_numeric(int _keypad_mode);
@ -130,33 +131,29 @@ static int btn_check(void)
int status = 0; int status = 0;
uint32_t ticks = chVTGetSystemTime(); uint32_t ticks = chVTGetSystemTime();
if (changed & (1<<BIT_PUSH)) { if (changed & (1<<BIT_PUSH)) {
if (ticks - last_button_down_ticks >= BUTTON_DEBOUNCE_TICKS) { if ((cur_button & (1<<BIT_PUSH))
if (cur_button & (1<<BIT_PUSH)) { && ticks >= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS) {
// button released // button released
status |= EVT_BUTTON_SINGLE_CLICK; status |= EVT_BUTTON_SINGLE_CLICK;
if (inhibit_until_release) { if (inhibit_until_release) {
status = 0; status = 0;
inhibit_until_release = FALSE; inhibit_until_release = FALSE;
}
} }
last_button_down_ticks = ticks;
} }
} }
if (changed & (1<<BIT_UP1)) { if (changed & (1<<BIT_UP1)) {
if ((cur_button & (1<<BIT_UP1)) if ((cur_button & (1<<BIT_UP1))
&& (ticks >= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS)) { && (ticks >= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS)) {
status |= EVT_UP; status |= EVT_UP;
} }
last_button_down_ticks = ticks;
} }
if (changed & (1<<BIT_DOWN1)) { if (changed & (1<<BIT_DOWN1)) {
if ((cur_button & (1<<BIT_DOWN1)) if ((cur_button & (1<<BIT_DOWN1))
&& (ticks >= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS)) { && (ticks >= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS)) {
status |= EVT_DOWN; status |= EVT_DOWN;
} }
last_button_down_ticks = ticks;
} }
last_button_down_ticks = ticks;
last_button = cur_button; last_button = cur_button;
return status; return status;
@ -169,15 +166,14 @@ static int btn_wait_release(void)
int changed = last_button ^ cur_button; int changed = last_button ^ cur_button;
uint32_t ticks = chVTGetSystemTime(); uint32_t ticks = chVTGetSystemTime();
int status = 0; int status = 0;
if (!inhibit_until_release) { if (!inhibit_until_release) {
if ((cur_button & (1<<BIT_PUSH)) if ((cur_button & (1<<BIT_PUSH))
&& ticks - last_button_down_ticks >= BUTTON_DOWN_LONG_TICKS) { && ticks >= last_button_down_ticks + BUTTON_DOWN_LONG_TICKS) {
inhibit_until_release = TRUE; inhibit_until_release = TRUE;
return EVT_BUTTON_DOWN_LONG; return EVT_BUTTON_DOWN_LONG;
} }
if ((changed & (1<<BIT_PUSH)) if ((changed & (1<<BIT_PUSH))
&& ticks - last_button_down_ticks < BUTTON_DOWN_LONG_TICKS) { && ticks < last_button_down_ticks + BUTTON_DOWN_LONG_TICKS) {
return EVT_BUTTON_SINGLE_CLICK; return EVT_BUTTON_SINGLE_CLICK;
} }
} }
@ -190,14 +186,12 @@ static int btn_wait_release(void)
return 0; return 0;
} }
if (ticks - last_button_down_ticks >= BUTTON_DOWN_LONG_TICKS if (ticks >= last_button_down_ticks + BUTTON_DOWN_LONG_TICKS
&& ticks - last_button_repeat_ticks >= BUTTON_REPEAT_TICKS) { && ticks >= last_button_repeat_ticks + BUTTON_REPEAT_TICKS) {
if (cur_button & (1<<BIT_DOWN1)) { if (cur_button & (1<<BIT_DOWN1))
status |= EVT_DOWN | EVT_REPEAT; status |= EVT_DOWN | EVT_REPEAT;
} if (cur_button & (1<<BIT_UP1))
if (cur_button & (1<<BIT_UP1)) {
status |= EVT_UP | EVT_REPEAT; status |= EVT_UP | EVT_REPEAT;
}
last_button_repeat_ticks = ticks; last_button_repeat_ticks = ticks;
return status; return status;
} }
@ -776,7 +770,7 @@ menu_marker_search_cb(int item, uint8_t data)
i = marker_search_right(markers[active_marker].index); i = marker_search_right(markers[active_marker].index);
break; break;
case 4: /* tracking */ case 4: /* tracking */
marker_tracking = !marker_tracking; uistat.marker_tracking = !uistat.marker_tracking;
break; break;
} }
if (i != -1) if (i != -1)
@ -1047,7 +1041,6 @@ const menuitem_t menu_top[] = {
}; };
#define MENU_STACK_DEPTH_MAX 4 #define MENU_STACK_DEPTH_MAX 4
uint8_t menu_current_level = 0;
const menuitem_t *menu_stack[MENU_STACK_DEPTH_MAX] = { const menuitem_t *menu_stack[MENU_STACK_DEPTH_MAX] = {
menu_top, NULL, NULL, NULL menu_top, NULL, NULL, NULL
}; };
@ -1171,7 +1164,6 @@ typedef struct {
} keypads_t; } keypads_t;
static const keypads_t *keypads; static const keypads_t *keypads;
static uint8_t keypads_last_index;
static const keypads_t keypads_freq[] = { static const keypads_t keypads_freq[] = {
{ 1, 3, KP_PERIOD }, { 1, 3, KP_PERIOD },
@ -1345,7 +1337,7 @@ menu_item_modify_attribute(const menuitem_t *menu, int item,
} }
} }
} else if (menu == menu_marker_search) { } else if (menu == menu_marker_search) {
if (item == 4 && marker_tracking) { if (item == 4 && uistat.marker_tracking) {
*bg = DEFAULT_MENU_TEXT_COLOR; *bg = DEFAULT_MENU_TEXT_COLOR;
*fg = config.menu_normal_color; *fg = config.menu_normal_color;
} }
@ -1535,7 +1527,7 @@ fetch_numeric_target(void)
x /= 10; x /= 10;
uistat.digit = n; uistat.digit = n;
} }
uistat.previous_value = uistat.value; // uistat.previous_value = uistat.value;
} }
static void static void
@ -2152,7 +2144,7 @@ touch_lever_mode_select(void)
static static
void ui_process_touch(void) void ui_process_touch(void)
{ {
awd_count++; // awd_count++;
adc_stop(ADC1); adc_stop(ADC1);
int status = touch_check(); int status = touch_check();
@ -2189,14 +2181,10 @@ void ui_process_touch(void)
void void
ui_process(void) ui_process(void)
{ {
switch (operation_requested) { if (operation_requested&OP_LEVER)
case OP_LEVER:
ui_process_lever(); ui_process_lever();
break; if (operation_requested&OP_TOUCH)
case OP_TOUCH:
ui_process_touch(); ui_process_touch();
break;
}
operation_requested = OP_NONE; operation_requested = OP_NONE;
} }
@ -2204,7 +2192,7 @@ ui_process(void)
static void extcb1(EXTDriver *extp, expchannel_t channel) { static void extcb1(EXTDriver *extp, expchannel_t channel) {
(void)extp; (void)extp;
(void)channel; (void)channel;
operation_requested = OP_LEVER; operation_requested|=OP_LEVER;
//cur_button = READ_PORT() & BUTTON_MASK; //cur_button = READ_PORT() & BUTTON_MASK;
} }
@ -2259,7 +2247,7 @@ test_touch(int *x, int *y)
void void
handle_touch_interrupt(void) handle_touch_interrupt(void)
{ {
operation_requested = OP_TOUCH; operation_requested|= OP_TOUCH;
} }
void void