mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
stm32u5: configure system clock to 160 MHz
- Uses PLL1 to boost the system clock from the 4 MHz MSIS default to 160 MHz. - Sets VOS to Range 1 (1.2V) and enables the EPOD booster for higher frequency support. - Configures flash latency (4 wait states) and enables prefetch for 160 MHz operation. - Updates CPU and APB timer frequencies in the machine package accordingly. - Fixes LPUART baud rate divisor computation by using 64-bit arithmetic to prevent overflow with the newly increased 160 MHz clock. Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
@@ -8,14 +8,14 @@ import (
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 4_000_000
|
||||
return 160_000_000
|
||||
}
|
||||
|
||||
// Internal use: configured speed of the APB1 and APB2 timers, this should be kept
|
||||
// in sync with any changes to runtime package which configures the oscillators
|
||||
// and clock frequencies
|
||||
const APB1_TIM_FREQ = 4e6 // 4MHz (MSI default)
|
||||
const APB2_TIM_FREQ = 4e6 // 4MHz (MSI default)
|
||||
const APB1_TIM_FREQ = 160e6 // 160MHz (PLL1: MSIS 4MHz × 80 / 1 / 2)
|
||||
const APB2_TIM_FREQ = 160e6 // 160MHz (PLL1: MSIS 4MHz × 80 / 1 / 2)
|
||||
|
||||
//---------- UART related code
|
||||
|
||||
@@ -55,8 +55,10 @@ func (uart *UART) isLPUART1() bool {
|
||||
// NOTE: keep this in sync with the runtime/runtime_stm32u5.go clock init code
|
||||
func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 {
|
||||
if uart.isLPUART1() {
|
||||
// LPUART uses BRR = 256 * fclk / baud
|
||||
return (256 * CPUFrequency()) / baudRate
|
||||
// LPUART uses BRR = 256 * fclk / baud.
|
||||
// Use 64-bit arithmetic to avoid overflow: at 160 MHz,
|
||||
// 256 * 160_000_000 = 40_960_000_000 which exceeds uint32 max.
|
||||
return uint32(uint64(256) * uint64(CPUFrequency()) / uint64(baudRate))
|
||||
}
|
||||
// USART requires BRR >= 16 for 16x oversampling (OVER8=0).
|
||||
// A divisor below 16 is invalid per the STM32 reference manual and causes
|
||||
|
||||
@@ -24,18 +24,52 @@ func buffered() int {
|
||||
}
|
||||
|
||||
func initCLK() {
|
||||
// Use MSI at 4MHz — the reset default clock configuration.
|
||||
// The MCU boots with MSI at 4MHz, VOS Range 4, and 0 flash wait states.
|
||||
// Configure SYSCLK to 160 MHz via PLL1 using MSIS (4 MHz reset default) as the source.
|
||||
// Formula: Fout = Fin × N / M / R = 4 × 80 / 1 / 2 = 160 MHz
|
||||
// - M = 1 (Div1), N = 80 (stored as N-1 = 79), R = 2 (Div2)
|
||||
// - VCO input = 4 MHz (PLL1RGE Range1: 4–8 MHz), VCO output = 320 MHz
|
||||
// VOS Range 1 (1.2V) is required for SYSCLK > 100 MHz (RM0456 §6.3.6).
|
||||
|
||||
// Enable PWR peripheral clock (required on STM32U5 before accessing PWR registers).
|
||||
stm32.RCC.AHB3ENR.SetBits(stm32.RCC_AHB3ENR_PWREN)
|
||||
_ = stm32.RCC.AHB3ENR.Get() // read-back for clock stabilization
|
||||
|
||||
// Switch from VOS Range 4 to Range 3. Range 4 doesn't support ADC (RM0456 §6.3.6).
|
||||
// Range 3 supports up to 50 MHz HCLK and enables ADC. No flash wait-state change needed at 4 MHz.
|
||||
// The EPOD booster must be enabled before changing VOS (RM0456 §10.5.4).
|
||||
// Enable the EPOD booster before raising VOS (RM0456 §10.5.4).
|
||||
stm32.PWR.VOSR.SetBits(stm32.PWR_VOSR_BOOSTEN)
|
||||
stm32.PWR.VOSR.ReplaceBits(stm32.PWR_VOSR_VOS_Range3<<stm32.PWR_VOSR_VOS_Pos, stm32.PWR_VOSR_VOS_Msk, 0)
|
||||
for !stm32.PWR.VOSR.HasBits(stm32.PWR_VOSR_VOSRDY) {
|
||||
|
||||
// Raise voltage scaling to Range 1 (1.2V) to support 160 MHz operation.
|
||||
stm32.PWR.VOSR.ReplaceBits(stm32.PWR_VOSR_VOS_Range1<<stm32.PWR_VOSR_VOS_Pos, stm32.PWR_VOSR_VOS_Msk, 0)
|
||||
|
||||
// Wait for both the VOS regulator and the EPOD booster to become ready.
|
||||
for !stm32.PWR.VOSR.HasBits(stm32.PWR_VOSR_VOSRDY | stm32.PWR_VOSR_BOOSTRDY) {
|
||||
}
|
||||
|
||||
// Set Flash latency to 4 wait states and enable prefetch before raising the clock
|
||||
// (required for 160 MHz at VOS Range 1, RM0456 §7.3.3).
|
||||
stm32.FLASH.ACR.ReplaceBits(4, stm32.Flash_ACR_LATENCY_Msk, 0)
|
||||
stm32.FLASH.ACR.SetBits(stm32.Flash_ACR_PRFTEN)
|
||||
|
||||
// Configure PLL1: source = MSIS (4 MHz), M = 1, PLL1RGE = 4–8 MHz, R output enabled.
|
||||
stm32.RCC.PLL1CFGR.Set(
|
||||
stm32.RCC_PLL1CFGR_PLL1SRC_MSIS |
|
||||
(stm32.RCC_PLL1CFGR_PLL1RGE_Range1 << stm32.RCC_PLL1CFGR_PLL1RGE_Pos) |
|
||||
(stm32.RCC_PLL1CFGR_PLL1M_Div1 << stm32.RCC_PLL1CFGR_PLL1M_Pos) |
|
||||
stm32.RCC_PLL1CFGR_PLL1REN,
|
||||
)
|
||||
|
||||
// Set PLL1 dividers: N = 80 (stored as N-1 = 79), R = 2 (Div2 = 1).
|
||||
stm32.RCC.PLL1DIVR.Set(
|
||||
(79 << stm32.RCC_PLL1DIVR_PLL1N_Pos) |
|
||||
(stm32.RCC_PLL1DIVR_PLL1R_Div2 << stm32.RCC_PLL1DIVR_PLL1R_Pos),
|
||||
)
|
||||
|
||||
// Enable PLL1 and wait for it to lock.
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLL1ON)
|
||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLL1RDY) {
|
||||
}
|
||||
|
||||
// Switch SYSCLK to PLL1 and wait for the hardware to confirm the switch.
|
||||
stm32.RCC.SetCFGR1_SW(stm32.RCC_CFGR1_SW_PLL)
|
||||
for stm32.RCC.GetCFGR1_SWS() != stm32.RCC_CFGR1_SWS_PLL {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user