diff --git a/os/hal/platforms/STM32/RTCv2/rtc_lld.c b/os/hal/platforms/STM32/RTCv2/rtc_lld.c index 481867d93..cae3f812b 100644 --- a/os/hal/platforms/STM32/RTCv2/rtc_lld.c +++ b/os/hal/platforms/STM32/RTCv2/rtc_lld.c @@ -24,7 +24,7 @@ /** * @file STM32/RTCv2/rtc_lld.c - * @brief STM32L1xx/STM32F2xx/STM32F4xx RTC low level driver header. + * @brief STM32L1xx/STM32F2xx/STM32F4xx RTC low level driver. * * @addtogroup RTC * @{ @@ -51,6 +51,31 @@ RTCDriver RTCD1; /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ +/** + * @brief Wait for synchronization of RTC registers with APB1 bus. + * @details This function must be invoked before trying to read RTC registers. + * + * @notapi + */ +#define rtc_lld_apb1_sync() {while ((RTCD1.id_rtc->ISR & RTC_ISR_RSF) == 0);} + +/** + * @brief Beginning of configuration procedure. + * + * @notapi + */ +#define rtc_lld_enter_init() { \ + RTCD1.id_rtc->ISR |= RTC_ISR_INIT; \ + while ((RTCD1.id_rtc->ISR & RTC_ISR_INITF) == 0) \ + ; \ +} + +/** + * @brief Finalizing of configuration procedure. + * + * @notapi + */ +#define rtc_lld_exit_init() {RTCD1.id_rtc->ISR &= ~RTC_ISR_INIT;} /*===========================================================================*/ /* Driver interrupt handlers. */ @@ -61,96 +86,52 @@ RTCDriver RTCD1; /*===========================================================================*/ /** - * @brief Enable access to registers and initialize RTC if BKP domain - * was previously reseted. - * @note: Cold start time of LSE oscillator on STM32 platform - * takes about 3 seconds. + * @brief Enable access to registers. * - * @notapi + * @api */ void rtc_lld_init(void){ RTCD1.id_rtc = RTC; /* Asynchronous part of preloader. Set it to maximum value. */ - #define PREDIV_A ((uint32_t)0x7F) + uint32_t prediv_a = 0x7F; - /* Add async part to preload value. */ - volatile uint32_t preload = PREDIV_A << 16; - - /* Enables access to BKP registers.*/ - PWR->CR |= PWR_CR_DBP; - - /* If the RTC is not enabled then performs a reset of the backup domain.*/ - if (!(RCC->BDCR & RCC_BDCR_RTCEN)) { - RCC->BDCR = RCC_BDCR_BDRST; - RCC->BDCR = 0; - } - -#if STM32_RTC == STM32_RTC_LSE - #define RTC_CLK STM32_LSECLK - if (!(RCC->BDCR & RCC_BDCR_LSEON)) { - RCC->BDCR |= RCC_BDCR_LSEON; - while (!(RCC->BDCR & RCC_BDCR_LSERDY)) - ; - } - -#elif STM32_RTC == STM32_RTC_LSI - #define RTC_CLK STM32_LSICLK - /* TODO: Move the LSI clock initialization in the HAL low level driver.*/ - RCC->CSR |= RCC_CSR_LSION; - while (!(RCC->CSR & RCC_CSR_LSIRDY)) - ; - -#elif STM32_RTC == STM32_RTC_HSE - #define RTC_CLK (STM32_HSICLK / 31) -#endif - - /* Add sync part to preload value. */ - preload |= ((RTC_CLK / (PREDIV_A + 1)) - 1) & 0x7FFF; - - /* Selects clock source (previously enabled and stabilized).*/ - RCC->BDCR = (RCC->BDCR & ~RCC_BDCR_RTCSEL) | STM32_RTCSEL; - - /* RTC enabled regardless its previous status.*/ - RCC->BDCR |= RCC_BDCR_RTCEN; - - /* Disable write protection on RTC registers. */ + /* Disable write protection. */ RTCD1.id_rtc->WPR = 0xCA; RTCD1.id_rtc->WPR = 0x53; /* If calendar not init yet. */ if (!(RTC->ISR & RTC_ISR_INITS)){ - /* Enter in init mode. */ - RTCD1.id_rtc->ISR |= RTC_ISR_INIT; - while(!(RTC->ISR & RTC_ISR_INITF)) - ; - /* Prescaler registers must be written in by two separate writes. */ - RTCD1.id_rtc->PRER = preload; - RTCD1.id_rtc->PRER = preload; - RTCD1.id_rtc->ISR &= ~RTC_ISR_INIT; + rtc_lld_enter_init(); + + /* Prescaler register must be written in two SEPARATE writes. */ + RTCD1.id_rtc->PRER = prediv_a << 16; + RTCD1.id_rtc->PRER = ((STM32_RTCCLK / (prediv_a + 1)) - 1) & 0x7FFF; + rtc_lld_exit_init(); } } - /** * @brief Set current time. * @note Fractional part will be silently ignored. There is no possibility - * to change it on STM32F1xx platform. + * to set it on STM32 platform. * * @param[in] rtcp pointer to RTC driver structure * @param[in] timespec pointer to a @p RTCTime structure * - * @notapi + * @api */ void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) { (void)rtcp; - RTCD1.id_rtc->ISR |= RTC_ISR_INIT; - while(!(RTC->ISR & RTC_ISR_INITF)) - ; + rtc_lld_enter_init(); + if (timespec->h12) + RTCD1.id_rtc->CR |= RTC_CR_FMT; + else + RTCD1.id_rtc->CR &= ~RTC_CR_FMT; RTCD1.id_rtc->TR = timespec->tv_time; RTCD1.id_rtc->DR = timespec->tv_date; - RTCD1.id_rtc->ISR &= ~RTC_ISR_INIT; + rtc_lld_exit_init(); } /** @@ -159,21 +140,17 @@ void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) { * @param[in] rtcp pointer to RTC driver structure * @param[out] timespec pointer to a @p RTCTime structure * - * @notapi + * @api */ void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec) { (void)rtcp; - /* TODO: If the frequency of the APB1 clock is less than seven times - * the frequency of RTCCLK, BYPSHAD must be set to ‘1’ .*/ - - /* Wait until calendar data will updated. */ - while(!(RTC->ISR & RTC_ISR_RSF)) - ; + rtc_lld_apb1_sync(); #if STM32_RTC_HAS_SUBSECONDS - timespec->tv_msec = (1000 * ((RTCD1.id_rtc->PRER & 0x7FFF) - RTCD1.id_rtc->SSR)) / - ((RTCD1.id_rtc->PRER & 0x7FFF) + 1); + timespec->tv_msec = + (1000 * ((RTCD1.id_rtc->PRER & 0x7FFF) - RTCD1.id_rtc->SSR)) / + ((RTCD1.id_rtc->PRER & 0x7FFF) + 1); #endif /* STM32_RTC_HAS_SUBSECONDS */ timespec->tv_time = RTCD1.id_rtc->TR; timespec->tv_date = RTCD1.id_rtc->DR; @@ -189,24 +166,38 @@ void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec) { * @param[in] alarm Alarm identifier. Can be 1 or 2. * @param[in] alarmspec Pointer to a @p RTCAlarm structure. * - * @notapi + * @api */ void rtc_lld_set_alarm(RTCDriver *rtcp, rtcalarm_t alarm, const RTCAlarm *alarmspec) { if (alarm == 1){ - rtcp->id_rtc->CR &= ~RTC_CR_ALRAE; - while(!(rtcp->id_rtc->ISR & RTC_ISR_ALRAWF)) - ; - rtcp->id_rtc->ALRMAR = alarmspec->tv_datetime; - rtcp->id_rtc->CR |= RTC_CR_ALRAE; + if (alarmspec != NULL){ + rtcp->id_rtc->CR &= ~RTC_CR_ALRAE; + while(!(rtcp->id_rtc->ISR & RTC_ISR_ALRAWF)) + ; + rtcp->id_rtc->ALRMAR = alarmspec->tv_datetime; + rtcp->id_rtc->CR |= RTC_CR_ALRAE; + rtcp->id_rtc->CR |= RTC_CR_ALRAIE; + } + else { + rtcp->id_rtc->CR &= ~RTC_CR_ALRAIE; + rtcp->id_rtc->CR &= ~RTC_CR_ALRAE; + } } else{ - rtcp->id_rtc->CR &= ~RTC_CR_ALRBE; - while(!(rtcp->id_rtc->ISR & RTC_ISR_ALRBWF)) - ; - rtcp->id_rtc->ALRMAR = alarmspec->tv_datetime; - rtcp->id_rtc->CR |= RTC_CR_ALRBE; + if (alarmspec != NULL){ + rtcp->id_rtc->CR &= ~RTC_CR_ALRBE; + while(!(rtcp->id_rtc->ISR & RTC_ISR_ALRBWF)) + ; + rtcp->id_rtc->ALRMBR = alarmspec->tv_datetime; + rtcp->id_rtc->CR |= RTC_CR_ALRBE; + rtcp->id_rtc->CR |= RTC_CR_ALRBIE; + } + else { + rtcp->id_rtc->CR &= ~RTC_CR_ALRBIE; + rtcp->id_rtc->CR &= ~RTC_CR_ALRBE; + } } } @@ -217,7 +208,7 @@ void rtc_lld_set_alarm(RTCDriver *rtcp, * @param[in] alarm alarm identifier * @param[out] alarmspec pointer to a @p RTCAlarm structure * - * @notapi + * @api */ void rtc_lld_get_alarm(RTCDriver *rtcp, rtcalarm_t alarm, @@ -236,18 +227,25 @@ void rtc_lld_get_alarm(RTCDriver *rtcp, * @param[in] rtcp pointer to RTC driver structure * @param[in] wakeupspec pointer to a @p RTCWakeup structure * - * @notapi + * @api */ -void rtc_lld_set_periodic_wakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec){ +void rtcSetPeriodicWakeup_v2(RTCDriver *rtcp, RTCWakeup *wakeupspec){ chDbgCheck((wakeupspec->wakeup != 0x30000), "rtc_lld_set_periodic_wakeup, forbidden combination"); - rtcp->id_rtc->CR &= ~RTC_CR_WUTE; - while(!(rtcp->id_rtc->ISR & RTC_ISR_WUTWF)) - ; - rtcp->id_rtc->WUTR = wakeupspec->wakeup & 0xFFFF; - rtcp->id_rtc->CR = (wakeupspec->wakeup >> 16) & 0x7; - rtcp->id_rtc->CR |= RTC_CR_WUTE; + if (wakeupspec != NULL){ + rtcp->id_rtc->CR &= ~RTC_CR_WUTE; + while(!(rtcp->id_rtc->ISR & RTC_ISR_WUTWF)) + ; + rtcp->id_rtc->WUTR = wakeupspec->wakeup & 0xFFFF; + rtcp->id_rtc->CR = (wakeupspec->wakeup >> 16) & 0x7; + rtcp->id_rtc->CR |= RTC_CR_WUTIE; + rtcp->id_rtc->CR |= RTC_CR_WUTE; + } + else { + rtcp->id_rtc->CR &= ~RTC_CR_WUTIE; + rtcp->id_rtc->CR &= ~RTC_CR_WUTE; + } } /** @@ -258,65 +256,110 @@ void rtc_lld_set_periodic_wakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec){ * @param[in] rtcp pointer to RTC driver structure * @param[out] wakeupspec pointer to a @p RTCWakeup structure * - * @notapi + * @api */ -void rtc_lld_get_periodic_wakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec){ +void rtcGetPeriodicWakeup_v2(RTCDriver *rtcp, RTCWakeup *wakeupspec){ wakeupspec->wakeup = 0; wakeupspec->wakeup |= rtcp->id_rtc->WUTR; wakeupspec->wakeup |= (((uint32_t)rtcp->id_rtc->CR) & 0x7) << 16; } -#if RTC_SUPPORTS_CALLBACKS - /** - * @brief Enables or disables RTC callbacks. - * @details To enable interrupt set corresponding bit in @p RTCCallbackConfig - * structure. To disable interrupt clear that bit. - * @note This function just enable/disable interrupts in RTC CR register. - * You must configure callbacks in EXTI driver for corresponding - * interrupts. See documentation for you MCU. + * @brief Converts from STM32 BCD to canonicalized time format. * - * @param[in] rtcp pointer to RTC driver structure - * @param[in] cb_cfg pointer to configuration structure with callbacks + * @param[out] timp pointer to a @p tm structure defined in time.h + * @param[in] timespec pointer to a @p RTCTime structure * - * @notapi + * @api */ -void rtc_lld_set_callback(RTCDriver *rtcp, RTCCallbackConfig *cb_cfg) { +void stm32_rtc_bcd2tm(struct tm *timp, RTCTime *timespec){ + uint32_t tv_time = timespec->tv_time; + uint32_t tv_date = timespec->tv_date; - if (cb_cfg->cb_cfg & ALARMA_CB_FLAG) - rtcp->id_rtc->CR |= RTC_CR_ALRAIE; - else - rtcp->id_rtc->CR &= ~RTC_CR_ALRAIE; +#if CH_DBG_ENABLE_CHECKS + timp->tm_isdst = 0; + timp->tm_wday = 0; + timp->tm_mday = 0; + timp->tm_yday = 0; + timp->tm_mon = 0; + timp->tm_year = 0; + timp->tm_sec = 0; + timp->tm_min = 0; + timp->tm_hour = 0; +#endif - if (cb_cfg->cb_cfg & ALARMB_CB_FLAG) - rtcp->id_rtc->CR |= RTC_CR_ALRBIE; - else - rtcp->id_rtc->CR &= ~RTC_CR_ALRBIE; + timp->tm_isdst = -1; - if (cb_cfg->cb_cfg & WAKEUP_CB_FLAG) - rtcp->id_rtc->CR |= RTC_CR_WUTIE; - else - rtcp->id_rtc->CR &= ~RTC_CR_WUTIE; + timp->tm_wday = (tv_date & RTC_DR_WDU) >> RTC_DR_WDU_OFFSET; + if(timp->tm_wday == 7) + timp->tm_wday = 0; - if (cb_cfg->cb_cfg & TIMESTAMP_CB_FLAG) - rtcp->id_rtc->CR |= RTC_CR_TSIE; - else - rtcp->id_rtc->CR &= ~RTC_CR_TSIE; + timp->tm_mday = (tv_date & RTC_DR_DU) >> RTC_DR_DU_OFFSET; + timp->tm_mday += ((tv_date & RTC_DR_DT) >> RTC_DR_DT_OFFSET) * 10; + + timp->tm_mon = (tv_date & RTC_DR_MU) >> RTC_DR_MU_OFFSET; + timp->tm_mon += ((tv_date & RTC_DR_MT) >> RTC_DR_MT_OFFSET) * 10; + timp->tm_mon -= 1; + + timp->tm_year = (tv_date & RTC_DR_YU) >> RTC_DR_YU_OFFSET; + timp->tm_year += ((tv_date & RTC_DR_YT) >> RTC_DR_YT_OFFSET) * 10; + timp->tm_year += 2000 - 1900; + + timp->tm_sec = (tv_time & RTC_TR_SU) >> RTC_TR_SU_OFFSET; + timp->tm_sec += ((tv_time & RTC_TR_ST) >> RTC_TR_ST_OFFSET) * 10; + + timp->tm_min = (tv_time & RTC_TR_MNU) >> RTC_TR_MNU_OFFSET; + timp->tm_min += ((tv_time & RTC_TR_MNT) >> RTC_TR_MNT_OFFSET) * 10; + + timp->tm_hour = (tv_time & RTC_TR_HU) >> RTC_TR_HU_OFFSET; + timp->tm_hour += ((tv_time & RTC_TR_HT) >> RTC_TR_HT_OFFSET) * 10; + timp->tm_hour += 12 * ((tv_time & RTC_TR_PM) >> RTC_TR_PM_OFFSET); } /** - * @brief Gets current RTC callbacks. + * @brief Converts from canonicalized to STM32 BCD time format. * - * @param[in] rtcp pointer to RTC driver structure - * @param[out] cb_cfg callback bitmask + * @param[in] timp pointer to a @p tm structure defined in time.h + * @param[out] timespec pointer to a @p RTCTime structure * - * @notapi + * @api */ -void rtc_lld_get_callback(RTCDriver *rtcp, RTCCallbackConfig *cb_cfg) { - cb_cfg->cb_cfg = rtcp->cb_cfg->cb_cfg; -} +void stm32_rtc_tm2bcd(struct tm *timp, RTCTime *timespec){ + uint32_t v = 0; -#endif /* RTC_SUPPORTS_CALLBACKS */ + timespec->tv_date = 0; + timespec->tv_time = 0; + + v = timp->tm_year - 100; + timespec->tv_date |= ((v / 10) << RTC_DR_YT_OFFSET) & RTC_DR_YT; + timespec->tv_date |= (v % 10) << RTC_DR_YU_OFFSET; + + if (timp->tm_wday == 0) + v = 7; + else + v = timp->tm_wday; + timespec->tv_date |= (v << RTC_DR_WDU_OFFSET) & RTC_DR_WDU; + + v = timp->tm_mon + 1; + timespec->tv_date |= ((v / 10) << RTC_DR_MT_OFFSET) & RTC_DR_MT; + timespec->tv_date |= (v % 10) << RTC_DR_MU_OFFSET; + + v = timp->tm_mday; + timespec->tv_date |= ((v / 10) << RTC_DR_DT_OFFSET) & RTC_DR_DT; + timespec->tv_date |= (v % 10) << RTC_DR_DU_OFFSET; + + v = timp->tm_hour; + timespec->tv_time |= ((v / 10) << RTC_TR_HT_OFFSET) & RTC_TR_HT; + timespec->tv_time |= (v % 10) << RTC_TR_HU_OFFSET; + + v = timp->tm_min; + timespec->tv_time |= ((v / 10) << RTC_TR_MNT_OFFSET) & RTC_TR_MNT; + timespec->tv_time |= (v % 10) << RTC_TR_MNU_OFFSET; + + v = timp->tm_sec; + timespec->tv_time |= ((v / 10) << RTC_TR_ST_OFFSET) & RTC_TR_ST; + timespec->tv_time |= (v % 10) << RTC_TR_SU_OFFSET; +} #endif /* HAL_USE_RTC */ diff --git a/os/hal/platforms/STM32/RTCv2/rtc_lld.h b/os/hal/platforms/STM32/RTCv2/rtc_lld.h index 4d543f58d..a9346b5ac 100644 --- a/os/hal/platforms/STM32/RTCv2/rtc_lld.h +++ b/os/hal/platforms/STM32/RTCv2/rtc_lld.h @@ -35,14 +35,7 @@ #if HAL_USE_RTC || defined(__DOXYGEN__) -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/** - * @brief This RTC implementation doesn't support callbacks. - */ -#define RTC_SUPPORTS_CALLBACKS FALSE +#include /*===========================================================================*/ /* Driver constants. */ @@ -54,12 +47,23 @@ #define RTC_ALARMS 2 /** - * @brief Callback enable masks. + * @brief Data offsets in RTC date and time registers. */ -#define ALARMA_CB_FLAG 0x1 -#define ALARMB_CB_FLAG 0x2 -#define WAKEUP_CB_FLAG 0x4 -#define TIMESTAMP_CB_FLAG 0x8 +#define RTC_TR_PM_OFFSET 22 +#define RTC_TR_HT_OFFSET 20 +#define RTC_TR_HU_OFFSET 16 +#define RTC_TR_MNT_OFFSET 12 +#define RTC_TR_MNU_OFFSET 8 +#define RTC_TR_ST_OFFSET 4 +#define RTC_TR_SU_OFFSET 0 + +#define RTC_DR_YT_OFFSET 20 +#define RTC_DR_YU_OFFSET 16 +#define RTC_DR_WDU_OFFSET 13 +#define RTC_DR_MT_OFFSET 12 +#define RTC_DR_MU_OFFSET 8 +#define RTC_DR_DT_OFFSET 4 +#define RTC_DR_DU_OFFSET 0 /*===========================================================================*/ /* Driver pre-compile time settings. */ @@ -79,8 +83,8 @@ #error "invalid source selected for RTC clock" #endif -#if RTC_SUPPORTS_CALLBACKS && !(HAL_USE_EXT) -#error "interrupts from RTC works only through EXTI on this platform" +#if !defined(RTC_USE_INTERRUPTS) || defined(__DOXYGEN__) +#define RTC_USE_INTERRUPTS FALSE #endif /*===========================================================================*/ @@ -108,17 +112,6 @@ typedef struct RTCCallbackConfig RTCCallbackConfig; */ typedef uint32_t rtcalarm_t; -/** - * @brief Type of an RTC event. - */ -typedef enum { - RTC_EVENT_WAKEUP = 0, /** Triggered every wakeup event. */ - RTC_EVENT_ALARM_A = 1, /** Triggered on alarm A. */ - RTC_EVENT_ALARM_B = 2, /** Triggered on alarm B. */ - RTC_EVENT_TAMPER = 3, /** Triggered on Tamper event. */ - RTC_EVENT_TIMESTAMP = 4, /** Triggered on TimeStamp event. */ -} rtcevent_t; - /** * @brief Structure representing an RTC time stamp. */ @@ -131,6 +124,10 @@ struct RTCTime { * @brief RTC time register in STM32 BCD format. */ uint32_t tv_time; + /** + * @brief Set this to TRUE to use 12 hour notation. + */ + bool_t h12; /** * @brief Fractional part of time. */ @@ -163,18 +160,6 @@ struct RTCWakeup { uint32_t wakeup; }; -/** - * @brief Structure representing an RTC callbacks config. - * @details It is bitmask. Set bit to enable callback, clear bit to disable. - * bit0 - alarmA - * bit1 - alarmB - * bit2 - wakeup - * bit3 - timestamp - */ -struct RTCCallbackConfig{ - uint32_t cb_cfg; -}; - /** * @brief Structure representing an RTC driver. */ @@ -183,10 +168,6 @@ struct RTCDriver{ * @brief Pointer to the RTC registers block. */ RTC_TypeDef *id_rtc; - /** - * @brief Current callback confuguration. - */ - const RTCCallbackConfig *cb_cfg; }; /*===========================================================================*/ @@ -213,9 +194,10 @@ extern "C" { void rtc_lld_get_alarm(RTCDriver *rtcp, rtcalarm_t alarm, RTCAlarm *alarmspec); - void rtc_lld_set_periodic_wakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec); - void rtc_lld_get_periodic_wakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec); - void rtc_lld_set_callback(RTCDriver *rtcp, RTCCallbackConfig *cb_cfg); + void rtcSetPeriodicWakeup_v2(RTCDriver *rtcp, RTCWakeup *wakeupspec); + void rtcGetPeriodicWakeup_v2(RTCDriver *rtcp, RTCWakeup *wakeupspec); + void stm32_rtc_bcd2tm(struct tm *timp, RTCTime *timespec); + void stm32_rtc_tm2bcd(struct tm *timp, RTCTime *timespec); #ifdef __cplusplus } #endif diff --git a/os/hal/platforms/STM32F4xx/hal_lld.h b/os/hal/platforms/STM32F4xx/hal_lld.h index c88ac3a96..a29c33cde 100644 --- a/os/hal/platforms/STM32F4xx/hal_lld.h +++ b/os/hal/platforms/STM32F4xx/hal_lld.h @@ -1103,6 +1103,9 @@ #if STM32_PCLK1 > STM32_PCLK1_MAX #error "STM32_PCLK1 exceeding maximum frequency (STM32_PCLK1_MAX)" #endif +#if STM32_PCLK1 < (STM32_RTCCLK * 7) +#error "STM32_PCLK1 frequency is too low to handle RTC without ugly workaround" +#endif /** * @brief APB2 frequency. diff --git a/testhal/STM32F4xx/RTC/Makefile b/testhal/STM32F4xx/RTC/Makefile index 02f7a7f98..e60937914 100644 --- a/testhal/STM32F4xx/RTC/Makefile +++ b/testhal/STM32F4xx/RTC/Makefile @@ -5,7 +5,7 @@ # Compiler options here. ifeq ($(USE_OPT),) - USE_OPT = -O0 -ggdb -fomit-frame-pointer -falign-functions=16 -mhard-float -mfpu=fpv4-sp-d16 -fsingle-precision-constant + USE_OPT = -O0 -ggdb -fomit-frame-pointer -falign-functions=16 endif # C specific options here (added to USE_OPT). @@ -79,6 +79,8 @@ CSRC = $(PORTSRC) \ $(BOARDSRC) \ $(CHIBIOS)/os/various/evtimer.c \ $(CHIBIOS)/os/various/syscalls.c \ + $(CHIBIOS)/os/various/shell.c \ + $(CHIBIOS)/os/various/chprintf.c \ main.c \ # C++ sources that can be compiled in ARM or THUMB mode depending on the global diff --git a/testhal/STM32F4xx/RTC/chconf.h b/testhal/STM32F4xx/RTC/chconf.h index 8fa81d603..5569fa3f2 100644 --- a/testhal/STM32F4xx/RTC/chconf.h +++ b/testhal/STM32F4xx/RTC/chconf.h @@ -32,9 +32,8 @@ #ifndef _CHCONF_H_ #define _CHCONF_H_ -//#define CORTEX_VTOR_INIT 0x000E0000 -#define CORTEX_VTOR_INIT 0x00000000 -#define CORTEX_USE_FPU FALSE +#define PORT_IDLE_THREAD_STACK_SIZE 32 +#define CORTEX_USE_FPU FALSE /*===========================================================================*/ /* Kernel parameters. */ diff --git a/testhal/STM32F4xx/RTC/halconf.h b/testhal/STM32F4xx/RTC/halconf.h index 84445b8b7..0f9c5163a 100644 --- a/testhal/STM32F4xx/RTC/halconf.h +++ b/testhal/STM32F4xx/RTC/halconf.h @@ -129,7 +129,7 @@ * @brief Enables the SERIAL subsystem. */ #if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) -#define HAL_USE_SERIAL FALSE +#define HAL_USE_SERIAL TRUE #endif /** @@ -303,7 +303,7 @@ * default configuration. */ #if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) -#define SERIAL_DEFAULT_BITRATE 38400 +#define SERIAL_DEFAULT_BITRATE 9600 #endif /** diff --git a/testhal/STM32F4xx/RTC/main.c b/testhal/STM32F4xx/RTC/main.c index 76a1efdf3..5bc51c7b6 100644 --- a/testhal/STM32F4xx/RTC/main.c +++ b/testhal/STM32F4xx/RTC/main.c @@ -17,201 +17,229 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include -#include -#include "ch.h" -#include "hal.h" - -/*===========================================================================*/ -/* Notes. */ -/*===========================================================================*/ /* This structure is used to hold the values representing a calendar time. It contains the following members, with the meanings as shown. int tm_sec seconds after minute [0-61] (61 allows for 2 leap-seconds) -int tm_min minutes after hour [0-59] -int tm_hour hours after midnight [0-23] -int tm_mday day of the month [1-31] -int tm_mon month of year [0-11] -int tm_year current year-1900 -int tm_wday days since Sunday [0-6] -int tm_yday days since January 1st [0-365] +int tm_min minutes after hour [0-59] +int tm_hour hours after midnight [0-23] +int tm_mday day of the month [1-31] +int tm_mon month of year [0-11] +int tm_year current year-1900 +int tm_wday days since Sunday [0-6] +int tm_yday days since January 1st [0-365] int tm_isdst daylight savings indicator (1 = yes, 0 = no, -1 = unknown) */ +#define WAKEUP_TEST FALSE -RTCTime timespec; -RTCAlarm alarmspec; -RTCWakeup wakeupspec; -RTCCallbackConfig cb_cfg; -time_t unix_time; +#include +#include +#include -/** - * Alarms callback - */ -static inline void exti_rtcalarm_cb(EXTDriver *extp, expchannel_t channel){ - (void)extp; - (void)channel; - if (RTCD1.id_rtc->ISR | RTC_ISR_ALRBF){ - RTCD1.id_rtc->ISR &= ~RTC_ISR_ALRBF; - } - if (RTCD1.id_rtc->ISR | RTC_ISR_ALRAF){ - RTCD1.id_rtc->ISR &= ~RTC_ISR_ALRAF; - } - palTogglePad(GPIOB, GPIOB_LED_R); -} +#include "ch.h" +#include "hal.h" -/** - * Periodic wakeup callback - */ -static inline void exti_rtcwakeup_cb(EXTDriver *extp, expchannel_t channel){ - (void)extp; - (void)channel; - /* manually clear flags because exti driver does not do that */ - if (RTCD1.id_rtc->ISR | RTC_ISR_WUTF){ - RTCD1.id_rtc->ISR &= ~RTC_ISR_WUTF; - } - palTogglePad(GPIOB, GPIOB_LED_B); - palTogglePad(GPIOB, GPIOB_LED_R); +#include "shell.h" +#include "chprintf.h" + +#if WAKEUP_TEST +static RTCWakeup wakeupspec; +#endif +static RTCTime timespec = {0,0,FALSE,0}; +static RTCAlarm alarmspec; +static time_t unix_time; + +/* libc stub */ +int _getpid(void) {return 1;} +/* libc stub */ +void _exit(int i) {(void)i;} +/* libc stub */ +#include +#undef errno +extern int errno; +int _kill(int pid, int sig) { + (void)pid; + (void)sig; + errno = EINVAL; + return -1; } -static const EXTConfig extcfg = { - { - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART, exti_rtcalarm_cb},/* RTC alarms */ - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL},/* timestamp */ - {EXT_CH_MODE_RISING_EDGE| EXT_CH_MODE_AUTOSTART, exti_rtcwakeup_cb},/* wakeup */ - }, - EXT_MODE_EXTI( - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0)/* 15 */ +/* sleep indicator thread */ +static WORKING_AREA(blinkWA, 128); +static msg_t blink_thd(void *arg){ + (void)arg; + while (TRUE) { + chThdSleepMilliseconds(100); + palTogglePad(GPIOB, GPIOB_LED_R); + } + return 0; +} + +static void func_sleep(void){ + chSysLock(); + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + PWR->CR |= (PWR_CR_PDDS | PWR_CR_LPDS | PWR_CR_CSBF | PWR_CR_CWUF); + RTC->ISR &= ~(RTC_ISR_ALRBF | RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TAMP1F | + RTC_ISR_TSOVF | RTC_ISR_TSF); + __WFI(); +} + +static void cmd_sleep(BaseChannel *chp, int argc, char *argv[]){ + (void)argv; + if (argc > 0) { + chprintf(chp, "Usage: sleep\r\n"); + return; + } + chprintf(chp, "Going to sleep.\r\n"); + + chThdSleepMilliseconds(200); + + /* going to anabiosis */ + func_sleep(); +} + +/* + * + */ +static void cmd_alarm(BaseChannel *chp, int argc, char *argv[]){ + int i = 0; + + (void)argv; + if (argc < 1) { + goto ERROR; + } + + if ((argc == 1) && (strcmp(argv[0], "get") == 0)){ + rtcGetAlarm(&RTCD1, 0, &alarmspec); + chprintf(chp, "%D%s",alarmspec," - alarm in STM internal format\r\n"); + return; + } + + if ((argc == 2) && (strcmp(argv[0], "set") == 0)){ + i = atol(argv[1]); + alarmspec.tv_datetime = ((i / 10) & 7 << 4) | (i % 10) | RTC_ALRMAR_MSK4 | + RTC_ALRMAR_MSK3 | RTC_ALRMAR_MSK2; + rtcSetAlarm(&RTCD1, 0, &alarmspec); + return; + } + else{ + goto ERROR; + } + +ERROR: + chprintf(chp, "Usage: alarm get\r\n"); + chprintf(chp, " alarm set N\r\n"); + chprintf(chp, "where N is alarm time in seconds\r\n"); +} + +/* + * + */ +static void cmd_date(BaseChannel *chp, int argc, char *argv[]){ + (void)argv; + struct tm timp; + + if (argc == 0) { + goto ERROR; + } + + if ((argc == 1) && (strcmp(argv[0], "get") == 0)){ + rtcGetTime(&RTCD1, ×pec); + stm32_rtc_bcd2tm(&timp, ×pec); + unix_time = mktime(&timp); + + if (unix_time == -1){ + chprintf(chp, "incorrect time in RTC cell\r\n"); + } + else{ + chprintf(chp, "%D%s",unix_time," - unix time\r\n"); + chprintf(chp, "%s%s",asctime(&timp)," - formatted time string\r\n"); + } + return; + } + + if ((argc == 2) && (strcmp(argv[0], "set") == 0)){ + unix_time = atol(argv[1]); + if (unix_time > 0){ + stm32_rtc_tm2bcd((localtime(&unix_time)), ×pec); + rtcSetTime(&RTCD1, ×pec); + return; + } + else{ + goto ERROR; + } + } + else{ + goto ERROR; + } + +ERROR: + chprintf(chp, "Usage: date get\r\n"); + chprintf(chp, " date set N\r\n"); + chprintf(chp, "where N is time in seconds sins Unix epoch\r\n"); + chprintf(chp, "you can get current N value from unix console by the command\r\n"); + chprintf(chp, "%s", "date +\%s\r\n"); + return; +} + +static SerialConfig ser_cfg = { + 115200, + 0, + 0, + 0, }; -/** - * Convert from STM32 BCD to classical format. - */ -void bcd2tm(struct tm *timp, uint32_t tv_time, uint32_t tv_date){ - timp->tm_isdst = -1; - - timp->tm_wday = ((tv_date >> 13) & 0x7); - if(timp->tm_wday == 7) - timp->tm_wday = 0; - timp->tm_mday = (tv_date & 0xF) + ((tv_date >> 4) & 0x3) * 10; - timp->tm_mon = (((tv_date >> 8) & 0xF) + ((tv_date >> 12) & 0x1) * 10) - 1; - timp->tm_year = (((tv_date >> 16)& 0xF) + ((tv_date >> 20) & 0xF) * 10) + 2000 - 1900; - - timp->tm_sec = (tv_time & 0xF) + ((tv_time >> 4) & 0x7) * 10; - timp->tm_min = ((tv_time >> 8)& 0xF) + ((tv_time >> 12) & 0x7) * 10; - timp->tm_hour = ((tv_time >> 16)& 0xF) + ((tv_time >> 20) & 0x3) * 10; -} - -/** - * Convert from classical format to STM32 BCD - */ -void tm2bcd(struct tm *timp, RTCTime *timespec){ - uint32_t v = 0; - - timespec->tv_date = 0; - timespec->tv_time = 0; - - v = timp->tm_year - 100; - timespec->tv_date |= (((v / 10) & 0xF) << 20) | ((v % 10) << 16); - if (timp->tm_wday == 0) - v = 7; - else - v = timp->tm_wday; - timespec->tv_date |= (v & 7) << 13; - v = timp->tm_mon + 1; - timespec->tv_date |= (((v / 10) & 1) << 12) | ((v % 10) << 8); - v = timp->tm_mday; - timespec->tv_date |= (((v / 10) & 3) << 4) | (v % 10); - v = timp->tm_hour; - timespec->tv_time |= (((v / 10) & 3) << 20) | ((v % 10) << 16); - v = timp->tm_min; - timespec->tv_time |= (((v / 10) & 7) << 12) | ((v % 10) << 8); - v = timp->tm_sec; - timespec->tv_time |= (((v / 10) & 7) << 4) | (v % 10); -} +static const ShellCommand commands[] = { + {"alarm", cmd_alarm}, + {"date", cmd_date}, + {"sleep", cmd_sleep}, + {NULL, NULL} +}; +static const ShellConfig shell_cfg1 = { + (BaseChannel *)&SD2, + commands +}; /** * Main function. */ int main(void){ - struct tm timp; halInit(); chSysInit(); + chThdCreateStatic(blinkWA, sizeof(blinkWA), NORMALPRIO, blink_thd, NULL); - extStart(&EXTD1, &extcfg); +#if !WAKEUP_TEST + /* switch off wakeup */ + rtcSetPeriodicWakeup_v2(&RTCD1, NULL); - /* tune wakeup callback */ - wakeupspec.wakeup = ((uint32_t)4) << 16; /* select 1 Hz clock source */ - wakeupspec.wakeup |= 3; /* set counter value to 3. Period will be 3+1 seconds. */ - rtcSetWakeup(&RTCD1, &wakeupspec); - - /* enable wakeup callback */ - cb_cfg.cb_cfg = WAKEUP_CB_FLAG; - rtcSetCallback(&RTCD1, &cb_cfg); - - /* get current time in unix format */ - rtcGetTime(&RTCD1, ×pec); - bcd2tm(&timp, timespec.tv_time, timespec.tv_date); - unix_time = mktime(&timp); - - if (unix_time == -1){/* incorrect time in RTC cell */ - unix_time = 1000000000; - } - /* set correct time */ - tm2bcd((localtime(&unix_time)), ×pec); - rtcSetTime(&RTCD1, ×pec); + /* Shell initialization.*/ + sdStart(&SD2, &ser_cfg); + shellInit(); + static WORKING_AREA(waShell, 1024); + shellCreateStatic(&shell_cfg1, waShell, sizeof(waShell), NORMALPRIO); + /* wait until user do not want to test wakeup */ while (TRUE){ - rtcGetTime(&RTCD1, ×pec); - bcd2tm(&timp, timespec.tv_time, timespec.tv_date); - unix_time = mktime(&timp); - chThdSleepMilliseconds(1500); + chThdSleepMilliseconds(200); } + +#else + /* set wakeup */ + wakeupspec.wakeup = ((uint32_t)4) << 16; /* select 1 Hz clock source */ + wakeupspec.wakeup |= 9; /* set counter value to 9. Period will be 9+1 seconds. */ + rtcSetPeriodicWakeup_v2(&RTCD1, &wakeupspec); + + chThdSleepSeconds(3); + func_sleep(); +#endif /* !WAKEUP_TEST */ + return 0; } - - - diff --git a/testhal/STM32F4xx/RTC/mcuconf.h b/testhal/STM32F4xx/RTC/mcuconf.h index 09567938f..ae0df4f34 100644 --- a/testhal/STM32F4xx/RTC/mcuconf.h +++ b/testhal/STM32F4xx/RTC/mcuconf.h @@ -158,7 +158,7 @@ * SERIAL driver system settings. */ #define STM32_SERIAL_USE_USART1 FALSE -#define STM32_SERIAL_USE_USART2 FALSE +#define STM32_SERIAL_USE_USART2 TRUE #define STM32_SERIAL_USE_USART3 FALSE #define STM32_SERIAL_USE_UART4 FALSE #define STM32_SERIAL_USE_UART5 FALSE