From 9fbd7f9dc5649f7e71db3a06fe4b86a464f9b3ae Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Wed, 3 Feb 2021 15:23:13 -0800 Subject: [PATCH] stm32h7:Add option to auto select LSE CAPABILITY This Knob will cycle through the correct* 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 *It will take into account the rev of the silicon and use the correct code points to achive the drive strength. See Eratta ES0392 Rev 7 2.2.14 LSE oscillator driving capability selection bits are swapped. --- arch/arm/src/stm32h7/Kconfig | 34 +++++++ .../src/stm32h7/hardware/stm32h7x3xx_rcc.h | 8 +- arch/arm/src/stm32h7/stm32_lse.c | 97 ++++++++++++++++--- 3 files changed, 125 insertions(+), 14 deletions(-) diff --git a/arch/arm/src/stm32h7/Kconfig b/arch/arm/src/stm32h7/Kconfig index f83ce52586..65a4cdd48b 100644 --- a/arch/arm/src/stm32h7/Kconfig +++ b/arch/arm/src/stm32h7/Kconfig @@ -1493,26 +1493,60 @@ endchoice #"RTC clock source" if STM32H7_RTC_LSECLOCK +config STM32H7_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 correct* 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 + + *It will take into account the rev of the silicon and use + the correct code points to achive the drive strength. + See Eratta ES0392 Rev 7 2.2.14 LSE oscillator driving capability + selection bits are swapped. + config STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY int "LSE oscillator drive capability level at LSE start-up" default 0 range 0 3 + depends on !STM32H7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY ---help--- 0 = Low drive capability (default) 1 = Medium high drive capability 2 = Medium low drive capability 3 = High drive capability + It will take into account the rev of the silicon and use + the correct code points tp achive the drive strength. + See Eratta ES0392 Rev 7 2.2.14 LSE oscillator driving capability + selection bits are swapped. + config STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY int "LSE oscillator drive capability level after LSE start-up" default 0 range 0 3 + depends on !STM32H7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY ---help--- 0 = Low drive capability (default) 1 = Medium high drive capability 2 = Medium low drive capability 3 = High drive capability + It will take into account the rev of the silicon and use + the correct code points tp achive the drive strength. + See Eratta ES0392 Rev 7 2.2.14 LSE oscillator driving capability + selection bits are swapped. + + WARNING this RUN setting does not apear to work! + it apears that the LSEDRV bits can not be changes once the OSC + is running. + endif # STM32H7_RTC_LSECLOCK endmenu # RTC Configuration diff --git a/arch/arm/src/stm32h7/hardware/stm32h7x3xx_rcc.h b/arch/arm/src/stm32h7/hardware/stm32h7x3xx_rcc.h index 15cdd86972..0adfe8be01 100644 --- a/arch/arm/src/stm32h7/hardware/stm32h7x3xx_rcc.h +++ b/arch/arm/src/stm32h7/hardware/stm32h7x3xx_rcc.h @@ -1132,10 +1132,12 @@ #define RCC_BDCR_LSERDY (1 << 1) /* Bit 1: External Low Speed oscillator Ready */ #define RCC_BDCR_LSEBYP (1 << 2) /* Bit 2: External Low Speed oscillator Bypass */ #define RCC_BDCR_LSEDRV_SHIFT (3) /* Bits 4:3: LSE oscillator Drive selection */ -#define RCC_BDCR_LSEDRV_MASK (3 << RCC_BDCR_LSEDRV_SHIFT) +#define RCC_BDCR_LSEDRV_MASK (3 << RCC_BDCR_LSEDRV_SHIFT) /* See errata ES0392 Rev 7. 2.2.14 */ # define RCC_BDCR_LSEDRV_LOW (0 << RCC_BDCR_LSEDRV_SHIFT) /* 00: Low driving capability */ -# define RCC_BDCR_LSEDRV_MEDHI (1 << RCC_BDCR_LSEDRV_SHIFT) /* 01: Medium high driving capability */ -# define RCC_BDCR_LSEDRV_MEDLO (2 << RCC_BDCR_LSEDRV_SHIFT) /* 10: Medium low driving capability */ +# define RCC_BDCR_LSEDRV_MEDHI_Y (1 << RCC_BDCR_LSEDRV_SHIFT) /* 01: Medium high driving capability rev y */ +# define RCC_BDCR_LSEDRV_MEDHI (2 << RCC_BDCR_LSEDRV_SHIFT) /* 10: Medium high driving capability */ +# define RCC_BDCR_LSEDRV_MEDLO_Y (2 << RCC_BDCR_LSEDRV_SHIFT) /* 10: Medium low driving capability rev y */ +# define RCC_BDCR_LSEDRV_MEDLO (1 << RCC_BDCR_LSEDRV_SHIFT) /* 01: Medium low driving capability */ # define RCC_BDCR_LSEDRV_HIGH (3 << RCC_BDCR_LSEDRV_SHIFT) /* 11: High driving capability */ #define RCC_BDCR_LSECSSON (1 << 5) /* Bit 5: LSE clock security system enable */ #define RCC_BDCR_LSECSSD (1 << 6) /* Bit 6: LSE clock security system failure detection */ diff --git a/arch/arm/src/stm32h7/stm32_lse.c b/arch/arm/src/stm32h7/stm32_lse.c index 6952d3597c..06f8854b05 100644 --- a/arch/arm/src/stm32h7/stm32_lse.c +++ b/arch/arm/src/stm32h7/stm32_lse.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32h7/stm32_lse.c * - * Copyright (C) 2017, 2019 Gregory Nutt. All rights reserved. + * Copyright (C) 2017, 2019, 2021 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt * David Sidrane * @@ -44,11 +44,14 @@ #include "stm32_rcc.h" #include "stm32_pwr.h" +#include "hardware/stm32h7xxx_dbgmcu.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +#define LSERDY_TIMEOUT (500 * CONFIG_BOARD_LOOPSPERMSEC) + #ifdef CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY # if CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY < 0 || \ CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY > 3 @@ -63,6 +66,30 @@ #endif #endif +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* See errata ES0392 Rev 7. 2.2.14 LSE oscillator driving capability + * selection bits are swapped. + */ + +static const uint32_t drives_rev_y[4] = +{ + RCC_BDCR_LSEDRV_LOW, + RCC_BDCR_LSEDRV_MEDLO_Y, + RCC_BDCR_LSEDRV_MEDHI_Y, + RCC_BDCR_LSEDRV_HIGH +}; + +const uint32_t drives_rev[4] = +{ + RCC_BDCR_LSEDRV_LOW, + RCC_BDCR_LSEDRV_MEDLO, + RCC_BDCR_LSEDRV_MEDHI, + RCC_BDCR_LSEDRV_HIGH +}; + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -77,7 +104,12 @@ void stm32_rcc_enablelse(void) { - uint32_t regval; + uint32_t regval; + volatile int32_t timeout; +#ifdef CONFIG_STM32H7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + volatile int32_t drive = 0; +#endif + const uint32_t *drives = drives_rev_y; /* Check if the External Low-Speed (LSE) oscillator is already running. */ @@ -86,6 +118,16 @@ void stm32_rcc_enablelse(void) if ((regval & (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) != (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) { + /* Check Silicon for LSE oscillator driving capability selection bits + * are swapped errata. + */ + + if ((getreg32(STM32_DEBUGMCU_BASE) & DBGMCU_IDCODE_REVID_MASK) != + STM32_IDCODE_REVID_Y) + { + drives = drives_rev; + } + /* 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. @@ -100,27 +142,60 @@ void stm32_rcc_enablelse(void) regval |= RCC_BDCR_LSEON; #ifdef CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY - /* Set start-up drive capability for LSE oscillator. */ + /* Set start-up drive capability for LSE oscillator. With the + * enable off + */ - regval &= ~RCC_BDCR_LSEDRV_MASK; - regval |= CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY << - RCC_BDCR_LSEDRV_SHIFT; + regval &= ~(RCC_BDCR_LSEDRV_MASK | RCC_BDCR_LSEON); + regval |= drives[CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY]; + putreg32(regval, STM32_RCC_BDCR); + regval |= RCC_BDCR_LSEON; #endif - putreg32(regval, STM32_RCC_BDCR); +#ifdef CONFIG_STM32H7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + do + { + regval &= ~(RCC_BDCR_LSEDRV_MASK | RCC_BDCR_LSEON); + regval |= drives[drive++]; + putreg32(regval, STM32_RCC_BDCR); + regval |= RCC_BDCR_LSEON; +#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_STM32H7_RTC_AUTO_LSECLOCK_START_DRV_CAPABILITY + if (timeout != 0) + { + break; + } + } + while (drive < sizeof(drives_rev_y) / sizeof(drives_rev_y[0])); + +#endif #if defined(CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY) && \ CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY != \ CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY /* Set running drive capability for LSE oscillator. */ regval &= ~RCC_BDCR_LSEDRV_MASK; - regval |= CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY << - RCC_BDCR_LSEDRV_SHIFT; + regval |= drives[CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY]; putreg32(regval, STM32_RCC_BDCR); #endif