Skip to content

Commit 906a20d

Browse files
committed
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>
1 parent 1be377c commit 906a20d

2 files changed

Lines changed: 48 additions & 12 deletions

File tree

src/machine/machine_stm32u585.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ import (
88
)
99

1010
func CPUFrequency() uint32 {
11-
return 4_000_000
11+
return 160_000_000
1212
}
1313

1414
// Internal use: configured speed of the APB1 and APB2 timers, this should be kept
1515
// in sync with any changes to runtime package which configures the oscillators
1616
// and clock frequencies
17-
const APB1_TIM_FREQ = 4e6 // 4MHz (MSI default)
18-
const APB2_TIM_FREQ = 4e6 // 4MHz (MSI default)
17+
const APB1_TIM_FREQ = 160e6 // 160MHz (PLL1: MSIS 4MHz × 80 / 1 / 2)
18+
const APB2_TIM_FREQ = 160e6 // 160MHz (PLL1: MSIS 4MHz × 80 / 1 / 2)
1919

2020
//---------- UART related code
2121

@@ -55,8 +55,10 @@ func (uart *UART) isLPUART1() bool {
5555
// NOTE: keep this in sync with the runtime/runtime_stm32u5.go clock init code
5656
func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 {
5757
if uart.isLPUART1() {
58-
// LPUART uses BRR = 256 * fclk / baud
59-
return (256 * CPUFrequency()) / baudRate
58+
// LPUART uses BRR = 256 * fclk / baud.
59+
// Use 64-bit arithmetic to avoid overflow: at 160 MHz,
60+
// 256 * 160_000_000 = 40_960_000_000 which exceeds uint32 max.
61+
return uint32(uint64(256) * uint64(CPUFrequency()) / uint64(baudRate))
6062
}
6163
// USART requires BRR >= 16 for 16x oversampling (OVER8=0).
6264
// A divisor below 16 is invalid per the STM32 reference manual and causes

src/runtime/runtime_stm32u5.go

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,52 @@ func buffered() int {
2424
}
2525

2626
func initCLK() {
27-
// Use MSI at 4MHz — the reset default clock configuration.
28-
// The MCU boots with MSI at 4MHz, VOS Range 4, and 0 flash wait states.
27+
// Configure SYSCLK to 160 MHz via PLL1 using MSIS (4 MHz reset default) as the source.
28+
// Formula: Fout = Fin × N / M / R = 4 × 80 / 1 / 2 = 160 MHz
29+
// - M = 1 (Div1), N = 80 (stored as N-1 = 79), R = 2 (Div2)
30+
// - VCO input = 4 MHz (PLL1RGE Range1: 4–8 MHz), VCO output = 320 MHz
31+
// VOS Range 1 (1.2V) is required for SYSCLK > 100 MHz (RM0456 §6.3.6).
2932

3033
// Enable PWR peripheral clock (required on STM32U5 before accessing PWR registers).
3134
stm32.RCC.AHB3ENR.SetBits(stm32.RCC_AHB3ENR_PWREN)
3235
_ = stm32.RCC.AHB3ENR.Get() // read-back for clock stabilization
3336

34-
// Switch from VOS Range 4 to Range 3. Range 4 doesn't support ADC (RM0456 §6.3.6).
35-
// Range 3 supports up to 50 MHz HCLK and enables ADC. No flash wait-state change needed at 4 MHz.
36-
// The EPOD booster must be enabled before changing VOS (RM0456 §10.5.4).
37+
// Enable the EPOD booster before raising VOS (RM0456 §10.5.4).
3738
stm32.PWR.VOSR.SetBits(stm32.PWR_VOSR_BOOSTEN)
38-
stm32.PWR.VOSR.ReplaceBits(stm32.PWR_VOSR_VOS_Range3<<stm32.PWR_VOSR_VOS_Pos, stm32.PWR_VOSR_VOS_Msk, 0)
39-
for !stm32.PWR.VOSR.HasBits(stm32.PWR_VOSR_VOSRDY) {
39+
40+
// Raise voltage scaling to Range 1 (1.2V) to support 160 MHz operation.
41+
stm32.PWR.VOSR.ReplaceBits(stm32.PWR_VOSR_VOS_Range1<<stm32.PWR_VOSR_VOS_Pos, stm32.PWR_VOSR_VOS_Msk, 0)
42+
43+
// Wait for both the VOS regulator and the EPOD booster to become ready.
44+
for !stm32.PWR.VOSR.HasBits(stm32.PWR_VOSR_VOSRDY | stm32.PWR_VOSR_BOOSTRDY) {
45+
}
46+
47+
// Set Flash latency to 4 wait states and enable prefetch before raising the clock
48+
// (required for 160 MHz at VOS Range 1, RM0456 §7.3.3).
49+
stm32.FLASH.ACR.ReplaceBits(4, stm32.Flash_ACR_LATENCY_Msk, 0)
50+
stm32.FLASH.ACR.SetBits(stm32.Flash_ACR_PRFTEN)
51+
52+
// Configure PLL1: source = MSIS (4 MHz), M = 1, PLL1RGE = 4–8 MHz, R output enabled.
53+
stm32.RCC.PLL1CFGR.Set(
54+
stm32.RCC_PLL1CFGR_PLL1SRC_MSIS |
55+
(stm32.RCC_PLL1CFGR_PLL1RGE_Range1 << stm32.RCC_PLL1CFGR_PLL1RGE_Pos) |
56+
(stm32.RCC_PLL1CFGR_PLL1M_Div1 << stm32.RCC_PLL1CFGR_PLL1M_Pos) |
57+
stm32.RCC_PLL1CFGR_PLL1REN,
58+
)
59+
60+
// Set PLL1 dividers: N = 80 (stored as N-1 = 79), R = 2 (Div2 = 1).
61+
stm32.RCC.PLL1DIVR.Set(
62+
(79 << stm32.RCC_PLL1DIVR_PLL1N_Pos) |
63+
(stm32.RCC_PLL1DIVR_PLL1R_Div2 << stm32.RCC_PLL1DIVR_PLL1R_Pos),
64+
)
65+
66+
// Enable PLL1 and wait for it to lock.
67+
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLL1ON)
68+
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLL1RDY) {
69+
}
70+
71+
// Switch SYSCLK to PLL1 and wait for the hardware to confirm the switch.
72+
stm32.RCC.SetCFGR1_SW(stm32.RCC_CFGR1_SW_PLL)
73+
for stm32.RCC.GetCFGR1_SWS() != stm32.RCC_CFGR1_SWS_PLL {
4074
}
4175
}

0 commit comments

Comments
 (0)