From 1e5754232ae8edf936cee441885de44ca251ee9e Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Thu, 4 Feb 2021 06:35:24 -0800 Subject: [PATCH] stm32f7:Add option to auto select LSE CAPABILITY This Knob will cycle through the values from low to high. To avoid damaging the crystal. We want to use the lowest setting that gets the OSC running. See app note AN2867 --- arch/arm/src/stm32f7/Kconfig | 15 +++++++ arch/arm/src/stm32f7/stm32_lse.c | 70 ++++++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig index 3af3678d6f3..3d5be60bca9 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 ee5cb9519cd..3ed6a128454 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