diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig index 3af3678d6f..3d5be60bca 100644 --- a/arch/arm/src/stm32f7/Kconfig +++ b/arch/arm/src/stm32f7/Kconfig @@ -2582,10 +2582,24 @@ endchoice #"RTC clock source" if STM32F7_RTC_LSECLOCK +config STM32F7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + bool "Automaticaly boost the LSE oscillator drive capability level until it starts-up" + default n + ---help--- + This will cycle through the values from low to high. To avoid + damaging the the crystal. We want to use the lowest setting that gets + the OSC running. See app note AN2867 + + 0 = Low drive capability (default) + 1 = Medium high drive capability + 2 = Medium low drive capability + 3 = High drive capability + config STM32F7_RTC_LSECLOCK_START_DRV_CAPABILITY int "LSE oscillator drive capability level at LSE start-up" default 0 range 0 3 + depends on !STM32F7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY ---help--- 0 = Low drive capability (default) 1 = Medium high drive capability @@ -2596,6 +2610,7 @@ config STM32F7_RTC_LSECLOCK_RUN_DRV_CAPABILITY int "LSE oscillator drive capability level after LSE start-up" default 0 range 0 3 + depends on !STM32F7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY ---help--- 0 = Low drive capability (default) 1 = Medium high drive capability diff --git a/arch/arm/src/stm32f7/stm32_lse.c b/arch/arm/src/stm32f7/stm32_lse.c index ee5cb9519c..3ed6a12845 100644 --- a/arch/arm/src/stm32f7/stm32_lse.c +++ b/arch/arm/src/stm32f7/stm32_lse.c @@ -1,9 +1,9 @@ /**************************************************************************** * arch/arm/src/stm32f7/stm32_lse.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017, 2021 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt - * David Sidrane + * David Sidrane * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -49,6 +49,8 @@ * Pre-processor Definitions ****************************************************************************/ +#define LSERDY_TIMEOUT (500 * CONFIG_BOARD_LOOPSPERMSEC) + #ifdef CONFIG_STM32F7_RTC_LSECLOCK_START_DRV_CAPABILITY # if CONFIG_STM32F7_RTC_LSECLOCK_START_DRV_CAPABILITY < 0 || \ CONFIG_STM32F7_RTC_LSECLOCK_START_DRV_CAPABILITY > 3 @@ -63,6 +65,18 @@ #endif #endif +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint32_t drives[4] = +{ + RCC_BDCR_LSEDRV_LOW, + RCC_BDCR_LSEDRV_MEDLO, + RCC_BDCR_LSEDRV_MEDHI, + RCC_BDCR_LSEDRV_HIGH +}; + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -77,7 +91,11 @@ void stm32_rcc_enablelse(void) { - uint32_t regval; + uint32_t regval; + volatile int32_t timeout; +#ifdef CONFIG_STM32F7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + volatile int32_t drive = 0; +#endif /* Check if the External Low-Speed (LSE) oscillator is already running. */ @@ -100,27 +118,55 @@ void stm32_rcc_enablelse(void) regval |= RCC_BDCR_LSEON; #ifdef CONFIG_STM32F7_RTC_LSECLOCK_START_DRV_CAPABILITY - /* Set start-up drive capability for LSE oscillator. */ + /* Set start-up drive capability for LSE oscillator. With the + * enable on. + */ - regval &= ~RCC_BDCR_LSEDRV_MASK; - regval |= CONFIG_STM32F7_RTC_LSECLOCK_START_DRV_CAPABILITY << - RCC_BDCR_LSEDRV_SHIFT; + regval &= ~(RCC_BDCR_LSEDRV_MASK); + regval |= drives[CONFIG_STM32F7_RTC_LSECLOCK_START_DRV_CAPABILITY]; #endif - putreg32(regval, STM32_RCC_BDCR); +#ifdef CONFIG_STM32F7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + do + { + regval &= ~(RCC_BDCR_LSEDRV_MASK); + regval |= drives[drive++]; +#endif - /* Wait for the LSE clock to be ready */ + putreg32(regval, STM32_RCC_BDCR); - while (((regval = getreg32(STM32_RCC_BDCR)) & RCC_BDCR_LSERDY) == 0); + /* Wait for the LSE clock to be ready (or until a timeout elapsed) + */ + for (timeout = LSERDY_TIMEOUT; timeout > 0; timeout--) + { + /* Check if the LSERDY flag is the set in the BDCR */ + + regval = getreg32(STM32_RCC_BDCR); + + if (regval & RCC_BDCR_LSERDY) + { + /* If so, then break-out with timeout > 0 */ + + break; + } + } + +#ifdef CONFIG_STM32F7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + if (timeout != 0) + { + break; + } + } + while (drive < sizeof(drives) / sizeof(drives[0])); +#endif #if defined(CONFIG_STM32F7_RTC_LSECLOCK_RUN_DRV_CAPABILITY) && \ CONFIG_STM32F7_RTC_LSECLOCK_START_DRV_CAPABILITY != \ CONFIG_STM32F7_RTC_LSECLOCK_RUN_DRV_CAPABILITY /* Set running drive capability for LSE oscillator. */ regval &= ~RCC_BDCR_LSEDRV_MASK; - regval |= CONFIG_STM32F7_RTC_LSECLOCK_RUN_DRV_CAPABILITY << - RCC_BDCR_LSEDRV_SHIFT; + regval |= drives[CONFIG_STM32F7_RTC_LSECLOCK_RUN_DRV_CAPABILITY]; putreg32(regval, STM32_RCC_BDCR); #endif