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
This commit is contained in:
Leif Jakob
2017-06-14 22:36:40 +02:00
parent a3d2a61aa7
commit 4a79547fb8
7 changed files with 177 additions and 29 deletions
+5
View File
@@ -387,6 +387,11 @@ void up_irqinitialize(void)
up_enable_irq(STM32_IRQ_MEMFAULT); up_enable_irq(STM32_IRQ_MEMFAULT);
#endif #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) */ /* Attach all other processor exceptions (except reset and sys tick) */
#ifdef CONFIG_DEBUG_FEATURES #ifdef CONFIG_DEBUG_FEATURES
+35 -4
View File
@@ -79,21 +79,35 @@
#define STM32_RTC_PRESCALER_SECOND 32767 /* Default prescaler to get a second base */ #define STM32_RTC_PRESCALER_SECOND 32767 /* Default prescaler to get a second base */
#define STM32_RTC_PRESCALER_MIN 1 /* Maximum speed of 16384 Hz */ #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) #if !defined(CONFIG_RTC_MAGIC)
# define CONFIG_RTC_MAGIC (0xfacefeee) # define CONFIG_RTC_MAGIC (0xface) /* only 16 bit */
#endif #endif
#if !defined(CONFIG_RTC_MAGIC_TIME_SET) #define RTC_MAGIC_REG STM32_BKP_DR2
# define CONFIG_RTC_MAGIC_TIME_SET (CONFIG_RTC_MAGIC + 1)
#else /* !CONFIG_STM32_STM32F10XX */
#if !defined(CONFIG_RTC_MAGIC)
# define CONFIG_RTC_MAGIC (0xfacefeee)
#endif #endif
#if !defined(CONFIG_RTC_MAGIC_REG) #if !defined(CONFIG_RTC_MAGIC_REG)
# define CONFIG_RTC_MAGIC_REG (0) # define CONFIG_RTC_MAGIC_REG (0)
#endif #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 CONFIG_RTC_MAGIC
#define RTC_MAGIC_TIME_SET CONFIG_RTC_MAGIC_TIME_SET #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 * Public Types
@@ -118,6 +132,23 @@ extern "C"
* Public Functions * 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 * Name: stm32_rtc_getdatetime_with_subseconds
* *
+4
View File
@@ -365,7 +365,11 @@ static int stm32_settime(FAR struct rtc_lowerhalf_s *lower,
static bool stm32_havesettime(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; return getreg32(RTC_MAGIC_REG) == RTC_MAGIC_TIME_SET;
#endif
} }
/**************************************************************************** /****************************************************************************
+23 -3
View File
@@ -763,17 +763,37 @@ int up_rtc_initialize(void)
* 3. Configure the RTC to generate RTC alarms (Alarm A or Alarm B). * 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 #ifdef CONFIG_RTC_ALARM
# warning "Missing EXTI setup logic" # 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); irq_attach(STM32_IRQ_RTC_WKUP, rtc_interrupt, NULL);
up_enable_irq(STM32_IRQ_RTC_WKUP); up_enable_irq(STM32_IRQ_RTC_WKUP);
#endif #endif
g_rtc_enabled = true;
rtc_dumpregs("After Initialization");
return OK; return OK;
} }
+68 -22
View File
@@ -331,7 +331,9 @@ static int stm32_rtc_interrupt(int irq, void *context, FAR void *arg)
#ifdef CONFIG_RTC_HIRES #ifdef CONFIG_RTC_HIRES
if ((source & RTC_CRL_OWF) != 0) if ((source & RTC_CRL_OWF) != 0)
{ {
stm32_pwr_enablebkp(true);
putreg16(getreg16(RTC_TIMEMSB_REG) + 1, RTC_TIMEMSB_REG); putreg16(getreg16(RTC_TIMEMSB_REG) + 1, RTC_TIMEMSB_REG);
stm32_pwr_enablebkp(false);
} }
#endif #endif
@@ -373,25 +375,33 @@ static int stm32_rtc_interrupt(int irq, void *context, FAR void *arg)
int up_rtc_initialize(void) int up_rtc_initialize(void)
{ {
uint32_t regval;
/* Enable write access to the backup domain (RTC registers, RTC backup data /* Enable write access to the backup domain (RTC registers, RTC backup data
* registers and backup SRAM). * registers and backup SRAM).
*/ */
stm32_pwr_enablebkp(true); 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 /* Select the lower power external 32,768Hz (Low-Speed External, LSE) oscillator
* as RTC Clock Source and enable the Clock */ * as RTC Clock Source and enable the Clock */
modifyreg16(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSE); 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); 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 */ /* TODO: Possible stall? should we set the timeout period? and return with -1 */
stm32_rtc_wait4rsf(); stm32_rtc_wait4rsf();
@@ -403,21 +413,19 @@ int up_rtc_initialize(void)
putreg16(STM32_RTC_PRESCALAR_VALUE & 0xffff, STM32_RTC_PRLL); putreg16(STM32_RTC_PRESCALAR_VALUE & 0xffff, STM32_RTC_PRLL);
stm32_rtc_endwr(); stm32_rtc_endwr();
/* Configure RTC interrupt to catch overflow and alarm interrupts. */ stm32_rtc_wait4rsf();
#if defined(CONFIG_RTC_HIRES) || defined(CONFIG_RTC_ALARM) #ifdef CONFIG_RTC_HIRES
irq_attach(STM32_IRQ_RTC, stm32_rtc_interrupt, NULL); /* enable overflow interrupt - alarm interrupt is enabled in stm32_rtc_setalarm */
up_enable_irq(STM32_IRQ_RTC); modifyreg16(STM32_RTC_CRH, 0, RTC_CRH_OWIE);
#endif #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) g_rtc_enabled = true;
{
up_waste();
}
modifyreg16(STM32_RTC_CRH, 0, RTC_CRH_OWIE);
/* Alarm Int via EXTI Line */ /* Alarm Int via EXTI Line */
@@ -432,6 +440,33 @@ int up_rtc_initialize(void)
return OK; 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 * Name: up_rtc_time
* *
@@ -613,6 +648,7 @@ int up_rtc_settime(FAR const struct timespec *tp)
do do
{ {
stm32_rtc_beginwr(); stm32_rtc_beginwr();
putreg16(RTC_MAGIC, RTC_MAGIC_TIME_SET);
putreg16(regvals.cnth, STM32_RTC_CNTH); putreg16(regvals.cnth, STM32_RTC_CNTH);
putreg16(regvals.cntl, STM32_RTC_CNTL); putreg16(regvals.cntl, STM32_RTC_CNTL);
cntl = getreg16(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; uint16_t cr;
int ret = -EBUSY; int ret = -EBUSY;
flags = enter_critical_section();
/* Is there already something waiting on the ALARM? */ /* Is there already something waiting on the ALARM? */
if (g_alarmcb == NULL) if (g_alarmcb == NULL)
@@ -664,6 +702,8 @@ int stm32_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback)
stm32_rtc_breakout(tp, &regvals); stm32_rtc_breakout(tp, &regvals);
stm32_pwr_enablebkp(true);
/* Enable RTC alarm */ /* Enable RTC alarm */
cr = getreg16(STM32_RTC_CRH); 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 */ /* The set the alarm */
flags = enter_critical_section();
stm32_rtc_beginwr(); stm32_rtc_beginwr();
putreg16(regvals.cnth, STM32_RTC_ALRH); putreg16(regvals.cnth, STM32_RTC_ALRH);
putreg16(regvals.cntl, STM32_RTC_ALRL); putreg16(regvals.cntl, STM32_RTC_ALRL);
stm32_rtc_endwr(); stm32_rtc_endwr();
leave_critical_section(flags);
stm32_pwr_enablebkp(false);
ret = OK; ret = OK;
} }
leave_critical_section(flags);
return ret; return ret;
} }
#endif #endif
@@ -706,6 +748,8 @@ int stm32_rtc_cancelalarm(void)
irqstate_t flags; irqstate_t flags;
int ret = -ENODATA; int ret = -ENODATA;
flags = enter_critical_section();
if (g_alarmcb != NULL) if (g_alarmcb != NULL)
{ {
/* Cancel the global callback function */ /* Cancel the global callback function */
@@ -714,16 +758,18 @@ int stm32_rtc_cancelalarm(void)
/* Unset the alarm */ /* Unset the alarm */
flags = enter_critical_section(); stm32_pwr_enablebkp(true);
stm32_rtc_beginwr(); stm32_rtc_beginwr();
putreg16(0xffff, STM32_RTC_ALRH); putreg16(0xffff, STM32_RTC_ALRH);
putreg16(0xffff, STM32_RTC_ALRL); putreg16(0xffff, STM32_RTC_ALRL);
stm32_rtc_endwr(); stm32_rtc_endwr();
leave_critical_section(flags); stm32_pwr_enablebkp(false);
ret = OK; ret = OK;
} }
leave_critical_section(flags);
return ret; return ret;
} }
#endif #endif
+21
View File
@@ -1058,6 +1058,27 @@ int up_rtc_initialize(void)
return OK; 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 * Name: stm32_rtc_getdatetime_with_subseconds
* *
+21
View File
@@ -1003,6 +1003,27 @@ int up_rtc_initialize(void)
return OK; 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 * Name: stm32l4_rtc_getdatetime_with_subseconds
* *