Skip to content

Commit

Permalink
stm32/powerctrlboot: Support STM32WL system clock from HSE+PLL.
Browse files Browse the repository at this point in the history
Switches default on the NUCLEO_WL55 board to use the HSE oscillator powered
from PB0_VDDTCXO pin.

Build-time configuration can select from MSI internal oscillator (previous
default), HSE via crystal, or HSE bypass with TCXO powered from PB0_VDDTCXO
pin (new default)

Signed-off-by: Angus Gratton <angus@redyak.com.au>
  • Loading branch information
projectgus authored and dpgeorge committed Aug 23, 2023
1 parent e6cfb77 commit 2c62adb
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 2 deletions.
7 changes: 7 additions & 0 deletions ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h
Expand Up @@ -28,6 +28,13 @@
#define MICROPY_HW_RTC_USE_LSE (1)
#define MICROPY_HW_RTC_USE_US (1)

// Use external 32MHz TCXO + PLL as system clock source
// (If unset, board will use the internal MSI oscillator instead.)
#define MICROPY_HW_CLK_USE_HSE (1)

// HSE bypass for STM32WL5x means TCXO is powered from PB0_VDDTCXO pin
#define MICROPY_HW_CLK_USE_BYPASS (1)

// UART buses
#define MICROPY_HW_UART1_TX (pin_B6) // Arduino D1, pin 7 on CN9
#define MICROPY_HW_UART1_RX (pin_B7) // Arduino D0, pin 8 on CN9
Expand Down
3 changes: 2 additions & 1 deletion ports/stm32/boards/NUCLEO_WL55/pins.csv
Expand Up @@ -14,7 +14,8 @@
,PA13
,PA14
,PA15
,PB0
# in the default board configuration, PB0 must stay muxed to analog for HSE VDDTCXO function
,-PB0
,PB1
,PB2
,PB3
Expand Down
4 changes: 4 additions & 0 deletions ports/stm32/mpconfigboard_common.h
Expand Up @@ -471,8 +471,12 @@
#define MICROPY_HW_RCC_HSI_STATE (RCC_HSI_OFF)
#define MICROPY_HW_RCC_FLAG_HSxRDY (RCC_FLAG_HSERDY)
#if MICROPY_HW_CLK_USE_BYPASS
#if !defined(STM32WL)
#define MICROPY_HW_RCC_HSE_STATE (RCC_HSE_BYPASS)
#else
#define MICROPY_HW_RCC_HSE_STATE (RCC_HSE_BYPASS_PWR)
#endif
#else
#define MICROPY_HW_RCC_HSE_STATE (RCC_HSE_ON)
#endif
#endif
Expand Down
62 changes: 61 additions & 1 deletion ports/stm32/powerctrlboot.c
Expand Up @@ -460,13 +460,71 @@ void SystemClock_Config(void) {
#include "stm32wlxx_ll_utils.h"

void SystemClock_Config(void) {
// Set flash latency
// Set flash latency (2 wait states, sysclk > 36MHz)
LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2) {
}

LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);

#if MICROPY_HW_CLK_USE_HSE
// Enable the 32MHz external oscillator and 48MHZ SYSCLK via PLL

#if MICROPY_HW_CLK_USE_BYPASS
// Use "bypass power" option, port PB0_VDDTCXO supplies TCXO
// (STM32WL5x has no other HSE bypass mode.)

// "PB0 must be configured in analog mode prior enabling the HSE"
//
// Note: PB0 analog mode muxes PB0_VDDTCXO pin to the VDDTCXO regulator, set
// to default voltage of 1.7V. Changing this voltage requires initializing
// the SUBGHZ radio and sending a Set_Tcxo command to it.
//
// For the Nucelo-WL55 board, ST uses the NDK "NT2016SF-32M-END5875A" TCXO
// which has no publicly available datasheet. However, the ST code for this
// board always keeps the pin at the default 1.7V voltage level so changing
// the level would only be needed if a different TCXO is used.
//
// (Note also that setting pin PB0 as a push-pull GPIO output is technically
// possible too, but 3.3V will be too high for many TCXOs.)
mp_hal_pin_config(pin_B0, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);

LL_RCC_HSE_EnableTcxo();

#endif // MICROPY_HW_CLK_USE_BYPASS

LL_RCC_HSE_Enable();
while (!LL_RCC_HSE_IsReady()) {
// Wait for HSE Ready signal
}

// Configure PLL for a 48MHz SYSCLK
#define PLLM (HSE_VALUE / 16000000) // VCO input 16MHz (recommended in ST docs)
#define PLLN (6) // 7*8MHz = 96MHz
#define PLLP (2) // f_P = 48MHz
#define PLLQ (2) // f_Q = 48MHz
#define PLLR (2) // f_R = 48MHz
RCC->PLLCFGR =
(PLLR - 1) << RCC_PLLCFGR_PLLR_Pos | RCC_PLLCFGR_PLLREN
| (PLLQ - 1) << RCC_PLLCFGR_PLLQ_Pos | RCC_PLLCFGR_PLLQEN
| (PLLP - 1) << RCC_PLLCFGR_PLLP_Pos | RCC_PLLCFGR_PLLPEN
| PLLN << RCC_PLLCFGR_PLLN_Pos
| (PLLM - 1) << RCC_PLLCFGR_PLLM_Pos
| LL_RCC_PLLSOURCE_HSE;

LL_RCC_PLL_Enable();
LL_RCC_PLL_EnableDomain_SYS();
while (!LL_RCC_PLL_IsReady()) {
// Wait for PLL to lock
}

LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
// Wait for system clock source to switch
}

#else // Use MSI as 48MHz source for SYSCLK

// Enable MSI
LL_RCC_MSI_Enable();
while (!LL_RCC_MSI_IsReady()) {
Expand All @@ -482,6 +540,8 @@ void SystemClock_Config(void) {
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) {
}

#endif // MICROPY_HW_CLK_USE_HSE

// Set bus dividers
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAHB3Prescaler(LL_RCC_SYSCLK_DIV_1);
Expand Down

0 comments on commit 2c62adb

Please sign in to comment.