mirror of
https://github.com/apache/nuttx.git
synced 2026-06-06 00:14:22 +08:00
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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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, ®vals);
|
stm32_rtc_breakout(tp, ®vals);
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -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
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user