From 4a79547fb8b8261cecab5f13ca74b5267173f38c Mon Sep 17 00:00:00 2001 From: Leif Jakob Date: Wed, 14 Jun 2017 22:36:40 +0200 Subject: [PATCH] multiple fixes for stm32f1xx RTC clock - compile issues because of missing RTC_MAGIC #defines - missing functionality based on RTC_MAGIC in RTC based on stm32_rtcounter.c - IRQ setup from up_rtc_initialize was later reset in up_irqinitialize - write access to backup registers without enabling access to backup domain - possible races in set/cancel alarm tested with STM32F103C8 only device now wakes up from forced STANDBY mode by alarm --- arch/arm/src/stm32/stm32_irq.c | 5 ++ arch/arm/src/stm32/stm32_rtc.h | 39 ++++++++-- arch/arm/src/stm32/stm32_rtc_lowerhalf.c | 4 ++ arch/arm/src/stm32/stm32_rtcc.c | 26 ++++++- arch/arm/src/stm32/stm32_rtcounter.c | 90 ++++++++++++++++++------ arch/arm/src/stm32/stm32f40xxx_rtcc.c | 21 ++++++ arch/arm/src/stm32l4/stm32l4_rtcc.c | 21 ++++++ 7 files changed, 177 insertions(+), 29 deletions(-) diff --git a/arch/arm/src/stm32/stm32_irq.c b/arch/arm/src/stm32/stm32_irq.c index 2a51836a52..0f9553210a 100644 --- a/arch/arm/src/stm32/stm32_irq.c +++ b/arch/arm/src/stm32/stm32_irq.c @@ -387,6 +387,11 @@ void up_irqinitialize(void) up_enable_irq(STM32_IRQ_MEMFAULT); #endif +#ifdef CONFIG_RTC + /* RTC was initialized earlier but IRQs weren't ready at that time */ + stm32_rtc_irqinitialize(); +#endif + /* Attach all other processor exceptions (except reset and sys tick) */ #ifdef CONFIG_DEBUG_FEATURES diff --git a/arch/arm/src/stm32/stm32_rtc.h b/arch/arm/src/stm32/stm32_rtc.h index d228a3c458..0c4e5ecbf3 100644 --- a/arch/arm/src/stm32/stm32_rtc.h +++ b/arch/arm/src/stm32/stm32_rtc.h @@ -79,21 +79,35 @@ #define STM32_RTC_PRESCALER_SECOND 32767 /* Default prescaler to get a second base */ #define STM32_RTC_PRESCALER_MIN 1 /* Maximum speed of 16384 Hz */ +#if defined(CONFIG_STM32_STM32F10XX) +/* RTC is only a counter, store RTC data in backup domain register DR1 (if CONFIG_RTC_HIRES) and DR2 (state) */ + #if !defined(CONFIG_RTC_MAGIC) -# define CONFIG_RTC_MAGIC (0xfacefeee) +# define CONFIG_RTC_MAGIC (0xface) /* only 16 bit */ #endif -#if !defined(CONFIG_RTC_MAGIC_TIME_SET) -# define CONFIG_RTC_MAGIC_TIME_SET (CONFIG_RTC_MAGIC + 1) +#define RTC_MAGIC_REG STM32_BKP_DR2 + +#else /* !CONFIG_STM32_STM32F10XX */ + +#if !defined(CONFIG_RTC_MAGIC) +# define CONFIG_RTC_MAGIC (0xfacefeee) #endif #if !defined(CONFIG_RTC_MAGIC_REG) # define CONFIG_RTC_MAGIC_REG (0) #endif +#define RTC_MAGIC_REG STM32_RTC_BKR(CONFIG_RTC_MAGIC_REG) + +#endif /* CONFIG_STM32_STM32F10XX */ + #define RTC_MAGIC CONFIG_RTC_MAGIC #define RTC_MAGIC_TIME_SET CONFIG_RTC_MAGIC_TIME_SET -#define RTC_MAGIC_REG STM32_RTC_BKR(CONFIG_RTC_MAGIC_REG) + +#if !defined(CONFIG_RTC_MAGIC_TIME_SET) +# define CONFIG_RTC_MAGIC_TIME_SET (CONFIG_RTC_MAGIC + 1) +#endif /**************************************************************************** * Public Types @@ -118,6 +132,23 @@ extern "C" * Public Functions ****************************************************************************/ +/************************************************************************************ + * Name: stm32_rtc_irqinitialize + * + * Description: + * Initialize IRQs for RTC, not possible during up_rtc_initialize because + * up_irqinitialize is called later. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int stm32_rtc_irqinitialize(void); + /**************************************************************************** * Name: stm32_rtc_getdatetime_with_subseconds * diff --git a/arch/arm/src/stm32/stm32_rtc_lowerhalf.c b/arch/arm/src/stm32/stm32_rtc_lowerhalf.c index 548b7fa81b..6a8c079399 100644 --- a/arch/arm/src/stm32/stm32_rtc_lowerhalf.c +++ b/arch/arm/src/stm32/stm32_rtc_lowerhalf.c @@ -365,7 +365,11 @@ static int stm32_settime(FAR struct rtc_lowerhalf_s *lower, static bool stm32_havesettime(FAR struct rtc_lowerhalf_s *lower) { +#if defined(CONFIG_STM32_STM32F10XX) + return getreg16(RTC_MAGIC_REG) == RTC_MAGIC_TIME_SET; +#else return getreg32(RTC_MAGIC_REG) == RTC_MAGIC_TIME_SET; +#endif } /**************************************************************************** diff --git a/arch/arm/src/stm32/stm32_rtcc.c b/arch/arm/src/stm32/stm32_rtcc.c index 9adc62433c..b7c96f336a 100644 --- a/arch/arm/src/stm32/stm32_rtcc.c +++ b/arch/arm/src/stm32/stm32_rtcc.c @@ -763,17 +763,37 @@ int up_rtc_initialize(void) * 3. Configure the RTC to generate RTC alarms (Alarm A or Alarm B). */ + g_rtc_enabled = true; + rtc_dumpregs("After Initialization"); + return OK; +} + +/************************************************************************************ + * Name: stm32_rtc_irqinitialize + * + * Description: + * Initialize IRQs for RTC, not possible during up_rtc_initialize because + * up_irqinitialize is called later. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int stm32_rtc_irqinitialize(void) +{ #ifdef CONFIG_RTC_ALARM # warning "Missing EXTI setup logic" - /* Then attach the ALARM interrupt handler */ + /* then attach the ALARM interrupt handler */ irq_attach(STM32_IRQ_RTC_WKUP, rtc_interrupt, NULL); up_enable_irq(STM32_IRQ_RTC_WKUP); #endif - g_rtc_enabled = true; - rtc_dumpregs("After Initialization"); return OK; } diff --git a/arch/arm/src/stm32/stm32_rtcounter.c b/arch/arm/src/stm32/stm32_rtcounter.c index 9a046f8318..5db3865c0d 100644 --- a/arch/arm/src/stm32/stm32_rtcounter.c +++ b/arch/arm/src/stm32/stm32_rtcounter.c @@ -331,7 +331,9 @@ static int stm32_rtc_interrupt(int irq, void *context, FAR void *arg) #ifdef CONFIG_RTC_HIRES if ((source & RTC_CRL_OWF) != 0) { + stm32_pwr_enablebkp(true); putreg16(getreg16(RTC_TIMEMSB_REG) + 1, RTC_TIMEMSB_REG); + stm32_pwr_enablebkp(false); } #endif @@ -373,25 +375,33 @@ static int stm32_rtc_interrupt(int irq, void *context, FAR void *arg) int up_rtc_initialize(void) { + uint32_t regval; + /* Enable write access to the backup domain (RTC registers, RTC backup data * registers and backup SRAM). */ stm32_pwr_enablebkp(true); + + regval = getreg32(RTC_MAGIC_REG); + + if (regval != RTC_MAGIC && regval != RTC_MAGIC_TIME_SET) + { + /* reset backup domain if bad magic */ + modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_BDRST); + modifyreg32(STM32_RCC_BDCR, RCC_BDCR_BDRST, 0); + putreg16(RTC_MAGIC, RTC_MAGIC_REG); + } /* Select the lower power external 32,768Hz (Low-Speed External, LSE) oscillator * as RTC Clock Source and enable the Clock */ modifyreg16(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSE); + + /* enable RTC and wait for RSF */ + modifyreg16(STM32_RCC_BDCR, 0, RCC_BDCR_RTCEN); - /* TODO: Get state from this function, if everything is - * okay and whether it is already enabled (if it was disabled - * reset upper time register) - */ - - g_rtc_enabled = true; - /* TODO: Possible stall? should we set the timeout period? and return with -1 */ stm32_rtc_wait4rsf(); @@ -403,21 +413,19 @@ int up_rtc_initialize(void) putreg16(STM32_RTC_PRESCALAR_VALUE & 0xffff, STM32_RTC_PRLL); stm32_rtc_endwr(); - /* Configure RTC interrupt to catch overflow and alarm interrupts. */ + stm32_rtc_wait4rsf(); -#if defined(CONFIG_RTC_HIRES) || defined(CONFIG_RTC_ALARM) - irq_attach(STM32_IRQ_RTC, stm32_rtc_interrupt, NULL); - up_enable_irq(STM32_IRQ_RTC); +#ifdef CONFIG_RTC_HIRES + /* enable overflow interrupt - alarm interrupt is enabled in stm32_rtc_setalarm */ + modifyreg16(STM32_RTC_CRH, 0, RTC_CRH_OWIE); #endif - /* Previous write is done? This is required prior writing into CRH */ + /* TODO: Get state from this function, if everything is + * okay and whether it is already enabled (if it was disabled + * reset upper time register) + */ - while ((getreg16(STM32_RTC_CRL) & RTC_CRL_RTOFF) == 0) - { - up_waste(); - } - - modifyreg16(STM32_RTC_CRH, 0, RTC_CRH_OWIE); + g_rtc_enabled = true; /* Alarm Int via EXTI Line */ @@ -432,6 +440,33 @@ int up_rtc_initialize(void) return OK; } +/************************************************************************************ + * Name: stm32_rtc_irqinitialize + * + * Description: + * Initialize IRQs for RTC, not possible during up_rtc_initialize because + * up_irqinitialize is called later. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int stm32_rtc_irqinitialize(void) +{ + /* Configure RTC interrupt to catch overflow and alarm interrupts. */ + +#if defined(CONFIG_RTC_HIRES) || defined(CONFIG_RTC_ALARM) + irq_attach(STM32_IRQ_RTC, stm32_rtc_interrupt, NULL); + up_enable_irq(STM32_IRQ_RTC); +#endif + + return OK; +} + /************************************************************************************ * Name: up_rtc_time * @@ -613,6 +648,7 @@ int up_rtc_settime(FAR const struct timespec *tp) do { stm32_rtc_beginwr(); + putreg16(RTC_MAGIC, RTC_MAGIC_TIME_SET); putreg16(regvals.cnth, STM32_RTC_CNTH); putreg16(regvals.cntl, STM32_RTC_CNTL); cntl = getreg16(STM32_RTC_CNTL); @@ -652,6 +688,8 @@ int stm32_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback) uint16_t cr; int ret = -EBUSY; + flags = enter_critical_section(); + /* Is there already something waiting on the ALARM? */ if (g_alarmcb == NULL) @@ -664,6 +702,8 @@ int stm32_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback) stm32_rtc_breakout(tp, ®vals); + stm32_pwr_enablebkp(true); + /* Enable RTC alarm */ cr = getreg16(STM32_RTC_CRH); @@ -672,16 +712,18 @@ int stm32_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback) /* The set the alarm */ - flags = enter_critical_section(); stm32_rtc_beginwr(); putreg16(regvals.cnth, STM32_RTC_ALRH); putreg16(regvals.cntl, STM32_RTC_ALRL); stm32_rtc_endwr(); - leave_critical_section(flags); + + stm32_pwr_enablebkp(false); ret = OK; } + leave_critical_section(flags); + return ret; } #endif @@ -706,6 +748,8 @@ int stm32_rtc_cancelalarm(void) irqstate_t flags; int ret = -ENODATA; + flags = enter_critical_section(); + if (g_alarmcb != NULL) { /* Cancel the global callback function */ @@ -714,16 +758,18 @@ int stm32_rtc_cancelalarm(void) /* Unset the alarm */ - flags = enter_critical_section(); + stm32_pwr_enablebkp(true); stm32_rtc_beginwr(); putreg16(0xffff, STM32_RTC_ALRH); putreg16(0xffff, STM32_RTC_ALRL); stm32_rtc_endwr(); - leave_critical_section(flags); + stm32_pwr_enablebkp(false); ret = OK; } + leave_critical_section(flags); + return ret; } #endif diff --git a/arch/arm/src/stm32/stm32f40xxx_rtcc.c b/arch/arm/src/stm32/stm32f40xxx_rtcc.c index e15c995a6c..751989b487 100644 --- a/arch/arm/src/stm32/stm32f40xxx_rtcc.c +++ b/arch/arm/src/stm32/stm32f40xxx_rtcc.c @@ -1058,6 +1058,27 @@ int up_rtc_initialize(void) return OK; } +/************************************************************************************ + * Name: stm32_rtc_irqinitialize + * + * Description: + * Initialize IRQs for RTC, not possible during up_rtc_initialize because + * up_irqinitialize is called later. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int stm32_rtc_irqinitialize(void) +{ + /* nothing to do */ + return OK; +} + /**************************************************************************** * Name: stm32_rtc_getdatetime_with_subseconds * diff --git a/arch/arm/src/stm32l4/stm32l4_rtcc.c b/arch/arm/src/stm32l4/stm32l4_rtcc.c index d053ee9929..9ca5c7b9f8 100644 --- a/arch/arm/src/stm32l4/stm32l4_rtcc.c +++ b/arch/arm/src/stm32l4/stm32l4_rtcc.c @@ -1003,6 +1003,27 @@ int up_rtc_initialize(void) return OK; } +/************************************************************************************ + * Name: stm32_rtc_irqinitialize + * + * Description: + * Initialize IRQs for RTC, not possible during up_rtc_initialize because + * up_irqinitialize is called later. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int stm32_rtc_irqinitialize(void) +{ + /* nothing to do */ + return OK; +} + /************************************************************************************ * Name: stm32l4_rtc_getdatetime_with_subseconds *