STMF7xxx RTC

Remove proxy #defines
 Ensure the LSE(ON) etal are set and remembered in
  a) A cold start (RTC_MAGIC invalid) of the RTC
  b) A warm start (RTC_MAGIC valid) of the RTC but a clock change.

The change was needed because in bench testing a merge of the latest's STM32  53ec3ca (and friends) it became apparent that the
Sequence of operation is wrong in the reset of the Backup Domain in the RCC code.  PWR is required before the Backup Domain
can be futzed with. !!!This Code should be tested on STM32 and if needed rippled to the STM32 families
This commit is contained in:
David Sidrane 2016-06-28 12:13:27 -10:00
parent e5ca333246
commit 0af47a93ae
3 changed files with 161 additions and 44 deletions

View File

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

View File

@ -0,0 +1,101 @@
/****************************************************************************
* arch/arm/src/stm32f/stm32_lsi.c
*
* Copyright (C) 2012, 2015-2016 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"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_rcc_enablelsi
*
* Description:
* Enable the Internal Low-Speed (LSI) RC Oscillator.
*
****************************************************************************/
void stm32_rcc_enablelsi(void)
{
/* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION bit
* the RCC CSR register.
*/
modifyreg32(STM32_RCC_CSR, 0, RCC_CSR_LSION);
/* Wait for the internal RC 40 kHz oscillator to be stable. */
while ((getreg32(STM32_RCC_CSR) & RCC_CSR_LSIRDY) == 0);
}
/****************************************************************************
* Name: stm32_rcc_disablelsi
*
* Description:
* Disable the Internal Low-Speed (LSI) RC Oscillator.
*
****************************************************************************/
void stm32_rcc_disablelsi(void)
{
/* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION bit
* the RCC CSR register.
*/
modifyreg32(STM32_RCC_CSR, RCC_CSR_LSION, 0);
/* LSIRDY should go low after 3 LSI clock cycles */
}

View File

