STM32F7: add support for LSE RTC and enable RTC subseconds

This commit is contained in:
Jussi Kivilinna 2017-03-31 10:13:40 -06:00 committed by Gregory Nutt
parent 44f1326046
commit 41912ed98c
6 changed files with 143 additions and 33 deletions

View File

@ -1823,7 +1823,7 @@ config STM32F7_HAVE_RTC_COUNTER
config STM32F7_HAVE_RTC_SUBSECONDS
bool
default n
default y
config RTC_MAGIC_REG
int "The BKP register used to store/check the Magic value to determine if RTC is set already"

View File

@ -149,6 +149,10 @@ ifeq ($(filter y,$(CONFIG_STM32F7_IWDG) $(CONFIG_STM32F7_RTC_LSICLOCK)),y)
CHIP_CSRCS += stm32_lsi.c
endif
ifeq ($(CONFIG_STM32F7_RTC_LSECLOCK),y)
CHIP_CSRCS += stm32_lse.c
endif
ifeq ($(CONFIG_STM32F7_I2C),y)
CHIP_CSRCS += stm32_i2c.c
endif

View File

@ -129,7 +129,7 @@ static int stm32_exti_pvd_isr(int irq, void *context, void *arg)
****************************************************************************/
int stm32_exti_pvd(bool risingedge, bool fallingedge, bool event,
xcpt_t func, void *arg);
xcpt_t func, void *arg)
{
/* Get the previous GPIO IRQ handler; Save the new IRQ handler. */

View File

@ -0,0 +1,86 @@
/****************************************************************************
* arch/arm/src/stm32f7/stm32_lse.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Authors: Gregory Nutt <gnutt@nuttx.org>
* David Sidrane <david_s5@nscdg.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "up_arch.h"
#include "stm32_rcc.h"
#include "stm32_pwr.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_rcc_enablelse
*
* Description:
* Enable the External Low-Speed (LSE) oscillator.
*
****************************************************************************/
void stm32_rcc_enablelse(void)
{
uint32_t regval;
/* The LSE is in the RTC domain and write access is denied to this domain
* after reset, you have to enable write access using DBP bit in the PWR CR
* register before to configuring the LSE.
*/
stm32_pwr_enablebkp(true);
/* Enable the External Low-Speed (LSE) oscillator by setting the LSEON bit
* the RCC BDCR register.
*/
regval = getreg32(STM32_RCC_BDCR);
regval |= RCC_BDCR_LSEON;
putreg32(regval,STM32_RCC_BDCR);
/* Wait for the LSE clock to be ready */
while (((regval = getreg32(STM32_RCC_BDCR)) & RCC_BDCR_LSERDY) == 0);
/* Disable backup domain access if it was disabled on entry */
stm32_pwr_enablebkp(false);
}

View File

@ -1,5 +1,5 @@
/****************************************************************************
* arch/arm/src/stm32f/stm32_lsi.c
* arch/arm/src/stm32f7/stm32_lsi.c
*
* Copyright (C) 2012, 2015-2016 Gregory Nutt. All rights reserved.
* Authors: Gregory Nutt <gnutt@nuttx.org>

View File

@ -196,7 +196,7 @@ static void rtc_dumpregs(FAR const char *msg)
rtcinfo(" TSDR: %08x\n", getreg32(STM32_RTC_TSDR));
rtcinfo(" TSSSR: %08x\n", getreg32(STM32_RTC_TSSSR));
rtcinfo(" CALR: %08x\n", getreg32(STM32_RTC_CALR));
rtcinfo(" TAFCR: %08x\n", getreg32(STM32_RTC_TAFCR));
rtcinfo(" TAMPCR: %08x\n", getreg32(STM32_RTC_TAMPCR));
rtcinfo("ALRMASSR: %08x\n", getreg32(STM32_RTC_ALRMASSR));
rtcinfo("ALRMBSSR: %08x\n", getreg32(STM32_RTC_ALRMBSSR));
rtcinfo("MAGICREG: %08x\n", getreg32(RTC_MAGIC_REG));
@ -227,7 +227,8 @@ static void rtc_dumpregs(FAR const char *msg)
****************************************************************************/
#ifdef CONFIG_DEBUG_RTC_INFO
static void rtc_dumptime(FAR const struct tm *tp, FAR const char *msg)
static void rtc_dumptime(FAR const struct tm *tp, FAR const uint32_t *usecs,
FAR const char *msg)
{
rtcinfo("%s:\n", msg);
rtcinfo(" tm_sec: %08x\n", tp->tm_sec);
@ -236,9 +237,14 @@ static void rtc_dumptime(FAR const struct tm *tp, FAR const char *msg)
rtcinfo(" tm_mday: %08x\n", tp->tm_mday);
rtcinfo(" tm_mon: %08x\n", tp->tm_mon);
rtcinfo(" tm_year: %08x\n", tp->tm_year);
if (usecs != NULL)
{
rtcinfo(" usecs: %08x\n", (unsigned int)*usecs);
}
}
#else
# define rtc_dumptime(tp, msg)
# define rtc_dumptime(tp, usecs, msg)
#endif
/****************************************************************************
@ -1069,34 +1075,48 @@ int up_rtc_initialize(void)
*
****************************************************************************/
#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS
int stm32_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec)
#else
int up_rtc_getdatetime(FAR struct tm *tp)
#endif
{
#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
uint32_t ssr;
#endif
uint32_t dr;
uint32_t tr;
uint32_t tmp;
#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS
uint32_t ssr;
uint32_t prediv_s;
uint32_t usecs;
#endif
/* 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
{
dr = getreg32(STM32_RTC_DR);
tr = getreg32(STM32_RTC_TR);
#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
#ifdef CONFIG_STM32F7_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");
@ -1141,31 +1161,31 @@ int up_rtc_getdatetime(FAR struct tm *tp)
tp->tm_isdst = 0
#endif
#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS
/* Return RTC sub-seconds if no configured and if a non-NULL value
* of nsec has been provided to receive the sub-second value.
*/
if (nsec)
prediv_s = getreg32(STM32_RTC_PRER) & RTC_PRER_PREDIV_S_MASK;
prediv_s >>= RTC_PRER_PREDIV_S_SHIFT;
ssr &= RTC_SSR_MASK;
/* Maximum prediv_s is 0x7fff, thus we can multiply by 100000 and
* still fit 32-bit unsigned integer.
*/
usecs = (((prediv_s - ssr) * 100000) / (prediv_s + 1)) * 10;
if (nsec != NULL)
{
uint32_t prediv_s;
uint32_t usecs;
prediv_s = getreg32(STM32_RTC_PRER) & RTC_PRER_PREDIV_S_MASK;
prediv_s >>= RTC_PRER_PREDIV_S_SHIFT;
ssr &= RTC_SSR_MASK;
/* Maximum prediv_s is 0x7fff, thus we can multiply by 100000 and
* still fit 32-bit unsigned integer.
*/
usecs = (((prediv_s - ssr) * 100000) / (prediv_s + 1)) * 10;
*nsec = usecs * 1000;
}
#endif /* CONFIG_STM32_HAVE_RTC_SUBSECONDS */
rtc_dumptime((FAR const struct tm *)tp, "Returning");
rtc_dumptime((FAR const struct tm *)tp, &usecs, "Returning");
#else /* CONFIG_STM32_HAVE_RTC_SUBSECONDS */
rtc_dumptime((FAR const struct tm *)tp, NULL, "Returning");
#endif
return OK;
}
@ -1192,7 +1212,7 @@ int up_rtc_getdatetime(FAR struct tm *tp)
*
****************************************************************************/
#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS
#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS
int up_rtc_getdatetime(FAR struct tm *tp)
{
return stm32_rtc_getdatetime_with_subseconds(tp, NULL);
@ -1221,7 +1241,7 @@ int stm32_rtc_setdatetime(FAR const struct tm *tp)
uint32_t dr;
int ret;
rtc_dumptime(tp, "Setting time");
rtc_dumptime(tp, NULL, "Setting time");
/* Then write the broken out values to the RTC */
@ -1337,7 +1357,7 @@ int stm32_rtc_setalarm(FAR struct alm_setalarm_s *alminfo)
/* REVISIT: Should test that the time is in the future */
rtc_dumptime(&alminfo->as_time, "New alarm time");
rtc_dumptime(&alminfo->as_time, NULL, "New alarm time");
/* Break out the values to the HW alarm register format. The values in
* all STM32 fields match the fields of struct tm in this case. Notice