mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
feat(machine/stm32): make HSE crystal frequency selectable.
Define the board's external crystal (HSE) frequency `xtalHz` in the respective `board_*.go` files. Per-topology PLL tables (F1, F4, F7) will compute the register dividers from it. Moving this parameter to the board definition level cleanly isolates board hardware characteristics from general MCU chip configurations, eliminating the need for custom target build tags. Targets using HSE-clocked STM32 chips must define `xtalHz` or fail to build.
This commit is contained in:
committed by
Ron Evans
parent
b8adb803c4
commit
5f02d6b659
@@ -7,6 +7,8 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const xtalHz = 8_000_000
|
||||
|
||||
// Pins printed on the silkscreen
|
||||
const (
|
||||
C13 = PC13
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const xtalHz = 12_000_000
|
||||
|
||||
const (
|
||||
NUM_DIGITAL_IO_PINS = 39
|
||||
NUM_ANALOG_IO_PINS = 7
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const xtalHz = 8_000_000
|
||||
|
||||
// LED is also wired to the SD card card detect (CD) pin.
|
||||
const LED = PD12
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const xtalHz = 8_000_000
|
||||
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED_BUILTIN = LED_GREEN
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const xtalHz = 8_000_000
|
||||
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED_BUILTIN = LED_GREEN
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const xtalHz = 8_000_000
|
||||
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED1 = LED_GREEN
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const xtalHz = 8_000_000
|
||||
|
||||
const (
|
||||
LED1 = LED_GREEN
|
||||
LED2 = LED_ORANGE
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
//go:build stm32
|
||||
|
||||
package machine
|
||||
|
||||
// PLLParams holds the HSE main-PLL dividers/multipliers (RCC_PLLCFGR M/N/P/Q/R
|
||||
// fields) needed to reach a chip's target VCO/SYSCLK frequency from a given
|
||||
// crystal frequency. R is left zero on chips without a PLLR output.
|
||||
type PLLParams struct {
|
||||
M, N, P, Q, R uint32
|
||||
}
|
||||
@@ -12,7 +12,10 @@ import (
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 72000000
|
||||
pll := PLLParams72MHz()
|
||||
// Prediv/Mul are raw RCC_CFGR register field values: the prescaler is
|
||||
// encoded as (divisor-1) and the multiplier as (multiplier-2).
|
||||
return xtalHz / (pll.Prediv + 1) * (pll.Mul + 2)
|
||||
}
|
||||
|
||||
var deviceIDAddr = []uintptr{0x1FFFF7E8, 0x1FFFF7EC, 0x1FFFF7F0}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//go:build stm32 && stm32f103
|
||||
|
||||
package machine
|
||||
|
||||
import "device/stm32"
|
||||
|
||||
// F103PLLParams holds the HSE prescaler (PLLXTPRE) and PLL multiplier
|
||||
// (PLLMUL) needed to reach 72MHz SYSCLK from a given crystal frequency. The
|
||||
// F1 PLL has no dedicated input divider, only an optional /2 HSE prescaler.
|
||||
type F103PLLParams struct {
|
||||
Prediv uint32
|
||||
Mul uint32
|
||||
}
|
||||
|
||||
func PLLParams72MHz() F103PLLParams {
|
||||
switch xtalHz {
|
||||
case 8_000_000:
|
||||
return F103PLLParams{Prediv: stm32.RCC_CFGR_PLLXTPRE_Div1, Mul: stm32.RCC_CFGR_PLLMUL_Mul9}
|
||||
case 12_000_000:
|
||||
return F103PLLParams{Prediv: stm32.RCC_CFGR_PLLXTPRE_Div1, Mul: stm32.RCC_CFGR_PLLMUL_Mul6}
|
||||
case 16_000_000:
|
||||
// 16MHz / 2 (PLLXTPRE) x9 = 72MHz.
|
||||
return F103PLLParams{Prediv: stm32.RCC_CFGR_PLLXTPRE_Div2, Mul: stm32.RCC_CFGR_PLLMUL_Mul9}
|
||||
default:
|
||||
panic("unsupported xtal frequency")
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,8 @@
|
||||
package machine
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 168000000
|
||||
pll := PLLParams168MHz()
|
||||
return xtalHz / pll.M * pll.N / pll.P
|
||||
}
|
||||
|
||||
// Internal use: configured speed of the APB1 and APB2 timers, this should be kept
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
package machine
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 180000000
|
||||
pll := PLLParams180MHz()
|
||||
return xtalHz / pll.M * pll.N / pll.P
|
||||
}
|
||||
|
||||
// Internal use: configured speed of the APB1 and APB2 timers, this should be kept
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//go:build stm32f4 && (stm32f405 || stm32f407)
|
||||
|
||||
package machine
|
||||
|
||||
// PLLParams168MHz returns the HSE PLL dividers needed to reach a 336MHz VCO
|
||||
// (168MHz SYSCLK, P=2, Q=7) for the configured crystal frequency. M is chosen
|
||||
// to bring the PLL input (HSE/M) to 2MHz, the value RM0090 pg. 95 recommends
|
||||
// to minimize jitter; the previous hardcoded F407 table used 1MHz.
|
||||
func PLLParams168MHz() PLLParams {
|
||||
switch xtalHz {
|
||||
case 8_000_000:
|
||||
return PLLParams{M: 4, N: 168, P: 2, Q: 7}
|
||||
case 12_000_000:
|
||||
return PLLParams{M: 6, N: 168, P: 2, Q: 7}
|
||||
case 16_000_000:
|
||||
return PLLParams{M: 8, N: 168, P: 2, Q: 7}
|
||||
default:
|
||||
panic("unsupported xtal frequency")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//go:build stm32f4 && stm32f469
|
||||
|
||||
package machine
|
||||
|
||||
// PLLParams180MHz returns the HSE PLL dividers needed to reach a 360MHz VCO
|
||||
// (180MHz SYSCLK, P=2, Q=7, R=6) for the configured crystal frequency.
|
||||
func PLLParams180MHz() PLLParams {
|
||||
switch xtalHz {
|
||||
case 8_000_000:
|
||||
return PLLParams{M: 4, N: 180, P: 2, Q: 7, R: 6}
|
||||
case 12_000_000:
|
||||
return PLLParams{M: 6, N: 180, P: 2, Q: 7, R: 6}
|
||||
case 16_000_000:
|
||||
return PLLParams{M: 8, N: 180, P: 2, Q: 7, R: 6}
|
||||
default:
|
||||
panic("unsupported xtal frequency")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//go:build stm32 && stm32f7x2
|
||||
|
||||
package machine
|
||||
|
||||
// PLLParams216MHz returns the HSE PLL dividers needed to reach a 432MHz VCO
|
||||
// (216MHz SYSCLK, P=2, Q=9) for the configured crystal frequency.
|
||||
func PLLParams216MHz() PLLParams {
|
||||
switch xtalHz {
|
||||
case 8_000_000:
|
||||
return PLLParams{M: 4, N: 216, P: 2, Q: 9}
|
||||
case 12_000_000:
|
||||
return PLLParams{M: 6, N: 216, P: 2, Q: 9}
|
||||
case 16_000_000:
|
||||
return PLLParams{M: 8, N: 216, P: 2, Q: 9}
|
||||
default:
|
||||
panic("unsupported xtal frequency")
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,8 @@ import (
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 216000000
|
||||
pll := PLLParams216MHz()
|
||||
return xtalHz / pll.M * pll.N / pll.P
|
||||
}
|
||||
|
||||
// Internal use: configured speed of the APB1 and APB2 timers, this should be kept
|
||||
|
||||
@@ -31,8 +31,10 @@ func buffered() int {
|
||||
return machine.Serial.Buffered()
|
||||
}
|
||||
|
||||
// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz).
|
||||
// initCLK sets clock to 72MHz using the board's HSE crystal (defined by the xtalHz) w/ PLL.
|
||||
func initCLK() {
|
||||
pll := machine.PLLParams72MHz()
|
||||
|
||||
stm32.FLASH.ACR.SetBits(stm32.FLASH_ACR_LATENCY_WS2) // Two wait states, per datasheet
|
||||
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PPRE1_Div2 << stm32.RCC_CFGR_PPRE1_Pos) // prescale PCLK1 = HCLK/2
|
||||
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PPRE2_Div1 << stm32.RCC_CFGR_PPRE2_Pos) // prescale PCLK2 = HCLK/1
|
||||
@@ -49,9 +51,10 @@ func initCLK() {
|
||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSIRDY) {
|
||||
}
|
||||
|
||||
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PLLSRC) // set PLL source to HSE
|
||||
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PLLMUL_Mul9 << stm32.RCC_CFGR_PLLMUL_Pos) // multiply by 9
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON) // enable the PLL
|
||||
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PLLSRC) // set PLL source to HSE
|
||||
stm32.RCC.CFGR.SetBits(pll.Prediv << stm32.RCC_CFGR_PLLXTPRE_Pos) // optional HSE /2 prescaler
|
||||
stm32.RCC.CFGR.SetBits(pll.Mul << stm32.RCC_CFGR_PLLMUL_Pos) // PLL multiplier
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON) // enable the PLL
|
||||
|
||||
// wait for the PLLRDY flag
|
||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||
|
||||
@@ -73,7 +73,7 @@ func initCLK() {
|
||||
// PCLK1 = HCLK / 4
|
||||
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PPRE1_Div4 << stm32.RCC_CFGR_PPRE1_Pos)
|
||||
// Configure the main PLL
|
||||
stm32.RCC.PLLCFGR.Set(PLL_CFGR)
|
||||
stm32.RCC.PLLCFGR.Set(pllCFGR())
|
||||
// Enable main PLL
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
|
||||
// Wait till the main PLL is ready
|
||||
|
||||
@@ -8,15 +8,15 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// +----------------------+
|
||||
// | Clock Settings |
|
||||
// +-------------+--------+
|
||||
// | HSE | 12mhz |
|
||||
// | SYSCLK | 168mhz |
|
||||
// | HCLK | 168mhz |
|
||||
// | APB1(PCLK1) | 42mhz |
|
||||
// | APB2(PCLK2) | 84mhz |
|
||||
// +-------------+--------+
|
||||
// +---------------------------------------------+
|
||||
// | Clock Settings |
|
||||
// +-------------+-------------------------------+
|
||||
// | HSE | selectable (xtal_8/12/16_mhz) |
|
||||
// | SYSCLK | 168mhz |
|
||||
// | HCLK | 168mhz |
|
||||
// | APB1(PCLK1) | 42mhz |
|
||||
// | APB2(PCLK2) | 84mhz |
|
||||
// +-------------+-------------------------------+
|
||||
HCLK_FREQ_HZ = 168000000
|
||||
PCLK1_FREQ_HZ = HCLK_FREQ_HZ / 4
|
||||
PCLK2_FREQ_HZ = HCLK_FREQ_HZ / 2
|
||||
@@ -29,11 +29,6 @@ const (
|
||||
PLL_SRC_HSE = 1 << stm32.RCC_PLLCFGR_PLLSRC_Pos // use HSE for PLL and PLLI2S
|
||||
PLL_SRC_HSI = 0 // use HSI for PLL and PLLI2S
|
||||
|
||||
PLL_DIV_M = 6 << stm32.RCC_PLLCFGR_PLLM_Pos
|
||||
PLL_MLT_N = 168 << stm32.RCC_PLLCFGR_PLLN_Pos
|
||||
PLL_DIV_P = ((2 >> 1) - 1) << stm32.RCC_PLLCFGR_PLLP_Pos
|
||||
PLL_DIV_Q = 7 << stm32.RCC_PLLCFGR_PLLQ_Pos
|
||||
|
||||
SYSCLK_SRC_PLL = stm32.RCC_CFGR_SW_PLL << stm32.RCC_CFGR_SW_Pos
|
||||
SYSCLK_STAT_PLL = stm32.RCC_CFGR_SWS_PLL << stm32.RCC_CFGR_SWS_Pos
|
||||
|
||||
@@ -94,7 +89,12 @@ func initOSC() {
|
||||
}
|
||||
|
||||
// set HSE as PLL source and configure clock divisors
|
||||
stm32.RCC.PLLCFGR.Set(PLL_SRC_HSE | PLL_DIV_M | PLL_MLT_N | PLL_DIV_P | PLL_DIV_Q)
|
||||
pll := machine.PLLParams168MHz()
|
||||
stm32.RCC.PLLCFGR.Set(PLL_SRC_HSE |
|
||||
pll.M<<stm32.RCC_PLLCFGR_PLLM_Pos |
|
||||
pll.N<<stm32.RCC_PLLCFGR_PLLN_Pos |
|
||||
((pll.P>>1)-1)<<stm32.RCC_PLLCFGR_PLLP_Pos |
|
||||
pll.Q<<stm32.RCC_PLLCFGR_PLLQ_Pos)
|
||||
|
||||
// enable PLL and wait for it to sync
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
|
||||
|
||||
@@ -2,26 +2,28 @@
|
||||
|
||||
package runtime
|
||||
|
||||
import "device/stm32"
|
||||
import (
|
||||
"device/stm32"
|
||||
"machine"
|
||||
)
|
||||
|
||||
/*
|
||||
clock settings
|
||||
|
||||
+-------------+--------+
|
||||
| HSE | 8mhz |
|
||||
| SYSCLK | 168mhz |
|
||||
| HCLK | 168mhz |
|
||||
| APB2(PCLK2) | 84mhz |
|
||||
| APB1(PCLK1) | 42mhz |
|
||||
+-------------+--------+
|
||||
+-------------+--------------------------------+
|
||||
| HSE | selectable (xtal_8/12/16_mhz) |
|
||||
| SYSCLK | 168mhz |
|
||||
| HCLK | 168mhz |
|
||||
| APB2(PCLK2) | 84mhz |
|
||||
| APB1(PCLK1) | 42mhz |
|
||||
+-------------+--------------------------------+
|
||||
*/
|
||||
const (
|
||||
HSE_STARTUP_TIMEOUT = 0x0500
|
||||
// PLL Options - See RM0090 Reference Manual pg. 95
|
||||
PLL_M = 8 // PLL_VCO = (HSE_VALUE or HSI_VLAUE / PLL_M) * PLL_N
|
||||
PLL_N = 336
|
||||
PLL_P = 2 // SYSCLK = PLL_VCO / PLL_P
|
||||
PLL_Q = 7 // USB OTS FS, SDIO and RNG Clock = PLL_VCO / PLL_Q
|
||||
PLL_CFGR = PLL_M | (PLL_N << stm32.RCC_PLLCFGR_PLLN_Pos) | (((PLL_P >> 1) - 1) << stm32.RCC_PLLCFGR_PLLP_Pos) |
|
||||
(1 << stm32.RCC_PLLCFGR_PLLSRC_Pos) | (PLL_Q << stm32.RCC_PLLCFGR_PLLQ_Pos)
|
||||
)
|
||||
const HSE_STARTUP_TIMEOUT = 0x0500
|
||||
|
||||
// pllCFGR builds the RCC_PLLCFGR value for the current xtal - see RM0090
|
||||
// Reference Manual pg. 95.
|
||||
func pllCFGR() uint32 {
|
||||
pll := machine.PLLParams168MHz()
|
||||
return pll.M | (pll.N << stm32.RCC_PLLCFGR_PLLN_Pos) | (((pll.P >> 1) - 1) << stm32.RCC_PLLCFGR_PLLP_Pos) |
|
||||
(1 << stm32.RCC_PLLCFGR_PLLSRC_Pos) | (pll.Q << stm32.RCC_PLLCFGR_PLLQ_Pos)
|
||||
}
|
||||
|
||||
@@ -2,27 +2,28 @@
|
||||
|
||||
package runtime
|
||||
|
||||
import "device/stm32"
|
||||
import (
|
||||
"device/stm32"
|
||||
"machine"
|
||||
)
|
||||
|
||||
/*
|
||||
clock settings
|
||||
|
||||
+-------------+--------+
|
||||
| HSE | 8mhz |
|
||||
| SYSCLK | 180mhz |
|
||||
| HCLK | 180mhz |
|
||||
| APB2(PCLK2) | 90mhz |
|
||||
| APB1(PCLK1) | 45mhz |
|
||||
+-------------+--------+
|
||||
+-------------+--------------------------------+
|
||||
| HSE | selectable (xtal_8/12/16_mhz) |
|
||||
| SYSCLK | 180mhz |
|
||||
| HCLK | 180mhz |
|
||||
| APB2(PCLK2) | 90mhz |
|
||||
| APB1(PCLK1) | 45mhz |
|
||||
+-------------+--------------------------------+
|
||||
*/
|
||||
const (
|
||||
HSE_STARTUP_TIMEOUT = 0x0500
|
||||
// PLL Options - See RM0386 Reference Manual pg. 148
|
||||
PLL_M = 8 // PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
|
||||
PLL_N = 360
|
||||
PLL_P = 2 // SYSCLK = PLL_VCO / PLL_P
|
||||
PLL_Q = 7 // USB OTS FS, SDIO and RNG Clock = PLL_VCO / PLL_Q
|
||||
PLL_R = 6 // DSI
|
||||
PLL_CFGR = PLL_M | (PLL_N << stm32.RCC_PLLCFGR_PLLN_Pos) | (((PLL_P >> 1) - 1) << stm32.RCC_PLLCFGR_PLLP_Pos) |
|
||||
(1 << stm32.RCC_PLLCFGR_PLLSRC_Pos) | (PLL_Q << stm32.RCC_PLLCFGR_PLLQ_Pos) | (PLL_R << stm32.RCC_PLLCFGR_PLLR_Pos)
|
||||
)
|
||||
const HSE_STARTUP_TIMEOUT = 0x0500
|
||||
|
||||
// pllCFGR builds the RCC_PLLCFGR value for the current xtal - see RM0386
|
||||
// Reference Manual pg. 148.
|
||||
func pllCFGR() uint32 {
|
||||
pll := machine.PLLParams180MHz()
|
||||
return pll.M | (pll.N << stm32.RCC_PLLCFGR_PLLN_Pos) | (((pll.P >> 1) - 1) << stm32.RCC_PLLCFGR_PLLP_Pos) |
|
||||
(1 << stm32.RCC_PLLCFGR_PLLSRC_Pos) | (pll.Q << stm32.RCC_PLLCFGR_PLLQ_Pos) | (pll.R << stm32.RCC_PLLCFGR_PLLR_Pos)
|
||||
}
|
||||
|
||||
@@ -10,21 +10,15 @@ import (
|
||||
/*
|
||||
clock settings
|
||||
|
||||
+-------------+--------+
|
||||
| HSE | 8mhz |
|
||||
| SYSCLK | 216mhz |
|
||||
| HCLK | 216mhz |
|
||||
| APB1(PCLK1) | 27mhz |
|
||||
| APB2(PCLK2) | 108mhz |
|
||||
+-------------+--------+
|
||||
+-------------+--------------------------------+
|
||||
| HSE | selectable (xtal_8/12/16_mhz) |
|
||||
| SYSCLK | 216mhz |
|
||||
| HCLK | 216mhz |
|
||||
| APB1(PCLK1) | 27mhz |
|
||||
| APB2(PCLK2) | 108mhz |
|
||||
+-------------+--------------------------------+
|
||||
*/
|
||||
const (
|
||||
HSE_STARTUP_TIMEOUT = 0x0500
|
||||
PLL_M = 4
|
||||
PLL_N = 216
|
||||
PLL_P = 2
|
||||
PLL_Q = 9
|
||||
)
|
||||
const HSE_STARTUP_TIMEOUT = 0x0500
|
||||
|
||||
func init() {
|
||||
initCLK()
|
||||
@@ -107,12 +101,13 @@ func initOsc() {
|
||||
}
|
||||
|
||||
// Configure the PLL: HSE as source, use SVD constants for positions.
|
||||
pll := machine.PLLParams216MHz()
|
||||
stm32.RCC.PLLCFGR.Set(
|
||||
(stm32.RCC_PLLCFGR_PLLSRC_HSE << stm32.RCC_PLLCFGR_PLLSRC_Pos) |
|
||||
(PLL_M << stm32.RCC_PLLCFGR_PLLM_Pos) |
|
||||
(PLL_N << stm32.RCC_PLLCFGR_PLLN_Pos) |
|
||||
(((PLL_P >> 1) - 1) << stm32.RCC_PLLCFGR_PLLP_Pos) |
|
||||
(PLL_Q << stm32.RCC_PLLCFGR_PLLQ_Pos))
|
||||
(pll.M << stm32.RCC_PLLCFGR_PLLM_Pos) |
|
||||
(pll.N << stm32.RCC_PLLCFGR_PLLN_Pos) |
|
||||
(((pll.P >> 1) - 1) << stm32.RCC_PLLCFGR_PLLP_Pos) |
|
||||
(pll.Q << stm32.RCC_PLLCFGR_PLLQ_Pos))
|
||||
|
||||
// Enable the PLL, wait until ready
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
|
||||
|
||||
Reference in New Issue
Block a user