From e255573b1ef5dd20c119629a08621bacf26b5b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Fri, 27 Nov 2020 17:07:39 +0100 Subject: [PATCH] application: port to STM32F4 (RTC is not working yet) --- application.c | 218 ++++++++++++++++++++------------------------------ 1 file changed, 86 insertions(+), 132 deletions(-) diff --git a/application.c b/application.c index 9e5e3d4..da00360 100644 --- a/application.c +++ b/application.c @@ -1,4 +1,4 @@ -/** STM32F1 application example +/** STM32F4 application example * @file * @author King Kévin * @copyright SPDX-License-Identifier: GPL-3.0-or-later @@ -28,9 +28,7 @@ /* own libraries */ #include "global.h" // board definitions #include "print.h" // printing utilities -#if !defined(STLINKV2) #include "uart.h" // USART utilities -#endif #include "usb_cdcacm.h" // USB CDC ACM utilities #include "terminal.h" // handle the terminal interface #include "menu.h" // menu utilities @@ -38,30 +36,6 @@ /** watchdog period in ms */ #define WATCHDOG_PERIOD 10000 -/** set to 0 if the RTC is reset when the board is powered on, only indicates the uptime - * set to 1 if VBAT can keep the RTC running when the board is unpowered, indicating the date and time - */ -#if defined(CORE_BOARD) -#define RTC_DATE_TIME 1 -#else -#define RTC_DATE_TIME 0 -#endif - -/** number of RTC ticks per second - * @note use integer divider of oscillator to keep second precision - */ -#define RTC_TICKS_SECOND 4 - -#if defined(RTC_DATE_TIME) && RTC_DATE_TIME -/** the start time from which to RTC ticks count - * @note this allows the 32-bit value to reach further in time, particularly when there are several ticks per second - */ -const time_t rtc_offset = 1577833200; // We 1. Jan 00:00:00 CET 2020 -#endif - -/** RTC time when device is started */ -static time_t time_start = 0; - /** @defgroup main_flags flag set in interrupts to be processed in main task * @{ */ @@ -74,22 +48,20 @@ size_t putc(char c) static char last_c = 0; // to remember on which character we last sent if ('\n' == c) { // send carriage return (CR) + line feed (LF) newline for each LF if ('\r' != last_c) { // CR has not already been sent -#if !defined(STLINKV2) uart_putchar_nonblocking('\r'); // send CR over USART -#endif usb_cdcacm_putchar('\r'); // send CR over USB length++; // remember we printed 1 character } } -#if !defined(STLINKV2) uart_putchar_nonblocking(c); // send byte over USART -#endif usb_cdcacm_putchar(c); // send byte over USB length++; // remember we printed 1 character last_c = c; // remember last character return length; // return number of characters printed } +// menu commands + /** display available commands * @param[in] argument no argument required */ @@ -98,29 +70,93 @@ static void command_help(void* argument); /** show software and hardware version * @param[in] argument no argument required */ -static void command_version(void* argument); +static void command_version(void* argument) +{ + (void)argument; // we won't use the argument + printf("firmware date: %04u-%02u-%02u\n", BUILD_YEAR, BUILD_MONTH, BUILD_DAY); // show firmware build date + printf("device serial: %08x%08x%08x\n", DESIG_UNIQUE_ID2, DESIG_UNIQUE_ID1, DESIG_UNIQUE_ID0); // show complete serial (different than the one used for USB) +} /** show uptime * @param[in] argument no argument required */ -static void command_uptime(void* argument); +static void command_uptime(void* argument) +{ + (void)argument; // we won't use the argument + // TODO calculate time difference + const uint32_t uptime = 0; // get time from internal RTC + printf("uptime: %u.%02u:%02u:%02u\n", uptime / (24 * 60 * 60), (uptime / (60 * 60)) % 24, (uptime / 60) % 60, uptime % 60); +} -#if RTC_DATE_TIME /** show date and time * @param[in] argument date and time to set */ -static void command_datetime(void* argument); -#endif +static void command_datetime(void* argument) +{ + char* datetime = (char*)argument; // argument is optional date time + if (NULL == argument) { // no date and time provided, just show the current day and time + // TODO wait until date/time is synchronised + const uint8_t year = ((RTC_DR >> RTC_DR_YT_SHIFT) & RTC_DR_YT_MASK) * 10 + ((RTC_DR >> RTC_DR_YU_SHIFT) & RTC_DR_YU_MASK); // get year + const uint8_t month = ((RTC_DR >> RTC_DR_MT_SHIFT) & RTC_DR_MT_MASK) * 10 + ((RTC_DR >> RTC_DR_MU_SHIFT) & RTC_DR_MU_MASK); // get month + const uint8_t day = ((RTC_DR >> RTC_DR_DT_SHIFT) & RTC_DR_DT_MASK) * 10 + ((RTC_DR >> RTC_DR_DU_SHIFT) & RTC_DR_DU_MASK); // get day + const uint8_t week_day = ((RTC_DR >> RTC_DR_WDU_SHIFT) & RTC_DR_WDU_MASK); // get week day + const char* days[] = { "??", "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}; // the days of the week + const uint8_t hour = ((RTC_TR >> RTC_TR_HT_SHIFT) * RTC_TR_HT_MASK) * 10 + ((RTC_TR >> RTC_TR_HU_SHIFT) & RTC_TR_HU_MASK); // get hours + const uint8_t minute = ((RTC_TR >> RTC_TR_MNT_SHIFT) & RTC_TR_MNT_MASK) * 10 + ((RTC_TR >> RTC_TR_MNU_SHIFT) & RTC_TR_MNU_MASK); // get minutes + const uint8_t second = ((RTC_TR >> RTC_TR_ST_SHIFT) & RTC_TR_ST_MASK) * 10 + ((RTC_TR >> RTC_TR_SU_SHIFT) & RTC_TR_SU_MASK); // get seconds + printf("date: %s 20%02d-%02d-%02d %02d:%02d:%02d\n", days[week_day], year, month, day, hour, minute, second); + } else { // date and time provided, set it + const char* malformed = "date and time malformed, expecting YYYY-MM-DD HH:MM:SS\n"; + if (strlen(datetime) != (4 + 1 + 2 + 1 + 2) + 1 + (2 + 1 + 2 + 1 + 2)) { // verify date/time is long enough + printf(malformed); + return; + } + if (!(isdigit((int8_t)datetime[0]) && isdigit((int8_t)datetime[1]) && isdigit((int8_t)datetime[2]) && isdigit((int8_t)datetime[3]) && '-' == datetime[4] && isdigit((int8_t)datetime[5]) && isdigit((int8_t)datetime[6]) && '-' == datetime[7] && isdigit((int8_t)datetime[8]) && isdigit((int8_t)datetime[9]) && ' ' == datetime[10] && isdigit((int8_t)datetime[11]) && isdigit((int8_t)datetime[12]) && ':' == datetime[13] && isdigit((int8_t)datetime[14]) && isdigit((int8_t)datetime[15]) && ':' == datetime[16] && isdigit((int8_t)datetime[17]) && isdigit((int8_t)datetime[18]))) { // verify format (good enough to not fail parsing) + printf(malformed); + return; + } + /* + time_tm.tm_year = strtol(&datetime[0], NULL, 10) - 1900; // parse year + time_tm.tm_mon = strtol(&datetime[5], NULL, 10) - 1; // parse month + time_tm.tm_mday = strtol(&datetime[8], NULL, 10); // parse day + time_tm.tm_hour = strtol(&datetime[11], NULL, 10); // parse hour + time_tm.tm_min = strtol(&datetime[14], NULL, 10); // parse minutes + time_tm.tm_sec = strtol(&datetime[17], NULL, 10); // parse seconds + time_t time_rtc = mktime(&time_tm); // get back seconds + time_rtc -= rtc_offset; // remove start offset + time_start = time_rtc * RTC_TICKS_SECOND + (rtc_get_counter_val() - time_start); // update uptime with current date + rtc_set_counter_val(time_rtc * RTC_TICKS_SECOND); // save date/time to internal RTC + */ + } +} /** reset board * @param[in] argument no argument required */ -static void command_reset(void* argument); +static void command_reset(void* argument) +{ + (void)argument; // we won't use the argument + scb_reset_system(); // reset device + while (true); // wait for the reset to happen +} + +/** switch to system memory (e.g. embedded bootloader) + * @param[in] argument no argument required + */ +static void command_system(void* argument) +{ + (void)argument; // we won't use the argument + system_memory(); // jump to system memory +} /** switch to DFU bootloader * @param[in] argument no argument required */ -static void command_bootloader(void* argument); +static void command_bootloader(void* argument) +{ + (void)argument; // we won't use the argument + dfu_bootloader(); // start DFU bootloader +} /** list of all supported commands */ static const struct menu_command_t menu_commands[] = { @@ -148,7 +184,6 @@ static const struct menu_command_t menu_commands[] = { .argument_description = NULL, .command_handler = &command_uptime, }, -#if RTC_DATE_TIME { .shortcut = 'd', .name = "date", @@ -157,7 +192,6 @@ static const struct menu_command_t menu_commands[] = { .argument_description = "[YYYY-MM-DD HH:MM:SS]", .command_handler = &command_datetime, }, -#endif { .shortcut = 'r', .name = "reset", @@ -166,6 +200,14 @@ static const struct menu_command_t menu_commands[] = { .argument_description = NULL, .command_handler = &command_reset, }, + { + .shortcut = 's', + .name = "system", + .command_description = "reboot into system memory", + .argument = MENU_ARGUMENT_NONE, + .argument_description = NULL, + .command_handler = &command_system, + }, { .shortcut = 'b', .name = "bootloader", @@ -183,74 +225,6 @@ static void command_help(void* argument) menu_print_commands(menu_commands, LENGTH(menu_commands)); // print global commands } -static void command_version(void* argument) -{ - (void)argument; // we won't use the argument - printf("firmware date: %04u-%02u-%02u\n", BUILD_YEAR, BUILD_MONTH, BUILD_DAY); // show firmware build date - printf("device serial: %08x%08x%04x%04x\n", DESIG_UNIQUE_ID2, DESIG_UNIQUE_ID1, DESIG_UNIQUE_ID0 & 0xffff, DESIG_UNIQUE_ID0 >> 16); // not that the half-works are reversed in the first word -} - -static void command_uptime(void* argument) -{ - (void)argument; // we won't use the argument - const uint32_t uptime = (rtc_get_counter_val() - time_start) / RTC_TICKS_SECOND; // get time from internal RTC - printf("uptime: %u.%02u:%02u:%02u\n", uptime / (24 * 60 * 60), (uptime / (60 * 60)) % 24, (uptime / 60) % 60, uptime % 60); -} - -#if RTC_DATE_TIME -static void command_datetime(void* argument) -{ - char* datetime = (char*)argument; // argument is optional date time - if (NULL == argument) { // no date and time provided, just show the current day and time - const time_t time_rtc = rtc_get_counter_val() / RTC_TICKS_SECOND + rtc_offset; // get time from internal RTC - const struct tm* time_tm = localtime(&time_rtc); // convert time - const char* days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}; // the days of the week - printf("date: %s %d-%02d-%02d %02d:%02d:%02d\n", days[time_tm->tm_wday], 1900 + time_tm->tm_year, 1 + time_tm->tm_mon, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec); - } else { // date and time provided, set it - const char* malformed = "date and time malformed, expecting YYYY-MM-DD HH:MM:SS\n"; - struct tm time_tm; // to store the parsed date time - if (strlen(datetime) != (4 + 1 + 2 + 1 + 2) + 1 + (2 + 1 + 2 + 1 + 2)) { // verify date/time is long enough - printf(malformed); - return; - } - if (!(isdigit((int8_t)datetime[0]) && isdigit((int8_t)datetime[1]) && isdigit((int8_t)datetime[2]) && isdigit((int8_t)datetime[3]) && '-' == datetime[4] && isdigit((int8_t)datetime[5]) && isdigit((int8_t)datetime[6]) && '-' == datetime[7] && isdigit((int8_t)datetime[8]) && isdigit((int8_t)datetime[9]) && ' ' == datetime[10] && isdigit((int8_t)datetime[11]) && isdigit((int8_t)datetime[12]) && ':' == datetime[13] && isdigit((int8_t)datetime[14]) && isdigit((int8_t)datetime[15]) && ':' == datetime[16] && isdigit((int8_t)datetime[17]) && isdigit((int8_t)datetime[18]))) { // verify format (good enough to not fail parsing) - printf(malformed); - return; - } - time_tm.tm_year = strtol(&datetime[0], NULL, 10) - 1900; // parse year - time_tm.tm_mon = strtol(&datetime[5], NULL, 10) - 1; // parse month - time_tm.tm_mday = strtol(&datetime[8], NULL, 10); // parse day - time_tm.tm_hour = strtol(&datetime[11], NULL, 10); // parse hour - time_tm.tm_min = strtol(&datetime[14], NULL, 10); // parse minutes - time_tm.tm_sec = strtol(&datetime[17], NULL, 10); // parse seconds - time_t time_rtc = mktime(&time_tm); // get back seconds - time_rtc -= rtc_offset; // remove start offset - time_start = time_rtc * RTC_TICKS_SECOND + (rtc_get_counter_val() - time_start); // update uptime with current date - rtc_set_counter_val(time_rtc * RTC_TICKS_SECOND); // save date/time to internal RTC - printf("date and time saved: %d-%02d-%02d %02d:%02d:%02d\n", 1900 + time_tm.tm_year, 1 + time_tm.tm_mon, time_tm.tm_mday, time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec); - } -} -#endif - -static void command_reset(void* argument) -{ - (void)argument; // we won't use the argument - scb_reset_system(); // reset device - while (true); // wait for the reset to happen -} - -static void command_bootloader(void* argument) -{ - (void)argument; // we won't use the argument - // set DFU magic to specific RAM location - __dfu_magic[0] = 'D'; - __dfu_magic[1] = 'F'; - __dfu_magic[2] = 'U'; - __dfu_magic[3] = '!'; - scb_reset_system(); // reset system (core and peripherals) - while (true); // wait for the reset to happen -} - /** process user command * @param[in] str user command string (\0 ended) */ @@ -279,7 +253,6 @@ static void process_command(char* str) void main(void); void main(void) { - rcc_clock_setup_in_hse_8mhz_out_72mhz(); // use 8 MHz high speed external clock to generate 72 MHz internal clock #if DEBUG // enable functionalities for easier debug @@ -295,11 +268,9 @@ void main(void) #endif board_setup(); // setup board -#if !defined(STLINKV2) uart_setup(); // setup USART (for printing) -#endif usb_cdcacm_setup(); // setup USB CDC ACM (for printing) - puts("\nwelcome to the CuVoodoo STM32F1 example application\n"); // print welcome message + puts("\nwelcome to the CuVoodoo STM32F4 example firmware\n"); // print welcome message #if DEBUG // show reset cause @@ -339,19 +310,6 @@ void main(void) } #endif - // setup RTC - puts("setup internal RTC: "); -#if defined(BLUE_PILL) || defined(STLINKV2) || defined(BLASTER) // for boards without a Low Speed External oscillator - // note: the blue pill LSE oscillator is affected when toggling the onboard LED, thus prefer the HSE - rtc_auto_awake(RCC_HSE, 8000000 / 128 / RTC_TICKS_SECOND - 1); // use High Speed External oscillator (8 MHz / 128) as RTC clock (VBAT can't be used to keep the RTC running) -#else // for boards with an precise Low Speed External oscillator - rtc_auto_awake(RCC_LSE, 32768 / RTC_TICKS_SECOND - 1); // ensure internal RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect) -#endif - rtc_interrupt_enable(RTC_SEC); // enable RTC interrupt on "seconds" - nvic_enable_irq(NVIC_RTC_IRQ); // allow the RTC to interrupt - time_start = rtc_get_counter_val(); // get start time from internal RTC - puts("OK\n"); - // setup terminal terminal_prefix = ""; // set default prefix terminal_process = &process_command; // set central function to process commands @@ -360,6 +318,7 @@ void main(void) // start main loop bool action = false; // if an action has been performed don't go to sleep button_flag = false; // reset button flag + led_on(); // switch LED to indicate booting completed while (true) { // infinite loop iwdg_reset(); // kick the dog if (user_input_available) { // user input is available @@ -375,6 +334,7 @@ void main(void) sleep_ms(100); // wait a bit to remove noise and double trigger button_flag = false; // reset flag } +/* if (rtc_internal_tick_flag) { // the internal RTC ticked rtc_internal_tick_flag = false; // reset flag action = true; // action has been performed @@ -382,6 +342,7 @@ void main(void) led_toggle(); // toggle LED (good to indicate if main function is stuck) } } +*/ if (action) { // go to sleep if nothing had to be done, else recheck for activity action = false; } else { @@ -389,10 +350,3 @@ void main(void) } } // main loop } - -/** @brief interrupt service routine called when tick passed on RTC */ -void rtc_isr(void) -{ - rtc_clear_flag(RTC_SEC); // clear flag - rtc_internal_tick_flag = true; // notify to show new time -}