diff --git a/main.c b/main.c index a874c86..7d87a65 100644 --- a/main.c +++ b/main.c @@ -75,8 +75,6 @@ static volatile vna_shellcmd_t shell_function = 0; //#define ENABLED_DUMP // Allow get threads debug info #define ENABLE_THREADS_COMMAND -// RTC time not used -//#define ENABLE_TIME_COMMAND // Enable vbat_offset command, allow change battery voltage correction in config #define ENABLE_VBAT_OFFSET_COMMAND // Info about NanoVNA, need fore soft @@ -620,17 +618,35 @@ VNA_SHELL_FUNCTION(cmd_power) } #endif -#ifdef ENABLE_TIME_COMMAND -#if HAL_USE_RTC == FALSE -#error "Error cmd_time require define HAL_USE_RTC = TRUE in halconf.h" -#endif +#ifdef __USE_RTC__ VNA_SHELL_FUNCTION(cmd_time) { - RTCDateTime timespec; (void)argc; (void)argv; - rtcGetTime(&RTCD1, ×pec); - shell_printf("%d/%d/%d %d\r\n", timespec.year+1980, timespec.month, timespec.day, timespec.millisecond); + uint32_t dt_buf[2]; + dt_buf[0] = rtc_get_tr_bcd(); // TR should be read first for sync + dt_buf[1] = rtc_get_dr_bcd(); // DR should be read second + static const uint8_t idx_to_time[] = {6,5,4,2, 1, 0}; + static const char time_cmd[] = "y|m|d|h|min|sec"; + // 0 1 2 4 5 6 + // time[] ={sec, min, hr, 0, day, month, year, 0} + uint8_t *time = (uint8_t*)dt_buf; + if (argc == 3 && get_str_index(argv[0], "b") == 0){ + rtc_set_time(my_atoui(argv[1]), my_atoui(argv[2])); + return; + } + if (argc!=2) goto usage; + int idx = get_str_index(argv[0], time_cmd); + uint32_t val = my_atoui(argv[1]); + if (idx < 0 || val > 99) + goto usage; + // Write byte value in struct + time[idx_to_time[idx]] = ((val/10)<<4)|(val%10); // value in bcd format + rtc_set_time(dt_buf[1], dt_buf[0]); + return; +usage: + shell_printf("20%02X/%02X/%02X %02X:%02X:%02X\r\n"\ + "usage: time {[%s] 0-99} or {b 0xYYMMDD 0xHHMMSS}\r\n", time[6], time[5], time[4], time[2], time[1], time[0], time_cmd); } #endif @@ -2429,7 +2445,7 @@ static const VNAShellCommand commands[] = #ifdef __VNA__ {"offset" , cmd_offset , 0}, #endif -#ifdef ENABLE_TIME_COMMAND +#ifdef __USE_RTC__ {"time" , cmd_time , 0}, #endif {"dac" , cmd_dac , 0}, diff --git a/rtc.c b/rtc.c index 9bac4d9..dee4384 100644 --- a/rtc.c +++ b/rtc.c @@ -56,90 +56,119 @@ uint32_t rtc_get_FAT(void) { return fattime; } -void rtc_set_time(uint32_t dr, uint32_t tr) { - // Beginning of configuration procedure. - RTC->ISR |= RTC_ISR_INIT; - while ((RTC->ISR & RTC_ISR_INITF) == 0) - ; - // Writing the registers. - RTC->TR = tr; - RTC->DR = dr; +// Finish of configuration procedure. +static void rtc_exit_init(void) { RTC->ISR &= ~RTC_ISR_INIT; } -#define RTC_PRER(a, s) ((((a) - 1) << 16) | ((s) - 1)) +// Beginning of configuration procedure. +static bool rtc_enter_init(void){ + RTC->ISR |= RTC_ISR_INIT; + uint32_t count = 4*65536; + while (--count) + if (RTC->ISR & RTC_ISR_INITF) + return true; + return false; +} + +void rtc_set_time(uint32_t dr, uint32_t tr) { + if (rtc_enter_init()){ + RTC->TR = tr; // Write TR register + RTC->DR = dr; // Write TD register + } + rtc_exit_init(); +} + +#ifdef VNA_AUTO_SELECT_RTC_SOURCE + +// Enable LSE bypass if need +#if defined(STM32_LSE_BYPASS) +#define STM32_LSE_BYPASS RCC_BDCR_LSEBYP +#else +#define STM32_LSE_BYPASS 0 +#endif + +// Startup LSE or if not work, LSI generator +static void rtc_start_source(void){ + // LSE already work (enabled and ready) + if ((RCC->BDCR & (RCC_BDCR_LSEON|RCC_BDCR_LSERDY|STM32_LSE_BYPASS)) == (RCC_BDCR_LSEON|RCC_BDCR_LSERDY|STM32_LSE_BYPASS)) + return; + + // If LSE not enabled, try startup + RCC->BDCR |= STM32_LSEDRV | STM32_LSE_BYPASS | RCC_BDCR_LSEON; + // Waits until LSE is stable (need ~150ms for startup). + chThdSleepMilliseconds(200); + if (RCC->BDCR & RCC_BDCR_LSERDY) return; + + // Startup LSI if not allow start LSE + RCC->CSR |= RCC_CSR_LSION; + while ((RCC->CSR & RCC_CSR_LSIRDY) == 0); +} + +static void resetBCDR(uint32_t rtc_drv){ + // Backup domain reset, for change source. + RCC->BDCR = RCC_BDCR_BDRST; + RCC->BDCR = 0; + // Startup again source generator + rtc_start_source(); + // Select new clock source. And enable + RCC->BDCR|= rtc_drv; +} -// Initiate RTC clock, LSE or LSI generators initiate by ChibiOS !!! +void auto_backup_domain_init(void){ + // Init Backup domain, RTC clock source + uint32_t rtc_drv; + // Backup domain access enabled and left open. + PWR->CR |= PWR_CR_DBP; + // Start/check source + rtc_start_source(); + // Check LSE ready, if ok, select as source + rtc_drv = RCC->BDCR & RCC_BDCR_LSERDY ? STM32_RTCSEL_LSE|RCC_BDCR_RTCEN : // Select LSE as source + STM32_RTCSEL_LSI|RCC_BDCR_RTCEN; // Select LSI as source + // If the backup domain hasn't been initialized yet or work on different source, then proceed with initialization + if ((RCC->BDCR & (STM32_RTCSEL_MASK|RCC_BDCR_RTCEN)) != rtc_drv) + resetBCDR(rtc_drv); +/* + // Check RTC clock, and reset backup domain to LSI if clock not start + if (rtc_enter_init()) + rtc_exit_init(); + else + resetBCDR(STM32_RTCSEL_LSI|RCC_BDCR_RTCEN); +*/ +} +#endif + +// Initiate RTC clock void rtc_init(void){ +#ifdef VNA_AUTO_SELECT_RTC_SOURCE + // Auto start LSE or LSI source for RTC + auto_backup_domain_init(); +#else + // ChibiOS init BDCR LSE or LSI source by self from user defined in mcuconf.h source + // For add auto select RTC source need rewrite it + // see hal_lld_backup_domain_init() in hal_lld.c for every CPU + // Default RTC clock is LSE, but it possible not launch if no quartz installed +#endif + uint32_t src = RCC->BDCR & STM32_RTCSEL_MASK; + if (src == STM32_RTCSEL_NOCLOCK) return; + // If calendar has not been initialized yet or different PRER settings then proceed with the initial setup. // Disable write protection. RTC->WPR = 0xCA; RTC->WPR = 0x53; + uint32_t rtc_prer = (src == STM32_RTCSEL_LSE) ? STM32_RTC_LSE_PRER : + STM32_RTC_LSI_PRER; // If calendar has not been initialized yet then proceed with the initial setup. - if (!(RTC->ISR & RTC_ISR_INITS)) { - // Beginning of configuration procedure. - RTC->ISR |= RTC_ISR_INIT; - while ((RTC->ISR & RTC_ISR_INITF) == 0) - ; - RTC->CR = 0; - RTC->ISR = RTC_ISR_INIT; // Clearing all but RTC_ISR_INIT. - RTC->PRER = RTC_PRER(STM32_RTC_PRESA_VALUE, STM32_RTC_PRESS_VALUE); - RTC->PRER = RTC_PRER(STM32_RTC_PRESA_VALUE, STM32_RTC_PRESS_VALUE); - RTC->ISR &= ~RTC_ISR_INIT; + if ((RTC->ISR & RTC_ISR_INITS) == 0 || RTC->PRER != rtc_prer) { + if (rtc_enter_init()){ + RTC->CR = 0; + RTC->ISR = RTC_ISR_INIT; // Clearing all but RTC_ISR_INIT. + RTC->PRER = rtc_prer; // Prescaler value loaded in registers 2 times + RTC->PRER = rtc_prer; + } + // Finalizing of configuration procedure. + rtc_exit_init(); } else RTC->ISR &= ~RTC_ISR_RSF; -#if 0 - // ChibiOS init BDCR by self!! - // For add auto select RTC source need rewrite it - // see hal_lld_backup_domain_init() in hal_lld.c for every CPU - // Default RTC clock is LSE, but it possible not launch if no quartz installed - uint32_t rtc_drv = STM32_RTCSEL_LSI; - uint32_t rtc_prer = RTC_PRER(40, 1000); - - // If LSE off try launch it - if ((RCC->BDCR & RCC_BDCR_LSEON) == 0){ - // Try start LSE - RCC->BDCR |= STM32_LSEDRV | RCC_BDCR_LSEON; - uint32_t count = 65535; - do{ - if (RCC->BDCR & RCC_BDCR_LSERDY) break; - }while (--count);// Waits until LSE is stable. or count == 0 - } - // Check, if LSE ready, then prepare it data - if (RCC->BDCR & RCC_BDCR_LSERDY){ - rtc_drv = STM32_RTCSEL_LSE; - rtc_prer = RTC_PRER(32, 1024); - } else{ - // Try start LSI - RCC->CSR |= RCC_CSR_LSION; - while ((RCC->CSR & RCC_CSR_LSIRDY) == 0) - ; - } - - PWR->CR |= PWR_CR_DBP; - // If the backup domain hasn't been initialized yet then proceed with initialization or source different - if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0 || (RCC->BDCR & STM32_RTCSEL_MASK)!=rtc_drv) { - // Backup domain reset. - RCC->BDCR = RCC_BDCR_BDRST; - RCC->BDCR = 0; - // Selects clock source. - RCC->BDCR |= rtc_drv; - // Disable write protection. - RTC->WPR = 0xCA; - RTC->WPR = 0x53; - // Beginning of configuration procedure. - RTC->ISR |= RTC_ISR_INIT; - while ((RTC->ISR & RTC_ISR_INITF) == 0) - ; - // Prescaler value loaded in registers. - RTC->CR = 0; - RTC->ISR = RTC_ISR_INIT; // Clearing all but RTC_ISR_INIT. - RTC->PRER = rtc_prer; - RTC->PRER = rtc_prer; - // Finalizing of configuration procedure. - RTC->ISR &= ~RTC_ISR_INIT; - RCC->BDCR |= RCC_BDCR_RTCEN; // RTC clock enabled. - } -#endif } -#endif +#endif // __USE_RTC__ diff --git a/ui.c b/ui.c index 2d109f8..43b7c00 100644 --- a/ui.c +++ b/ui.c @@ -474,8 +474,8 @@ show_version(void) do {shift>>=1; y+=5;} while (shift&1); ili9341_drawstring(info_about[i++], x, y+=5); } + char buf[96]; #ifdef TINYSA4 - static char buf[96]; extern const char *states[]; #define ENABLE_THREADS_COMMAND @@ -501,14 +501,34 @@ extern const char *states[]; } while (tp != NULL); #endif - #endif // TINYSA4 + uint16_t cnt = 0; while (true) { if (touch_check() == EVT_TOUCH_PRESSED) break; if (btn_check() & EVT_BUTTON_SINGLE_CLICK) break; + chThdSleepMilliseconds(40); + if ((cnt++)&0x07) continue; // Not update time so fast +#ifdef __USE_RTC__ + uint32_t tr = rtc_get_tr_bin(); // TR read first + uint32_t dr = rtc_get_dr_bin(); // DR read second + plot_printf(buf, sizeof(buf), "Time: 20%02d/%02d/%02d %02d:%02d:%02d" " (LS%c)", + RTC_DR_YEAR(dr), + RTC_DR_MONTH(dr), + RTC_DR_DAY(dr), + RTC_TR_HOUR(dr), + RTC_TR_MIN(dr), + RTC_TR_SEC(dr), + (RCC->BDCR & STM32_RTCSEL_MASK) == STM32_RTCSEL_LSE ? 'E' : 'I'); + ili9341_drawstring(buffer, x, y); +#endif +#if 1 + uint32_t vbat=adc_vbat_read(); + plot_printf(buf, sizeof(buf), "Batt: %d.%03dV", vbat/1000, vbat%1000); + ili9341_drawstring(buf, x, y + FONT_STR_HEIGHT + 2); +#endif } touch_start_watchdog();