Merged in juniskane/nuttx_stm32l4/stm32l4_rtc_pm_fixes_pr (pull request #502)
STM32L4 RTC, PM: small fixes to subseconds handling, ADC power-management hooks * STM32L4 ADC: add PM hooks from Motorola MDK * STM32L4 RTC: add up_rtc_getdatetime_with_subseconds * STM32 RTC: workaround for potential subseconds race condition In all recent STM32 chips reading either RTC_SSR or RTC_TR is supposed to lock the values in the higher-order calendar shadow registers until RTC_DR is read. However many old chips have in their errata this silicon bug (at least F401xB/C, F42xx, F43xx, L15xxE, L15xVD and likely others): "When reading the calendar registers with BYPSHAD=0, the RTC_TR and RTC_DR registers may not be locked after reading the RTC_SSR register. This happens if the read operation is initiated one APB clock period before the shadow registers are updated. This can result in a non-consistency of the three registers. Similarly, RTC_DR register can be updated after reading the RTC_TR register instead of being locked." * STM32L4 RTC: correct RTC_SSR and RTC_TR read ordering In all recent STM32 chips reading either RTC_SSR or RTC_TR is supposed to lock the values in the higher-order calendar shadow registers until RTC_DR is read. Change the register read ordering to match this and don't keep a workaround for a hypothetical race condition (not in any L4 errata, lets for once assume ST's silicon works as it is documented...) * STM32L4 PM: remove useless #ifdefs and old non-L4 STM32 code Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
parent
5c4d45a331
commit
2997a49e51
@ -832,9 +832,12 @@ int up_rtc_getdatetime(FAR struct tm *tp)
|
||||
uint32_t tr;
|
||||
uint32_t tmp;
|
||||
|
||||
/* Sample the data time registers. There is a race condition here... If we sample
|
||||
* the time just before midnight on December 31, the date could be wrong because
|
||||
* the day rolled over while were sampling.
|
||||
/* Sample the data time registers. There is a race condition here... If
|
||||
* we sample the time just before midnight on December 31, the date could
|
||||
* be wrong because the day rolled over while were sampling. Thus loop for
|
||||
* checking overflow here is needed. There is a race condition with
|
||||
* subseconds too. If we sample TR register just before second rolling
|
||||
* and subseconds are read at wrong second, we get wrong time.
|
||||
*/
|
||||
|
||||
do
|
||||
@ -843,16 +846,24 @@ int up_rtc_getdatetime(FAR struct tm *tp)
|
||||
tr = getreg32(STM32_RTC_TR);
|
||||
#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
|
||||
ssr = getreg32(STM32_RTC_SSR);
|
||||
tmp = getreg32(STM32_RTC_TR);
|
||||
if (tmp != tr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
tmp = getreg32(STM32_RTC_DR);
|
||||
if (tmp == dr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (tmp != dr);
|
||||
while (1);
|
||||
|
||||
rtc_dumpregs("Reading Time");
|
||||
|
||||
/* Convert the RTC time to fields in struct tm format. All of the STM32
|
||||
* All of the ranges of values correspond between struct tm and the time
|
||||
* register.
|
||||
* ranges of values correspond between struct tm and the time register.
|
||||
*/
|
||||
|
||||
tmp = (tr & (RTC_TR_SU_MASK | RTC_TR_ST_MASK)) >> RTC_TR_SU_SHIFT;
|
||||
@ -887,7 +898,7 @@ int up_rtc_getdatetime(FAR struct tm *tp)
|
||||
tmp = (dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT;
|
||||
tp->tm_wday = tmp % 7;
|
||||
tp->tm_yday = tp->tm_mday + clock_daysbeforemonth(tp->tm_mon, clock_isleapyear(tp->tm_year + 1900));
|
||||
tp->tm_isdst = 0
|
||||
tp->tm_isdst = 0;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
|
||||
|
@ -770,8 +770,7 @@ static int rtchw_set_alrmar(rtc_alarmreg_t alarmreg)
|
||||
/* Set the RTC Alarm register */
|
||||
|
||||
putreg32(alarmreg, STM32_RTC_ALRMAR);
|
||||
rtcinfo(" TR: %08x ALRMAR: %08x\n",
|
||||
getreg32(STM32_RTC_TR), getreg32(STM32_RTC_ALRMAR));
|
||||
rtcinfo(" ALRMAR: %08x\n", getreg32(STM32_RTC_ALRMAR));
|
||||
|
||||
/* Enable RTC alarm */
|
||||
|
||||
@ -807,8 +806,7 @@ static int rtchw_set_alrmbr(rtc_alarmreg_t alarmreg)
|
||||
/* Set the RTC Alarm register */
|
||||
|
||||
putreg32(alarmreg, STM32_RTC_ALRMBR);
|
||||
rtcinfo(" TR: %08x ALRMBR: %08x\n",
|
||||
getreg32(STM32_RTC_TR), getreg32(STM32_RTC_ALRMBR));
|
||||
rtcinfo(" ALRMBR: %08x\n", getreg32(STM32_RTC_ALRMBR));
|
||||
|
||||
/* Enable RTC alarm B */
|
||||
|
||||
@ -1168,7 +1166,10 @@ int up_rtc_getdatetime(FAR struct tm *tp)
|
||||
|
||||
/* Sample the data time registers. There is a race condition here... If
|
||||
* we sample the time just before midnight on December 31, the date could
|
||||
* be wrong because the day rolled over while were sampling.
|
||||
* be wrong because the day rolled over while were sampling. Thus loop for
|
||||
* checking overflow here is needed. There is a race condition with
|
||||
* subseconds too. If we sample TR register just before second rolling
|
||||
* and subseconds are read at wrong second, we get wrong time.
|
||||
*/
|
||||
|
||||
do
|
||||
@ -1177,16 +1178,24 @@ int up_rtc_getdatetime(FAR struct tm *tp)
|
||||
tr = getreg32(STM32_RTC_TR);
|
||||
#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
|
||||
ssr = getreg32(STM32_RTC_SSR);
|
||||
tmp = getreg32(STM32_RTC_TR);
|
||||
if (tmp != tr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
tmp = getreg32(STM32_RTC_DR);
|
||||
if (tmp == dr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (tmp != dr);
|
||||
while (1);
|
||||
|
||||
rtc_dumpregs("Reading Time");
|
||||
|
||||
/* Convert the RTC time to fields in struct tm format. All of the STM32
|
||||
* All of the ranges of values correspond between struct tm and the time
|
||||
* register.
|
||||
* ranges of values correspond between struct tm and the time register.
|
||||
*/
|
||||
|
||||
tmp = (tr & (RTC_TR_SU_MASK | RTC_TR_ST_MASK)) >> RTC_TR_SU_SHIFT;
|
||||
@ -1221,7 +1230,7 @@ int up_rtc_getdatetime(FAR struct tm *tp)
|
||||
tmp = (dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT;
|
||||
tp->tm_wday = tmp % 7;
|
||||
tp->tm_yday = tp->tm_mday + clock_daysbeforemonth(tp->tm_mon, clock_isleapyear(tp->tm_year + 1900));
|
||||
tp->tm_isdst = 0
|
||||
tp->tm_isdst = 0;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
|
||||
|
@ -1405,6 +1405,11 @@ config ARCH_BOARD_STM32L4_CUSTOM_CLOCKCONFIG
|
||||
---help---
|
||||
Enables special, board-specific STM32 clock configuration.
|
||||
|
||||
config STM32L4_HAVE_RTC_SUBSECONDS
|
||||
bool
|
||||
select ARCH_HAVE_RTC_SUBSECONDS
|
||||
default y
|
||||
|
||||
choice
|
||||
prompt "RTC clock source"
|
||||
default STM32L4_RTC_LSECLOCK
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
#include <nuttx/power/pm.h>
|
||||
#include <nuttx/analog/adc.h>
|
||||
#include <nuttx/analog/ioctl.h>
|
||||
|
||||
@ -88,6 +89,12 @@
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef container_of
|
||||
# define container_of(ptr, type, member) \
|
||||
((type *)((intptr_t)(ptr) - offsetof(type, member)))
|
||||
#endif
|
||||
|
||||
/* RCC reset ****************************************************************/
|
||||
|
||||
#define STM32L4_RCC_RSTR STM32L4_RCC_AHB2RSTR
|
||||
@ -195,6 +202,10 @@ struct stm32_dev_s
|
||||
uint32_t freq; /* The desired frequency of conversions */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct pm_callback_s pm_callback;
|
||||
#endif
|
||||
|
||||
#ifdef ADC_HAVE_DMA
|
||||
DMA_HANDLE dma; /* Allocated DMA channel */
|
||||
|
||||
@ -258,6 +269,11 @@ static int adc_setoffset(FAR struct stm32_dev_s *priv, uint8_t ch, uint8_t i,
|
||||
|
||||
static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int adc_pm_prepare(struct pm_callback_s *cb, int domain,
|
||||
enum pm_state_e state);
|
||||
#endif
|
||||
|
||||
/* ADC Interrupt Handler */
|
||||
|
||||
static int adc_interrupt(FAR struct adc_dev_s *dev, uint32_t regval);
|
||||
@ -317,6 +333,12 @@ static struct stm32_dev_s g_adcpriv1 =
|
||||
#ifdef ADC1_HAVE_DFSDM
|
||||
.hasdfsdm = true,
|
||||
#endif
|
||||
#ifdef CONFIG_PM
|
||||
.pm_callback =
|
||||
{
|
||||
.prepare = adc_pm_prepare,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct adc_dev_s g_adcdev1 =
|
||||
@ -349,6 +371,12 @@ static struct stm32_dev_s g_adcpriv2 =
|
||||
#ifdef ADC2_HAVE_DFSDM
|
||||
.hasdfsdm = true,
|
||||
#endif
|
||||
#ifdef CONFIG_PM
|
||||
.pm_callback =
|
||||
{
|
||||
.prepare = adc_pm_prepare,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct adc_dev_s g_adcdev2 =
|
||||
@ -381,6 +409,12 @@ static struct stm32_dev_s g_adcpriv3 =
|
||||
#ifdef ADC3_HAVE_DFSDM
|
||||
.hasdfsdm = true,
|
||||
#endif
|
||||
#ifdef CONFIG_PM
|
||||
.pm_callback =
|
||||
{
|
||||
.prepare = adc_pm_prepare,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct adc_dev_s g_adcdev3 =
|
||||
@ -974,6 +1008,32 @@ static int adc_timinit(FAR struct stm32_dev_s *priv)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc_pm_prepare
|
||||
*
|
||||
* Description:
|
||||
* Called by power management framework when it wants to enter low power
|
||||
* states. Check if ADC is in progress and if so prevent from entering STOP.
|
||||
*
|
||||
****************************************************************************/
|
||||
#if CONFIG_PM
|
||||
static int adc_pm_prepare(struct pm_callback_s *cb, int domain,
|
||||
enum pm_state_e state)
|
||||
{
|
||||
FAR struct stm32_dev_s *priv =
|
||||
container_of(cb, struct stm32_dev_s, pm_callback);
|
||||
uint32_t regval;
|
||||
|
||||
regval = adc_getreg(priv, STM32L4_ADC_CR_OFFSET);
|
||||
if ((state >= PM_IDLE) && (regval & ADC_CR_ADSTART))
|
||||
{
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc_wdog_enable
|
||||
*
|
||||
@ -1962,6 +2022,14 @@ struct adc_dev_s *stm32l4_adc_initialize(int intf, FAR const uint8_t *chanlist,
|
||||
priv->cchannels = cchannels;
|
||||
memcpy(priv->chanlist, chanlist, cchannels);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (pm_register(&priv->pm_callback) != OK)
|
||||
{
|
||||
aerr("Power management registration failed\n");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
@ -97,10 +97,7 @@ int stm32l4_pmstop(bool lpds);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_STM32L4_STM32L4X3) || defined(CONFIG_STM32L4_STM32L4X5) || \
|
||||
defined(CONFIG_STM32L4_STM32L4X6)
|
||||
int stm32l4_pmstop2(void);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32l4_pmstandby
|
||||
@ -159,10 +156,7 @@ void stm32l4_pmsleep(bool sleeponexit);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_STM32L4_STM32L4X3) || defined(CONFIG_STM32L4_STM32L4X5) || \
|
||||
defined(CONFIG_STM32L4_STM32L4X6)
|
||||
int stm32l4_pmlpr(void);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
|
@ -48,9 +48,6 @@
|
||||
#include "stm32l4_pm.h"
|
||||
#include "stm32l4_rcc.h"
|
||||
|
||||
#if defined(CONFIG_STM32L4_STM32L4X3) || defined(CONFIG_STM32L4_STM32L4X5) || \
|
||||
defined(CONFIG_STM32L4_STM32L4X6)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -108,5 +105,3 @@ int stm32l4_pmlpr(void)
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_STM32L4_STM32L4X3 || CONFIG_STM32L4_STM32L4X5 || CONFIG_STM32L4_STM32L4X6 */
|
||||
|
@ -72,8 +72,6 @@ int stm32l4_pmstandby(void)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
#if defined(CONFIG_STM32L4_STM32L4X3) || defined(CONFIG_STM32L4_STM32L4X5) || \
|
||||
defined(CONFIG_STM32L4_STM32L4X6)
|
||||
/* Clear the Wake-Up Flags by setting the CWUFx bits in the power status
|
||||
* clear register
|
||||
*/
|
||||
@ -82,25 +80,12 @@ int stm32l4_pmstandby(void)
|
||||
putreg32(regval, STM32L4_PWR_SCR);
|
||||
|
||||
/* Select Standby mode */
|
||||
|
||||
regval = getreg32(STM32L4_PWR_CR1);
|
||||
regval &= ~PWR_CR1_LPMS_MASK;
|
||||
regval |= PWR_CR1_LPMS_STANDBY;
|
||||
|
||||
putreg32(regval, STM32L4_PWR_CR1);
|
||||
#else
|
||||
/* Clear the Wake-Up Flag by setting the CWUF bit in the power control
|
||||
* register.
|
||||
*/
|
||||
|
||||
regval = getreg32(STM32L4_PWR_CR);
|
||||
regval |= PWR_CR_CWUF;
|
||||
putreg32(regval, STM32L4_PWR_CR);
|
||||
|
||||
/* Set the Power Down Deep Sleep (PDDS) bit in the power control register. */
|
||||
|
||||
regval |= PWR_CR_PDDS;
|
||||
putreg32(regval, STM32L4_PWR_CR);
|
||||
#endif
|
||||
|
||||
/* Set SLEEPDEEP bit of Cortex System Control Register */
|
||||
|
||||
|
@ -109,38 +109,19 @@ int stm32l4_pmstop(bool lpds)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
#if defined(CONFIG_STM32L4_STM32L4X3) || defined(CONFIG_STM32L4_STM32L4X5) || \
|
||||
defined(CONFIG_STM32L4_STM32L4X6)
|
||||
/* Clear Low-Power Mode Selection (LPMS) bits in power control register 1. */
|
||||
|
||||
regval = getreg32(STM32L4_PWR_CR1);
|
||||
regval &= ~PWR_CR1_LPMS_MASK;
|
||||
|
||||
/* Select Stop 1 mode with low-power regulator if so requested */
|
||||
|
||||
if (lpds)
|
||||
{
|
||||
regval |= PWR_CR1_LPMS_STOP1LPR;
|
||||
}
|
||||
|
||||
putreg32(regval, STM32L4_PWR_CR1);
|
||||
#else
|
||||
/* Clear the Power Down Deep Sleep (PDDS), Low Power Deep Sleep (LPDS), and
|
||||
* Low Power regulator Low Voltage in Deep Sleep (LPLVDS) bits in the power
|
||||
* control register.
|
||||
*/
|
||||
|
||||
regval = getreg32(STM32L4_PWR_CR);
|
||||
regval &= ~(PWR_CR_LPDS | PWR_CR_PDDS | PWR_CR_LPLVDS);
|
||||
|
||||
/* Set the Low Power Deep Sleep (LPDS) and Low Power regulator Low Voltage
|
||||
* in Deep Sleep (LPLVDS) bits if so requested */
|
||||
|
||||
if (lpds)
|
||||
{
|
||||
regval |= PWR_CR_LPDS | PWR_CR_LPLVDS;
|
||||
}
|
||||
|
||||
putreg32(regval, STM32L4_PWR_CR);
|
||||
#endif
|
||||
|
||||
return do_stop();
|
||||
}
|
||||
@ -161,8 +142,6 @@ int stm32l4_pmstop(bool lpds)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_STM32L4_STM32L4X3) || defined(CONFIG_STM32L4_STM32L4X5) || \
|
||||
defined(CONFIG_STM32L4_STM32L4X6)
|
||||
int stm32l4_pmstop2(void)
|
||||
{
|
||||
uint32_t regval;
|
||||
@ -176,4 +155,3 @@ int stm32l4_pmstop2(void)
|
||||
|
||||
return do_stop();
|
||||
}
|
||||
#endif
|
||||
|
@ -43,12 +43,12 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sched.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/time.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
@ -717,8 +717,7 @@ static int rtchw_set_alrmar(rtc_alarmreg_t alarmreg)
|
||||
|
||||
putreg32(alarmreg, STM32L4_RTC_ALRMAR);
|
||||
putreg32(0, STM32L4_RTC_ALRMASSR);
|
||||
rtcinfo(" TR: %08x ALRMAR: %08x\n",
|
||||
getreg32(STM32L4_RTC_TR), getreg32(STM32L4_RTC_ALRMAR));
|
||||
rtcinfo(" ALRMAR: %08x\n", getreg32(STM32L4_RTC_ALRMAR));
|
||||
|
||||
/* Enable RTC alarm A */
|
||||
|
||||
@ -763,8 +762,7 @@ static int rtchw_set_alrmbr(rtc_alarmreg_t alarmreg)
|
||||
|
||||
putreg32(alarmreg, STM32L4_RTC_ALRMBR);
|
||||
putreg32(0, STM32L4_RTC_ALRMBSSR);
|
||||
rtcinfo(" TR: %08x ALRMBR: %08x\n",
|
||||
getreg32(STM32L4_RTC_TR), getreg32(STM32L4_RTC_ALRMBR));
|
||||
rtcinfo(" ALRMBR: %08x\n", getreg32(STM32L4_RTC_ALRMBR));
|
||||
|
||||
/* Enable RTC alarm B */
|
||||
|
||||
@ -1092,30 +1090,25 @@ int stm32_rtc_irqinitialize(void)
|
||||
|
||||
int stm32l4_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec)
|
||||
{
|
||||
#ifdef CONFIG_STM32L4_HAVE_RTC_SUBSECONDS
|
||||
uint32_t ssr;
|
||||
#endif
|
||||
uint32_t dr;
|
||||
uint32_t tr;
|
||||
uint32_t tmp;
|
||||
|
||||
/* Sample the data time registers. There is a race condition here... If we sample
|
||||
* the time just before midnight on December 31, the date could be wrong because
|
||||
* the day rolled over while were sampling.
|
||||
*/
|
||||
/* Sample the date time registers. Must read in this order. */
|
||||
|
||||
do
|
||||
{
|
||||
dr = getreg32(STM32L4_RTC_DR);
|
||||
tr = getreg32(STM32L4_RTC_TR);
|
||||
ssr = getreg32(STM32L4_RTC_SSR);
|
||||
tmp = getreg32(STM32L4_RTC_DR);
|
||||
}
|
||||
while (tmp != dr);
|
||||
#ifdef CONFIG_STM32L4_HAVE_RTC_SUBSECONDS
|
||||
ssr = getreg32(STM32L4_RTC_SSR);
|
||||
#endif
|
||||
tr = getreg32(STM32L4_RTC_TR);
|
||||
dr = getreg32(STM32L4_RTC_DR);
|
||||
|
||||
rtc_dumpregs("Reading Time");
|
||||
|
||||
/* Convert the RTC time to fields in struct tm format. All of the STM32
|
||||
* All of the ranges of values correspond between struct tm and the time
|
||||
* register.
|
||||
/* Convert the RTC time to fields in struct tm format. All of the STM32
|
||||
* ranges of values correspond between struct tm and the time register.
|
||||
*/
|
||||
|
||||
tmp = (tr & (RTC_TR_SU_MASK | RTC_TR_ST_MASK)) >> RTC_TR_SU_SHIFT;
|
||||
@ -1150,13 +1143,14 @@ int stm32l4_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec)
|
||||
tmp = (dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT;
|
||||
tp->tm_wday = tmp % 7;
|
||||
tp->tm_yday = tp->tm_mday + clock_daysbeforemonth(tp->tm_mon, clock_isleapyear(tp->tm_year + 1900));
|
||||
tp->tm_isdst = 0
|
||||
tp->tm_isdst = 0;
|
||||
#endif
|
||||
|
||||
/* Return RTC sub-seconds if a non-NULL value
|
||||
* of nsec has been provided to receive the sub-second value.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STM32L4_HAVE_RTC_SUBSECONDS
|
||||
if (nsec)
|
||||
{
|
||||
uint32_t prediv_s;
|
||||
@ -1174,6 +1168,9 @@ int stm32l4_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec)
|
||||
usecs = (((prediv_s - ssr) * 100000) / (prediv_s + 1)) * 10;
|
||||
*nsec = usecs * 1000;
|
||||
}
|
||||
#else
|
||||
DEBUGASSERT(nsec == NULL);
|
||||
#endif
|
||||
|
||||
rtc_dumptime(tp, "Returning");
|
||||
return OK;
|
||||
@ -1207,6 +1204,40 @@ int up_rtc_getdatetime(FAR struct tm *tp)
|
||||
return stm32l4_rtc_getdatetime_with_subseconds(tp, NULL);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: up_rtc_getdatetime_with_subseconds
|
||||
*
|
||||
* Description:
|
||||
* Get the current date and time from the date/time RTC. This interface
|
||||
* is only supported by the date/time RTC hardware implementation.
|
||||
* It is used to replace the system timer. It is only used by the RTOS during
|
||||
* initialization to set up the system time when CONFIG_RTC and CONFIG_RTC_DATETIME
|
||||
* are selected (and CONFIG_RTC_HIRES is not).
|
||||
*
|
||||
* NOTE: This interface exposes sub-second accuracy capability of RTC hardware.
|
||||
* This interface allow maintaining timing accuracy when system time needs constant
|
||||
* resynchronization with RTC, for example with board level power-save mode utilizing
|
||||
* deep-sleep modes such as STOP on STM32 MCUs.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - The location to return the high resolution time value.
|
||||
* nsec - The location to return the subsecond time value.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ARCH_HAVE_RTC_SUBSECONDS
|
||||
# ifndef CONFIG_STM32L4_HAVE_RTC_SUBSECONDS
|
||||
# error "Invalid config, enable CONFIG_STM32L4_HAVE_RTC_SUBSECONDS."
|
||||
# endif
|
||||
int up_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec)
|
||||
{
|
||||
return stm32l4_rtc_getdatetime_with_subseconds(tp, nsec);
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Name: stm32l4_rtc_setdatetime
|
||||
*
|
||||
@ -1300,7 +1331,7 @@ int stm32l4_rtc_setdatetime(FAR const struct tm *tp)
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: stm32l4_rtc_setdatetime
|
||||
* Name: stm32l4_rtc_havesettime
|
||||
*
|
||||
* Description:
|
||||
* Check if RTC time has been set.
|
||||
|
Loading…
x
Reference in New Issue
Block a user