@ -84,19 +84,19 @@
/* Constants ************************************************************************/ /* Constants ************************************************************************/
#if defined(CONFIG_STM32F7_RTC_HSECLOCK)
# define RCC_BDCR_RTCSEL RCC_BDCR_RTCSEL_HSE
#elif defined(CONFIG_STM32F7_RTC_LSICLOCK)
# define RCC_BDCR_RTCSEL RCC_BDCR_RTCSEL_LSI
#elif defined(CONFIG_STM32F7_RTC_LSECLOCK)
# define RCC_BDCR_RTCSEL RCC_BDCR_RTCSEL_LSE
#else
# warning "RCC_BDCR_RTCSEL_NOCLK has been selected - RTC will not count"
#endif
#define SYNCHRO_TIMEOUT (0x00020000) #define SYNCHRO_TIMEOUT (0x00020000)
#define INITMODE_TIMEOUT (0x00010000) #define INITMODE_TIMEOUT (0x00010000)
/* Proxy definitions to make the same code work for all the STM32 series ************/
# define STM32_RCC_XXX STM32_RCC_BDCR
# define RCC_XXX_YYYRST RCC_BDCR_BDRST
# define RCC_XXX_RTCEN RCC_BDCR_RTCEN
# define RCC_XXX_RTCSEL_MASK RCC_BDCR_RTCSEL_MASK
# define RCC_XXX_RTCSEL_LSE RCC_BDCR_RTCSEL_LSE
# define RCC_XXX_RTCSEL_LSI RCC_BDCR_RTCSEL_LSI
# define RCC_XXX_RTCSEL_HSE RCC_BDCR_RTCSEL_HSE
/* Time conversions */ /* Time conversions */
#define MINUTES_IN_HOUR 60 #define MINUTES_IN_HOUR 60
@ -844,7 +844,7 @@ int up_rtc_initialize(void)
int nretry = 0; int nretry = 0;
/* Clocking for the PWR block must be provided. However, this is done /* Clocking for the PWR block must be provided. However, this is done
* unconditionally in stm32f40xxx_rcc.c on power up. This done unconditionally * unconditionally in stm32f7xxx_rcc.c on power up. This done unconditionally
* because the PWR block is also needed to set the internal voltage regulator for * because the PWR block is also needed to set the internal voltage regulator for
* maximum performance. * maximum performance.
*/ */
@ -858,79 +858,91 @@ int up_rtc_initialize(void)
if (regval != RTC_MAGIC) if (regval != RTC_MAGIC)
{ {
/* 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 /* Issue the Backup domain Reset Per Section 5.3.20 DocID028270 Rev 2
* rate clock * The LSEON, LSEBYP, RTCSEL and RTCEN bits in the RCC backup domain control
* register (RCC_BDCR) are in the Backup domain. As a result, after Reset,
* these bits are write-protected and the DBP bit in the PWR power control
* register (PWR_CR1) has to be set before these can be modified.
* Refer to Section 5.1.1: System reset on page 148 for further information.
* These bits are only reset after a Backup domain Reset
* (see Section 5.1.3: Backup domain reset).
*
* This has to be done here so that PWR is already enabled
*/ */
modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_BDRST);
modifyreg32(STM32_RCC_BDCR, RCC_BDCR_BDRST, 0);
#if RCC_BDCR_RTCSEL == RCC_BDCR_RTCSEL_LSE
/* Because of the Backup domain Reset - we must re enable the LSE */
stm32_rcc_enablelse();
#endif
/* 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_STM32F7_RTC_HSECLOCK #ifdef CONFIG_STM32F7_RTC_HSECLOCK
/* Use the HSE clock as the input to the RTC block */ /* Use the HSE clock as the input to the RTC block */
rtc_dumpregs("On reset HSE"); rtc_dumpregs("On reset HSE");
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_HSE);
#elif defined(CONFIG_STM32F7_RTC_LSICLOCK) #elif defined(CONFIG_STM32F7_RTC_LSICLOCK)
/* Use the LSI clock as the input to the RTC block */ /* Use the LSI clock as the input to the RTC block */
rtc_dumpregs("On reset LSI"); rtc_dumpregs("On reset LSI");
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSI);
#elif defined(CONFIG_STM32F7_RTC_LSECLOCK) #elif defined(CONFIG_STM32F7_RTC_LSECLOCK)
/* Use the LSE clock as the input to the RTC block */ /* Use the LSE clock as the input to the RTC block */
rtc_dumpregs("On reset LSE"); rtc_dumpregs("On reset LSE");
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSE);
#endif #endif
modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL);
/* Enable the RTC Clock by setting the RTCEN bit in the RCC register */ /* Enable the RTC Clock by setting the RTCEN bit in the RCC register */
modifyreg32(STM32_RCC_XXX, 0, RCC_XXX_RTCEN); modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_RTCEN);
} }
else /* The RTC is already in use: check if the clock source is changed */ else
{ {
#if defined(CONFIG_STM32F7_RTC_HSECLOCK) || defined(CONFIG_RTC_LSICLOCK) || \ uint32_t clksrc = getreg32(STM32_RCC_BDCR);
defined(CONFIG_STM32F7_RTC_LSECLOCK)
uint32_t clksrc = getreg32(STM32_RCC_XXX);
rtc_dumpregs("On reset warm"); rtc_dumpregs("On reset warm");
#if defined(CONFIG_STM32F7_RTC_HSECLOCK) /* The RTC is already in use: check if the clock source has changed */
if ((clksrc & RCC_XXX_RTCSEL_MASK) != RCC_XXX_RTCSEL_HSE)
#elif defined(CONFIG_STM32F7_RTC_LSICLOCK) if ((clksrc & RCC_BDCR_RTCSEL_MASK) != RCC_BDCR_RTCSEL)
if ((clksrc & RCC_XXX_RTCSEL_MASK) != RCC_XXX_RTCSEL_LSI)
#elif defined(CONFIG_STM32F7_RTC_LSECLOCK)
if ((clksrc & RCC_XXX_RTCSEL_MASK) != RCC_XXX_RTCSEL_LSE)
#endif
#endif
{ {
tr_bkp = getreg32(STM32_RTC_TR); tr_bkp = getreg32(STM32_RTC_TR);
dr_bkp = getreg32(STM32_RTC_DR); dr_bkp = getreg32(STM32_RTC_DR);
modifyreg32(STM32_RCC_XXX, 0, RCC_XXX_YYYRST); modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_BDRST);
modifyreg32(STM32_RCC_XXX, RCC_XXX_YYYRST, 0); modifyreg32(STM32_RCC_BDCR, RCC_BDCR_BDRST, 0);
#if defined(CONFIG_STM32F7_RTC_HSECLOCK) # if RCC_BDCR_RTCSEL == RCC_BDCR_RTCSEL_LSE
/* Because of the Backup domain Reset - we must re enable the LSE
* if it is used
*/
stm32_rcc_enablelse();
#endif
/* Change to the new clock as the input to the RTC block */ /* Change to the new clock as the input to the RTC block */
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_HSE); modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL);
#elif defined(CONFIG_STM32F7_RTC_LSICLOCK)
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSI);
#elif defined(CONFIG_STM32F7_RTC_LSECLOCK)
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSE);
#endif
putreg32(tr_bkp, STM32_RTC_TR); putreg32(tr_bkp, STM32_RTC_TR);
putreg32(dr_bkp, STM32_RTC_DR); putreg32(dr_bkp, STM32_RTC_DR);
/* Remember that the RTC is initialized */ /* Keep the fact that the RTC is initialized */
putreg32(RTC_MAGIC, RTC_MAGIC_REG); putreg32(RTC_MAGIC, RTC_MAGIC_REG);
/* Enable the RTC Clock by setting the RTCEN bit in the RCC register */ /* Enable the RTC Clock by setting the RTCEN bit in the RCC register */
modifyreg32(STM32_RCC_XXX, 0, RCC_XXX_RTCEN); modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_RTCEN);
} }
} }