You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2021/03/02 17:35:45 UTC

[incubator-nuttx] 01/02: stm32h7:Add option to auto select LSE CAPABILITY

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 9fbd7f9dc5649f7e71db3a06fe4b86a464f9b3ae
Author: David Sidrane <Da...@NscDg.com>
AuthorDate: Wed Feb 3 15:23:13 2021 -0800

    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 +++++++++
 arch/arm/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 f83ce52..65a4cdd 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 15cdd86..0adfe8b 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 6952d35..06f8854 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 <gn...@nuttx.org>
  *            David Sidrane <da...@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
@@ -64,6 +67,30 @@
 #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