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.
This commit is contained in:
David Sidrane 2021-02-03 15:23:13 -08:00 committed by Alan Carvalho de Assis
parent 9d370fc363
commit 9fbd7f9dc5
3 changed files with 125 additions and 14 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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 <gnutt@nuttx.org>
* David Sidrane <david.sidrane@nscdg.com>
*
@ -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