diff --git a/arch/arm/src/stm32/stm32_rtc_lowerhalf.c b/arch/arm/src/stm32/stm32_rtc_lowerhalf.c index ec2ddd6f98..90eb345d06 100644 --- a/arch/arm/src/stm32/stm32_rtc_lowerhalf.c +++ b/arch/arm/src/stm32/stm32_rtc_lowerhalf.c @@ -203,7 +203,7 @@ static void stm32_alarm_callback(FAR void *arg, unsigned int alarmid) #else static void stm32_alarm_callback(void) { - struct stm32_cbinfo_s *cbinfo = &g_rtc_lowerhalf.cbinfo[0]; + FAR struct stm32_cbinfo_s *cbinfo = &g_rtc_lowerhalf.cbinfo[0]; /* Sample and clear the callback information to minimize the window in * time in which race conditions can occur. @@ -462,48 +462,128 @@ static int stm32_setrelative(FAR struct rtc_lowerhalf_s *lower, FAR const struct lower_setrelative_s *alarminfo) { #ifdef CONFIG_STM32_STM32F40XX - FAR struct stm32_lowerhalf_s *priv; - struct alm_setrelative_s lowerinfo; - struct stm32_cbinfo_s *cbinfo; + struct lower_setalarm_s setalarm; + struct tm time; + time_t seconds; int ret = -EINVAL; - /* ID0-> Alarm A; ID1 -> Alarm B */ - - DEBUGASSERT(lower != NULL && alarminfo != NULL); + ASSERT(lower != NULL && alarminfo != NULL); DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB); - priv = (FAR struct stm32_lowerhalf_s *)lower; - if (alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) + if ((alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) && + alarminfo->reltime > 0) { - /* Remember the callback information */ + /* Disable pre-emption while we do this so that we don't have to worry + * about being suspended and working on an old time. + */ - cbinfo = &priv->cbinfo[alarminfo->id]; - cbinfo->cb = alarminfo->cb; - cbinfo->priv = alarminfo->priv; - cbinfo->id = alarminfo->id; + sched_lock(); - /* Set the alarm */ + /* Get the current time in broken out format */ - lowerinfo.asr_id = alarminfo->id; - lowerinfo.asr_minutes = alarminfo->reltime / 60; - lowerinfo.asr_cb = stm32_alarm_callback; - lowerinfo.asr_arg = priv; - - /* And set the alarm */ - - ret = stm32_rtc_setalarm_rel(&lowerinfo); - if (ret < 0) + ret = up_rtc_getdatetime(&time); + if (ret >= 0) { - cbinfo->cb = NULL; - cbinfo->priv = NULL; + /* Convert to seconds since the epoch */ + + seconds = mktime(&time); + + /* Add the seconds offset */ + + seconds += alarminfo->reltime; + + /* 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 = stm32_setalarm(lower, &setalarm); } + + sched_unlock(); } return ret; #else -# warning Missing logic - return -ENOSYS; + FAR struct stm32_lowerhalf_s *priv; + FAR struct stm32_cbinfo_s *cbinfo; +#if defined(CONFIG_RTC_DATETIME) + struct tm time; +#endif + FAR struct timespec ts; + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0); + priv = (FAR struct stm32_lowerhalf_s *)lower; + + if (alarminfo->id == 0 && alarminfo->reltime > 0) + { + /* Disable pre-emption 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 seconds */ + +#if defined(CONFIG_RTC_DATETIME) + /* Get the broken out time and convert to seconds */ + + ret = up_rtc_getdatetime(&time); + if (ret < 0) + { + sched_unlock(); + return ret; + } + + ts.tv_sec = mktime(&time); + ts.tv_nsec = 0; + +#elif defined(CONFIG_RTC_HIRES) + /* Get the higher resolution time */ + + ret = up_rtc_gettime(&ts); + if (ret < 0) + { + sched_unlock(); + return ret; + } +#else + /* The resolution of time is only 1 second */ + + ts.tv_sec = up_rtc_time(); + ts.tv_nsec = 0; +#endif + + /* Add the seconds offset */ + + ts.tv_sec += alarminfo->reltime; + + /* Remember the callback information */ + + cbinfo = &priv->cbinfo[0]; + cbinfo->cb = alarminfo->cb; + cbinfo->priv = alarminfo->priv; + + /* And set the alarm */ + + ret = stm32_rtc_setalarm(&ts, stm32_alarm_callback); + if (ret < 0) + { + cbinfo->cb = NULL; + cbinfo->priv = NULL; + } + + sched_unlock(); + } + + return ret; #endif } #endif diff --git a/arch/arm/src/stm32/stm32f40xxx_alarm.h b/arch/arm/src/stm32/stm32f40xxx_alarm.h index af45665268..bd58643844 100644 --- a/arch/arm/src/stm32/stm32f40xxx_alarm.h +++ b/arch/arm/src/stm32/stm32f40xxx_alarm.h @@ -41,6 +41,7 @@ ****************************************************************************/ #include +#include #ifdef CONFIG_RTC_ALARM @@ -62,9 +63,8 @@ enum alm_id_e RTC_ALARM_LAST }; -/* Structure used to pass parmaters to set a absolute alarm */ +/* Structure used to pass parmaters to set an alarm */ -struct tm; /* Forward reference */ struct alm_setalarm_s { int as_id; /* enum alm_id_e */ @@ -73,18 +73,6 @@ struct alm_setalarm_s FAR void *as_arg; /* Argument for callback */ }; -/* Structure used to pass parmaters to set an alaram relative to the - * current time. - */ - -struct alm_setrelative_s -{ - int asr_id; /* enum alm_id_e */ - int asr_minutes; /* Relative time in minutes */ - alm_callback_t asr_cb; /* Callback (if non-NULL) */ - FAR void *asr_arg; /* Argument for callback */ -}; - /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -103,23 +91,7 @@ struct alm_setrelative_s * ****************************************************************************/ -int stm32_rtc_setalarm(struct alm_setalarm_s *alminfo); - -/**************************************************************************** - * Name: stm32_rtc_setalarm_rel - * - * Description: - * Set a relative alarm in minutes using associated hardware. - * - * Input Parameters: - * alminfo - Information about the relative alarm configuration. - * - * Returned Value: - * Zero (OK) on success; a negated errno on failure - * - ****************************************************************************/ - -int stm32_rtc_setalarm_rel(struct alm_setrelative_s *alminfo); +int stm32_rtc_setalarm(FAR struct alm_setalarm_s *alminfo); #endif /* CONFIG_RTC_ALARM */ #endif /* __ARCH_ARM_SRC_STM32_STM32F40XXX_ALARM_H */ diff --git a/arch/arm/src/stm32/stm32f40xxx_rtcc.c b/arch/arm/src/stm32/stm32f40xxx_rtcc.c index cef9085217..4ef236b34d 100644 --- a/arch/arm/src/stm32/stm32f40xxx_rtcc.c +++ b/arch/arm/src/stm32/stm32f40xxx_rtcc.c @@ -39,6 +39,7 @@ ************************************************************************************/ #include +#include #include #include #include @@ -135,13 +136,10 @@ time->tm_hour = (parm_hrs - HOURS_IN_DAY);\ } -#define THRESHOLD_SECS 57 - #define RTC_ALRMR_DIS_MASK (RTC_ALRMR_MSK4 | RTC_ALRMR_MSK3 | \ RTC_ALRMR_MSK2 | RTC_ALRMR_MSK1) -#define RTC_ALRMR_DIS_DATE_HOURS_MASK (RTC_ALRMR_MSK4 | RTC_ALRMR_MSK3) #define RTC_ALRMR_DIS_DATE_MASK (RTC_ALRMR_MSK4) -#define ALARMAR_TIME_EN (RTC_ALRMR_MSK4 | RTC_ALRMR_WDSEL) +#define RTC_ALRMR_ENABLE (0) /* Debug ****************************************************************************/ @@ -852,88 +850,6 @@ rtchw_set_alrmbr_exit: } #endif -/************************************************************************************ - * Name: stm32_offset_time - * - * Description: - * Set up an alarm. Up to two alarms can be supported (ALARM A and ALARM B). - * - * Input Parameters: - * time - The location to return the offset time - * - * Returned Value: - * Zero (OK) on success; a negated errno on failure - * - ************************************************************************************/ - -#ifdef CONFIG_RTC_ALARM -static int stm32_offset_time(struct tm *time, unsigned int min) -{ - /* This sets it accurately to alarm on every 10min 0sec */ - - uint32_t timereg; - uint32_t hour; - uint32_t tmp1; - uint32_t tmp2; - int ret = OK; - - /* Error checking */ - - if (MAX_RTC_ALARM_REL_MINUTES < min) - { - rtcvdbg("error min too large %d\n", min); - ret = -EINVAL; - goto errout; - } - - /* Current Time - bcd format */ - - timereg = getreg32(STM32_RTC_TR); - - /* Convert the RTC BCD to accessible form of tm - * Check if the seconds is close to the next minute - * which could result in setting a time that has already passed - * and if so go to the next minute - */ - - tmp1 = (timereg & (RTC_TR_SU_MASK | RTC_TR_ST_MASK)) >> RTC_TR_SU_SHIFT; - time->tm_sec = rtc_bcd2bin(tmp1); - if (THRESHOLD_SECS < time->tm_sec) - { - rtcvdbg("compensate for being close to the next minute %d\n", time->tm_sec); - min++; - } - - time->tm_sec = 0; - tmp1 = (timereg & (RTC_ALRMR_MNU_MASK | RTC_ALRMR_MNT_MASK)) >> RTC_ALRMR_MNU_SHIFT; - time->tm_min = rtc_bcd2bin(tmp1); - - tmp2 = (timereg & (RTC_ALRMR_HU_MASK | RTC_ALRMR_HT_MASK)) >> RTC_ALRMR_HU_SHIFT; - time->tm_hour = rtc_bcd2bin(tmp2); - - /* Add next alarm time - * Update for next alarm in 1-MAX_RTC_ALARM_REL_MINUTES - */ - - hour = min / MINUTES_IN_HOUR; - if (0 < hour) - { - hours_add(hour); - min -= hour * MINUTES_IN_HOUR; - } - - time->tm_min += min; - if ((time->tm_min) > MINUTES_IN_HOUR - 1) - { - time->tm_min = 0; - hours_add(1); - } - -errout: - return ret; -} -#endif - /************************************************************************************ * Public Functions ************************************************************************************/ @@ -1430,7 +1346,7 @@ int up_rtc_settime(FAR const struct timespec *tp) ****************************************************************************/ #ifdef CONFIG_RTC_ALARM -int stm32_rtc_setalarm(struct alm_setalarm_s *alminfo) +int stm32_rtc_setalarm(FAR struct alm_setalarm_s *alminfo) { FAR struct alm_cbinfo_s *cbinfo; rtc_alarmreg_t alarmreg; @@ -1457,7 +1373,7 @@ int stm32_rtc_setalarm(struct alm_setalarm_s *alminfo) cbinfo->ac_cb = alminfo->as_cb; cbinfo->ac_arg = alminfo->as_arg; - ret = rtchw_set_alrmar(alarmreg | ALARMAR_TIME_EN); + ret = rtchw_set_alrmar(alarmreg | RTC_ALRMR_ENABLE); if (ret < 0) { cbinfo->ac_cb = NULL; @@ -1472,7 +1388,7 @@ int stm32_rtc_setalarm(struct alm_setalarm_s *alminfo) cbinfo->ac_cb = alminfo->as_cb; cbinfo->ac_arg = alminfo->as_arg; - ret = rtchw_set_alrmbr(alarmreg | ALARMAR_TIME_EN); + ret = rtchw_set_alrmbr(alarmreg | RTC_ALRMR_ENABLE); if (ret < 0) { cbinfo->ac_cb = NULL; @@ -1490,84 +1406,4 @@ int stm32_rtc_setalarm(struct alm_setalarm_s *alminfo) } #endif -/**************************************************************************** - * Name: stm32_rtc_setalarm_rel - * - * Description: - * Set a relative alarm in minutes using associated hardware. - * - * Input Parameters: - * alminfo - Information about the relative alarm configuration. - * - * Returned Value: - * Zero (OK) on success; a negated errno on failure - * - ****************************************************************************/ - -#ifdef CONFIG_RTC_ALARM -int stm32_rtc_setalarm_rel(struct alm_setrelative_s *alminfo) -{ - FAR struct alm_cbinfo_s *cbinfo; - rtc_alarmreg_t alarmreg; - struct tm time; - int ret = -EINVAL; - - ASSERT(alminfo != NULL); - DEBUGASSERT(RTC_ALARM_LAST > alminfo->asr_id); - - switch (alminfo->asr_id) - { - case RTC_ALARMA: - case RTC_ALARMB: - ret = stm32_offset_time(&time, alminfo->asr_minutes); - break; - - default: - rtcvdbg("error unknown %d\n", alminfo->asr_id); - break; - } - - if (OK == ret) - { - rtc_dumptime(&time, "New alarm time"); - alarmreg = rtc_reg_alrmr_bin2bcd(&time); - - switch (alminfo->asr_id) - { - case RTC_ALARMA: - { - cbinfo = &g_alarmcb[RTC_ALARMA]; - cbinfo->ac_cb = alminfo->asr_cb; - cbinfo->ac_arg = alminfo->asr_arg; - - ret = rtchw_set_alrmar(alarmreg | RTC_ALRMR_DIS_DATE_MASK); - if (ret >= 0) - { - cbinfo->ac_cb = NULL; - cbinfo->ac_arg = NULL; - } - } - break; - - case RTC_ALARMB: - { - cbinfo = &g_alarmcb[RTC_ALARMA]; - cbinfo->ac_cb = alminfo->asr_cb; - cbinfo->ac_arg = alminfo->asr_arg; - - ret = rtchw_set_alrmbr(alarmreg | RTC_ALRMR_DIS_DATE_MASK); - if (ret >= 0) - { - cbinfo->ac_cb = NULL; - cbinfo->ac_arg = NULL; - } - } - break; - } - } - - return ret; -} -#endif - #endif /* CONFIG_RTC */