diff --git a/arch/arm/src/stm32l4/stm32l4_exti_alarm.c b/arch/arm/src/stm32l4/stm32l4_exti_alarm.c index 8f145ccd4fd..2935cacef81 100644 --- a/arch/arm/src/stm32l4/stm32l4_exti_alarm.c +++ b/arch/arm/src/stm32l4/stm32l4_exti_alarm.c @@ -86,17 +86,17 @@ static int stm32l4_exti_alarm_isr(int irq, void *context) { int ret = OK; - /* Clear the pending EXTI interrupt */ - - putreg32(EXTI1_RTC_ALARM, STM32L4_EXTI1_PR); - - /* And dispatch the interrupt to the handler */ + /* Dispatch the interrupt to the handler */ if (stm32l4_exti_callback) { ret = stm32l4_exti_callback(irq, context); } + /* Clear the pending EXTI interrupt */ + + putreg32(EXTI1_RTC_ALARM, STM32L4_EXTI1_PR); + return ret; } diff --git a/arch/arm/src/stm32l4/stm32l4_rtc.h b/arch/arm/src/stm32l4/stm32l4_rtc.h index 5292f6f4eb9..b155bef8b0b 100644 --- a/arch/arm/src/stm32l4/stm32l4_rtc.h +++ b/arch/arm/src/stm32l4/stm32l4_rtc.h @@ -43,6 +43,7 @@ #ifndef __ARCH_ARM_SRC_STM32L4_STM32L4_RTC_H #define __ARCH_ARM_SRC_STM32L4_STM32L4_RTC_H +#include #include #include "chip.h" @@ -62,9 +63,30 @@ #ifndef __ASSEMBLY__ +#ifdef CONFIG_RTC_ALARM + /* The form of an alarm callback */ -typedef CODE void (*alarmcb_t)(void); +typedef CODE void (*alm_callback_t)(FAR void *arg, unsigned int alarmid); + +enum alm_id_e +{ + RTC_ALARMA = 0, /* RTC ALARM A */ + RTC_ALARMB, /* RTC ALARM B */ + RTC_ALARM_LAST +}; + +/* Structure used to pass parmaters to set an alarm */ + +struct alm_setalarm_s +{ + int as_id; /* enum alm_id_e */ + struct tm as_time; /* Alarm expiration time */ + alm_callback_t as_cb; /* Callback (if non-NULL) */ + FAR void *as_arg; /* Argument for callback */ +}; + +#endif /* CONFIG_RTC_ALARM */ /**************************************************************************** * Public Data @@ -93,8 +115,7 @@ extern "C" * during initialization to set up the system time when CONFIG_RTC and * CONFIG_RTC_DATETIME are selected (and CONFIG_RTC_HIRES is not). * - * NOTE: Some date/time RTC hardware is capability of sub-second accuracy. - * That sub-second accuracy is returned through 'nsec'. + * NOTE: The sub-second accuracy is returned through 'nsec'. * * Input Parameters: * tp - The location to return the high resolution time value. @@ -130,43 +151,39 @@ struct tm; int stm32l4_rtc_setdatetime(FAR const struct tm *tp); #endif +#ifdef CONFIG_RTC_ALARM /**************************************************************************** * Name: stm32l4_rtc_setalarm * * Description: - * Set up an alarm. + * Set an alarm to an asbolute time using associated hardware. * * Input Parameters: - * tp - the time to set the alarm - * callback - the function to call when the alarm expires. + * alminfo - Information about the alarm configuration. * * Returned Value: * Zero (OK) on success; a negated errno on failure * ****************************************************************************/ -#ifdef CONFIG_RTC_ALARM -struct timespec; -int stm32l4_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback); -#endif +int stm32l4_rtc_setalarm(FAR struct alm_setalarm_s *alminfo); /**************************************************************************** * Name: stm32l4_rtc_cancelalarm * * Description: - * Cancel a pending alarm alarm + * Cancel an alaram. * * Input Parameters: - * none + * alarmid - Identifies the alarm to be cancelled * * Returned Value: * Zero (OK) on success; a negated errno on failure * ****************************************************************************/ -#ifdef CONFIG_RTC_ALARM -int stm32l4_rtc_cancelalarm(void); -#endif +int stm32l4_rtc_cancelalarm(enum alm_id_e alarmid); +#endif /* CONFIG_RTC_ALARM */ /**************************************************************************** * Name: stm32l4_rtc_lowerhalf diff --git a/arch/arm/src/stm32l4/stm32l4_rtc_lowerhalf.c b/arch/arm/src/stm32l4/stm32l4_rtc_lowerhalf.c index 033a191e411..bb0b7551fdb 100644 --- a/arch/arm/src/stm32l4/stm32l4_rtc_lowerhalf.c +++ b/arch/arm/src/stm32l4/stm32l4_rtc_lowerhalf.c @@ -34,8 +34,6 @@ * ****************************************************************************/ -/* REVISIT: This driver is *not* thread-safe! */ - /**************************************************************************** * Included Files ****************************************************************************/ @@ -44,6 +42,7 @@ #include #include +#include #include #include @@ -54,10 +53,25 @@ #ifdef CONFIG_RTC_DRIVER +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define STM32_NALARMS 2 + /**************************************************************************** * Private Types ****************************************************************************/ +#ifdef CONFIG_RTC_ALARM +struct stm32l4_cbinfo_s +{ + volatile rtc_alarm_callback_t cb; /* Callback when the alarm expires */ + volatile FAR void *priv; /* Private argurment to accompany callback */ + uint8_t id; /* Identifies the alarm */ +}; +#endif + /* This is the private type for the RTC state. It must be cast compatible * with struct rtc_lowerhalf_s. */ @@ -73,6 +87,14 @@ struct stm32l4_lowerhalf_s /* Data following is private to this driver and not visible outside of * this file. */ + + sem_t devsem; /* Threads can only exclusively access the RTC */ + +#ifdef CONFIG_RTC_ALARM + /* Alarm callback information */ + + struct stm32l4_cbinfo_s cbinfo[STM32_NALARMS]; +#endif }; /**************************************************************************** @@ -85,6 +107,15 @@ static int stm32l4_rdtime(FAR struct rtc_lowerhalf_s *lower, static int stm32l4_settime(FAR struct rtc_lowerhalf_s *lower, FAR const struct rtc_time *rtctime); +#ifdef CONFIG_RTC_ALARM +static int stm32l4_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo); +static int stm32l4_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo); +static int stm32l4_cancelalarm(FAR struct rtc_lowerhalf_s *lower, + int alarmid); +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -96,9 +127,9 @@ static const struct rtc_ops_s g_rtc_ops = .rdtime = stm32l4_rdtime, .settime = stm32l4_settime, #ifdef CONFIG_RTC_ALARM - .setalarm = NULL, - .setrelative = NULL, - .cancelalarm = NULL, + .setalarm = stm32l4_setalarm, + .setrelative = stm32l4_setrelative, + .cancelalarm = stm32l4_cancelalarm, #endif #ifdef CONFIG_RTC_IOCTL .ioctl = NULL, @@ -120,7 +151,56 @@ static struct stm32l4_lowerhalf_s g_rtc_lowerhalf = ****************************************************************************/ /**************************************************************************** - * Name: stm32l4_rdtime + * Name: stm32l4_alarm_callback + * + * Description: + * This is the function that is called from the RTC driver when the alarm + * goes off. It just invokes the upper half drivers callback. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static void stm32l4_alarm_callback(FAR void *arg, unsigned int alarmid) +{ + FAR struct stm32l4_lowerhalf_s *lower; + FAR struct stm32l4_cbinfo_s *cbinfo; + rtc_alarm_callback_t cb; + FAR void *priv; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(alarmid == RTC_ALARMA || alarmid == RTC_ALARMB); + + lower = (struct stm32l4_lowerhalf_s *)arg; + cbinfo = &lower->cbinfo[alarmid]; + + /* Sample and clear the callback information to minimize the window in + * time in which race conditions can occur. + */ + + cb = (rtc_alarm_callback_t)cbinfo->cb; + priv = (FAR void *)cbinfo->priv; + + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Perform the callback */ + + if (cb != NULL) + { + cb(priv, alarmid); + } + +} +#endif /* CONFIG_RTC_ALARM */ + +/**************************************************************************** + * Name: stm32_rdtime * * Description: * Implements the rdtime() method of the RTC driver interface @@ -138,11 +218,25 @@ static struct stm32l4_lowerhalf_s g_rtc_lowerhalf = static int stm32l4_rdtime(FAR struct rtc_lowerhalf_s *lower, FAR struct rtc_time *rtctime) { + FAR struct stm32l4_lowerhalf_s *priv; + int ret; + + priv = (FAR struct stm32l4_lowerhalf_s *)lower; + + if (sem_wait(&priv->devsem) != OK) + { + return -errno; + } + /* This operation depends on the fact that struct rtc_time is cast * compatible with struct tm. */ - return up_rtc_getdatetime((FAR struct tm *)rtctime); + ret = up_rtc_getdatetime((FAR struct tm *)rtctime); + + sem_post(&priv->devsem); + + return ret; } /**************************************************************************** @@ -164,13 +258,223 @@ static int stm32l4_rdtime(FAR struct rtc_lowerhalf_s *lower, static int stm32l4_settime(FAR struct rtc_lowerhalf_s *lower, FAR const struct rtc_time *rtctime) { - /* This operation depends on the fact that struct rtc_time is cast + FAR struct stm32l4_lowerhalf_s *priv; + int ret; + + priv = (FAR struct stm32l4_lowerhalf_s *)lower; + + if (sem_wait(&priv->devsem) != OK) + { + return -errno; + } + + /* This operation depends on the fact that struct rtc_time is cast * compatible with struct tm. */ - return stm32l4_rtc_setdatetime((FAR const struct tm *)rtctime); + ret = stm32l4_rtc_setdatetime((FAR const struct tm *)rtctime); + + sem_post(&priv->devsem); + + return ret; } +/**************************************************************************** + * Name: stm32l4_setalarm + * + * Description: + * Set a new alarm. This function implements the setalarm() method of the + * RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int stm32l4_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo) +{ + FAR struct stm32l4_lowerhalf_s *priv; + FAR struct stm32l4_cbinfo_s *cbinfo; + struct alm_setalarm_s lowerinfo; + int ret = -EINVAL; + + /* ID0-> Alarm A; ID1 -> Alarm B */ + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB); + priv = (FAR struct stm32l4_lowerhalf_s *)lower; + + if (sem_wait(&priv->devsem) != OK) + { + return -errno; + } + + if (alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) + { + /* Remember the callback information */ + + cbinfo = &priv->cbinfo[alarminfo->id]; + cbinfo->cb = alarminfo->cb; + cbinfo->priv = alarminfo->priv; + cbinfo->id = alarminfo->id; + + /* Set the alarm */ + + lowerinfo.as_id = alarminfo->id; + lowerinfo.as_cb = stm32l4_alarm_callback; + lowerinfo.as_arg = priv; + memcpy(&lowerinfo.as_time, &alarminfo->time, sizeof(struct tm)); + + /* And set the alarm */ + + ret = stm32l4_rtc_setalarm(&lowerinfo); + if (ret < 0) + { + cbinfo->cb = NULL; + cbinfo->priv = NULL; + } + } + + sem_post(&priv->devsem); + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32l4_setrelative + * + * Description: + * Set a new alarm relative to the current time. This function implements + * the setrelative() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int stm32l4_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo) +{ + struct lower_setalarm_s setalarm; + struct tm time; + time_t seconds; + int ret = -EINVAL; + + ASSERT(lower != NULL && alarminfo != NULL); + DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB); + + if ((alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) && + alarminfo->reltime > 0) + { + /* Disable preemption while we do this so that we don't have to worry + * about being suspended and working on an old time. + */ + + sched_lock(); + + /* Get the current time in broken out format */ + + ret = up_rtc_getdatetime(&time); + if (ret >= 0) + { + /* Convert to seconds since the epoch */ + + seconds = mktime(&time); + + /* Add the seconds offset. Add one to the number of seconds + * because we are unsure of the phase of the timer. + */ + + seconds += (alarminfo->reltime + 1); + + /* And convert the time back to broken out format */ + + (void)gmtime_r(&seconds, (FAR struct tm *)&setalarm.time); + + /* The set the alarm using this absolute time */ + + setalarm.id = alarminfo->id; + setalarm.cb = alarminfo->cb; + setalarm.priv = alarminfo->priv; + + ret = stm32l4_setalarm(lower, &setalarm); + } + + sched_unlock(); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32l4_cancelalarm + * + * Description: + * Cancel the current alarm. This function implements the cancelalarm() + * method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int stm32l4_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid) +{ + FAR struct stm32l4_lowerhalf_s *priv; + FAR struct stm32l4_cbinfo_s *cbinfo; + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL); + DEBUGASSERT(alarmid == RTC_ALARMA || alarmid == RTC_ALARMB); + priv = (FAR struct stm32l4_lowerhalf_s *)lower; + + if (sem_wait(&priv->devsem) != OK) + { + return -errno; + } + + /* ID0-> Alarm A; ID1 -> Alarm B */ + + if (alarmid == RTC_ALARMA || alarmid == RTC_ALARMB) + { + /* Nullify callback information to reduce window for race conditions */ + + cbinfo = &priv->cbinfo[alarmid]; + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Then cancel the alarm */ + + ret = stm32l4_rtc_cancelalarm((enum alm_id_e)alarmid); + } + + sem_post(&priv->devsem); + + return ret; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -199,6 +503,8 @@ static int stm32l4_settime(FAR struct rtc_lowerhalf_s *lower, FAR struct rtc_lowerhalf_s *stm32l4_rtc_lowerhalf(void) { + sem_init(&g_rtc_lowerhalf.devsem, 0, 1); + return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf; } diff --git a/arch/arm/src/stm32l4/stm32l4_rtcc.c b/arch/arm/src/stm32l4/stm32l4_rtcc.c index 1b7bb5f12ad..5dacc7a62de 100644 --- a/arch/arm/src/stm32l4/stm32l4_rtcc.c +++ b/arch/arm/src/stm32l4/stm32l4_rtcc.c @@ -42,6 +42,7 @@ #include "chip.h" #include +#include #include #include #include @@ -65,7 +66,10 @@ ************************************************************************************/ /* Configuration ********************************************************************/ -/* This RTC implementation supports only date/time RTC hardware */ +/* This RTC implementation supports + * - date/time RTC hardware + * - extended functions Alarm A and B + * */ #ifndef CONFIG_RTC_DATETIME # error "CONFIG_RTC_DATETIME must be set to use this driver" @@ -95,8 +99,21 @@ #define SYNCHRO_TIMEOUT (0x00020000) #define INITMODE_TIMEOUT (0x00010000) -#define RTC_MAGIC CONFIG_RTC_MAGIC -#define RTC_MAGIC_REG STM32L4_RTC_BKR(CONFIG_RTC_MAGIC_REG) + +/* BCD conversions */ + +#define rtc_reg_tr_bin2bcd(tp) \ + ((rtc_bin2bcd((tp)->tm_sec) << RTC_TR_SU_SHIFT) | \ + (rtc_bin2bcd((tp)->tm_min) << RTC_TR_MNU_SHIFT) | \ + (rtc_bin2bcd((tp)->tm_hour) << RTC_TR_HU_SHIFT)) + +#define rtc_reg_alrmr_bin2bcd(tm) \ + ((rtc_bin2bcd((tm)->tm_sec) << RTC_ALRMR_SU_SHIFT) | \ + (rtc_bin2bcd((tm)->tm_min) << RTC_ALRMR_MNU_SHIFT) | \ + (rtc_bin2bcd((tm)->tm_hour) << RTC_ALRMR_HU_SHIFT)) + +/* need to ignore DATE/DOW part of alarm; rtc_reg_alrmr_bin2bcd only encodes hms */ +#define RTC_ALRMR_ENABLE (0x80000000) /* Debug ****************************************************************************/ @@ -112,14 +129,28 @@ # define rtcllvdbg(x...) #endif +/************************************************************************************ + * Private Types + ************************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +typedef unsigned int rtc_alarmreg_t; + +struct alm_cbinfo_s +{ + volatile alm_callback_t ac_cb; /* Client callback function */ + volatile FAR void *ac_arg; /* Argument to pass with the callback function */ +}; +#endif + /************************************************************************************ * Private Data ************************************************************************************/ -/* Callback to use when the alarm expires */ - #ifdef CONFIG_RTC_ALARM -static alarmcb_t g_alarmcb; +/* Callback to use when an EXTI is activated */ + +static struct alm_cbinfo_s g_alarmcb[RTC_ALARM_LAST]; #endif /************************************************************************************ @@ -130,6 +161,17 @@ static alarmcb_t g_alarmcb; volatile bool g_rtc_enabled = false; +/************************************************************************************ + * Private Function Prototypes + ************************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int rtchw_check_alrawf(void); +static int rtchw_check_alrbwf(void); +static int rtchw_set_alrmar(rtc_alarmreg_t alarmreg); +static int rtchw_set_alrmbr(rtc_alarmreg_t alarmreg); +#endif + /************************************************************************************ * Private Functions ************************************************************************************/ @@ -166,10 +208,9 @@ static void rtc_dumpregs(FAR const char *msg) rtclldbg(" TSDR: %08x\n", getreg32(STM32L4_RTC_TSDR)); rtclldbg(" TSSSR: %08x\n", getreg32(STM32L4_RTC_TSSSR)); rtclldbg(" CALR: %08x\n", getreg32(STM32L4_RTC_CALR)); - rtclldbg(" TAFCR: %08x\n", getreg32(STM32L4_RTC_TAMPCR_OFFSET)); + rtclldbg(" TAMPCR: %08x\n", getreg32(STM32L4_RTC_TAMPCR)); rtclldbg("ALRMASSR: %08x\n", getreg32(STM32L4_RTC_ALRMASSR)); rtclldbg("ALRMBSSR: %08x\n", getreg32(STM32L4_RTC_ALRMBSSR)); - rtclldbg("MAGICREG: %08x\n", getreg32(RTC_MAGIC_REG)); } #else # define rtc_dumpregs(msg) @@ -193,17 +234,48 @@ static void rtc_dumpregs(FAR const char *msg) static void rtc_dumptime(FAR const struct tm *tp, FAR const char *msg) { rtclldbg("%s:\n", msg); +#if 0 rtclldbg(" tm_sec: %08x\n", tp->tm_sec); rtclldbg(" tm_min: %08x\n", tp->tm_min); rtclldbg(" tm_hour: %08x\n", tp->tm_hour); rtclldbg(" tm_mday: %08x\n", tp->tm_mday); rtclldbg(" tm_mon: %08x\n", tp->tm_mon); rtclldbg(" tm_year: %08x\n", tp->tm_year); +#else + rtclldbg(" tm: %04d-%02d-%02d %02d:%02d:%02d\n", + tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec); +#endif } #else # define rtc_dumptime(tp, msg) #endif +/************************************************************************************ + * Name: rtc_is_inits + * + * Description: + * Returns 'true' if the RTC has been initialized (according to the RTC itself). + * It will be 'false' if the RTC has never been initialized since first time power + * up, and the counters are stopped until it is first initialized. + * + * Input Parameters: + * None + * + * Returned Value: + * bool -- true if the INITS flag is set in the ISR. + * + ************************************************************************************/ + +static bool rtc_is_inits(void) +{ + uint32_t regval; + + regval = getreg32(STM32L4_RTC_ISR); + + return (regval & RTC_ISR_INITS) ? true : false; +} + /************************************************************************************ * Name: rtc_wprunlock * @@ -432,74 +504,6 @@ static int rtc_bcd2bin(uint32_t value) return (int)(tens + (value & 0x0f)); } -/************************************************************************************ - * Name: rtc_setup - * - * Description: - * Performs first time configuration of the RTC. A special value written into - * back-up register 0 will prevent this function from being called on sub-sequent - * resets or power up. - * - * Input Parameters: - * None - * - * Returned Value: - * Zero (OK) on success; a negated errno on failure - * - ************************************************************************************/ - -static int rtc_setup(void) -{ - uint32_t regval; - int ret; - - /* Disable the write protection for RTC registers */ - - rtc_wprunlock(); - - /* Set Initialization mode */ - - ret = rtc_enterinit(); - if (ret == OK) - { - /* Set the 24 hour format by clearing the FMT bit in the RTC - * control register - */ - - regval = getreg32(STM32L4_RTC_CR); - regval &= ~RTC_CR_FMT; - putreg32(regval, STM32L4_RTC_CR); - - /* Configure RTC pre-scaler with the required values */ - -#ifdef CONFIG_STM32L4_RTC_HSECLOCK - /* For a 1 MHz clock this yields 0.9999360041 Hz on the second - * timer - which is pretty close. - */ - - putreg32(((uint32_t)7182 << RTC_PRER_PREDIV_S_SHIFT) | - ((uint32_t)0x7f << RTC_PRER_PREDIV_A_SHIFT), - STM32L4_RTC_PRER); -#else - /* Correct values for 32.768 KHz LSE clock and inaccurate LSI clock */ - - putreg32(((uint32_t)0xff << RTC_PRER_PREDIV_S_SHIFT) | - ((uint32_t)0x7f << RTC_PRER_PREDIV_A_SHIFT), - STM32L4_RTC_PRER); -#endif - - /* Exit RTC initialization mode */ - - rtc_exitinit(); - } - - /* Re-enable the write protection for RTC registers */ - - rtc_wprlock(); - - return ret; -} - /************************************************************************************ * Name: rtc_resume * @@ -528,15 +532,15 @@ static void rtc_resume(void) /* Clear the EXTI Line 18 Pending bit (Connected internally to RTC Alarm) */ - putreg32((1 << 18), STM32L4_EXTI1_PR); + putreg32(EXTI1_RTC_ALARM, STM32L4_EXTI1_PR); #endif } /************************************************************************************ - * Name: rtc_interrupt + * Name: stm32l4_rtc_alarm_handler * * Description: - * RTC interrupt service routine + * RTC ALARM interrupt service routine through the EXTI line * * Input Parameters: * irq - The IRQ number that generated the interrupt @@ -548,10 +552,259 @@ static void rtc_resume(void) ************************************************************************************/ #ifdef CONFIG_RTC_ALARM -static int rtc_interrupt(int irq, void *context) +static int stm32l4_rtc_alarm_handler(int irq, void *context) { -#warning "Missing logic" - return OK; + FAR struct alm_cbinfo_s *cbinfo; + alm_callback_t cb; + FAR void *arg; + uint32_t isr; + uint32_t cr; + int ret = OK; + + /* Enable write access to the backup domain (RTC registers, RTC + * backup data registers and backup SRAM). + */ + + (void)stm32l4_pwr_enablebkp(true); + + /* Check for EXTI from Alarm A or B and handle according */ + + cr = getreg32(STM32L4_RTC_CR); + if ((cr & RTC_CR_ALRAIE) != 0) + { + isr = getreg32(STM32L4_RTC_ISR); + if ((isr & RTC_ISR_ALRAF) != 0) + { + cbinfo = &g_alarmcb[RTC_ALARMA]; + if (cbinfo->ac_cb != NULL) + { + /* Alarm A callback */ + + cb = cbinfo->ac_cb; + arg = (FAR void *)cbinfo->ac_arg; + + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + + cb(arg, RTC_ALARMA); + } + + /* note, bits 8-13 do /not/ require the write enable procedure */ + + isr = getreg32(STM32L4_RTC_ISR); + isr &= ~RTC_ISR_ALRAF; + putreg32(isr, STM32L4_RTC_ISR); + } + } + + cr = getreg32(STM32L4_RTC_CR); + if ((cr & RTC_CR_ALRBIE) != 0) + { + isr = getreg32(STM32L4_RTC_ISR); + if ((isr & RTC_ISR_ALRBF) != 0) + { + cbinfo = &g_alarmcb[RTC_ALARMB]; + if (cbinfo->ac_cb != NULL) + { + /* Alarm B callback */ + + cb = cbinfo->ac_cb; + arg = (FAR void *)cbinfo->ac_arg; + + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + + cb(arg, RTC_ALARMB); + } + + /* note, bits 8-13 do /not/ require the write enable procedure */ + + isr = getreg32(STM32L4_RTC_ISR); + isr &= ~RTC_ISR_ALRBF; + putreg32(isr, STM32L4_RTC_ISR); + } + } + + /* Disable write access to the backup domain (RTC registers, RTC backup + * data registers and backup SRAM). + */ + + (void)stm32l4_pwr_enablebkp(false); + + return ret; +} +#endif + +/************************************************************************************ + * Name: rtchw_check_alrXwf X= a or B + * + * Description: + * Check registers + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int rtchw_check_alrawf(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret = -ETIMEDOUT; + + /* Check RTC_ISR ALRAWF for access to alarm register, + * Can take 2 RTCCLK cycles or timeout + * CubeMX use GetTick. + */ + + for (timeout = 0; timeout < INITMODE_TIMEOUT; timeout++) + { + regval = getreg32(STM32L4_RTC_ISR); + if ((regval & RTC_ISR_ALRAWF) != 0) + { + ret = OK; + break; + } + } + + return ret; +} +#endif + +#ifdef CONFIG_RTC_ALARM +static int rtchw_check_alrbwf(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret = -ETIMEDOUT; + + /* Check RTC_ISR ALRAWF for access to alarm register, + * can take 2 RTCCLK cycles or timeout + * CubeMX use GetTick. + */ + + for (timeout = 0; timeout < INITMODE_TIMEOUT; timeout++) + { + regval = getreg32(STM32L4_RTC_ISR); + if ((regval & RTC_ISR_ALRBWF) != 0) + { + ret = OK; + break; + } + } + + return ret; +} +#endif + +/************************************************************************************ + * Name: stm32_rtchw_set_alrmXr X is a or b + * + * Description: + * Set the alarm (A or B) hardware registers, using the required hardware access + * protocol + * + * Input Parameters: + * alarmreg - the register + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int rtchw_set_alrmar(rtc_alarmreg_t alarmreg) +{ + int isr; + int ret = -EBUSY; + + /* Need to allow RTC register write + * Disable the write protection for RTC registers + */ + + rtc_wprunlock(); + + /* Disable RTC alarm A & Interrupt A */ + + modifyreg32(STM32L4_RTC_CR, (RTC_CR_ALRAE | RTC_CR_ALRAIE), 0); + + /* Ensure Alarm A flag reset; this is edge triggered */ + + isr = getreg32(STM32L4_RTC_ISR) & ~RTC_ISR_ALRAF; + putreg32(isr, STM32L4_RTC_ISR); + + /* Wait for Alarm A to be writable */ + + ret = rtchw_check_alrawf(); + if (ret != OK) + { + goto errout_with_wprunlock; + } + + /* Set the RTC Alarm A register */ + + putreg32(alarmreg, STM32L4_RTC_ALRMAR); + putreg32(0, STM32L4_RTC_ALRMASSR); + rtcvdbg(" TR: %08x ALRMAR: %08x\n", + getreg32(STM32L4_RTC_TR), getreg32(STM32L4_RTC_ALRMAR)); + + /* Enable RTC alarm A */ + + modifyreg32(STM32L4_RTC_CR, 0, (RTC_CR_ALRAE | RTC_CR_ALRAIE)); + +errout_with_wprunlock: + rtc_wprlock(); + return ret; +} +#endif + +#ifdef CONFIG_RTC_ALARM +static int rtchw_set_alrmbr(rtc_alarmreg_t alarmreg) +{ + int isr; + int ret = -EBUSY; + + /* Need to allow RTC register write + * Disable the write protection for RTC registers + */ + + rtc_wprunlock(); + + /* Disable RTC alarm B & Interrupt B */ + + modifyreg32(STM32L4_RTC_CR, (RTC_CR_ALRBE | RTC_CR_ALRBIE), 0); + + /* Ensure Alarm B flag reset; this is edge triggered */ + + isr = getreg32(STM32L4_RTC_ISR) & ~RTC_ISR_ALRBF; + putreg32(isr, STM32L4_RTC_ISR); + + /* Wait for Alarm B to be writable */ + + ret = rtchw_check_alrbwf(); + if (ret != OK) + { + goto rtchw_set_alrmbr_exit; + } + + /* Set the RTC Alarm B register */ + + putreg32(alarmreg, STM32L4_RTC_ALRMBR); + putreg32(0, STM32L4_RTC_ALRMBSSR); + rtcvdbg(" TR: %08x ALRMBR: %08x\n", + getreg32(STM32L4_RTC_TR), getreg32(STM32L4_RTC_ALRMBR)); + + /* Enable RTC alarm B */ + + modifyreg32(STM32L4_RTC_CR, 0, (RTC_CR_ALRBE | RTC_CR_ALRBIE)); + +rtchw_set_alrmbr_exit: + rtc_wprlock(); + return ret; } #endif @@ -576,209 +829,174 @@ static int rtc_interrupt(int irq, void *context) int up_rtc_initialize(void) { + bool init_stat; uint32_t regval; - uint32_t tr_bkp; - uint32_t dr_bkp; int ret; - int maxretry = 10; - int nretry = 0; - /* Clocking for the PWR block must be provided. + rtc_dumpregs("Before Initialization"); + + /* See if the clock has already been initialized; since it is battery + * backed, we don't need or want to re-initialize on each reset. */ - rtc_dumpregs("On reset"); + init_stat = rtc_is_inits(); - /* Select the clock source */ - /* Save the token before losing it when resetting */ - - regval = getreg32(RTC_MAGIC_REG); - - (void)stm32l4_pwr_enablebkp(true); - - if (regval != RTC_MAGIC) + if(!init_stat) { - /* We might be changing RTCSEL - to ensure such changes work, we must reset the - * backup domain (having backed up the RTC_MAGIC token) - */ - - modifyreg32(STM32L4_RCC_BDCR, 0, RCC_BDCR_BDRST); - modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_BDRST, 0); - - /* Some boards do not have the external 32khz oscillator installed, for those - * boards we must fallback to the crummy internal RC clock or the external high - * rate clock - */ - -#ifdef CONFIG_STM32L4_RTC_HSECLOCK - /* Use the HSE clock as the input to the RTC block */ - - modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_HSE); - -#elif defined(CONFIG_STM32L4_RTC_LSICLOCK) - /* Use the LSI clock as the input to the RTC block */ - - modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSI); - -#elif defined(CONFIG_STM32L4_RTC_LSECLOCK) - /* Use the LSE clock as the input to the RTC block */ - - modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSE); - -#endif - /* Enable the RTC Clock by setting the RTCEN bit in the RCC register */ - - modifyreg32(STM32L4_RCC_BDCR, 0, RCC_BDCR_RTCEN); - } - else /* The RTC is already in use: check if the clock source is changed */ - { -#if defined(CONFIG_STM32L4_RTC_HSECLOCK) || defined(CONFIG_STM32L4_RTC_LSICLOCK) || \ - defined(CONFIG_STM32L4_RTC_LSECLOCK) - - uint32_t clksrc = getreg32(STM32L4_RCC_BDCR); - -#if defined(CONFIG_STM32L4_RTC_HSECLOCK) - if ((clksrc & RCC_BDCR_RTCSEL_MASK) != RCC_BDCR_RTCSEL_HSE) -#elif defined(CONFIG_STM32L4_RTC_LSICLOCK) - if ((clksrc & RCC_BDCR_RTCSEL_MASK) != RCC_BDCR_RTCSEL_LSI) -#elif defined(CONFIG_STM32L4_RTC_LSECLOCK) - if ((clksrc & RCC_BDCR_RTCSEL_MASK) != RCC_BDCR_RTCSEL_LSE) -#endif -#endif - { - tr_bkp = getreg32(STM32L4_RTC_TR); - dr_bkp = getreg32(STM32L4_RTC_DR); - modifyreg32(STM32L4_RCC_BDCR, 0, RCC_BDCR_BDRST); - modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_BDRST, 0); - -#if defined(CONFIG_STM32L4_RTC_HSECLOCK) - /* Change to the new clock as the input to the RTC block */ - - modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_HSE); - -#elif defined(CONFIG_STM32L4_RTC_LSICLOCK) - modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSI); - -#elif defined(CONFIG_STM32L4_RTC_LSECLOCK) - modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSE); -#endif - - putreg32(tr_bkp, STM32L4_RTC_TR); - putreg32(dr_bkp, STM32L4_RTC_DR); - - /* Remember that the RTC is initialized */ - - putreg32(RTC_MAGIC, RTC_MAGIC_REG); - - /* Enable the RTC Clock by setting the RTCEN bit in the RCC register */ - - modifyreg32(STM32L4_RCC_BDCR, 0, RCC_BDCR_RTCEN); - } - } - - (void)stm32l4_pwr_enablebkp(false); - - /* Loop, attempting to initialize/resume the RTC. This loop is necessary - * because it seems that occasionally it takes longer to initialize the RTC - * (the actual failure is in rtc_synchwait()). - */ - - do - { - /* Wait for the RTC Time and Date registers to be synchronized with RTC APB - * clock. - */ - - ret = rtc_synchwait(); - - /* Check that rtc_syncwait() returned successfully */ - - switch (ret) - { - case OK: - { - rtclldbg("rtc_syncwait() okay\n"); - break; - } - - default: - { - rtclldbg("rtc_syncwait() failed (%d)\n", ret); - break; - } - } - } - while (ret != OK && ++nretry < maxretry); - - /* Check if the one-time initialization of the RTC has already been - * performed. We can determine this by checking if the magic number - * has been writing to to back-up date register DR0. - */ - - if (regval != RTC_MAGIC) - { - rtclldbg("Do setup\n"); - - /* Perform the one-time setup of the LSE clocking to the RTC */ - - ret = rtc_setup(); - /* Enable write access to the backup domain (RTC registers, RTC * backup data registers and backup SRAM). */ (void)stm32l4_pwr_enablebkp(true); - /* Remember that the RTC is initialized */ +#if 0 + /* Do not reset the backup domain; you will lose your clock setup done in *rcc.c */ - putreg32(RTC_MAGIC, RTC_MAGIC_REG); + modifyreg32(STM32L4_RCC_BDCR, 0, RCC_BDCR_BDRST); + modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_BDRST, 0); +#endif + +#if defined(CONFIG_STM32L4_RTC_HSECLOCK) + modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_HSE); +#elif defined(CONFIG_STM32L4_RTC_LSICLOCK) + modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSI); +#elif defined(CONFIG_STM32L4_RTC_LSECLOCK) + modifyreg32(STM32L4_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSE); +#endif + + /* Enable the RTC Clock by setting the RTCEN bit in the RCC register */ + + modifyreg32(STM32L4_RCC_BDCR, 0, RCC_BDCR_RTCEN); + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Set Initialization mode */ + + if (OK != rtc_enterinit()) + { + /* Enable the write protection for RTC registers */ + + rtc_wprlock(); + + /* Disable write access to the backup domain (RTC registers, RTC backup + * data registers and backup SRAM). + */ + + (void)stm32l4_pwr_enablebkp(false); + + rtc_dumpregs("After Failed Initialization"); + + return -1; + } + else + { + /* Clear RTC_CR FMT, OSEL and POL Bits */ + + regval = getreg32(STM32L4_RTC_CR); + regval &= ~(RTC_CR_FMT | RTC_CR_OSEL_MASK | RTC_CR_POL); + + /* Configure RTC pre-scaler with the required values */ + +#ifdef CONFIG_STM32L4_RTC_HSECLOCK + /* The HSE is divided by 32 prior to the prescaler we set here. + * 1953 + * NOTE: max HSE/32 is 4 MHz if it is to be used with RTC + */ + + /* For a 1 MHz clock this yields 0.9999360041 Hz on the second + * timer - which is pretty close. + */ + + putreg32(((uint32_t)7812 << RTC_PRER_PREDIV_S_SHIFT) | + ((uint32_t)0x7f << RTC_PRER_PREDIV_A_SHIFT), + STM32L4_RTC_PRER); +#elif defined(CONFIG_STM32L4_RTC_LSICLOCK) + /* Suitable values for 32.000 KHz LSI clock (29.5 - 34 KHz, though) */ + + putreg32(((uint32_t)0xf9 << RTC_PRER_PREDIV_S_SHIFT) | + ((uint32_t)0x7f << RTC_PRER_PREDIV_A_SHIFT), + STM32L4_RTC_PRER); +#else /* defined(CONFIG_STM32L4_RTC_LSECLOCK) */ + /* Correct values for 32.768 KHz LSE clock */ + + putreg32(((uint32_t)0xff << RTC_PRER_PREDIV_S_SHIFT) | + ((uint32_t)0x7f << RTC_PRER_PREDIV_A_SHIFT), + STM32L4_RTC_PRER); +#endif + + /* Wait for the RTC Time and Date registers to be synchronized with RTC APB + * clock. + */ + + ret = rtc_synchwait(); + (void)ret; + + /* Exit Initialization mode */ + + rtc_exitinit(); + + /* Enable the write protection for RTC registers */ + + rtc_wprlock(); + + /* Disable write access to the backup domain (RTC registers, RTC backup + * data registers and backup SRAM). + */ + + (void)stm32l4_pwr_enablebkp(false); + } } else { - rtclldbg("Do resume\n"); + /* Enable write access to the backup domain (RTC registers, RTC + * backup data registers and backup SRAM). + */ - /* RTC already set-up, just resume normal operation */ + (void)stm32l4_pwr_enablebkp(true); + + /* Disable the write protection for RTC registers */ + + //rtc_wprunlock(); rtc_resume(); - rtc_dumpregs("Did resume"); - } - - /* Disable write access to the backup domain (RTC registers, RTC backup - * data registers and backup SRAM). - */ - - (void)stm32l4_pwr_enablebkp(false); - - if (ret != OK && nretry > 0) - { - rtclldbg("setup/resume ran %d times and failed with %d\n", - nretry, ret); - return -ETIMEDOUT; + + /* Enable the write protection for RTC registers */ + + //rtc_wprlock(); + + /* Disable write access to the backup domain (RTC registers, RTC backup + * data registers and backup SRAM). + */ + + (void)stm32l4_pwr_enablebkp(false); } +#ifdef CONFIG_RTC_ALARM /* Configure RTC interrupt to catch alarm interrupts. All RTC interrupts are * connected to the EXTI controller. To enable the RTC Alarm interrupt, the * following sequence is required: * * 1. Configure and enable the EXTI Line 18 in interrupt mode and select the * rising edge sensitivity. + * EXTI line 19 RTC Tamper or Timestamp or CSS_LSE + * EXTI line 20 RTC Wakeup * 2. Configure and enable the RTC_Alarm IRQ channel in the NVIC. * 3. Configure the RTC to generate RTC alarms (Alarm A or Alarm B). */ -#ifdef CONFIG_RTC_ALARM -# warning "Missing EXTI setup logic" - - /* Then attach the ALARM interrupt handler */ - - irq_attach(STM32L4_IRQ_RTC_WKUP, rtc_interrupt); - up_enable_irq(STM32L4_IRQ_RTC_WKUP); + stm32l4_exti_alarm(true, false, true, stm32l4_rtc_alarm_handler); #endif g_rtc_enabled = true; rtc_dumpregs("After Initialization"); + return OK; } + + /************************************************************************************ * Name: stm32l4_rtc_getdatetime_with_subseconds * @@ -1029,11 +1247,10 @@ int up_rtc_settime(FAR const struct timespec *tp) * Name: stm32l4_rtc_setalarm * * Description: - * Set up an alarm. Up to two alarms can be supported (ALARM A and ALARM B). + * Set an alarm to an absolute time using associated hardware. * * Input Parameters: - * tp - the time to set the alarm - * callback - the function to call when the alarm expires. + * alminfo - Information about the alarm configuration. * * Returned Value: * Zero (OK) on success; a negated errno on failure @@ -1041,27 +1258,166 @@ int up_rtc_settime(FAR const struct timespec *tp) ************************************************************************************/ #ifdef CONFIG_RTC_ALARM -int stm32l4_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback) +int stm32l4_rtc_setalarm(FAR struct alm_setalarm_s *alminfo) { - int ret = -EBUSY; + FAR struct alm_cbinfo_s *cbinfo; + rtc_alarmreg_t alarmreg; + int ret = -EINVAL; - /* Is there already something waiting on the ALARM? */ + ASSERT(alminfo != NULL); + DEBUGASSERT(RTC_ALARM_LAST > alminfo->as_id); - if (g_alarmcb == NULL) + /* REVISIT: Should test that the time is in the future */ + + rtc_dumptime(&alminfo->as_time, "New alarm time"); + + /* Break out the values to the HW alarm register format */ + + alarmreg = rtc_reg_alrmr_bin2bcd(&alminfo->as_time); + + /* Set the alarm in hardware and enable interrupts */ + + switch (alminfo->as_id) { - /* No.. Save the callback function pointer */ + case RTC_ALARMA: + { + cbinfo = &g_alarmcb[RTC_ALARMA]; + cbinfo->ac_cb = alminfo->as_cb; + cbinfo->ac_arg = alminfo->as_arg; - g_alarmcb = callback; + ret = rtchw_set_alrmar(alarmreg | RTC_ALRMR_ENABLE); + if (ret < 0) + { + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + } + } + break; - /* Break out the time values */ -#warning "Missing logic" + case RTC_ALARMB: + { + cbinfo = &g_alarmcb[RTC_ALARMB]; + cbinfo->ac_cb = alminfo->as_cb; + cbinfo->ac_arg = alminfo->as_arg; - /* The set the alarm */ -#warning "Missing logic" + ret = rtchw_set_alrmbr(alarmreg | RTC_ALRMR_ENABLE); + if (ret < 0) + { + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + } + } + break; - ret = OK; + default: + rtcvdbg("ERROR: Invalid ALARM%d\n", alminfo->as_id); + break; } + rtc_dumpregs("After alarm setting"); + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32l4_rtc_cancelalarm + * + * Description: + * Cancel an alaram. + * + * Input Parameters: + * alarmid - Identifies the alarm to be cancelled + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int stm32l4_rtc_cancelalarm(enum alm_id_e alarmid) +{ + int ret = -EINVAL; + + DEBUGASSERT(RTC_ALARM_LAST > alarmid); + + /* Cancel the alarm in hardware and disable interrupts */ + + switch (alarmid) + { + case RTC_ALARMA: + { + /* Cancel the global callback function */ + + g_alarmcb[alarmid].ac_cb = NULL; + g_alarmcb[alarmid].ac_arg = NULL; + + /* Need to follow RTC register wrote protection. + * Disable the write protection for RTC registers + */ + + rtc_wprunlock(); + + /* Disable RTC alarm and interrupt */ + + modifyreg32(STM32L4_RTC_CR, (RTC_CR_ALRAE | RTC_CR_ALRAIE), 0); + + ret = rtchw_check_alrawf(); + if (ret < 0) + { + goto errout_with_wprunlock; + } + + /* Unset the alarm */ + + putreg32(-1, STM32L4_RTC_ALRMAR); + modifyreg32(STM32L4_RTC_ISR, RTC_ISR_ALRAF, 0); + rtc_wprlock(); + ret = OK; + } + break; + + case RTC_ALARMB: + { + /* Cancel the global callback function */ + + g_alarmcb[alarmid].ac_cb = NULL; + g_alarmcb[alarmid].ac_arg = NULL; + + /* Need to follow RTC register wrote protection. + * Disable the write protection for RTC registers + */ + + rtc_wprunlock(); + + /* Disable RTC alarm and interrupt */ + + modifyreg32(STM32L4_RTC_CR, (RTC_CR_ALRBE | RTC_CR_ALRBIE), 0); + + ret = rtchw_check_alrbwf(); + if (ret < 0) + { + goto errout_with_wprunlock; + } + + /* Unset the alarm */ + + putreg32(-1, STM32L4_RTC_ALRMBR); + modifyreg32(STM32L4_RTC_ISR, RTC_ISR_ALRBF, 0); + rtc_wprlock(); + ret = OK; + } + break; + + default: + rtcvdbg("ERROR: Invalid ALARM%d\n", alarmid); + break; + } + + return ret; + +errout_with_wprunlock: + rtc_wprlock(); return ret; } #endif diff --git a/configs/nucleo-l476rg/nsh/defconfig b/configs/nucleo-l476rg/nsh/defconfig index b6954d05d56..a4c68715642 100644 --- a/configs/nucleo-l476rg/nsh/defconfig +++ b/configs/nucleo-l476rg/nsh/defconfig @@ -69,6 +69,7 @@ CONFIG_DEBUG_LIB=y CONFIG_DEBUG_LEDS=y CONFIG_DEBUG_ANALOG=y CONFIG_DEBUG_GPIO=y +# CONFIG_DEBUG_RTC is not set CONFIG_DEBUG_SPI=y CONFIG_ARCH_HAVE_STACKCHECK=y # CONFIG_STACK_COLORATION is not set @@ -290,6 +291,9 @@ CONFIG_STM32L4_FIREWALL=y CONFIG_STM32L4_FLASH_PREFETCH=y CONFIG_STM32L4_DISABLE_IDLE_SLEEP_DURING_DEBUG=y # CONFIG_ARCH_BOARD_STM32L4_CUSTOM_CLOCKCONFIG is not set +CONFIG_STM32L4_RTC_LSECLOCK=y +# CONFIG_STM32L4_RTC_LSICLOCK is not set +# CONFIG_STM32L4_RTC_HSECLOCK is not set CONFIG_STM32L4_SAI1PLL=y # CONFIG_STM32L4_SAI2PLL is not set @@ -377,7 +381,14 @@ CONFIG_NSH_MMCSDMINOR=0 # # Board-Specific Options # -# CONFIG_LIB_BOARDCTL is not set +CONFIG_LIB_BOARDCTL=y +# CONFIG_BOARDCTL_RESET is not set +# CONFIG_BOARDCTL_UNIQUEID is not set +# CONFIG_BOARDCTL_TSCTEST is not set +# CONFIG_BOARDCTL_ADCTEST is not set +# CONFIG_BOARDCTL_PWMTEST is not set +# CONFIG_BOARDCTL_GRAPHICS is not set +# CONFIG_BOARDCTL_IOCTL is not set # # RTOS Features @@ -396,9 +407,6 @@ CONFIG_USEC_PER_TICK=10000 # CONFIG_SYSTEM_TIME64 is not set # CONFIG_CLOCK_MONOTONIC is not set # CONFIG_JULIAN_TIME is not set -CONFIG_START_YEAR=2014 -CONFIG_START_MONTH=5 -CONFIG_START_DAY=5 CONFIG_MAX_WDOGPARMS=2 CONFIG_PREALLOC_WDOGS=8 CONFIG_WDOG_INTRESERVE=1 @@ -517,7 +525,13 @@ CONFIG_SPI_EXCHANGE=y # Timer Driver Support # # CONFIG_TIMER is not set -# CONFIG_RTC is not set +CONFIG_RTC=y +CONFIG_RTC_DATETIME=y +CONFIG_RTC_ALARM=y +CONFIG_RTC_NALARMS=2 +CONFIG_RTC_DRIVER=y +CONFIG_RTC_IOCTL=y +# CONFIG_RTC_EXTERNAL is not set # CONFIG_WATCHDOG is not set # CONFIG_ANALOG is not set # CONFIG_AUDIO_DEVICES is not set @@ -755,6 +769,11 @@ CONFIG_BUILTIN_PROXY_STACKSIZE=1024 # # Examples # +CONFIG_EXAMPLES_ALARM=y +CONFIG_EXAMPLES_ALARM_PRIORITY=100 +CONFIG_EXAMPLES_ALARM_STACKSIZE=2048 +CONFIG_EXAMPLES_ALARM_DEVPATH="/dev/rtc0" +CONFIG_EXAMPLES_ALARM_SIGNO=1 # CONFIG_EXAMPLES_CHAT is not set # CONFIG_EXAMPLES_CONFIGDATA is not set # CONFIG_EXAMPLES_CPUHOG is not set @@ -813,6 +832,7 @@ CONFIG_EXAMPLES_NSAMPLES=8 # CONFIG_EXAMPLES_TIFF is not set # CONFIG_EXAMPLES_TOUCHSCREEN is not set # CONFIG_EXAMPLES_WEBSERVER is not set +# CONFIG_EXAMPLES_USBSERIAL is not set # CONFIG_EXAMPLES_USBTERM is not set # CONFIG_EXAMPLES_WATCHDOG is not set @@ -944,7 +964,7 @@ CONFIG_NSH_FILEIOSIZE=512 # CONFIG_NSH_CONSOLE=y # CONFIG_NSH_ALTCONDEV is not set -# CONFIG_NSH_ARCHINIT is not set +CONFIG_NSH_ARCHINIT=y # CONFIG_NSH_LOGIN is not set # CONFIG_NSH_CONSOLE_LOGIN is not set diff --git a/configs/nucleo-l476rg/src/nucleo-l476rg.h b/configs/nucleo-l476rg/src/nucleo-l476rg.h index b5b56eb5a0c..7f1ef0feef7 100644 --- a/configs/nucleo-l476rg/src/nucleo-l476rg.h +++ b/configs/nucleo-l476rg/src/nucleo-l476rg.h @@ -52,7 +52,15 @@ ************************************************************************************/ /* Configuration ********************************************************************/ +#define HAVE_RTC_DRIVER 1 #define HAVE_MMCSD 1 + +/* Check if we can support the RTC driver */ + +#if !defined(CONFIG_RTC) || !defined(CONFIG_RTC_DRIVER) +# undef HAVE_RTC_DRIVER +#endif + #if !defined(CONFIG_STM32_SDIO) || !defined(CONFIG_MMCSD) || \ !defined(CONFIG_MMCSD_SDIO) # undef HAVE_MMCSD diff --git a/configs/nucleo-l476rg/src/stm32_appinit.c b/configs/nucleo-l476rg/src/stm32_appinit.c index b7f5f1e6b4d..5a8b78513ab 100644 --- a/configs/nucleo-l476rg/src/stm32_appinit.c +++ b/configs/nucleo-l476rg/src/stm32_appinit.c @@ -55,6 +55,11 @@ #include "nucleo-l476rg.h" +#ifdef HAVE_RTC_DRIVER +# include +# include "stm32l4_rtc.h" +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -83,9 +88,12 @@ void up_netinitialize(void) int board_app_initialize(void) { -#if defined(HAVE_MMCSD) || defined(CONFIG_AJOYSTICK) - int ret; +#ifdef HAVE_RTC_DRIVER + FAR struct rtc_lowerhalf_s *rtclower; #endif + int ret; + + (void)ret; /* Configure CPU load estimation */ @@ -93,6 +101,30 @@ int board_app_initialize(void) cpuload_initialize_once(); #endif +#ifdef HAVE_RTC_DRIVER + /* Instantiate the STM32L4 lower-half RTC driver */ + + rtclower = stm32l4_rtc_lowerhalf(); + if (!rtclower) + { + sdbg("ERROR: Failed to instantiate the RTC lower-half driver\n"); + return -ENOMEM; + } + else + { + /* Bind the lower half driver and register the combined RTC driver + * as /dev/rtc0 + */ + + ret = rtc_initialize(0, rtclower); + if (ret < 0) + { + sdbg("ERROR: Failed to bind/register the RTC driver: %d\n", ret); + return ret; + } + } +#endif + #ifdef HAVE_MMCSD /* First, get an instance of the SDIO interface */ diff --git a/configs/stm32l476vg-disco/nsh/defconfig b/configs/stm32l476vg-disco/nsh/defconfig index 1ad001dd866..78242a4deb8 100644 --- a/configs/stm32l476vg-disco/nsh/defconfig +++ b/configs/stm32l476vg-disco/nsh/defconfig @@ -543,7 +543,8 @@ CONFIG_SPI_EXCHANGE=y # CONFIG_TIMER is not set CONFIG_RTC=y CONFIG_RTC_DATETIME=y -# CONFIG_RTC_ALARM is not set +CONFIG_RTC_ALARM=y +CONFIG_RTC_NALARMS=2 CONFIG_RTC_DRIVER=y CONFIG_RTC_IOCTL=y # CONFIG_RTC_EXTERNAL is not set @@ -834,6 +835,11 @@ CONFIG_BUILTIN_PROXY_STACKSIZE=1024 # # Examples # +CONFIG_EXAMPLES_ALARM=y +CONFIG_EXAMPLES_ALARM_PRIORITY=100 +CONFIG_EXAMPLES_ALARM_STACKSIZE=2048 +CONFIG_EXAMPLES_ALARM_DEVPATH="/dev/rtc0" +CONFIG_EXAMPLES_ALARM_SIGNO=1 CONFIG_EXAMPLES_BUTTONS=y CONFIG_EXAMPLES_BUTTONS_MIN=0 CONFIG_EXAMPLES_BUTTONS_MAX=4