From 47115f03800377fd9e02b4d0eb520b7647a401ae Mon Sep 17 00:00:00 2001 From: deadprogram Date: Sun, 15 Mar 2026 15:43:56 +0100 Subject: [PATCH] machine/stm32: add STM32U585 target definition and runtime Add processor target (cortex-m33), linker script (2048K flash, 768K RAM), and arduino-uno-q board target. Runtime initializes 160MHz clock via PLL1 from HSI16, with PWR Range 1 and EPOD booster. Also add psctype abstraction for timer PSC register width, needed because the U5 SVD defines PSC as a 16-bit register. --- src/machine/machine_stm32_tim.go | 2 +- src/machine/machine_stm32f103.go | 1 + src/machine/machine_stm32f4.go | 1 + src/machine/machine_stm32f7.go | 1 + src/machine/machine_stm32g0.go | 1 + src/machine/machine_stm32l0x1.go | 1 + src/machine/machine_stm32l0x2.go | 1 + src/machine/machine_stm32l4.go | 1 + src/machine/machine_stm32l5.go | 1 + src/machine/machine_stm32wlx.go | 1 + src/runtime/runtime_stm32u5.go | 101 +++++++++++++++++++++++++++++++ src/runtime/runtime_stm32u585.go | 15 +++++ targets/arduino-uno-q.json | 7 +++ targets/stm32u585.json | 16 +++++ targets/stm32u585.ld | 10 +++ 15 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/runtime/runtime_stm32u5.go create mode 100644 src/runtime/runtime_stm32u585.go create mode 100644 targets/arduino-uno-q.json create mode 100644 targets/stm32u585.json create mode 100644 targets/stm32u585.ld diff --git a/src/machine/machine_stm32_tim.go b/src/machine/machine_stm32_tim.go index 4898ed9f6..da11b44e1 100644 --- a/src/machine/machine_stm32_tim.go +++ b/src/machine/machine_stm32_tim.go @@ -150,7 +150,7 @@ func (t *TIM) setPeriod(period uint64, updatePrescaler bool) error { psc = ceil(top, ARR_MAX) top = top / psc - t.Device.PSC.Set(uint32(psc - 1)) + t.Device.PSC.Set(psctype(psc - 1)) } else { psc = uint64(t.Device.PSC.Get()) + 1 top = top / psc diff --git a/src/machine/machine_stm32f103.go b/src/machine/machine_stm32f103.go index 9e7bb347c..d946ef4aa 100644 --- a/src/machine/machine_stm32f103.go +++ b/src/machine/machine_stm32f103.go @@ -731,6 +731,7 @@ func (t *TIM) enableMainOutput() { } type arrtype = uint32 +type psctype = uint32 type arrRegType = volatile.Register32 const ( diff --git a/src/machine/machine_stm32f4.go b/src/machine/machine_stm32f4.go index 31f1d2c63..2a989b10a 100644 --- a/src/machine/machine_stm32f4.go +++ b/src/machine/machine_stm32f4.go @@ -607,6 +607,7 @@ func (t *TIM) enableMainOutput() { } type arrtype = uint32 +type psctype = uint32 type arrRegType = volatile.Register32 const ( diff --git a/src/machine/machine_stm32f7.go b/src/machine/machine_stm32f7.go index 11eff1108..7944769de 100644 --- a/src/machine/machine_stm32f7.go +++ b/src/machine/machine_stm32f7.go @@ -712,6 +712,7 @@ func (t *TIM) enableMainOutput() { } type arrtype = uint32 +type psctype = uint32 type arrRegType = volatile.Register32 const ( diff --git a/src/machine/machine_stm32g0.go b/src/machine/machine_stm32g0.go index 530c77aad..7390aed6c 100644 --- a/src/machine/machine_stm32g0.go +++ b/src/machine/machine_stm32g0.go @@ -554,6 +554,7 @@ func (t *TIM) enableMainOutput() { } type arrtype = uint32 +type psctype = uint32 type arrRegType = volatile.Register32 const ( diff --git a/src/machine/machine_stm32l0x1.go b/src/machine/machine_stm32l0x1.go index 292b81f46..3157f947e 100644 --- a/src/machine/machine_stm32l0x1.go +++ b/src/machine/machine_stm32l0x1.go @@ -189,6 +189,7 @@ func (t *TIM) enableMainOutput() { } type arrtype = uint32 +type psctype = uint32 type arrRegType = volatile.Register32 const ( diff --git a/src/machine/machine_stm32l0x2.go b/src/machine/machine_stm32l0x2.go index fe1ba3a22..d8873fc4b 100644 --- a/src/machine/machine_stm32l0x2.go +++ b/src/machine/machine_stm32l0x2.go @@ -246,6 +246,7 @@ func (t *TIM) enableMainOutput() { } type arrtype = uint32 +type psctype = uint32 type arrRegType = volatile.Register32 const ( diff --git a/src/machine/machine_stm32l4.go b/src/machine/machine_stm32l4.go index b5babc0b2..8453b2829 100644 --- a/src/machine/machine_stm32l4.go +++ b/src/machine/machine_stm32l4.go @@ -532,6 +532,7 @@ func (t *TIM) enableMainOutput() { } type arrtype = uint32 +type psctype = uint32 type arrRegType = volatile.Register32 const ( diff --git a/src/machine/machine_stm32l5.go b/src/machine/machine_stm32l5.go index faa583c9c..89b3a1f14 100644 --- a/src/machine/machine_stm32l5.go +++ b/src/machine/machine_stm32l5.go @@ -542,6 +542,7 @@ func (t *TIM) enableMainOutput() { } type arrtype = uint32 +type psctype = uint32 type arrRegType = volatile.Register32 const ( diff --git a/src/machine/machine_stm32wlx.go b/src/machine/machine_stm32wlx.go index 80ca791e6..b94e551ff 100644 --- a/src/machine/machine_stm32wlx.go +++ b/src/machine/machine_stm32wlx.go @@ -433,6 +433,7 @@ func initRNG() { //---------- type arrtype = uint32 +type psctype = uint32 type arrRegType = volatile.Register32 const ( diff --git a/src/runtime/runtime_stm32u5.go b/src/runtime/runtime_stm32u5.go new file mode 100644 index 000000000..be55b5e37 --- /dev/null +++ b/src/runtime/runtime_stm32u5.go @@ -0,0 +1,101 @@ +//go:build stm32u5 + +package runtime + +import ( + "device/stm32" + "machine" +) + +func putchar(c byte) { + machine.Serial.WriteByte(c) +} + +func getchar() byte { + for machine.Serial.Buffered() == 0 { + Gosched() + } + v, _ := machine.Serial.ReadByte() + return v +} + +func buffered() int { + return machine.Serial.Buffered() +} + +func initCLK() { + // Initialize clock to 160MHz using PLL1 with HSI16 as source. + // PLL1 configuration: HSI16 (16MHz) / PLLM(1) * PLLN(10) / PLLR(1) = 160MHz + // VCO = 16 * 10 = 160MHz, PLLR = /1 -> 160MHz SYSCLK + + // Enable PWR clock + stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_CRSEN) // CRS enable not needed but ensures APB1 is clocked + _ = stm32.RCC.APB1ENR1.Get() + + // Set voltage scaling to Range 1 for 160MHz operation + // On U5, voltage scaling is in PWR.VOSR register + // VOS = 11 (Range 1, up to 160MHz) + stm32.PWR.VOSR.ReplaceBits(stm32.PWR_VOSR_VOS_Range1, stm32.PWR_VOSR_VOS_Msk, 0) + // Wait for VOS ready + for !stm32.PWR.VOSR.HasBits(stm32.PWR_VOSR_VOSRDY) { + } + + // Enable EPOD booster for high performance (required for Range 1 >100MHz) + stm32.PWR.VOSR.SetBits(stm32.PWR_VOSR_BOOSTEN) + for !stm32.PWR.VOSR.HasBits(stm32.PWR_VOSR_BOOSTRDY) { + } + + // Enable HSI16 + stm32.RCC.CR.SetBits(stm32.RCC_CR_HSION) + for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSIRDY) { + } + + // Disable PLL1 before configuration + stm32.RCC.CR.ClearBits(stm32.RCC_CR_PLL1ON) + for stm32.RCC.CR.HasBits(stm32.RCC_CR_PLL1RDY) { + } + + // Configure PLL1: + // Source = HSI16 (0x2) + // PLLM = 0 (divide by 1) + // PLL1RGE = 0x3 (input range 8-16MHz) + // Enable PLLR output + stm32.RCC.PLL1CFGR.Set( + (stm32.RCC_PLL1CFGR_PLL1SRC_HSI16 << stm32.RCC_PLL1CFGR_PLL1SRC_Pos) | + (stm32.RCC_PLL1CFGR_PLL1M_Div1 << stm32.RCC_PLL1CFGR_PLL1M_Pos) | + (stm32.RCC_PLL1CFGR_PLL1RGE_Range2 << stm32.RCC_PLL1CFGR_PLL1RGE_Pos)) + + // Enable PLL1R output + stm32.RCC.PLL1CFGR.SetBits(1 << stm32.RCC_PLL1CFGR_PLL1REN_Pos) + + // Set PLL1 dividers in PLL1DIVR: + // PLL1N = 10 (value - 1 = 9 in register) + // PLL1R = 1 (value - 1 = 0 in register) + // VCO = HSI16/1 * 10 = 160MHz + // PLLR output = 160MHz / 1 = 160MHz + stm32.RCC.SetPLL1DIVR_PLL1N(9) // N = 10, register value = N-1 = 9 + stm32.RCC.SetPLL1DIVR_PLL1R(0) // R = 1, register value = R-1 = 0 + + // Enable PLL1 + stm32.RCC.CR.SetBits(stm32.RCC_CR_PLL1ON) + for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLL1RDY) { + } + + // Set flash latency to 4 wait states (required for 160MHz in Range 1) + const FLASH_LATENCY_4 = 4 + stm32.FLASH.ACR.ReplaceBits(FLASH_LATENCY_4, stm32.Flash_ACR_LATENCY_Msk, 0) + for (stm32.FLASH.ACR.Get() & stm32.Flash_ACR_LATENCY_Msk) != FLASH_LATENCY_4 { + } + + // Set AHB prescaler to 1 (no division) in CFGR2 + stm32.RCC.CFGR2.ReplaceBits(stm32.RCC_CFGR2_HPRE_Div1, stm32.RCC_CFGR2_HPRE_Msk, 0) + + // Set APB1 and APB2 prescalers to 1 (no division) in CFGR2 + stm32.RCC.CFGR2.ReplaceBits(stm32.RCC_CFGR2_PPRE1_Div1, stm32.RCC_CFGR2_PPRE1_Msk, 0) + stm32.RCC.CFGR2.ReplaceBits(stm32.RCC_CFGR2_PPRE2_Div1, stm32.RCC_CFGR2_PPRE2_Msk, 0) + + // Switch system clock to PLL1 (SW = 11 = PLL) + stm32.RCC.CFGR1.ReplaceBits(stm32.RCC_CFGR1_SW_PLL, stm32.RCC_CFGR1_SW_Msk, 0) + for (stm32.RCC.CFGR1.Get() & stm32.RCC_CFGR1_SWS_Msk) != (stm32.RCC_CFGR1_SWS_PLL << stm32.RCC_CFGR1_SWS_Pos) { + } +} diff --git a/src/runtime/runtime_stm32u585.go b/src/runtime/runtime_stm32u585.go new file mode 100644 index 000000000..be878cc11 --- /dev/null +++ b/src/runtime/runtime_stm32u585.go @@ -0,0 +1,15 @@ +//go:build stm32u585 + +package runtime + +import ( + "machine" +) + +func init() { + initCLK() + + machine.InitSerial() + + initTickTimer(&machine.TIM16) +} diff --git a/targets/arduino-uno-q.json b/targets/arduino-uno-q.json new file mode 100644 index 000000000..89b0689f7 --- /dev/null +++ b/targets/arduino-uno-q.json @@ -0,0 +1,7 @@ +{ + "inherits": ["stm32u585"], + "build-tags": ["arduino_uno_q"], + "serial": "uart", + "openocd-interface": "stlink", + "openocd-target": "stm32u5x" +} diff --git a/targets/stm32u585.json b/targets/stm32u585.json new file mode 100644 index 000000000..2b6d6eeb3 --- /dev/null +++ b/targets/stm32u585.json @@ -0,0 +1,16 @@ +{ + "inherits": [ + "cortex-m33" + ], + "build-tags": [ + "stm32u585", + "stm32u5", + "stm32" + ], + "extra-files": [ + "src/device/stm32/stm32u585.s" + ], + "linkerscript": "targets/stm32u585.ld", + "flash-method": "openocd", + "openocd-target": "stm32u5x" +} diff --git a/targets/stm32u585.ld b/targets/stm32u585.ld new file mode 100644 index 000000000..c2ffd3c00 --- /dev/null +++ b/targets/stm32u585.ld @@ -0,0 +1,10 @@ + +MEMORY +{ + FLASH_TEXT (rw) : ORIGIN = 0x08000000, LENGTH = 2048K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 768K +} + +_stack_size = 4K; + +INCLUDE "targets/arm.ld"