feat(machine/stm32): add STM32F401 and NUCLEO-F401RE support - #5597
feat(machine/stm32): add STM32F401 and NUCLEO-F401RE support#5597akif999 wants to merge 4 commits into
Conversation
|
Hello @akif999 thanks for the PR. Here are some editied comments from an assisted code review:
Suggested fix: add per-chip APB1_FREQ/APB2_FREQ constants alongside the existing APB1_TIM_FREQ/APB2_TIM_FREQ in machine_stm32f401.go, machine_stm32f40x.go, and machine_stm32f469.go, and use those in all four functions. That also lets getBaudRateDivisor stay in the shared file instead of being duplicated.
adc → adc.go:11:32: undefined: machine.ADC2 To answer your question in the description: yes, please pull in src/examples/pwm/nucleo-f401re.go (see nucleo-f722ze.go for the pattern) and ADC0/ADC1/ADC2 aliases in the board file (as board_stm32f4disco.go has). Those make the results you reported reproducible. The rest of that commit can stay out. Minor / optional:
|
|
Hello @deadprogram thanks for the review — I’ve addressed the comments. RequiredAdded per-chip APB1_FREQ / APB2_FREQ next to the existing timer constants, and switched SPI getBaudRate, I2C getFreqRange / getSpeed, and UART getBaudRateDivisor to use them. getBaudRateDivisor now lives in the shared F4 file instead of being duplicated. Optional / minormachine_stm32f401.go now uses a bare stm32f401 build tag. Happy to adjust anything further. |
|
I will check failure of Actions. |
|
|
Thanks @akif999. I checked out the PR head ( All the earlier points are fixed and verified. There are 2 new items, both minor:
NUCLEO-F401RE has no OTG connector, so it is acceptable to keep the exclusion for that. But the three chip-wide Notes
|
Required: - Add APB1_FREQ/APB2_FREQ and use them for SPI, I2C, and UART clock divisors - Move getBaudRateDivisor into the shared F4 file - Fix F4 ADC sample-time shifts and drop machine_stm32f401_adc.go - Add ADC0-ADC15 aliases and examples/pwm/nucleo-f401re.go Optional: - Use a bare stm32f401 build tag on machine_stm32f401.go - Switch the full-peripheral F4 file to a positive F405/F407/F469 tag - Rename machine_stm32f4_extended.go to machine_stm32f40x_periph.go - Enable HSE with SetBits and set APB prescalers before switching to PLL - Reindent targets/nucleo-f401re.json to 2 spaces
Untyped APB1_FREQ made clock := APB1_FREQ infer int and broke the F4 smoketest.
Remove unused initRNG, document why USB is excluded chip-wide, note that ADC2 is VCP TX, and add nucleo-f401re PWM to the smoketest.
a4e6086 to
52f09b7
Compare
|
@deadprogram Thanks for the second review.
initRNG() was only a leftover stub. I did not intend to wire up RNG on F401 (the chip has no hardware RNG). So, I removed the unused function.
You are right about USB. Device files come from lib/stm32-svd, and the earlier “register names do not match” reason was wrong. I kept the chip-wide !stm32f401 exclude because NUCLEO-F401RE has no OTG connector. I updated the comments in usb.go / machine_stm32_otgfs_usb.go and the PR description to say that. The description now also says device files are generated from lib/stm32-svd via make/gen-device.mk, not from lib/cmsis-svd. I noted that this chip-wide exclude will block later F401 boards that do have USB, such as the Blackpill F401CC.
I added a short comment on the ADC aliases. examples/adc uses ADC2 (PA2 / ST-Link VCP TX), so users should use A0 instead.
I added nucleo-f401re examples/pwm to make/smoketest.mk, next to stm32f4disco-1. The GitHub PR body is updated to match these comments. |
1. Requirements
What was implemented
What was NOT implemented in this PR
!stm32f401exclude is kept for this board. It also blocks later F401 boards that have USB (for example Blackpill F401CC). Device files come fromlib/stm32-svd, notlib/cmsis-svd.crypto/rand(HW RNG)crypto/randpanics with"no rng", consistent with TinyGo's behavior on other platforms without HW RNG;math/randworks normallyblinky2Board Information
Board
Chip
2. Design
Already had comprehensive support for the STM32F4 family (F405/F407 via
feather-stm32f405,stm32f4disco; F722/F469 for other NUCLEO/disco boards). These provided:machine_stm32f4.gofor GPIO, UART, SPI, I2C, ADC, and PWM driversmachine_stm32f40x_periph.gofor F405/F407-specific peripherals (extra UARTs, TIMs, DAC, CAN, etc.)runtime/runtime_stm32f4.goThe STM32F401 shares the same Cortex-M4 core and peripheral bus architecture as the F405/F407, but has a reduced peripheral set and a lower maximum clock speed (84 MHz vs. 168 MHz). The following approach was taken:
targets/stm32f401.ld— linker script (512 KB Flash, 96 KB SRAM; no CCM region)src/machine/machine_stm32f401.go— CPU frequency (84 MHz), APB timer frequency constantssrc/machine/machine_stm32f4_pll_84mhz.go— PLL parameters for 84 MHz from 8 MHz HSE (M=4, N=168, P=4, Q=7; VCO=336 MHz)src/runtime/runtime_stm32f401.go— clock initialization (HSE → PLL → 84 MHz SYSCLK),TIM3as the 1 kHz system tick timer (no CCM SRAM setup)src/device/stm32/stm32f401.go/stm32f401.s— generated fromlib/stm32-svd(make/gen-device.mk)machine_stm32f4.goThe shared
machine_stm32f4.gocontainedgetPort()(which referenced GPIO ports F–K, not present on F401) andenableAltFuncClock()(which referenced DAC, CAN1/2, TIM6/7/8/12/13/14, SDIO, USART3–6 — none of which exist on F401), as well asTIM6,TIM7,TIM8,TIM12,TIM13,TIM14variable definitions. These were extracted out; the F405/F407/F469 versions remain undermachine_stm32f40x_periph.go(positive tagstm32f405 || stm32f407 || stm32f469), and F401-specific versions are provided inmachine_stm32f401_periph.go.src/machine/machine_stm32f401_periph.go(new) — F401-specific implementations of:getPort(): GPIO ports A–E and H only (F401 does not have ports F, G, I–K)enableAltFuncClock(): only the peripheral clocks present on F401APB1_FREQ/APB2_FREQconstants added alongside the existing timer frequencies inmachine_stm32f401.go,machine_stm32f40x.go, andmachine_stm32f469.go. SPIgetBaudRate, I2CgetFreqRange/getSpeed, and UARTgetBaudRateDivisornow use these so F401 does not run SPI/I2C/UART at 2× the requested clock.getBaudRateDivisorlives in the sharedmachine_stm32f4.go(not duplicated per chip).machine_stm32_adc_f4.gosample-time shift was wrong (ch * 6and a left-associative<</*mix). It now uses4 << (ch * 3)/4 << ((ch - 10) * 3), which also compiles for F401 without a separate ADC file.machine_stm32f40x_periph.go—//go:build stm32f4 && (stm32f405 || stm32f407 || stm32f469)for the full F4 peripheral setmachine_stm32_adc_f4.go— remainsstm32f4(shared with F401 after the sample-time fix)machine_stm32_otgfs_usb.go— changed fromstm32f4 || stm32f7to(stm32f4 && !stm32f401) || stm32f7. NUCLEO-F401RE has no USB OTG connector. This chip-wide exclude also blocks later F401 boards that have USB.machine_stm32f4_otgfs_vbus.go— removedstm32f401from the build tag for the same reasonusb.go— added!stm32f401to the build tag for the same reasonruntime/rand_hwrng.go— added!stm32f401(no hardware RNG on F401)runtime/rand_norng.goandcrypto/rand/rand_baremetal.go— includestm32f401to route to the software RNG pathsrc/machine/board_nucleof401re.go— LED, button, UART1/UART2, SPI0, I2C0, ADC aliases (A0–A5 / ADC0–ADC15), Arduino digital pin aliases (D0–D15)targets/nucleo-f401re.json— inheritscortex-m4(same soft-float / FPU-disabled setting as the other F4 targets), linker script, OpenOCDstlinkinterface,reset_config srst_only connect_assert_srstsrc/examples/pwm/nucleo-f401re.go— TIM2 on D6/D3 (TIM3is the runtime tick timer)GNUmakefile— addednucleo-f401retarget tomake smoketest(afternucleo-f103rb)3. Implementation
Please refer to Files changed on GitHub. Key files are listed below.
4. Testing
Environment
devbranchFunctional Tests on NUCLEO-F401RE
examples/blinky1examples/echo/echo2examples/buttonexamples/pininterruptexamples/device-idexamples/rand(crypto/rand)panic: no rng— F401RE has no HW RNG; consistent with TinyGo designtx == rxconfirmedexamples/adcexamples/pwmRegression Testing
make smoketestexecuted on both the upstreamdevbranch and the fork branchfeather-stm32f405,stm32f4disco,nucleo-f103rb,nucleo-f722ze,pico,xiao-rp2040, and others)