diff --git a/adc.c b/adc.c index 1da498d..2486210 100644 --- a/adc.c +++ b/adc.c @@ -28,80 +28,79 @@ #define ADC_SMPR_SMP_239P5 7U /**< @brief 252 cycles conversion time. */ #define ADC_CFGR1_RES_12BIT (0U << 3U) +#define VNA_ADC ADC1 + void adc_init(void) { rccEnableADC1(FALSE); /* Ensure flag states */ - ADC1->IER = 0; + VNA_ADC->IER = 0; /* Calibration procedure.*/ ADC->CCR = 0; - if (ADC1->CR & ADC_CR_ADEN) { - ADC1->CR |= ~ADC_CR_ADDIS; /* Disable ADC */ + if (VNA_ADC->CR & ADC_CR_ADEN) { + VNA_ADC->CR |= ~ADC_CR_ADDIS; /* Disable ADC */ } - while (ADC1->CR & ADC_CR_ADEN) + while (VNA_ADC->CR & ADC_CR_ADEN) ; - ADC1->CFGR1 &= ~ADC_CFGR1_DMAEN; - ADC1->CR |= ADC_CR_ADCAL; - while (ADC1->CR & ADC_CR_ADCAL) + VNA_ADC->CFGR1 &= ~ADC_CFGR1_DMAEN; + VNA_ADC->CR |= ADC_CR_ADCAL; + while (VNA_ADC->CR & ADC_CR_ADCAL) ; - if (ADC1->ISR & ADC_ISR_ADRDY) { - ADC1->ISR |= ADC_ISR_ADRDY; /* clear ADRDY */ + if (VNA_ADC->ISR & ADC_ISR_ADRDY) { + VNA_ADC->ISR |= ADC_ISR_ADRDY; /* clear ADRDY */ } /* Enable ADC */ - ADC1->CR |= ADC_CR_ADEN; - while (!(ADC1->ISR & ADC_ISR_ADRDY)) + VNA_ADC->CR |= ADC_CR_ADEN; + while (!(VNA_ADC->ISR & ADC_ISR_ADRDY)) ; } -uint16_t adc_single_read(ADC_TypeDef *adc, uint32_t chsel) +uint16_t adc_single_read(uint32_t chsel) { /* ADC setup */ - adc->ISR = adc->ISR; - adc->IER = 0; - adc->TR = ADC_TR(0, 0); - adc->SMPR = ADC_SMPR_SMP_239P5; - adc->CFGR1 = ADC_CFGR1_RES_12BIT; - adc->CHSELR = chsel; + VNA_ADC->ISR = VNA_ADC->ISR; + VNA_ADC->IER = 0; + VNA_ADC->TR = ADC_TR(0, 0); + VNA_ADC->SMPR = ADC_SMPR_SMP_239P5; + VNA_ADC->CFGR1 = ADC_CFGR1_RES_12BIT; + VNA_ADC->CHSELR = chsel; /* ADC conversion start.*/ - adc->CR |= ADC_CR_ADSTART; + VNA_ADC->CR |= ADC_CR_ADSTART; - while (adc->CR & ADC_CR_ADSTART) + while (VNA_ADC->CR & ADC_CR_ADSTART) ; - return adc->DR; + return VNA_ADC->DR; } -int16_t adc_vbat_read(ADC_TypeDef *adc) +int16_t adc_vbat_read(void) { #define ADC_FULL_SCALE 3300 -#define VBAT_DIODE_VF 500 #define VREFINT_CAL (*((uint16_t*)0x1FFFF7BA)) - float vbat = 0; - float vrefint = 0; - - ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_VBATEN; - // VREFINT == ADC_IN17 - vrefint = adc_single_read(adc, ADC_CHSELR_CHSEL17); - // VBAT == ADC_IN18 - // VBATEN enables resiter devider circuit. It consume vbat power. - vbat = adc_single_read(adc, ADC_CHSELR_CHSEL18); - ADC->CCR &= ~(ADC_CCR_VREFEN | ADC_CCR_VBATEN); - - uint16_t vbat_raw = (ADC_FULL_SCALE * VREFINT_CAL * vbat * 2 / (vrefint * ((1<<12)-1))); - if (vbat_raw < 100) { - // maybe D2 is not installed - return -1; - } - - return vbat_raw + VBAT_DIODE_VF; - + adc_stop(); + float vbat = 0; + float vrefint = 0; + ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_VBATEN; + // VREFINT == ADC_IN17 + vrefint = adc_single_read(ADC_CHSELR_CHSEL17); + // VBAT == ADC_IN18 + // VBATEN enables resiter devider circuit. It consume vbat power. + vbat = adc_single_read(ADC_CHSELR_CHSEL18); + ADC->CCR &= ~(ADC_CCR_VREFEN | ADC_CCR_VBATEN); + touch_start_watchdog(); + uint16_t vbat_raw = (ADC_FULL_SCALE * VREFINT_CAL * vbat * 2 / (vrefint * ((1<<12)-1))); + if (vbat_raw < 100) { + // maybe D2 is not installed + return -1; + } + return vbat_raw + config.vbat_offset; } -void adc_start_analog_watchdogd(ADC_TypeDef *adc, uint32_t chsel) +void adc_start_analog_watchdogd(uint32_t chsel) { uint32_t cfgr1; @@ -111,38 +110,38 @@ void adc_start_analog_watchdogd(ADC_TypeDef *adc, uint32_t chsel) /* ADC setup, if it is defined a callback for the analog watch dog then it is enabled.*/ - adc->ISR = adc->ISR; - adc->IER = ADC_IER_AWDIE; - adc->TR = ADC_TR(0, TOUCH_THRESHOLD); - adc->SMPR = ADC_SMPR_SMP_1P5; - adc->CHSELR = chsel; + VNA_ADC->ISR = VNA_ADC->ISR; + VNA_ADC->IER = ADC_IER_AWDIE; + VNA_ADC->TR = ADC_TR(0, TOUCH_THRESHOLD); + VNA_ADC->SMPR = ADC_SMPR_SMP_1P5; + VNA_ADC->CHSELR = chsel; /* ADC configuration and start.*/ - adc->CFGR1 = cfgr1; + VNA_ADC->CFGR1 = cfgr1; /* ADC conversion start.*/ - adc->CR |= ADC_CR_ADSTART; + VNA_ADC->CR |= ADC_CR_ADSTART; } -void adc_stop(ADC_TypeDef *adc) +void adc_stop(void) { - if (adc->CR & ADC_CR_ADEN) { - if (adc->CR & ADC_CR_ADSTART) { - adc->CR |= ADC_CR_ADSTP; - while (adc->CR & ADC_CR_ADSTP) + if (VNA_ADC->CR & ADC_CR_ADEN) { + if (VNA_ADC->CR & ADC_CR_ADSTART) { + VNA_ADC->CR |= ADC_CR_ADSTP; + while (VNA_ADC->CR & ADC_CR_ADSTP) ; } - /* adc->CR |= ADC_CR_ADDIS; - while (adc->CR & ADC_CR_ADDIS) + /* VNA_ADC->CR |= ADC_CR_ADDIS; + while (VNA_ADC->CR & ADC_CR_ADDIS) ;*/ } } -void adc_interrupt(ADC_TypeDef *adc) +void adc_interrupt(void) { - uint32_t isr = adc->ISR; - adc->ISR = isr; + uint32_t isr = VNA_ADC->ISR; + VNA_ADC->ISR = isr; if (isr & ADC_ISR_OVR) { /* ADC overflow condition, this could happen only if the DMA is unable @@ -159,7 +158,7 @@ OSAL_IRQ_HANDLER(STM32_ADC1_HANDLER) { OSAL_IRQ_PROLOGUE(); - adc_interrupt(ADC1); + adc_interrupt(); OSAL_IRQ_EPILOGUE(); } diff --git a/main.c b/main.c index bb5580b..2593545 100644 --- a/main.c +++ b/main.c @@ -57,6 +57,8 @@ static char shell_line[VNA_SHELL_MAX_LENGTH]; //#define ENABLED_DUMP //#define ENABLE_THREADS_COMMAND //#define ENABLE_TIME_COMMAND +#define ENABLE_VBAT_OFFSET_COMMAND +#define ENABLE_INFO_COMMAND static void apply_error_term_at(int i); static void apply_edelay_at(int i); @@ -72,20 +74,30 @@ static MUTEX_DECL(mutex); #define DRIVE_STRENGTH_AUTO (-1) #define FREQ_HARMONICS (config.harmonic_freq_threshold) #define IS_HARMONIC_MODE(f) ((f) > FREQ_HARMONICS) +// Obsolete, always use interpolate +#define cal_auto_interpolate TRUE -int32_t frequency_offset = 5000; -uint32_t frequency = 10000000; -int8_t drive_strength = DRIVE_STRENGTH_AUTO; -int8_t sweep_enabled = TRUE; -volatile int8_t sweep_once = FALSE; -int8_t cal_auto_interpolate = TRUE; -uint16_t redraw_request = 0; // contains REDRAW_XXX flags -int16_t vbat = 0; +static int32_t frequency_offset = 5000; +static uint32_t frequency = 10000000; +static int8_t drive_strength = DRIVE_STRENGTH_AUTO; +int8_t sweep_mode = SWEEP_ENABLE; +volatile uint8_t redraw_request = 0; // contains REDRAW_XXX flags + +// Version text, displayed in Config->Version menu, also send by info command +const char *info_about[]={ + BOARD_NAME, + "2016-2020 Copyright @edy555", + "Licensed under GPL. See: https://github.com/ttrftech/NanoVNA", + "Version: " VERSION, + "Build Time: " __DATE__ " - " __TIME__, + "Kernel: " CH_KERNEL_VERSION, + "Compiler: " PORT_COMPILER_NAME, + "Architecture: " PORT_ARCHITECTURE_NAME " Core Variant: " PORT_CORE_VARIANT_NAME, + "Port Info: " PORT_INFO, + "Platform: " PLATFORM_NAME, + 0 // sentinel +}; -// -// Profile stack usage (enable threads command by def ENABLE_THREADS_COMMAND) show: -// Stack maximum usage = 576 bytes, free stack = 64 bytes -// static THD_WORKING_AREA(waThread1, 640); static THD_FUNCTION(Thread1, arg) { @@ -94,36 +106,27 @@ static THD_FUNCTION(Thread1, arg) while (1) { bool completed = false; - if (sweep_enabled || sweep_once) { + if (sweep_mode&(SWEEP_ENABLE|SWEEP_ONCE)) { chMtxLock(&mutex); - // Sweep require 8367 system tick completed = sweep(true); - sweep_once = FALSE; + sweep_mode&=~SWEEP_ONCE; chMtxUnlock(&mutex); } else { __WFI(); } chMtxLock(&mutex); - // Ui and render require 800 system tick ui_process(); - if (sweep_enabled) { - if (vbat != -1) { - adc_stop(ADC1); - vbat = adc_vbat_read(ADC1); - touch_start_watchdog(); - draw_battery_status(); - } - + if (sweep_mode&SWEEP_ENABLE) { // calculate trace coordinates and plot only if scan completed if (completed) { if ((domain_mode & DOMAIN_MODE) == DOMAIN_TIME) transform_domain(); plot_into_index(measured); - redraw_request |= REDRAW_CELLS; + redraw_request |= REDRAW_CELLS|REDRAW_BATTERY; - if (marker_tracking) { + if (uistat.marker_tracking) { int i = marker_search(); if (i != -1 && active_marker != -1) { markers[active_marker].index = i; @@ -141,19 +144,19 @@ static THD_FUNCTION(Thread1, arg) static inline void pause_sweep(void) { - sweep_enabled = FALSE; + sweep_mode&=~SWEEP_ENABLE; } static inline void resume_sweep(void) { - sweep_enabled = TRUE; + sweep_mode|=SWEEP_ENABLE; } void toggle_sweep(void) { - sweep_enabled = !sweep_enabled; + sweep_mode^=SWEEP_ENABLE; } static float @@ -316,19 +319,18 @@ const int8_t gain_table[] = { 95 // 2400MHz ~ }; -#define DELAY_GAIN_CHANGE 10 +#define DELAY_GAIN_CHANGE 2 static int -adjust_gain(int newfreq) +adjust_gain(uint32_t newfreq) { - int delay = 0; int new_order = newfreq / FREQ_HARMONICS; int old_order = frequency / FREQ_HARMONICS; if (new_order != old_order) { tlv320aic3204_set_gain(gain_table[new_order], gain_table[new_order]); - delay += DELAY_GAIN_CHANGE; + return DELAY_GAIN_CHANGE; } - return delay; + return 0; } int set_frequency(uint32_t freq) @@ -429,9 +431,9 @@ static int getStringIndex(char *v, const char *list){ } // Set new substring ptr while (1){ - // End of string, not found - if (*list == 0 ) return -1; - if (*list++ == '|') break; + // End of string, not found + if (*list == 0 ) return -1; + if (*list++ == '|') break; } i++; } @@ -474,7 +476,7 @@ VNA_SHELL_FUNCTION(cmd_power) #ifdef ENABLE_TIME_COMMAND #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 VNA_SHELL_FUNCTION(cmd_time) { @@ -559,15 +561,6 @@ volatile int16_t wait_count = 0; float measured[2][POINTS_COUNT][2]; -static void -wait_dsp(int count) -{ - wait_count = count; - //reset_dsp_accumerator(); - while (wait_count) - __WFI(); -} - #ifdef ENABLED_DUMP static void duplicate_buffer_to_dump(int16_t *p) @@ -725,7 +718,8 @@ config_t config = { .trace_color = { DEFAULT_TRACE_1_COLOR, DEFAULT_TRACE_2_COLOR, DEFAULT_TRACE_3_COLOR, DEFAULT_TRACE_4_COLOR }, // .touch_cal = { 693, 605, 124, 171 }, // 2.4 inch LCD panel .touch_cal = { 338, 522, 153, 192 }, // 2.8 inch LCD panel - .harmonic_freq_threshold = 300000000 + .harmonic_freq_threshold = 300000000, + .vbat_offset = 500 }; properties_t current_props; @@ -745,7 +739,8 @@ static const marker_t def_markers[MARKERS_MAX] = { // Load propeties default settings 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._frequency1 = 900000000; // end = 900MHz current_props._sweep_points = POINTS_COUNT; @@ -761,6 +756,8 @@ void loadDefaultProps(void){ current_props._active_marker = 0; current_props._domain_mode = 0; current_props._marker_smith_format = MS_RLC; +//Checksum add on caldata_save +//current_props.checksum = 0; } void @@ -775,24 +772,37 @@ ensure_edit_config(void) cal_status = 0; } -#define DELAY_CHANNEL_CHANGE 3 +#define DSP_START(delay) wait_count = delay; +#define DSP_WAIT_READY while (wait_count) __WFI(); + +#define DELAY_CHANNEL_CHANGE 2 // main loop for measurement bool sweep(bool break_on_operation) { - int i; + int i, delay; // blink LED while scanning palClearPad(GPIOC, GPIOC_LED); - for (i = 0; i < sweep_points; i++) { // 8365 - int delay = set_frequency(frequencies[i]); // 1560 + // Power stabilization after LED off, also align timings + // Also touch made some + DSP_START(1); DSP_WAIT_READY; + for (i = 0; i < sweep_points; i++) { // 5300 + delay = set_frequency(frequencies[i]); // 700 tlv320aic3204_select(0); // 60 CH0:REFLECT - - wait_dsp(delay); // 3270 + DSP_START(delay); // 1900 + //================================================ + // Place some code thats need execute while delay + //================================================ + DSP_WAIT_READY; // calculate reflection coefficient (*sample_func)(measured[0][i]); // 60 tlv320aic3204_select(1); // 60 CH1:TRANSMISSION - wait_dsp(DELAY_CHANNEL_CHANGE); // 2700 + DSP_START(DELAY_CHANNEL_CHANGE); // 1700 + //================================================ + // Place some code thats need execute while delay + //================================================ + DSP_WAIT_READY; // calculate transmission coefficient (*sample_func)(measured[1][i]); // 60 // ======== 170 =========== @@ -841,11 +851,11 @@ VNA_SHELL_FUNCTION(cmd_scan) if (cal_auto_interpolate && (cal_status & CALSTAT_APPLY)) cal_interpolate(lastsaveid); - sweep_once = TRUE; + sweep_mode|= SWEEP_ONCE; chMtxUnlock(&mutex); // wait finishing sweep - while (sweep_once) + while (sweep_mode&SWEEP_ONCE) chThdSleepMilliseconds(10); } @@ -912,7 +922,7 @@ update_frequencies(void) } set_frequencies(start, stop, sweep_points); - operation_requested = OP_FREQCHANGE; +// operation_requested|= OP_FREQCHANGE; update_marker_index(); @@ -1430,6 +1440,7 @@ VNA_SHELL_FUNCTION(cmd_cal) shell_printf("\r\n"); return; } + redraw_request|=REDRAW_CAL_STATUS; // 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"; switch (getStringIndex(argv[0], cmd_cal_list)){ @@ -1439,9 +1450,9 @@ VNA_SHELL_FUNCTION(cmd_cal) case 3:cal_collect(CAL_THRU ); return; case 4:cal_collect(CAL_ISOLN); return; case 5:cal_done(); return; - case 6:cal_status|= CALSTAT_APPLY;redraw_request|=REDRAW_CAL_STATUS; return; - case 7:cal_status&=~CALSTAT_APPLY;redraw_request|=REDRAW_CAL_STATUS; return; - case 8:cal_status = 0; redraw_request|=REDRAW_CAL_STATUS; return; + case 6:cal_status|= CALSTAT_APPLY;return; + case 7:cal_status&=~CALSTAT_APPLY;return; + case 8:cal_status = 0; return; 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_OPEN ][0][0], cal_data[CAL_OPEN ][0][1]); @@ -1451,11 +1462,9 @@ VNA_SHELL_FUNCTION(cmd_cal) return; case 10: cal_interpolate((argc > 1) ? my_atoi(argv[1]) : 0); - redraw_request|=REDRAW_CAL_STATUS; return; default:break; } - shell_printf("usage: cal [%s]\r\n", cmd_cal_list); } @@ -1687,14 +1696,13 @@ VNA_SHELL_FUNCTION(cmd_marker) } return; } + redraw_request |= REDRAW_MARKER; if (strcmp(argv[0], "off") == 0) { active_marker = -1; for (t = 0; t < MARKERS_MAX; t++) markers[t].enabled = FALSE; - redraw_request |= REDRAW_MARKER; return; } - t = my_atoi(argv[0])-1; if (t < 0 || t >= MARKERS_MAX) goto usage; @@ -1703,13 +1711,12 @@ VNA_SHELL_FUNCTION(cmd_marker) active_marker = t; // select active marker markers[t].enabled = TRUE; - redraw_request |= REDRAW_MARKER; return; } static const char cmd_marker_list[] = "on|off"; switch (getStringIndex(argv[1], cmd_marker_list)){ - case 0: markers[t].enabled = TRUE; active_marker = t; redraw_request |= REDRAW_MARKER; return; - case 1: markers[t].enabled =FALSE; if (active_marker == t) active_marker = -1; 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; return; default: // select active marker and move to index markers[t].enabled = TRUE; @@ -1717,7 +1724,6 @@ VNA_SHELL_FUNCTION(cmd_marker) markers[t].index = index; markers[t].frequency = frequencies[index]; active_marker = t; - redraw_request |= REDRAW_MARKER; return; } usage: @@ -1923,8 +1929,8 @@ VNA_SHELL_FUNCTION(cmd_stat) //shell_printf("interval cycle: %d\r\n", stat.interval_cycles); //shell_printf("busy cycle: %d\r\n", stat.busy_cycles); //shell_printf("load: %d\r\n", stat.busy_cycles * 100 / stat.interval_cycles); - extern int awd_count; - shell_printf("awd: %d\r\n", awd_count); +// extern int awd_count; +// shell_printf("awd: %d\r\n", awd_count); } @@ -1945,9 +1951,31 @@ VNA_SHELL_FUNCTION(cmd_vbat) { (void)argc; (void)argv; - shell_printf("%d mV\r\n", vbat); + shell_printf("%d mV\r\n", adc_vbat_read()); } +#ifdef ENABLE_VBAT_OFFSET_COMMAND +VNA_SHELL_FUNCTION(cmd_vbat_offset) +{ + if (argc != 1) { + shell_printf("%d\r\n", config.vbat_offset); + return; + } + config.vbat_offset = (int16_t)my_atoi(argv[0]); +} +#endif + +#ifdef ENABLE_INFO_COMMAND +VNA_SHELL_FUNCTION(cmd_info) +{ + (void)argc; + (void)argv; + int i=0; + while (info_about[i]) + shell_printf("%s\r\n", info_about[i++]); +} +#endif + #ifdef ENABLE_THREADS_COMMAND #if CH_CFG_USE_REGISTRY == FALSE #error "Threads Requite enabled CH_CFG_USE_REGISTRY in chconf.h" @@ -1969,8 +1997,6 @@ VNA_SHELL_FUNCTION(cmd_threads) { #else uint32_t stklimit = 0U; #endif - - shell_printf("%08x|%08x|%08x|%08x|%4u|%4u|%9s|%12s"VNA_SHELL_NEWLINE_STR, stklimit, (uint32_t)tp->ctx.sp, max_stack_use, (uint32_t)tp, (uint32_t)tp->refs - 1, (uint32_t)tp->prio, states[tp->state], @@ -2031,9 +2057,15 @@ static const VNAShellCommand commands[] = {"edelay" , cmd_edelay , 0}, {"capture" , cmd_capture , CMD_WAIT_MUTEX}, {"vbat" , cmd_vbat , 0}, +#ifdef ENABLE_VBAT_OFFSET_COMMAND + {"vbat_offset" , cmd_vbat_offset , 0}, +#endif {"transform" , cmd_transform , 0}, {"threshold" , cmd_threshold , 0}, {"help" , cmd_help , 0}, +#ifdef ENABLE_INFO_COMMAND + {"info" , cmd_info , 0}, +#endif #ifdef ENABLE_THREADS_COMMAND {"threads" , cmd_threads , 0}, #endif @@ -2160,10 +2192,28 @@ THD_FUNCTION(myshellThread, p) { } #endif +// I2C clock bus setting: depend from STM32_I2C1SW in mcuconf.h static const I2CConfig i2ccfg = { - 0x00300506, //voodoo magic 400kHz @ HSI 8MHz - 0, - 0 + .timingr = // TIMINGR register initialization. (use I2C timing configuration tool for STM32F3xx and STM32F0xx microcontrollers (AN4235)) +#if STM32_I2C1SW == STM32_I2C1SW_HSI + // STM32_I2C1SW == STM32_I2C1SW_HSI (HSI=8MHz) + // 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 + //0x00300506, +#elif STM32_I2C1SW == STM32_I2C1SW_SYSCLK + // STM32_I2C1SW == STM32_I2C1SW_SYSCLK (SYSCLK = 48MHz) + // 400kHz @ SYSCLK 48MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual) + STM32_TIMINGR_PRESC(5U) | + STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(3U) | + STM32_TIMINGR_SCLH(3U) | STM32_TIMINGR_SCLL(9U), +#else +#error "Need Define STM32_I2C1SW and set correct TIMINGR settings" +#endif + .cr1 = 0, // CR1 register initialization. + .cr2 = 0 // CR2 register initialization. }; static DACConfig dac1cfg1 = { diff --git a/mcuconf.h b/mcuconf.h index 3db6404..9021c85 100644 --- a/mcuconf.h +++ b/mcuconf.h @@ -58,7 +58,8 @@ #define STM32_ADCSW STM32_ADCSW_HSI14 #define STM32_USBSW STM32_USBSW_HSI48 #define STM32_CECSW STM32_CECSW_HSI -#define STM32_I2C1SW STM32_I2C1SW_HSI +//#define STM32_I2C1SW STM32_I2C1SW_HSI +#define STM32_I2C1SW STM32_I2C1SW_SYSCLK #define STM32_USART1SW STM32_USART1SW_PCLK #define STM32_RTCSEL STM32_RTCSEL_LSI diff --git a/nanovna.h b/nanovna.h index 524b2aa..d5d14cc 100644 --- a/nanovna.h +++ b/nanovna.h @@ -86,31 +86,10 @@ double my_atof(const char *p); void toggle_sweep(void); void loadDefaultProps(void); -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; +#define SWEEP_ENABLE 0x01 +#define SWEEP_ONCE 0x02 +extern int8_t sweep_mode; +extern const char *info_about[]; /* * dsp.c @@ -134,9 +113,6 @@ void calculate_gamma(float *gamma); void fetch_amplitude(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 */ @@ -243,8 +219,8 @@ typedef struct config { int16_t touch_cal[4]; int8_t reserved_1; uint32_t harmonic_freq_threshold; - - uint8_t _reserved[24]; + uint16_t vbat_offset; + uint8_t _reserved[22]; uint32_t checksum; } config_t; @@ -259,7 +235,6 @@ void set_trace_refpos(int t, float refpos); float get_trace_scale(int t); float get_trace_refpos(int t); const char *get_trace_typename(int t); -void draw_battery_status(void); void set_electrical_delay(float picoseconds); float get_electrical_delay(void); @@ -302,14 +277,13 @@ int marker_search(void); int marker_search_left(int from); int marker_search_right(int from); -extern uint16_t redraw_request; - +// _request flag for update screen #define REDRAW_CELLS (1<<0) #define REDRAW_FREQUENCY (1<<1) #define REDRAW_CAL_STATUS (1<<2) #define REDRAW_MARKER (1<<3) - -extern int16_t vbat; +#define REDRAW_BATTERY (1<<4) +extern volatile uint8_t redraw_request; /* * ili9341.c @@ -366,6 +340,16 @@ void show_logo(void); * 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 typedef struct properties { uint32_t magic; @@ -432,6 +416,15 @@ void clear_all_config_prop_data(void); /* * 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 enum lever_mode { @@ -448,13 +441,13 @@ typedef struct uistat { int8_t digit_mode; int8_t current_trace; /* 0..3 */ uint32_t value; // for editing at numeric input area - uint32_t previous_value; +// uint32_t previous_value; uint8_t lever_mode; - bool marker_delta; + uint8_t marker_delta; + uint8_t marker_tracking; } uistat_t; extern uistat_t uistat; - void ui_init(void); void ui_show(void); void ui_hide(void); @@ -474,11 +467,11 @@ void enter_dfu(void); */ void adc_init(void); -uint16_t adc_single_read(ADC_TypeDef *adc, uint32_t chsel); -void adc_start_analog_watchdogd(ADC_TypeDef *adc, uint32_t chsel); -void adc_stop(ADC_TypeDef *adc); -void adc_interrupt(ADC_TypeDef *adc); -int16_t adc_vbat_read(ADC_TypeDef *adc); +uint16_t adc_single_read(uint32_t chsel); +void adc_start_analog_watchdogd(uint32_t chsel); +void adc_stop(void); +void adc_interrupt(void); +int16_t adc_vbat_read(void); /* * misclinous diff --git a/plot.c b/plot.c index 70f5e31..5d712a6 100644 --- a/plot.c +++ b/plot.c @@ -6,6 +6,7 @@ #include "nanovna.h" static void cell_draw_marker_info(int x0, int y0); +static void draw_battery_status(void); int16_t grid_offset; int16_t grid_width; @@ -1056,7 +1057,6 @@ static int greater(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; -int8_t marker_tracking = false; int marker_search(void) @@ -1389,6 +1389,8 @@ draw_all(bool flush) draw_frequencies(); if (redraw_request & REDRAW_CAL_STATUS) draw_cal_status(); + if (redraw_request & REDRAW_BATTERY) + draw_battery_status(); redraw_request = 0; } @@ -1662,10 +1664,10 @@ draw_cal_status(void) #define BATTERY_BOTTOM_LEVEL 3100 #define BATTERY_WARNING_LEVEL 3300 -void -draw_battery_status(void) +static void draw_battery_status(void) { - if (vbat<=0) + int16_t vbat = adc_vbat_read(); + if (vbat <= 0) return; uint8_t string_buf[16]; // Set battery color diff --git a/si5351.c b/si5351.c index 56ba597..92eeb8a 100644 --- a/si5351.c +++ b/si5351.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com + * Modified by DiSlord dislordlive@gmail.com * All rights reserved. * * This is free software; you can redistribute it and/or modify @@ -21,40 +22,64 @@ #include "nanovna.h" #include "si5351.h" -#define SI5351_I2C_ADDR (0x60<<1) +// Enable cache for SI5351 CLKX_CONTROL register, little speedup exchange +#define USE_CLK_CONTROL_CACHE TRUE -static void -si5351_write(uint8_t reg, uint8_t dat) -{ - int addr = SI5351_I2C_ADDR>>1; - uint8_t buf[] = { reg, dat }; - i2cAcquireBus(&I2CD1); - (void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, 2, NULL, 0, 1000); - i2cReleaseBus(&I2CD1); -} +// XTAL frequency on si5351 +#define XTALFREQ 26000000U +// MCLK (processor clock if set, audio codec) frequency clock +#define CLK2_FREQUENCY 8000000U + +// Fixed PLL mode multiplier (used in band 1) +#define PLL_N 32 + +// I2C address on bus (only 0x60 for Si5351A in 10-Pin MSOP) +#define SI5351_I2C_ADDR 0x60 + +static uint8_t current_band = 0; +static uint32_t current_freq = 0; static void si5351_bulk_write(const uint8_t *buf, int len) +{ + i2cAcquireBus(&I2CD1); + (void)i2cMasterTransmitTimeout(&I2CD1, SI5351_I2C_ADDR, buf, len, NULL, 0, 1000); + 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); - (void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, len, NULL, 0, 1000); + msg_t mr = i2cMasterTransmitTimeout(&I2CD1, addr, ®, 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, ... const uint8_t si5351_configs[] = { 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff, 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, +// All of this init code run late on sweep +#if 0 // 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 - 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) 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_3_OUTPUT_ENABLE_CONTROL, 0, +#endif + 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, ~(SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN), 0 // sentinel }; @@ -71,232 +96,207 @@ si5351_init(void) static const uint8_t disable_output[] = { SI5351_REG_16_CLK0_CONTROL, - SI5351_CLK_POWERDOWN, - SI5351_CLK_POWERDOWN, - SI5351_CLK_POWERDOWN + SI5351_CLK_POWERDOWN, // CLK 0 + SI5351_CLK_POWERDOWN, // CLK 1 + 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 +}; + +// Reset PLL need then band changes +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(400); + si5351_write(SI5351_REG_177_PLL_RESET, mask | 0x0C); +} + void si5351_disable_output(void) { - 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)); + current_band = 0; } void si5351_enable_output(void) { - si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0x00); + si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, ~(SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN)); +//si5351_reset_pll(SI5351_PLL_RESET_A | SI5351_PLL_RESET_B); + current_freq = 0; + current_band = 0; } -static void si5351_reset_pll(void) +// Set PLL freq = XTALFREQ * (mult + num/denom) +static void si5351_setupPLL(uint8_t pllSource, /* SI5351_REG_PLL_A or SI5351_REG_PLL_B */ + uint32_t mult, + uint32_t num, + uint32_t denom) { - //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 */ - uint8_t mult, - uint32_t num, - 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 P2; - uint32_t P3; - /* Feedback Multisynth Divider Equation * where: a = mult, b = num and c = denom * P1 register is an 18-bit value using following formula: - * P1[17:0] = 128 * mult + floor(128*(num/denom)) - 512 + * P1[17:0] = 128 * mult + int((128*num)/denom) - 512 * P2 register is a 20-bit value using the following formula: - * P2[19:0] = 128 * num - denom * floor(128*(num/denom)) + * P2[19:0] = (128 * num) % denom * P3 register is a 20-bit value using the following formula: * P3[19:0] = denom */ - /* Set the main PLL config registers */ - if (num == 0) - { - /* Integer mode */ - P1 = 128 * mult - 512; - P2 = 0; - P3 = 1; - } - else - { - /* Fractional mode */ - //P1 = (uint32_t)(128 * mult + floor(128 * ((float)num/(float)denom)) - 512); - P1 = 128 * mult + ((128 * num) / denom) - 512; - //P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom))); - P2 = 128 * num - denom * ((128 * num) / denom); + mult<<=7; + num<<=7; + uint32_t P1 = mult - 512; // Integer mode + uint32_t P2 = 0; + uint32_t P3 = 1; + if (num){ // Fractional mode + P1+= num / denom; + P2 = num % denom; P3 = denom; } - - /* The datasheet is a nightmare of typos and inconsistencies here! */ + // Pll MSN(A|B) registers Datasheet uint8_t reg[9]; - reg[0] = pllreg_base[pll]; - reg[1] = (P3 & 0x0000FF00) >> 8; - reg[2] = (P3 & 0x000000FF); - reg[3] = (P1 & 0x00030000) >> 16; - reg[4] = (P1 & 0x0000FF00) >> 8; - reg[5] = (P1 & 0x000000FF); - reg[6] = ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16); - reg[7] = (P2 & 0x0000FF00) >> 8; - reg[8] = (P2 & 0x000000FF); + reg[0]= pllSource; // SI5351_REG_PLL_A or SI5351_REG_PLL_B + reg[1]=( P3 & 0x0FF00)>> 8; // MSN_P3[15: 8] + reg[2]=( P3 & 0x000FF); // MSN_P3[ 7: 0] + reg[3]=( P1 & 0x30000)>>16; // MSN_P1[17:16] + reg[4]=( P1 & 0x0FF00)>> 8; // MSN_P1[15: 8] + reg[5]=( P1 & 0x000FF); // MSN_P1[ 7: 0] + reg[6]=((P3 & 0xF0000)>>12)|((P2 & 0xF0000)>>16); // MSN_P3[19:16] | MSN_P2[19:16] + reg[7]=( P2 & 0x0FF00)>> 8; // MSN_P2[15: 8] + reg[8]=( P2 & 0x000FF); // MSN_P2[ 7: 0] si5351_bulk_write(reg, 9); } +// Set Multisynth divider = (div + num/denom) * rdiv static void -si5351_setupMultisynth(uint8_t output, - uint8_t pllSource, - uint32_t div, // 4,6,8, 8+ ~ 900 - uint32_t num, - uint32_t denom, - uint32_t rdiv, // SI5351_R_DIV_1~128 - uint8_t drive_strength) +si5351_setupMultisynth(uint8_t channel, + uint32_t div, // 4,6,8, 8+ ~ 900 + uint32_t num, + uint32_t denom, + uint32_t rdiv, // SI5351_R_DIV_1~128 + uint8_t chctrl) // SI5351_REG_16_CLKX_CONTROL settings { - /* 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; - - uint32_t P1; - uint32_t P2; - uint32_t P3; - uint32_t div4 = 0; - /* Output Multisynth Divider Equations * where: a = div, b = num and c = denom * P1 register is an 18-bit value using following formula: - * P1[17:0] = 128 * a + floor(128*(b/c)) - 512 + * P1[17:0] = 128 * a + int((128*b)/c) - 512 * P2 register is a 20-bit value using the following formula: - * P2[19:0] = 128 * b - c * floor(128*(b/c)) + * P2[19:0] = (128 * b) % c * P3 register is a 20-bit value using the following formula: - * P3[19:0] = c + * P3[19:0] = c */ /* Set the main PLL config registers */ - if (div == 4) { - div4 = SI5351_DIVBY4; - P1 = P2 = 0; - P3 = 1; - } else if (num == 0) { - /* Integer mode */ - P1 = 128 * div - 512; - P2 = 0; - P3 = 1; - } else { - /* Fractional mode */ - P1 = 128 * div + ((128 * num) / denom) - 512; - P2 = 128 * num - denom * ((128 * num) / denom); - P3 = denom; + uint32_t P1 = 0; + uint32_t P2 = 0; + uint32_t P3 = 1; + if (div == 4) + rdiv|= SI5351_DIVBY4; + else { + num<<=7; + div<<=7; + P1 = div - 512; // Integer mode + if (num){ // Fractional mode + P1+= num / denom; + P2 = num % denom; + P3 = denom; + } } - /* Set the MSx config registers */ uint8_t reg[9]; - reg[0] = msreg_base[output]; - reg[1] = (P3 & 0x0000FF00) >> 8; - reg[2] = (P3 & 0x000000FF); - reg[3] = ((P1 & 0x00030000) >> 16) | div4 | rdiv; - reg[4] = (P1 & 0x0000FF00) >> 8; - reg[5] = (P1 & 0x000000FF); - reg[6] = ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16); - reg[7] = (P2 & 0x0000FF00) >> 8; - reg[8] = (P2 & 0x000000FF); + reg[0]= msreg_base[channel]; // SI5351_REG_42_MULTISYNTH0, SI5351_REG_50_MULTISYNTH1, SI5351_REG_58_MULTISYNTH2 + reg[1]=( P3 & 0x0FF00)>>8; // MSx_P3[15: 8] + reg[2]=( P3 & 0x000FF); // MSx_P3[ 7: 0] + reg[3]=((P1 & 0x30000)>>16)| rdiv; // Rx_DIV[2:0] | MSx_DIVBY4[1:0] | MSx_P1[17:16] + reg[4]=( P1 & 0x0FF00)>> 8; // MSx_P1[15: 8] + reg[5]=( P1 & 0x000FF); // MSx_P1[ 7: 0] + reg[6]=((P3 & 0xF0000)>>12)|((P2 & 0xF0000)>>16); // MSx_P3[19:16] | MSx_P2[19:16] + reg[7]=( P2 & 0x0FF00)>>8; // MSx_P2[15: 8] + reg[8]=( P2 & 0x000FF); // MSx_P2[ 7: 0] si5351_bulk_write(reg, 9); /* Configure the clk control and enable the output */ - dat = drive_strength | SI5351_CLK_INPUT_MULTISYNTH_N; - if (pllSource == SI5351_PLL_B) - dat |= SI5351_CLK_PLL_SELECT_B; + uint8_t dat = chctrl | SI5351_CLK_INPUT_MULTISYNTH_N; if (num == 0) dat |= SI5351_CLK_INTEGER_MODE; - si5351_write(clkctrl[output], dat); + +#if USE_CLK_CONTROL_CACHE == TRUE + // Use cache for this reg, not update if not change + static uint8_t clk_cache[3]; + if (clk_cache[channel]!=dat){ + si5351_write(clkctrl[channel], dat); + clk_cache[channel]=dat; + } +#else + si5351_write(clkctrl[channel], dat); +#endif } -#define XTALFREQ 26000000L -#define PLL_N 32 -#define PLLFREQ (XTALFREQ * PLL_N) - -static void -si5351_set_frequency_fixedpll(int channel, int pll, uint32_t pllfreq, uint32_t freq, - int rdiv, uint8_t drive_strength, int mul) -{ - int denom = freq; - int div = (pllfreq * mul) / denom; // range: 8 ~ 1800 - int num = (pllfreq * mul) - denom * div; - - // cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227 - int max_denominator = (1 << 20) - 1; - if (denom > max_denominator) { - int p0 = 0, q0 = 1, p1 = 1, q1 = 0; - while (denom != 0) { - int a = num / denom; - int q2 = q0 + a*q1; - if (q2 > max_denominator) - break; - int p2 = p0 + a*p1; - p0 = p1; q0 = q1; p1 = p2; q1 = q2; - int new_denom = num - a * denom; - num = denom; denom = new_denom; - } - num = p1; - denom = q1; +// Find better approximate values for n/d +#define MAX_DENOMINATOR ((1 << 20) - 1) +static inline void fractionalSolve(uint32_t *n, uint32_t *d){ + // cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227 + uint32_t denom = *d; + if (denom > MAX_DENOMINATOR) { + uint32_t num = *n; + uint32_t p0 = 0, q0 = 1, p1 = 1, q1 = 0; + while (denom != 0) { + uint32_t a = num / denom; + uint32_t b = num % denom; + uint32_t q2 = q0 + a*q1; + if (q2 > MAX_DENOMINATOR) + break; + uint32_t p2 = p0 + a*p1; + p0 = p1; q0 = q1; p1 = p2; q1 = q2; + num = denom; denom = b; } - - si5351_setupMultisynth(channel, pll, div, num, denom, rdiv, drive_strength); + *n = p1; + *d = q1; + } } +// Setup Multisynth divider for get correct output freq if fixed PLL = pllfreq static void -si5351_set_frequency_fixeddiv(int channel, int pll, uint32_t freq, int div, - uint8_t drive_strength, int mul) +si5351_set_frequency_fixedpll(uint8_t channel, uint64_t pllfreq, uint32_t freq, uint32_t rdiv, uint8_t chctrl) { - int denom = XTALFREQ * mul; - 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 - int max_denominator = (1 << 20) - 1; - if (denom > max_denominator) { - int p0 = 0, q0 = 1, p1 = 1, q1 = 0; - while (denom != 0) { - int a = num / denom; - int q2 = q0 + a*q1; - if (q2 > max_denominator) - break; - int p2 = p0 + a*p1; - p0 = p1; q0 = q1; p1 = p2; q1 = q2; - int new_denom = num - a * denom; - num = denom; denom = new_denom; - } - num = p1; - denom = q1; - } - - si5351_setupPLL(pll, multi, num, denom); - si5351_setupMultisynth(channel, pll, div, 0, 1, SI5351_R_DIV_1, drive_strength); + uint32_t denom = freq; + uint32_t div = pllfreq / denom; // range: 8 ~ 1800 + uint32_t num = pllfreq % denom; + fractionalSolve(&num, &denom); + si5351_setupMultisynth(channel, div, num, denom, rdiv, chctrl); +} + +// Setup PLL freq if Multisynth divider fixed = div (need get output = freq/mul) +static void +si5351_setupPLL_freq(uint32_t pllSource, uint32_t freq, uint32_t div, uint32_t mul){ + uint32_t denom = XTALFREQ * mul; + uint64_t pllfreq = (uint64_t)freq * div; + uint32_t multi = pllfreq / denom; + uint32_t num = pllfreq % denom; + fractionalSolve(&num, &denom); + si5351_setupPLL(pllSource, 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 -void -si5351_set_frequency(int channel, int freq, uint8_t drive_strength) +static void +si5351_set_frequency_fixeddiv(uint8_t channel, uint32_t pll, uint32_t freq, uint32_t div, + uint8_t chctrl, uint32_t mul) { + si5351_setupPLL_freq(pll, freq, div, mul); + si5351_setupMultisynth(channel, div, 0, 1, SI5351_R_DIV_1, chctrl); +} + +void +si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength){ if (freq <= 100000000) { 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); @@ -308,117 +308,116 @@ si5351_set_frequency(int channel, int freq, uint8_t drive_strength) } #endif -int current_band = -1; +/* + * Frequency generation divide on 3 band + * Band 1 + * 1~100MHz fixed PLL = XTALFREQ * PLL_N, fractional divider + * Band 2 + * 100~150MHz fractional PLL = 600- 900MHz, fixed divider 'fdiv = 6' + * Band 3 + * 150~300MHz fractional PLL = 600-1200MHz, fixed divider 'fdiv = 4' + * + * For FREQ_HARMONICS = 300MHz - band range is: + * +-----------------------------------------------------------------------------------------------------------------------+ + * | Band 1 | Band 2 | Band 3 | Band 2 | Band 3 | + * +-----------------------------------------------------------------------------------------------------------------------+ + * | Direct mode x1 : x1 | x3 : x5 | x5-x7 | x7-x9 | x9-x11 | + * +-----------------------------------------------------------------------------------------------------------------------+ + * | 50kHz - 100MHz | 100 - 150MHz | 150 - 300MHz | 300-450MHz | 450-900MHz | 900-1500MHz | 1500-2100MHz | 2100-2700MHz | + * +-----------------------------------------------------------------------------------------------------------------------+ + * | f = 50kHz-300MHz | f=100-150 | f=150-300 | f=150-300 | f=214-300 | f=233-300 | + * | of = 50kHz-300MHz |of= 60- 90 |of= 90-180 |of=128-215 |of=166-234 |of=190-246 | + * +-----------------------------------------------------------------------------------------------------------------------+ + */ +static inline uint8_t si5351_getBand(uint32_t freq){ + if (freq < 100000000U) return 1; + if (freq < 150000000U) return 2; + return 3; +} -#define DELAY_NORMAL 3 -#define DELAY_BANDCHANGE 1 -#define DELAY_LOWBAND 1 +// Minimum value is 2, freq change apply at next dsp measure, and need skip it +#define DELAY_NORMAL 2 +// Additional delay for band 1 (remove unstable generation at begin) +#define DELAY_BAND_1 1 +// Band changes need additional delay after reset PLL +#define DELAY_BANDCHANGE_1 2 +#define DELAY_BANDCHANGE_2 2 /* + * Maximum supported frequency = FREQ_HARMONICS * 9U * configure output as follows: * CLK0: frequency + offset * CLK1: frequency * CLK2: fixed 8MHz */ -#define CLK2_FREQUENCY 8000000L int -si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength) -{ - int band; +si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength){ + uint8_t band; int delay = DELAY_NORMAL; + if (freq == current_freq) + return delay; uint32_t ofreq = freq + offset; uint32_t mul = 1, omul = 1; uint32_t rdiv = SI5351_R_DIV_1; + uint32_t fdiv; + current_freq = freq; if (freq >= config.harmonic_freq_threshold * 7U) { - mul = 9; + mul = 9; omul = 11; } else if (freq >= config.harmonic_freq_threshold * 5U) { - mul = 7; + mul = 7; omul = 9; } else if (freq >= config.harmonic_freq_threshold * 3U) { - mul = 5; + mul = 5; omul = 7; } else if (freq >= config.harmonic_freq_threshold) { - mul = 3; + mul = 3; omul = 5; } - if ((freq / mul) < 100000000U) { - band = 0; - } else if ((freq / mul) < 150000000U) { - band = 1; - } else { - band = 2; - } - if (freq <= 500000U) { + else if (freq <= 500000U) { rdiv = SI5351_R_DIV_64; + freq<<= 6; + ofreq<<= 6; } else if (freq <= 4000000U) { rdiv = SI5351_R_DIV_8; + freq<<= 3; + ofreq<<= 3; } -#if 1 - if (current_band != band) - si5351_disable_output(); -#endif - + band = si5351_getBand(freq/mul); 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: - // Set PLL twice on changing from band 2 - if (current_band == 2) { - si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul); - si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul); + // Setup CH0 and CH1 constant PLLA freq at band change, and set CH2 freq = CLK2_FREQUENCY + if (current_band != 1){ + si5351_setupPLL(SI5351_REG_PLL_A, PLL_N, 0, 1); + si5351_set_frequency_fixedpll(2, XTALFREQ * PLL_N, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA|SI5351_CLK_PLL_SELECT_A); + delay+=DELAY_BANDCHANGE_1; } - - // div by 6 mode. both PLL A and B are dedicated for CLK0, CLK1 - si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul); - 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); + // Calculate and set CH0 and CH1 divider + si5351_set_frequency_fixedpll(0, (uint64_t)omul * XTALFREQ * PLL_N, ofreq, rdiv, drive_strength|SI5351_CLK_PLL_SELECT_A); + si5351_set_frequency_fixedpll(1, (uint64_t) mul * XTALFREQ * PLL_N, freq, rdiv, drive_strength|SI5351_CLK_PLL_SELECT_A); + delay+=DELAY_BAND_1; break; - - case 2: - // div by 4 mode. both PLL A and B are dedicated for CLK0, CLK1 - si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 4, drive_strength, omul); - si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 4, drive_strength, mul); - si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq / mul * 4, CLK2_FREQUENCY, - SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1); + case 2:// fdiv = 6 + case 3:// fdiv = 4; + fdiv = (band == 2) ? 6 : 4; + // Setup CH0 and CH1 constant fdiv divider at change + if (current_band != band){ + si5351_setupMultisynth(0, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength|SI5351_CLK_PLL_SELECT_A); + si5351_setupMultisynth(1, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength|SI5351_CLK_PLL_SELECT_B); + delay+=DELAY_BANDCHANGE_2; + } + // 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, (uint64_t)freq*fdiv, CLK2_FREQUENCY*mul, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA|SI5351_CLK_PLL_SELECT_B); break; } if (current_band != band) { - si5351_reset_pll(); -#if 1 - si5351_enable_output(); -#endif - delay += DELAY_BANDCHANGE; + si5351_reset_pll(SI5351_PLL_RESET_A|SI5351_PLL_RESET_B); + current_band = band; } - if (band == 0) - delay += DELAY_LOWBAND; - - current_band = band; return delay; } diff --git a/si5351.h b/si5351.h index 0a10c96..6b5bdf5 100644 --- a/si5351.h +++ b/si5351.h @@ -17,12 +17,39 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ -#define SI5351_PLL_A 0 -#define SI5351_PLL_B 1 -#define SI5351_MULTISYNTH_DIV_4 4 -#define SI5351_MULTISYNTH_DIV_6 6 -#define SI5351_MULTISYNTH_DIV_8 8 +#define SI5351_REG_3_OUTPUT_ENABLE_CONTROL 3 +#define SI5351_CLK0_EN (1<<0) +#define SI5351_CLK1_EN (1<<1) +#define SI5351_CLK2_EN (1<<2) + +// Reg 16-18 CLKX_CONTROL +#define SI5351_REG_16_CLK0_CONTROL 16 +#define SI5351_REG_17_CLK1_CONTROL 17 +#define SI5351_REG_18_CLK2_CONTROL 18 +#define SI5351_CLK_POWERDOWN (1<<7) +#define SI5351_CLK_INTEGER_MODE (1<<6) +#define SI5351_CLK_PLL_SELECT_A (0<<5) +#define SI5351_CLK_PLL_SELECT_B (1<<5) +#define SI5351_CLK_INVERT (1<<4) +#define SI5351_CLK_INPUT_MASK (3<<2) +#define SI5351_CLK_INPUT_XTAL (0<<2) +#define SI5351_CLK_INPUT_CLKIN (1<<2) +#define SI5351_CLK_INPUT_MULTISYNTH_0_4 (2<<2) +#define SI5351_CLK_INPUT_MULTISYNTH_N (3<<2) +#define SI5351_CLK_DRIVE_STRENGTH_MASK (3<<0) +#define SI5351_CLK_DRIVE_STRENGTH_2MA (0<<0) +#define SI5351_CLK_DRIVE_STRENGTH_4MA (1<<0) +#define SI5351_CLK_DRIVE_STRENGTH_6MA (2<<0) +#define SI5351_CLK_DRIVE_STRENGTH_8MA (3<<0) + +#define SI5351_REG_PLL_A 26 +#define SI5351_REG_PLL_B 34 + +#define SI5351_REG_42_MULTISYNTH0 42 +#define SI5351_REG_50_MULTISYNTH1 50 +#define SI5351_REG_58_MULTISYNTH2 58 +#define SI5351_DIVBY4 (3<<2) #define SI5351_R_DIV_1 (0<<4) #define SI5351_R_DIV_2 (1<<4) #define SI5351_R_DIV_4 (2<<4) @@ -31,35 +58,6 @@ #define SI5351_R_DIV_32 (5<<4) #define SI5351_R_DIV_64 (6<<4) #define SI5351_R_DIV_128 (7<<4) -#define SI5351_DIVBY4 (3<<2) - -#define SI5351_REG_3_OUTPUT_ENABLE_CONTROL 3 -#define SI5351_REG_16_CLK0_CONTROL 16 -#define SI5351_REG_17_CLK1_CONTROL 17 -#define SI5351_REG_18_CLK2_CONTROL 18 -#define SI5351_REG_26_PLL_A 26 -#define SI5351_REG_34_PLL_B 34 -#define SI5351_REG_42_MULTISYNTH0 42 -#define SI5351_REG_50_MULTISYNTH1 50 -#define SI5351_REG_58_MULTISYNTH2 58 - -#define SI5351_CLK_POWERDOWN (1<<7) -#define SI5351_CLK_INTEGER_MODE (1<<6) -#define SI5351_CLK_PLL_SELECT_B (1<<5) -#define SI5351_CLK_INVERT (1<<4) - -#define SI5351_CLK_INPUT_MASK (3<<2) -#define SI5351_CLK_INPUT_XTAL (0<<2) -#define SI5351_CLK_INPUT_CLKIN (1<<2) -#define SI5351_CLK_INPUT_MULTISYNTH_0_4 (2<<2) -#define SI5351_CLK_INPUT_MULTISYNTH_N (3<<2) - -#define SI5351_CLK_DRIVE_STRENGTH_MASK (3<<0) -#define SI5351_CLK_DRIVE_STRENGTH_2MA (0<<0) -#define SI5351_CLK_DRIVE_STRENGTH_4MA (1<<0) -#define SI5351_CLK_DRIVE_STRENGTH_6MA (2<<0) -#define SI5351_CLK_DRIVE_STRENGTH_8MA (3<<0) - #define SI5351_REG_177_PLL_RESET 177 #define SI5351_PLL_RESET_B (1<<7) @@ -70,8 +68,8 @@ #define SI5351_CRYSTAL_LOAD_8PF (2<<6) #define SI5351_CRYSTAL_LOAD_10PF (3<<6) -#define SI5351_CRYSTAL_FREQ_25MHZ 25000000 - 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); diff --git a/tlv320aic3204.c b/tlv320aic3204.c index cb86ad5..c1b57b5 100644 --- a/tlv320aic3204.c +++ b/tlv320aic3204.c @@ -25,74 +25,78 @@ #define wait_ms(ms) chThdSleepMilliseconds(ms) -static const uint8_t conf_data_pll[] = { - // len, ( reg, data ), - 2, 0x00, 0x00, /* Initialize to Page 0 */ - 2, 0x01, 0x01, /* Initialize the device through software reset */ - 2, 0x04, 0x43, /* PLL Clock High, MCLK, PLL */ +static const uint8_t conf_data[] = { +// reg, data, +// PLL clock config + 0x00, 0x00, /* Initialize to Page 0 */ + 0x01, 0x01, /* Initialize the device through software reset */ + 0x04, 0x43, /* PLL Clock High, MCLK, PLL */ #ifdef REFCLK_8000KHZ /* 8.000MHz*10.7520 = 86.016MHz, 86.016MHz/(2*7*128) = 48kHz */ - 2, 0x05, 0x91, /* Power up PLL, P=1,R=1 */ - 2, 0x06, 0x0a, /* J=10 */ - 2, 0x07, 29, /* D=7520 = (29<<8) + 96 */ - 2, 0x08, 96, + 0x05, 0x91, /* Power up PLL, P=1,R=1 */ + 0x06, 0x0a, /* J=10 */ + 0x07, 29, /* D=7520 = (29<<8) + 96 */ + 0x08, 96, #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_clk[] = { - 2, 0x0b, 0x82, /* Power up the NDAC divider with value 2 */ - 2, 0x0c, 0x87, /* Power up the MDAC divider with value 7 */ - 2, 0x0d, 0x00, /* Program the OSR of DAC to 128 */ - 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_unmute[] = { +// reg, data, + 0x00, 0x00, /* Select Page 0 */ + 0x51, 0xc0, /* Power up Left and Right ADC Channels */ + 0x52, 0x00, /* Unmute Left and Right ADC Digital Volume Control */ }; -static const uint8_t conf_data_routing[] = { - 2, 0x00, 0x01, /* Select Page 1 */ - 2, 0x01, 0x08, /* Disable Internal Crude AVdd in presence of external AVdd supply or before powering up internal AVdd LDO*/ - 2, 0x02, 0x01, /* Enable Master Analog Power Control */ - 2, 0x7b, 0x01, /* Set the REF charging time to 40ms */ - 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 +static const uint8_t conf_data_ch3_select[] = { +// reg, data, + 0x00, 0x01, /* Select Page 1 */ + 0x37, 0x04, /* Route IN3R to RIGHT_P with input impedance of 10K */ + 0x39, 0x04, /* Route IN3L to RIGHT_N with input impedance of 10K */ }; -const uint8_t conf_data_unmute[] = { - 2, 0x00, 0x00, /* Select Page 0 */ - 2, 0x51, 0xc0, /* Power up Left and Right ADC Channels */ - 2, 0x52, 0x00, /* Unmute Left and Right ADC Digital Volume Control */ - 0 // sentinel +static const uint8_t conf_data_ch1_select[] = { +// reg, data, + 0x00, 0x01, /* Select Page 1 */ + 0x37, 0x40, /* Route IN1R to RIGHT_P with input impedance of 10K */ + 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) { - int addr = AIC3204_ADDR; - i2cAcquireBus(&I2CD1); - (void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, len, NULL, 0, 1000); - i2cReleaseBus(&I2CD1); + (void)i2cMasterTransmitTimeout(&I2CD1, AIC3204_ADDR, buf, len, NULL, 0, 1000); } #if 0 @@ -109,49 +113,32 @@ tlv320aic3204_read(uint8_t d0) #endif static void -tlv320aic3204_config(const uint8_t *data) +tlv320aic3204_config(const uint8_t *data, int len) { - const uint8_t *p = data; - while (*p) { - uint8_t len = *p++; - tlv320aic3204_bulk_write(p, len); - p += len; - } + i2cAcquireBus(&I2CD1); + for (;len--;data+=2) + tlv320aic3204_bulk_write(data, 2); + i2cReleaseBus(&I2CD1); } void tlv320aic3204_init(void) { - tlv320aic3204_config(conf_data_pll); - tlv320aic3204_config(conf_data_clk); - tlv320aic3204_config(conf_data_routing); + tlv320aic3204_config(conf_data, sizeof(conf_data)/2); wait_ms(40); - tlv320aic3204_config(conf_data_unmute); + tlv320aic3204_config(conf_data_unmute, sizeof(conf_data_unmute)/2); } void tlv320aic3204_select(int channel) { - const uint8_t ch3[] = { - 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); + tlv320aic3204_config(channel ? conf_data_ch1_select : conf_data_ch3_select, sizeof(conf_data_ch3_select)/2); } void tlv320aic3204_set_gain(int lgain, int rgain) { - uint8_t data[] = { - 2, 0x00, 0x01, /* Select Page 1 */ - 2, 0x3b, lgain, /* Unmute Left MICPGA, set gain */ - 2, 0x3c, rgain, /* Unmute Right MICPGA, set gain */ - 0 // sentinel - }; - tlv320aic3204_config(data); + uint8_t data[] = { + 0x00, 0x01, /* Select Page 1 */ + 0x3b, lgain, /* Unmute Left MICPGA, set gain */ + 0x3c, rgain, /* Unmute Right MICPGA, set gain */ + }; + tlv320aic3204_config(data, sizeof(data)/2); } diff --git a/ui.c b/ui.c index 681c8bb..a2267da 100644 --- a/ui.c +++ b/ui.c @@ -25,12 +25,12 @@ //#include #include - uistat_t uistat = { digit: 6, current_trace: 0, lever_mode: LM_MARKER, marker_delta: FALSE, + marker_tracking : FALSE, }; #define NO_EVENT 0 @@ -41,9 +41,9 @@ uistat_t uistat = { #define EVT_DOWN 0x20 #define EVT_REPEAT 0x40 -#define BUTTON_DOWN_LONG_TICKS 5000 /* 1sec */ -#define BUTTON_DOUBLE_TICKS 5000 /* 500ms */ -#define BUTTON_REPEAT_TICKS 1000 /* 100ms */ +#define BUTTON_DOWN_LONG_TICKS 5000 /* 1sec */ +#define BUTTON_DOUBLE_TICKS 2500 /* 500ms */ +#define BUTTON_REPEAT_TICKS 625 /* 125ms */ #define BUTTON_DEBOUNCE_TICKS 200 /* lever switch assignment */ @@ -59,7 +59,7 @@ static uint32_t last_button_down_ticks; static uint32_t last_button_repeat_ticks; 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; @@ -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 }; +#define NUMINPUT_LEN 10 + static uint8_t ui_mode = UI_NORMAL; 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; // 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] = { 620, 600, 130, 180 }; -int awd_count; +//int awd_count; //int touch_x, touch_y; -#define NUMINPUT_LEN 10 - #define KP_CONTINUE 0 #define KP_DONE 1 #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_menu(void); static void ui_mode_numeric(int _keypad_mode); @@ -130,33 +131,29 @@ static int btn_check(void) int status = 0; uint32_t ticks = chVTGetSystemTime(); if (changed & (1<= BUTTON_DEBOUNCE_TICKS) { - if (cur_button & (1<= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS) { + // button released + status |= EVT_BUTTON_SINGLE_CLICK; + if (inhibit_until_release) { + status = 0; + inhibit_until_release = FALSE; } - last_button_down_ticks = ticks; } } - if (changed & (1<= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS)) { status |= EVT_UP; } - last_button_down_ticks = ticks; } if (changed & (1<= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS)) { status |= EVT_DOWN; } - last_button_down_ticks = ticks; } + last_button_down_ticks = ticks; last_button = cur_button; return status; @@ -169,15 +166,14 @@ static int btn_wait_release(void) int changed = last_button ^ cur_button; uint32_t ticks = chVTGetSystemTime(); int status = 0; - if (!inhibit_until_release) { if ((cur_button & (1<= BUTTON_DOWN_LONG_TICKS) { + && ticks >= last_button_down_ticks + BUTTON_DOWN_LONG_TICKS) { inhibit_until_release = TRUE; return EVT_BUTTON_DOWN_LONG; } if ((changed & (1<= BUTTON_DOWN_LONG_TICKS - && ticks - last_button_repeat_ticks >= BUTTON_REPEAT_TICKS) { - if (cur_button & (1<= last_button_down_ticks + BUTTON_DOWN_LONG_TICKS + && ticks >= last_button_repeat_ticks + BUTTON_REPEAT_TICKS) { + if (cur_button & (1< TOUCH_THRESHOLD; + return adc_single_read(ADC_CHSELR_CHSEL7) > TOUCH_THRESHOLD; } static int @@ -308,7 +302,7 @@ touch_cal_exec(void) { int x1, x2, y1, y2; - adc_stop(ADC1); + adc_stop(); setForegroundColor(DEFAULT_FG_COLOR); setBackgroundColor(DEFAULT_BG_COLOR); clearScreen(); @@ -344,7 +338,7 @@ touch_draw_test(void) int x0, y0; int x1, y1; - adc_stop(ADC1); + adc_stop(); setForegroundColor(DEFAULT_FG_COLOR); setBackgroundColor(DEFAULT_BG_COLOR); @@ -373,30 +367,21 @@ touch_position(int *x, int *y) *y = (last_touch_y - config.touch_cal[1]) * 16 / config.touch_cal[3]; } - void show_version(void) { - int x = 5, y = 5; - adc_stop(ADC1); + int x = 5, y = 5, i = 0; + adc_stop(); setForegroundColor(DEFAULT_FG_COLOR); setBackgroundColor(DEFAULT_BG_COLOR); clearScreen(); - ili9341_drawstring_size(BOARD_NAME, x, y, 4); - y += 25; - - ili9341_drawstring("2016-2020 Copyright @edy555", x, y += 10); - ili9341_drawstring("Licensed under GPL. See: https://github.com/ttrftech/NanoVNA", x, y += 10); - ili9341_drawstring("Version: " VERSION, x, y += 10); - ili9341_drawstring("Build Time: " __DATE__ " - " __TIME__, x, y += 10); - y += 5; - ili9341_drawstring("Kernel: " CH_KERNEL_VERSION, x, y += 10); - ili9341_drawstring("Compiler: " PORT_COMPILER_NAME, x, y += 10); - ili9341_drawstring("Architecture: " PORT_ARCHITECTURE_NAME " Core Variant: " PORT_CORE_VARIANT_NAME, x, y += 10); - ili9341_drawstring("Port Info: " PORT_INFO, x, y += 10); - ili9341_drawstring("Platform: " PLATFORM_NAME, x, y += 10); - + uint16_t shift = 0b0000010000111110; + ili9341_drawstring_size(info_about[i++], x , y, 4); + while (info_about[i]){ + do {shift>>=1; y+=5;} while (shift&1); + ili9341_drawstring(info_about[i++], x, y+=5); + } while (true) { if (touch_check() == EVT_TOUCH_PRESSED) break; @@ -410,7 +395,7 @@ show_version(void) void enter_dfu(void) { - adc_stop(ADC1); + adc_stop(); int x = 5, y = 5; setForegroundColor(DEFAULT_FG_COLOR); @@ -776,7 +761,7 @@ menu_marker_search_cb(int item, uint8_t data) i = marker_search_right(markers[active_marker].index); break; case 4: /* tracking */ - marker_tracking = !marker_tracking; + uistat.marker_tracking = !uistat.marker_tracking; break; } if (i != -1) @@ -1047,7 +1032,6 @@ const menuitem_t menu_top[] = { }; #define MENU_STACK_DEPTH_MAX 4 -uint8_t menu_current_level = 0; const menuitem_t *menu_stack[MENU_STACK_DEPTH_MAX] = { menu_top, NULL, NULL, NULL }; @@ -1171,7 +1155,6 @@ typedef struct { } keypads_t; static const keypads_t *keypads; -static uint8_t keypads_last_index; static const keypads_t keypads_freq[] = { { 1, 3, KP_PERIOD }, @@ -1345,7 +1328,7 @@ menu_item_modify_attribute(const menuitem_t *menu, int item, } } } else if (menu == menu_marker_search) { - if (item == 4 && marker_tracking) { + if (item == 4 && uistat.marker_tracking) { *bg = DEFAULT_MENU_TEXT_COLOR; *fg = config.menu_normal_color; } @@ -1366,7 +1349,7 @@ menu_item_modify_attribute(const menuitem_t *menu, int item, *fg = config.menu_normal_color; } } else if (menu == menu_stimulus) { - if (item == 5 /* PAUSE */ && !sweep_enabled) { + if (item == 5 /* PAUSE */ && !(sweep_mode&SWEEP_ENABLE)) { *bg = DEFAULT_MENU_TEXT_COLOR; *fg = config.menu_normal_color; } @@ -1535,7 +1518,7 @@ fetch_numeric_target(void) x /= 10; uistat.digit = n; } - uistat.previous_value = uistat.value; +// uistat.previous_value = uistat.value; } static void @@ -2011,7 +1994,7 @@ static void ui_process_keypad(void) { int status; - adc_stop(ADC1); + adc_stop(); kp_index = 0; while (TRUE) { @@ -2139,7 +2122,7 @@ touch_lever_mode_select(void) select_lever_mode(touch_x < FREQUENCIES_XPOS2 ? LM_CENTER : LM_SPAN); return TRUE; } - if (touch_y < 15) { + if (touch_y < 25) { if (touch_x < FREQUENCIES_XPOS2 && get_electrical_delay() != 0.0) { select_lever_mode(LM_EDELAY); } else @@ -2152,8 +2135,8 @@ touch_lever_mode_select(void) static void ui_process_touch(void) { - awd_count++; - adc_stop(ADC1); +// awd_count++; + adc_stop(); int status = touch_check(); if (status == EVT_TOUCH_PRESSED || status == EVT_TOUCH_DOWN) { @@ -2189,14 +2172,10 @@ void ui_process_touch(void) void ui_process(void) { - switch (operation_requested) { - case OP_LEVER: + if (operation_requested&OP_LEVER) ui_process_lever(); - break; - case OP_TOUCH: + if (operation_requested&OP_TOUCH) ui_process_touch(); - break; - } operation_requested = OP_NONE; } @@ -2204,7 +2183,7 @@ ui_process(void) static void extcb1(EXTDriver *extp, expchannel_t channel) { (void)extp; (void)channel; - operation_requested = OP_LEVER; + operation_requested|=OP_LEVER; //cur_button = READ_PORT() & BUTTON_MASK; } @@ -2259,7 +2238,7 @@ test_touch(int *x, int *y) void handle_touch_interrupt(void) { - operation_requested = OP_TOUCH; + operation_requested|= OP_TOUCH; } void