aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--os/hal/platforms/STM32/RTCv2/rtc_lld.c303
-rw-r--r--os/hal/platforms/STM32/RTCv2/rtc_lld.h72
-rw-r--r--os/hal/platforms/STM32F4xx/hal_lld.h3
-rw-r--r--testhal/STM32F4xx/RTC/Makefile4
-rw-r--r--testhal/STM32F4xx/RTC/chconf.h5
-rw-r--r--testhal/STM32F4xx/RTC/halconf.h4
-rw-r--r--testhal/STM32F4xx/RTC/main.c338
-rw-r--r--testhal/STM32F4xx/RTC/mcuconf.h2
8 files changed, 394 insertions, 337 deletions
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)
-
- /* Add async part to preload value. */
- volatile uint32_t preload = PREDIV_A << 16;
+ uint32_t prediv_a = 0x7F;
- /* 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 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 & ALARMA_CB_FLAG)
- rtcp->id_rtc->CR |= RTC_CR_ALRAIE;
- else
- rtcp->id_rtc->CR &= ~RTC_CR_ALRAIE;
+ timp->tm_isdst = -1;
- 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_wday = (tv_date & RTC_DR_WDU) >> RTC_DR_WDU_OFFSET;
+ if(timp->tm_wday == 7)
+ timp->tm_wday = 0;
- 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_mday = (tv_date & RTC_DR_DU) >> RTC_DR_DU_OFFSET;
+ timp->tm_mday += ((tv_date & RTC_DR_DT) >> RTC_DR_DT_OFFSET) * 10;
- 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_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 <time.h>
/*===========================================================================*/
/* 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
/*===========================================================================*/
@@ -109,17 +113,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.
*/
struct RTCTime {
@@ -132,6 +125,10 @@ struct RTCTime {
*/
uint32_t tv_time;
/**
+ * @brief Set this to TRUE to use 12 hour notation.
+ */
+ bool_t h12;
+ /**
* @brief Fractional part of time.
*/
#if STM32_RTC_HAS_SUBSECONDS
@@ -164,18 +161,6 @@ struct RTCWakeup {
};
/**
- * @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.
*/
struct RTCDriver{
@@ -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 <http://www.gnu.org/licenses/>.
*/
-#include <time.h>
-#include <stdlib.h>
-
-#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 <string.h>
+#include <stdlib.h>
+#include <time.h>
-/**
- * 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;
+#include "ch.h"
+#include "hal.h"
+
+#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 <errno.h>
+#undef errno
+extern int errno;
+int _kill(int pid, int sig) {
+ (void)pid;
+ (void)sig;
+ errno = EINVAL;
+ return -1;
+}
+
+
+/* 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);
}
- if (RTCD1.id_rtc->ISR | RTC_ISR_ALRAF){
- RTCD1.id_rtc->ISR &= ~RTC_ISR_ALRAF;
+ 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;
}
- palTogglePad(GPIOB, GPIOB_LED_R);
+ chprintf(chp, "Going to sleep.\r\n");
+
+ chThdSleepMilliseconds(200);
+
+ /* going to anabiosis */
+ func_sleep();
}
-/**
- * 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;
+static void cmd_alarm(BaseChannel *chp, int argc, char *argv[]){
+ int i = 0;
+
+ (void)argv;
+ if (argc < 1) {
+ goto ERROR;
}
- palTogglePad(GPIOB, GPIOB_LED_B);
- palTogglePad(GPIOB, GPIOB_LED_R);
-}
+ 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;
+ }
-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 */
-};
+ 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;
+ }
-/**
- * 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;
+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");
}
-/**
- * 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 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, &timespec);
+ stm32_rtc_bcd2tm(&timp, &timespec);
+ 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)), &timespec);
+ rtcSetTime(&RTCD1, &timespec);
+ 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,
+};
+
+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);
-
- /* 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, &timespec);
- bcd2tm(&timp, timespec.tv_time, timespec.tv_date);
- unix_time = mktime(&timp);
+#if !WAKEUP_TEST
+ /* switch off wakeup */
+ rtcSetPeriodicWakeup_v2(&RTCD1, NULL);
- if (unix_time == -1){/* incorrect time in RTC cell */
- unix_time = 1000000000;
- }
- /* set correct time */
- tm2bcd((localtime(&unix_time)), &timespec);
- rtcSetTime(&RTCD1, &timespec);
+ /* 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, &timespec);
- bcd2tm(&timp, timespec.tv_time, timespec.tv_date);
- unix_time = mktime(&timp);
- chThdSleepMilliseconds(1500);
+ chThdSleepMilliseconds(200);
}
- return 0;
-}
+#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