diff --git a/make/smoketest.mk b/make/smoketest.mk index 9b540da947..7ef6edf170 100644 --- a/make/smoketest.mk +++ b/make/smoketest.mk @@ -362,6 +362,8 @@ ifneq ($(STM32), 0) @$(MD5SUM) $(SMOKE_OUT).hex $(TINYGO) build -size short -o $(SMOKE_OUT).hex -target=nucleo-f103rb examples/blinky1 @$(MD5SUM) $(SMOKE_OUT).hex + $(TINYGO) build -size short -o $(SMOKE_OUT).hex -target=nucleo-f401re examples/blinky1 + @$(MD5SUM) $(SMOKE_OUT).hex $(TINYGO) build -size short -o $(SMOKE_OUT).hex -target=nucleo-f722ze examples/blinky1 @$(MD5SUM) $(SMOKE_OUT).hex $(TINYGO) build -size short -o $(SMOKE_OUT).hex -target=nucleo-h753zi examples/blinky1 @@ -384,6 +386,8 @@ ifneq ($(STM32), 0) @$(MD5SUM) $(SMOKE_OUT).hex $(TINYGO) build -size short -o $(SMOKE_OUT).hex -target=stm32f4disco-1 examples/pwm @$(MD5SUM) $(SMOKE_OUT).hex + $(TINYGO) build -size short -o $(SMOKE_OUT).hex -target=nucleo-f401re examples/pwm + @$(MD5SUM) $(SMOKE_OUT).hex $(TINYGO) build -size short -o $(SMOKE_OUT).hex -target=stm32f469disco examples/blinky1 @$(MD5SUM) $(SMOKE_OUT).hex $(TINYGO) build -size short -o $(SMOKE_OUT).hex -target=lorae5 examples/blinky1 diff --git a/src/crypto/rand/rand_baremetal.go b/src/crypto/rand/rand_baremetal.go index 6cf847ae64..82b43ad7ed 100644 --- a/src/crypto/rand/rand_baremetal.go +++ b/src/crypto/rand/rand_baremetal.go @@ -1,4 +1,4 @@ -//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1 || stm32u0)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt) +//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1 || stm32u0 || stm32f401)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt) // If you update the above build constraint, you'll probably also need to update // src/runtime/rand_hwrng.go. diff --git a/src/examples/pwm/nucleo-f401re.go b/src/examples/pwm/nucleo-f401re.go new file mode 100644 index 0000000000..821dec297f --- /dev/null +++ b/src/examples/pwm/nucleo-f401re.go @@ -0,0 +1,13 @@ +//go:build nucleof401re + +package main + +import "machine" + +// TIM3 is reserved by the runtime tick timer on STM32F401. +// Use TIM2 instead: PB10=D6 (TIM2_CH3/AF1), PB3=D3 (TIM2_CH2/AF1). +var ( + pwm = &machine.TIM2 + pinA = machine.D6 + pinB = machine.D3 +) diff --git a/src/machine/board_nucleof401re.go b/src/machine/board_nucleof401re.go new file mode 100644 index 0000000000..8b194c5f2e --- /dev/null +++ b/src/machine/board_nucleof401re.go @@ -0,0 +1,140 @@ +//go:build nucleof401re + +// Schematic: https://www.st.com/resource/en/user_manual/um1724-stm32-nucleo64-boards-mb1136-stmicroelectronics.pdf +// Datasheet: https://www.st.com/resource/en/datasheet/stm32f401re.pdf + +package machine + +import ( + "device/stm32" + "runtime/interrupt" +) + +const xtalHz = 8_000_000 + +const ( + // Arduino Pins + A0 = PA0 + A1 = PA1 + A2 = PA4 + A3 = PB0 + A4 = PC1 + A5 = PC0 + + D0 = PA3 + D1 = PA2 + D2 = PA10 + D3 = PB3 + D4 = PB5 + D5 = PB4 + D6 = PB10 + D7 = PA8 + D8 = PA9 + D9 = PC7 + D10 = PB6 + D11 = PA7 + D12 = PA6 + D13 = PA5 + D14 = PB9 + D15 = PB8 +) + +// Analog pins (ADC1 channels). +// examples/adc uses ADC2 (PA2). That pin is ST-Link VCP TX, so use A0 instead. +const ( + ADC0 = PA0 + ADC1 = PA1 + ADC2 = PA2 + ADC3 = PA3 + ADC4 = PA4 + ADC5 = PA5 + ADC6 = PA6 + ADC7 = PA7 + ADC8 = PB0 + ADC9 = PB1 + ADC10 = PC0 + ADC11 = PC1 + ADC12 = PC2 + ADC13 = PC3 + ADC14 = PC4 + ADC15 = PC5 +) + +// User LD2: the green LED is a user LED connected to Arduino signal D13 +// corresponding to STM32 I/O PA5. +const ( + LED = LED_BUILTIN + LED_BUILTIN = LED_GREEN + LED_GREEN = PA5 +) + +// BUTTON is the user button B1 connected to PC13 (active low). +const BUTTON = PC13 + +const ( + // UART pins + // PA2 and PA3 are connected to the ST-Link Virtual Com Port (VCP). + UART_TX_PIN = PA2 + UART_RX_PIN = PA3 + UART1_TX_PIN = UART_TX_PIN + UART1_RX_PIN = UART_RX_PIN + + // USART1 on Arduino D8 (PA9 = TX) / D2 (PA10 = RX). + // Use for external UART communication (e.g. with another board). + UART2_TX_PIN = PA9 + UART2_RX_PIN = PA10 + + // I2C pins + // PB8 / Arduino D15 is SCL, PB9 / Arduino D14 is SDA. + I2C0_SCL_PIN = PB8 + I2C0_SDA_PIN = PB9 + + // SPI pins + SPI1_SCK_PIN = PA5 + SPI1_SDI_PIN = PA6 + SPI1_SDO_PIN = PA7 + SPI0_SCK_PIN = SPI1_SCK_PIN + SPI0_SDI_PIN = SPI1_SDI_PIN + SPI0_SDO_PIN = SPI1_SDO_PIN +) + +var ( + // USART2 is the hardware serial port connected to the onboard ST-LINK + // debugger, exposed as a virtual COM port over USB. + UART1 = &_UART1 + _UART1 = UART{ + Buffer: NewRingBuffer(), + Bus: stm32.USART2, + TxAltFuncSelector: AF7_USART1_2_3, + RxAltFuncSelector: AF7_USART1_2_3, + } + DefaultUART = UART1 + + // USART1 on PA9 (TX=D8) / PA10 (RX=D2). Use for external communication. + UART2 = &_UART2 + _UART2 = UART{ + Buffer: NewRingBuffer(), + Bus: stm32.USART1, + TxAltFuncSelector: AF7_USART1_2_3, + RxAltFuncSelector: AF7_USART1_2_3, + } + + // I2C1 is documented; I2C0 is an alias. + I2C1 = &I2C{ + Bus: stm32.I2C1, + AltFuncSelector: AF4_I2C1_2_3, + } + I2C0 = I2C1 + + // SPI1 is documented; SPI0 is an alias. + SPI1 = &SPI{ + Bus: stm32.SPI1, + AltFuncSelector: AF5_SPI1_SPI2, + } + SPI0 = SPI1 +) + +func init() { + UART1.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART1.handleInterrupt) + UART2.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART2.handleInterrupt) +} diff --git a/src/machine/machine_stm32_adc_f4.go b/src/machine/machine_stm32_adc_f4.go index df4984c1b4..f47d48978c 100644 --- a/src/machine/machine_stm32_adc_f4.go +++ b/src/machine/machine_stm32_adc_f4.go @@ -37,12 +37,15 @@ func InitADC() { func (a ADC) Configure(ADCConfig) { a.Pin.ConfigureAltFunc(PinConfig{Mode: PinInputAnalog}, 0) - // set sample time + // set sample time (84 ADC cycles). Each SMPx field is 3 bits wide; the + // encoding for 84 cycles is 4. Named Cycles84 constants are not present + // in every F4 SVD, so use the literal values. + const cycles84 = 4 ch := a.getChannel() if ch > 9 { - stm32.ADC1.SMPR1.SetBits(stm32.ADC_SMPR1_SMP11_Cycles84 << (ch - 10) * stm32.ADC_SMPR1_SMP11_Pos) + stm32.ADC1.SMPR1.SetBits(cycles84 << ((ch - 10) * 3)) } else { - stm32.ADC1.SMPR2.SetBits(stm32.ADC_SMPR2_SMP1_Cycles84 << (ch * stm32.ADC_SMPR2_SMP1_Pos)) + stm32.ADC1.SMPR2.SetBits(cycles84 << (ch * 3)) } return diff --git a/src/machine/machine_stm32_otgfs_usb.go b/src/machine/machine_stm32_otgfs_usb.go index 639a301ee7..0048838c08 100644 --- a/src/machine/machine_stm32_otgfs_usb.go +++ b/src/machine/machine_stm32_otgfs_usb.go @@ -1,4 +1,6 @@ -//go:build stm32f4 || stm32f7 +// NUCLEO-F401RE has no USB OTG connector. This chip-wide exclude +// also blocks later F401 boards that have USB (for example Blackpill F401CC). +//go:build (stm32f4 && !stm32f401) || stm32f7 package machine diff --git a/src/machine/machine_stm32_rng.go b/src/machine/machine_stm32_rng.go index 5b05d2daa7..318f5dc1ad 100644 --- a/src/machine/machine_stm32_rng.go +++ b/src/machine/machine_stm32_rng.go @@ -1,4 +1,4 @@ -//go:build stm32 && !(stm32f103 || stm32l0x1 || stm32g0 || stm32u0) +//go:build stm32 && !(stm32f103 || stm32l0x1 || stm32g0 || stm32u0 || stm32f401) package machine diff --git a/src/machine/machine_stm32f4.go b/src/machine/machine_stm32f4.go index 2a989b10a8..e7ab21298f 100644 --- a/src/machine/machine_stm32f4.go +++ b/src/machine/machine_stm32f4.go @@ -188,35 +188,6 @@ const ( PK15 = portK + 15 ) -func (p Pin) getPort() *stm32.GPIO_Type { - switch p / 16 { - case 0: - return stm32.GPIOA - case 1: - return stm32.GPIOB - case 2: - return stm32.GPIOC - case 3: - return stm32.GPIOD - case 4: - return stm32.GPIOE - case 5: - return stm32.GPIOF - case 6: - return stm32.GPIOG - case 7: - return stm32.GPIOH - case 8: - return stm32.GPIOI - case 9: - return stm32.GPIOJ - case 10: - return stm32.GPIOK - default: - panic("machine: unknown port") - } -} - // enableClock enables the clock for this desired GPIO port. func (p Pin) enableClock() { bit := p / 16 @@ -268,84 +239,6 @@ func (p Pin) registerInterrupt() interrupt.Interrupt { return interrupt.Interrupt{} } -// Enable peripheral clock -func enableAltFuncClock(bus unsafe.Pointer) { - switch bus { - case unsafe.Pointer(stm32.DAC): // DAC interface clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_DACEN) - case unsafe.Pointer(stm32.PWR): // Power interface clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN) - case unsafe.Pointer(stm32.CAN2): // CAN 2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_CAN2EN) - case unsafe.Pointer(stm32.CAN1): // CAN 1 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_CAN1EN) - case unsafe.Pointer(stm32.I2C3): // I2C3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C3EN) - case unsafe.Pointer(stm32.I2C2): // I2C2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C2EN) - case unsafe.Pointer(stm32.I2C1): // I2C1 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN) - case unsafe.Pointer(stm32.UART5): // UART5 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_UART5EN) - case unsafe.Pointer(stm32.UART4): // UART4 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_UART4EN) - case unsafe.Pointer(stm32.USART3): // USART3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART3EN) - case unsafe.Pointer(stm32.USART2): // USART2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN) - case unsafe.Pointer(stm32.SPI3): // SPI3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI3EN) - case unsafe.Pointer(stm32.SPI2): // SPI2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI2EN) - case unsafe.Pointer(stm32.WWDG): // Window watchdog clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_WWDGEN) - case unsafe.Pointer(stm32.TIM14): // TIM14 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM14EN) - case unsafe.Pointer(stm32.TIM13): // TIM13 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM13EN) - case unsafe.Pointer(stm32.TIM12): // TIM12 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM12EN) - case unsafe.Pointer(stm32.TIM7): // TIM7 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN) - case unsafe.Pointer(stm32.TIM6): // TIM6 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM6EN) - case unsafe.Pointer(stm32.TIM5): // TIM5 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM5EN) - case unsafe.Pointer(stm32.TIM4): // TIM4 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM4EN) - case unsafe.Pointer(stm32.TIM3): // TIM3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN) - case unsafe.Pointer(stm32.TIM2): // TIM2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM2EN) - case unsafe.Pointer(stm32.TIM11): // TIM11 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM11EN) - case unsafe.Pointer(stm32.TIM10): // TIM10 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM10EN) - case unsafe.Pointer(stm32.TIM9): // TIM9 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM9EN) - case unsafe.Pointer(stm32.SYSCFG): // System configuration controller clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN) - case unsafe.Pointer(stm32.SPI1): // SPI1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN) - case unsafe.Pointer(stm32.SDIO): // SDIO clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SDIOEN) - case unsafe.Pointer(stm32.ADC3): // ADC3 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC3EN) - case unsafe.Pointer(stm32.ADC2): // ADC2 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC2EN) - case unsafe.Pointer(stm32.ADC1): // ADC1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC1EN) - case unsafe.Pointer(stm32.USART6): // USART6 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART6EN) - case unsafe.Pointer(stm32.USART1): // USART1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) - case unsafe.Pointer(stm32.TIM8): // TIM8 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM8EN) - case unsafe.Pointer(stm32.TIM1): // TIM1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN) - } -} - //---------- Timer related code var ( @@ -414,45 +307,6 @@ var ( busFreq: APB1_TIM_FREQ, } - TIM6 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM6EN, - Device: stm32.TIM6, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM7 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM7EN, - Device: stm32.TIM7, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM8 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM8EN, - Device: stm32.TIM8, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PC6, AF3_TIM8_9_10_11}, {PI5, AF3_TIM8_9_10_11}}}, - TimerChannel{Pins: []PinFunction{{PC7, AF3_TIM8_9_10_11}, {PI6, AF3_TIM8_9_10_11}}}, - TimerChannel{Pins: []PinFunction{{PC8, AF3_TIM8_9_10_11}, {PI7, AF3_TIM8_9_10_11}}}, - TimerChannel{Pins: []PinFunction{{PC9, AF3_TIM8_9_10_11}, {PI2, AF3_TIM8_9_10_11}}}, - }, - busFreq: APB2_TIM_FREQ, - } - TIM9 = TIM{ EnableRegister: &stm32.RCC.APB2ENR, EnableFlag: stm32.RCC_APB2ENR_TIM9EN, @@ -491,117 +345,8 @@ var ( }, busFreq: APB2_TIM_FREQ, } - - TIM12 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM12EN, - Device: stm32.TIM12, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PB14, AF9_CAN1_CAN2_TIM12_13_14}, {PH6, AF9_CAN1_CAN2_TIM12_13_14}}}, - TimerChannel{Pins: []PinFunction{{PB15, AF9_CAN1_CAN2_TIM12_13_14}, {PH9, AF9_CAN1_CAN2_TIM12_13_14}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM13 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM13EN, - Device: stm32.TIM13, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA6, AF9_CAN1_CAN2_TIM12_13_14}, {PF8, AF9_CAN1_CAN2_TIM12_13_14}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM14 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM14EN, - Device: stm32.TIM14, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA7, AF9_CAN1_CAN2_TIM12_13_14}, {PF9, AF9_CAN1_CAN2_TIM12_13_14}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } ) -func (t *TIM) registerUPInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM1.handleUPInterrupt) - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleUPInterrupt) - case &TIM4: - return interrupt.New(stm32.IRQ_TIM4, TIM4.handleUPInterrupt) - case &TIM5: - return interrupt.New(stm32.IRQ_TIM5, TIM5.handleUPInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6_DAC, TIM6.handleUPInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleUPInterrupt) - case &TIM8: - return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM8.handleUPInterrupt) - case &TIM9: - return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleUPInterrupt) - case &TIM10: - return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleUPInterrupt) - case &TIM11: - return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleUPInterrupt) - case &TIM12: - return interrupt.New(stm32.IRQ_TIM8_BRK_TIM12, TIM12.handleUPInterrupt) - case &TIM13: - return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM13.handleUPInterrupt) - case &TIM14: - return interrupt.New(stm32.IRQ_TIM8_TRG_COM_TIM14, TIM14.handleUPInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) registerOCInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(stm32.IRQ_TIM1_CC, TIM1.handleOCInterrupt) - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleOCInterrupt) - case &TIM4: - return interrupt.New(stm32.IRQ_TIM4, TIM4.handleOCInterrupt) - case &TIM5: - return interrupt.New(stm32.IRQ_TIM5, TIM5.handleOCInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6_DAC, TIM6.handleOCInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt) - case &TIM8: - return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM8.handleOCInterrupt) - case &TIM9: - return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleOCInterrupt) - case &TIM10: - return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleOCInterrupt) - case &TIM11: - return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleOCInterrupt) - case &TIM12: - return interrupt.New(stm32.IRQ_TIM8_BRK_TIM12, TIM12.handleOCInterrupt) - case &TIM13: - return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM13.handleOCInterrupt) - case &TIM14: - return interrupt.New(stm32.IRQ_TIM8_TRG_COM_TIM14, TIM14.handleOCInterrupt) - } - - return interrupt.Interrupt{} -} - func (t *TIM) enableMainOutput() { t.Device.BDTR.SetBits(stm32.TIM_BDTR_MOE) } @@ -615,11 +360,6 @@ const ( PSC_MAX = 0x10000 ) -func initRNG() { - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_RNGEN) - stm32.RNG.CR.SetBits(stm32.RNG_CR_RNGEN) -} - // Alternative peripheral pin functions const ( AF0_SYSTEM = 0 @@ -648,24 +388,25 @@ func (uart *UART) configurePins(config UARTConfig) { config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector) } +func (uart *UART) setRegisters() { + uart.rxReg = &uart.Bus.DR + uart.txReg = &uart.Bus.DR + uart.statusReg = &uart.Bus.SR + uart.txEmptyFlag = stm32.USART_SR_TXE +} + func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 { var clock uint32 switch uart.Bus { case stm32.USART1, stm32.USART6: - clock = CPUFrequency() / 2 // APB2 Frequency - case stm32.USART2, stm32.USART3, stm32.UART4, stm32.UART5: - clock = CPUFrequency() / 4 // APB1 Frequency + clock = APB2_FREQ + default: + // USART2 and (when present) USART3/UART4/UART5 are on APB1. + clock = APB1_FREQ } return clock / baudRate } -func (uart *UART) setRegisters() { - uart.rxReg = &uart.Bus.DR - uart.txReg = &uart.Bus.DR - uart.statusReg = &uart.Bus.SR - uart.txEmptyFlag = stm32.USART_SR_TXE -} - // -- SPI ---------------------------------------------------------------------- type SPI struct { @@ -687,9 +428,9 @@ func (spi *SPI) getBaudRate(config SPIConfig) uint32 { var clock uint32 switch spi.Bus { case stm32.SPI1: - clock = CPUFrequency() / 2 + clock = APB2_FREQ case stm32.SPI2, stm32.SPI3: - clock = CPUFrequency() / 4 + clock = APB1_FREQ } // limit requested frequency to bus frequency and min frequency (DIV256) @@ -733,7 +474,7 @@ func (i2c *I2C) configurePins(config I2CConfig) { func (i2c *I2C) getFreqRange(config I2CConfig) uint32 { // all I2C interfaces are on APB1 - clock := CPUFrequency() / 4 + var clock uint32 = APB1_FREQ // convert to MHz clock /= 1000000 // must be between 2 MHz (or 4 MHz for fast mode (Fm)) and 50 MHz, inclusive @@ -784,7 +525,7 @@ func (i2c *I2C) getSpeed(config I2CConfig) uint32 { } } // all I2C interfaces are on APB1 - clock := CPUFrequency() / 4 + var clock uint32 = APB1_FREQ if config.Frequency <= 100000 { return sm(clock, config.Frequency) } else { diff --git a/src/machine/machine_stm32f401.go b/src/machine/machine_stm32f401.go new file mode 100644 index 0000000000..7e73c4dbdd --- /dev/null +++ b/src/machine/machine_stm32f401.go @@ -0,0 +1,19 @@ +//go:build stm32f401 + +package machine + +// CPUFrequency returns the current CPU frequency of the STM32F401. +// The PLL is configured to 84MHz SYSCLK from an external crystal. +func CPUFrequency() uint32 { + pll := PLLParams84MHz() + return xtalHz / pll.M * pll.N / pll.P +} + +// Internal use: configured speed of the APB1 and APB2 buses and timers. +// STM32F401 at 84MHz: SYSCLK=84MHz, AHB=84MHz, APB1=42MHz, APB2=84MHz. +// APB1 prescaler = 2, so APB1 timer clock = 42MHz × 2 = 84MHz. +// APB2 prescaler = 1, so APB2 timer clock = 84MHz × 1 = 84MHz. +const APB1_FREQ = 42_000_000 +const APB2_FREQ = 84_000_000 +const APB1_TIM_FREQ = APB1_FREQ * 2 +const APB2_TIM_FREQ = APB2_FREQ diff --git a/src/machine/machine_stm32f401_periph.go b/src/machine/machine_stm32f401_periph.go new file mode 100644 index 0000000000..60f72e692a --- /dev/null +++ b/src/machine/machine_stm32f401_periph.go @@ -0,0 +1,130 @@ +//go:build stm32f401 + +package machine + +// STM32F401 peripheral implementations. The F401 has a reduced set of +// peripherals compared to F405/F407, so this file provides F401-specific +// versions of the functions in machine_stm32f40x_periph.go. + +import ( + "device/stm32" + "runtime/interrupt" + "unsafe" +) + +func (p Pin) getPort() *stm32.GPIO_Type { + switch p / 16 { + case 0: + return stm32.GPIOA + case 1: + return stm32.GPIOB + case 2: + return stm32.GPIOC + case 3: + return stm32.GPIOD + case 4: + return stm32.GPIOE + case 7: + return stm32.GPIOH + default: + panic("machine: unknown port") + } +} + +// Enable peripheral clock for STM32F401 peripherals. +func enableAltFuncClock(bus unsafe.Pointer) { + switch bus { + case unsafe.Pointer(stm32.PWR): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN) + case unsafe.Pointer(stm32.I2C3): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C3EN) + case unsafe.Pointer(stm32.I2C2): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C2EN) + case unsafe.Pointer(stm32.I2C1): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN) + case unsafe.Pointer(stm32.USART2): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN) + case unsafe.Pointer(stm32.SPI3): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI3EN) + case unsafe.Pointer(stm32.SPI2): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI2EN) + case unsafe.Pointer(stm32.WWDG): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_WWDGEN) + case unsafe.Pointer(stm32.TIM5): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM5EN) + case unsafe.Pointer(stm32.TIM4): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM4EN) + case unsafe.Pointer(stm32.TIM3): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN) + case unsafe.Pointer(stm32.TIM2): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM2EN) + case unsafe.Pointer(stm32.TIM11): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM11EN) + case unsafe.Pointer(stm32.TIM10): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM10EN) + case unsafe.Pointer(stm32.TIM9): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM9EN) + case unsafe.Pointer(stm32.SYSCFG): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN) + case unsafe.Pointer(stm32.SPI4): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI4EN) + case unsafe.Pointer(stm32.SPI1): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN) + case unsafe.Pointer(stm32.SDIO): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SDIOEN) + case unsafe.Pointer(stm32.ADC1): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC1EN) + case unsafe.Pointer(stm32.USART6): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART6EN) + case unsafe.Pointer(stm32.USART1): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) + case unsafe.Pointer(stm32.TIM1): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN) + } +} + +func (t *TIM) registerUPInterrupt() interrupt.Interrupt { + switch t { + case &TIM1: + return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM1.handleUPInterrupt) + case &TIM2: + return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt) + case &TIM3: + return interrupt.New(stm32.IRQ_TIM3, TIM3.handleUPInterrupt) + case &TIM4: + return interrupt.New(stm32.IRQ_TIM4, TIM4.handleUPInterrupt) + case &TIM5: + return interrupt.New(stm32.IRQ_TIM5, TIM5.handleUPInterrupt) + case &TIM9: + return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleUPInterrupt) + case &TIM10: + return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleUPInterrupt) + case &TIM11: + return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleUPInterrupt) + } + + return interrupt.Interrupt{} +} + +func (t *TIM) registerOCInterrupt() interrupt.Interrupt { + switch t { + case &TIM1: + return interrupt.New(stm32.IRQ_TIM1_CC, TIM1.handleOCInterrupt) + case &TIM2: + return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt) + case &TIM3: + return interrupt.New(stm32.IRQ_TIM3, TIM3.handleOCInterrupt) + case &TIM4: + return interrupt.New(stm32.IRQ_TIM4, TIM4.handleOCInterrupt) + case &TIM5: + return interrupt.New(stm32.IRQ_TIM5, TIM5.handleOCInterrupt) + case &TIM9: + return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleOCInterrupt) + case &TIM10: + return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleOCInterrupt) + case &TIM11: + return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleOCInterrupt) + } + + return interrupt.Interrupt{} +} diff --git a/src/machine/machine_stm32f40x.go b/src/machine/machine_stm32f40x.go index 5fcbbcbe86..afbd835220 100644 --- a/src/machine/machine_stm32f40x.go +++ b/src/machine/machine_stm32f40x.go @@ -7,8 +7,10 @@ func CPUFrequency() uint32 { return xtalHz / pll.M * pll.N / pll.P } -// 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 = 42000000 * 2 -const APB2_TIM_FREQ = 84000000 * 2 +// Internal use: configured speed of the APB1 and APB2 buses and timers, this +// should be kept in sync with any changes to runtime package which configures +// the oscillators and clock frequencies. +const APB1_FREQ = 42000000 +const APB2_FREQ = 84000000 +const APB1_TIM_FREQ = APB1_FREQ * 2 +const APB2_TIM_FREQ = APB2_FREQ * 2 diff --git a/src/machine/machine_stm32f40x_periph.go b/src/machine/machine_stm32f40x_periph.go new file mode 100644 index 0000000000..09dbb93f7c --- /dev/null +++ b/src/machine/machine_stm32f40x_periph.go @@ -0,0 +1,275 @@ +//go:build stm32f4 && (stm32f405 || stm32f407 || stm32f469) + +package machine + +// This file contains stm32f4 peripheral implementations for chips that have the +// full set of F4 peripherals (F405, F407, F469). Chips with fewer peripherals +// (e.g. F401) use machine_stm32f401_periph.go instead. + +import ( + "device/stm32" + "runtime/interrupt" + "unsafe" +) + +func (p Pin) getPort() *stm32.GPIO_Type { + switch p / 16 { + case 0: + return stm32.GPIOA + case 1: + return stm32.GPIOB + case 2: + return stm32.GPIOC + case 3: + return stm32.GPIOD + case 4: + return stm32.GPIOE + case 5: + return stm32.GPIOF + case 6: + return stm32.GPIOG + case 7: + return stm32.GPIOH + case 8: + return stm32.GPIOI + case 9: + return stm32.GPIOJ + case 10: + return stm32.GPIOK + default: + panic("machine: unknown port") + } +} + +// Enable peripheral clock +func enableAltFuncClock(bus unsafe.Pointer) { + switch bus { + case unsafe.Pointer(stm32.DAC): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_DACEN) + case unsafe.Pointer(stm32.PWR): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN) + case unsafe.Pointer(stm32.CAN2): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_CAN2EN) + case unsafe.Pointer(stm32.CAN1): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_CAN1EN) + case unsafe.Pointer(stm32.I2C3): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C3EN) + case unsafe.Pointer(stm32.I2C2): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C2EN) + case unsafe.Pointer(stm32.I2C1): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN) + case unsafe.Pointer(stm32.UART5): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_UART5EN) + case unsafe.Pointer(stm32.UART4): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_UART4EN) + case unsafe.Pointer(stm32.USART3): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART3EN) + case unsafe.Pointer(stm32.USART2): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN) + case unsafe.Pointer(stm32.SPI3): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI3EN) + case unsafe.Pointer(stm32.SPI2): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI2EN) + case unsafe.Pointer(stm32.WWDG): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_WWDGEN) + case unsafe.Pointer(stm32.TIM14): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM14EN) + case unsafe.Pointer(stm32.TIM13): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM13EN) + case unsafe.Pointer(stm32.TIM12): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM12EN) + case unsafe.Pointer(stm32.TIM7): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN) + case unsafe.Pointer(stm32.TIM6): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM6EN) + case unsafe.Pointer(stm32.TIM5): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM5EN) + case unsafe.Pointer(stm32.TIM4): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM4EN) + case unsafe.Pointer(stm32.TIM3): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN) + case unsafe.Pointer(stm32.TIM2): + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM2EN) + case unsafe.Pointer(stm32.TIM11): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM11EN) + case unsafe.Pointer(stm32.TIM10): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM10EN) + case unsafe.Pointer(stm32.TIM9): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM9EN) + case unsafe.Pointer(stm32.SYSCFG): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN) + case unsafe.Pointer(stm32.SPI1): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN) + case unsafe.Pointer(stm32.SDIO): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SDIOEN) + case unsafe.Pointer(stm32.ADC3): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC3EN) + case unsafe.Pointer(stm32.ADC2): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC2EN) + case unsafe.Pointer(stm32.ADC1): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC1EN) + case unsafe.Pointer(stm32.USART6): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART6EN) + case unsafe.Pointer(stm32.USART1): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) + case unsafe.Pointer(stm32.TIM8): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM8EN) + case unsafe.Pointer(stm32.TIM1): + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN) + } +} + +var ( + TIM6 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM6EN, + Device: stm32.TIM6, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM7 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM7EN, + Device: stm32.TIM7, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM8 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM8EN, + Device: stm32.TIM8, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PC6, AF3_TIM8_9_10_11}, {PI5, AF3_TIM8_9_10_11}}}, + TimerChannel{Pins: []PinFunction{{PC7, AF3_TIM8_9_10_11}, {PI6, AF3_TIM8_9_10_11}}}, + TimerChannel{Pins: []PinFunction{{PC8, AF3_TIM8_9_10_11}, {PI7, AF3_TIM8_9_10_11}}}, + TimerChannel{Pins: []PinFunction{{PC9, AF3_TIM8_9_10_11}, {PI2, AF3_TIM8_9_10_11}}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM12 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM12EN, + Device: stm32.TIM12, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PB14, AF9_CAN1_CAN2_TIM12_13_14}, {PH6, AF9_CAN1_CAN2_TIM12_13_14}}}, + TimerChannel{Pins: []PinFunction{{PB15, AF9_CAN1_CAN2_TIM12_13_14}, {PH9, AF9_CAN1_CAN2_TIM12_13_14}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM13 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM13EN, + Device: stm32.TIM13, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA6, AF9_CAN1_CAN2_TIM12_13_14}, {PF8, AF9_CAN1_CAN2_TIM12_13_14}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM14 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM14EN, + Device: stm32.TIM14, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA7, AF9_CAN1_CAN2_TIM12_13_14}, {PF9, AF9_CAN1_CAN2_TIM12_13_14}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } +) + +func (t *TIM) registerUPInterrupt() interrupt.Interrupt { + switch t { + case &TIM1: + return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM1.handleUPInterrupt) + case &TIM2: + return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt) + case &TIM3: + return interrupt.New(stm32.IRQ_TIM3, TIM3.handleUPInterrupt) + case &TIM4: + return interrupt.New(stm32.IRQ_TIM4, TIM4.handleUPInterrupt) + case &TIM5: + return interrupt.New(stm32.IRQ_TIM5, TIM5.handleUPInterrupt) + case &TIM6: + return interrupt.New(stm32.IRQ_TIM6_DAC, TIM6.handleUPInterrupt) + case &TIM7: + return interrupt.New(stm32.IRQ_TIM7, TIM7.handleUPInterrupt) + case &TIM8: + return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM8.handleUPInterrupt) + case &TIM9: + return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleUPInterrupt) + case &TIM10: + return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleUPInterrupt) + case &TIM11: + return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleUPInterrupt) + case &TIM12: + return interrupt.New(stm32.IRQ_TIM8_BRK_TIM12, TIM12.handleUPInterrupt) + case &TIM13: + return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM13.handleUPInterrupt) + case &TIM14: + return interrupt.New(stm32.IRQ_TIM8_TRG_COM_TIM14, TIM14.handleUPInterrupt) + } + + return interrupt.Interrupt{} +} + +func (t *TIM) registerOCInterrupt() interrupt.Interrupt { + switch t { + case &TIM1: + return interrupt.New(stm32.IRQ_TIM1_CC, TIM1.handleOCInterrupt) + case &TIM2: + return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt) + case &TIM3: + return interrupt.New(stm32.IRQ_TIM3, TIM3.handleOCInterrupt) + case &TIM4: + return interrupt.New(stm32.IRQ_TIM4, TIM4.handleOCInterrupt) + case &TIM5: + return interrupt.New(stm32.IRQ_TIM5, TIM5.handleOCInterrupt) + case &TIM6: + return interrupt.New(stm32.IRQ_TIM6_DAC, TIM6.handleOCInterrupt) + case &TIM7: + return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt) + case &TIM8: + return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM8.handleOCInterrupt) + case &TIM9: + return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleOCInterrupt) + case &TIM10: + return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleOCInterrupt) + case &TIM11: + return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleOCInterrupt) + case &TIM12: + return interrupt.New(stm32.IRQ_TIM8_BRK_TIM12, TIM12.handleOCInterrupt) + case &TIM13: + return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM13.handleOCInterrupt) + case &TIM14: + return interrupt.New(stm32.IRQ_TIM8_TRG_COM_TIM14, TIM14.handleOCInterrupt) + } + + return interrupt.Interrupt{} +} + +func initRNG() { + stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_RNGEN) + stm32.RNG.CR.SetBits(stm32.RNG_CR_RNGEN) +} diff --git a/src/machine/machine_stm32f469.go b/src/machine/machine_stm32f469.go index 9d0c7e473a..ef41399d7f 100644 --- a/src/machine/machine_stm32f469.go +++ b/src/machine/machine_stm32f469.go @@ -7,8 +7,10 @@ func CPUFrequency() uint32 { return xtalHz / pll.M * pll.N / pll.P } -// 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 = 45000000 * 2 -const APB2_TIM_FREQ = 90000000 * 2 +// Internal use: configured speed of the APB1 and APB2 buses and timers, this +// should be kept in sync with any changes to runtime package which configures +// the oscillators and clock frequencies. +const APB1_FREQ = 45000000 +const APB2_FREQ = 90000000 +const APB1_TIM_FREQ = APB1_FREQ * 2 +const APB2_TIM_FREQ = APB2_FREQ * 2 diff --git a/src/machine/machine_stm32f4_otgfs_vbus.go b/src/machine/machine_stm32f4_otgfs_vbus.go index e9830d9969..7a2fbb5939 100644 --- a/src/machine/machine_stm32f4_otgfs_vbus.go +++ b/src/machine/machine_stm32f4_otgfs_vbus.go @@ -1,4 +1,4 @@ -//go:build stm32f4 && (stm32f429 || stm32f427 || stm32f411 || stm32f407 || stm32f405 || stm32f401) +//go:build stm32f4 && (stm32f429 || stm32f427 || stm32f411 || stm32f407 || stm32f405) package machine diff --git a/src/machine/machine_stm32f4_pll_84mhz.go b/src/machine/machine_stm32f4_pll_84mhz.go new file mode 100644 index 0000000000..5936e2645b --- /dev/null +++ b/src/machine/machine_stm32f4_pll_84mhz.go @@ -0,0 +1,19 @@ +//go:build stm32f4 && stm32f401 + +package machine + +// PLLParams84MHz returns the HSE PLL dividers needed to reach a 336MHz VCO +// (84MHz SYSCLK, P=4, Q=7) for the configured crystal frequency. M is chosen +// to bring the PLL input (HSE/M) to 2MHz, as recommended by the STM32F401 +// reference manual (RM0368). With VCO=336MHz and P=4, SYSCLK=84MHz. Q=7 +// produces the 48MHz USB clock (VCO/Q). +func PLLParams84MHz() PLLParams { + switch xtalHz { + case 8_000_000: + return PLLParams{M: 4, N: 168, P: 4, Q: 7} + case 16_000_000: + return PLLParams{M: 8, N: 168, P: 4, Q: 7} + default: + panic("unsupported xtal frequency") + } +} diff --git a/src/machine/usb.go b/src/machine/usb.go index 9fcc1997d7..ac28a57fce 100644 --- a/src/machine/usb.go +++ b/src/machine/usb.go @@ -1,4 +1,6 @@ -//go:build sam || nrf52840 || rp2040 || rp2350 || stm32f4 || stm32f7 || stm32h7 +// NUCLEO-F401RE has no USB OTG connector. This chip-wide exclude +// also blocks later F401 boards that have USB (for example Blackpill F401CC). +//go:build sam || nrf52840 || rp2040 || rp2350 || (stm32f4 && !stm32f401) || stm32f7 || stm32h7 package machine diff --git a/src/runtime/rand_hwrng.go b/src/runtime/rand_hwrng.go index bc7b72d6c0..8a59e732c2 100644 --- a/src/runtime/rand_hwrng.go +++ b/src/runtime/rand_hwrng.go @@ -1,4 +1,4 @@ -//go:build baremetal && (nrf || (stm32 && !(stm32f103 || stm32l0x1 || stm32g0 || stm32u0)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt) || rp2040 || rp2350) +//go:build baremetal && (nrf || (stm32 && !(stm32f103 || stm32l0x1 || stm32g0 || stm32u0 || stm32f401)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt) || rp2040 || rp2350) // If you update the above build constraint, you'll probably also need to update // src/crypto/rand/rand_baremetal.go. diff --git a/src/runtime/rand_norng.go b/src/runtime/rand_norng.go index ee77df09fa..46de54f91a 100644 --- a/src/runtime/rand_norng.go +++ b/src/runtime/rand_norng.go @@ -1,4 +1,4 @@ -//go:build baremetal && !(nrf || (stm32 && !(stm32f103 || stm32l0x1 || stm32g0 || stm32u0)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt) || rp2040 || rp2350) +//go:build baremetal && !(nrf || (stm32 && !(stm32f103 || stm32l0x1 || stm32g0 || stm32u0 || stm32f401)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt) || rp2040 || rp2350) package runtime diff --git a/src/runtime/runtime_stm32f401.go b/src/runtime/runtime_stm32f401.go new file mode 100644 index 0000000000..cacf9b592c --- /dev/null +++ b/src/runtime/runtime_stm32f401.go @@ -0,0 +1,127 @@ +//go:build stm32f401 + +package runtime + +import ( + "device/stm32" + "machine" +) + +const ( + // +---------------------------------------------+ + // | Clock Settings | + // +-------------+-------------------------------+ + // | HSE | selectable (xtal_8/16_mhz) | + // | SYSCLK | 84mhz | + // | HCLK | 84mhz | + // | APB1(PCLK1) | 42mhz | + // | APB2(PCLK2) | 84mhz | + // +-------------+-------------------------------+ + HCLK_FREQ_HZ = 84000000 + PCLK1_FREQ_HZ = HCLK_FREQ_HZ / 2 + PCLK2_FREQ_HZ = HCLK_FREQ_HZ / 1 +) + +const ( + // VOS Scale 1 (bits [15:14] = 0b11): max HCLK = 84 MHz + PWR_SCALE1 = 3 << stm32.PWR_CR_VOS_Pos + + PLL_SRC_HSE = 1 << stm32.RCC_PLLCFGR_PLLSRC_Pos + PLL_SRC_HSI = 0 + + 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 + + RCC_DIV_PCLK1 = stm32.RCC_CFGR_PPRE1_Div2 << stm32.RCC_CFGR_PPRE1_Pos // HCLK / 2 + RCC_DIV_PCLK2 = stm32.RCC_CFGR_PPRE2_Div1 << stm32.RCC_CFGR_PPRE2_Pos // HCLK / 1 + RCC_DIV_HCLK = stm32.RCC_CFGR_HPRE_Div1 << stm32.RCC_CFGR_HPRE_Pos // SYSCLK / 1 +) + +const ( + // +-----------------------------------+ + // | Voltage range = 2.7V - 3.6V | + // +----------------+------------------+ + // | Wait states | System Bus | + // | (WS, LATENCY) | HCLK (MHz) | + // +----------------+------------------+ + // | 0 WS, 1 cycle | 0 < HCLK ≤ 30 | + // | 1 WS, 2 cycles | 30 < HCLK ≤ 64 | + // | 2 WS, 3 cycles | 64 < HCLK ≤ 84 | + // +----------------+------------------+ + FLASH_LATENCY = 2 << stm32.FLASH_ACR_LATENCY_Pos // 2 WS (3 CPU cycles) + + // instruction cache, data cache, and prefetch + FLASH_OPTIONS = stm32.FLASH_ACR_ICEN | stm32.FLASH_ACR_DCEN | stm32.FLASH_ACR_PRFTEN +) + +func init() { + initOSC() + initCLK() + + machine.InitSerial() + + initTickTimer(&machine.TIM3) +} + +func initOSC() { + // enable voltage regulator + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN) + stm32.PWR.CR.SetBits(PWR_SCALE1) + + // enable HSE + stm32.RCC.CR.SetBits(stm32.RCC_CR_HSEON) + for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) { + } + + // disable PLL before configuring it + stm32.RCC.CR.ClearBits(stm32.RCC_CR_PLLON) + for stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) { + } + + // set HSE as PLL source and configure dividers for 84MHz SYSCLK + pll := machine.PLLParams84MHz() + stm32.RCC.PLLCFGR.Set(PLL_SRC_HSE | + pll.M<>1)-1)<