# stm32f4xx-hal covers seventeen STM32F4 parts with one feature gated API

> stm32-rs/stm32f4xx-hal is a 0BSD licensed Rust hardware abstraction layer for the STM32F4 family, selecting the exact microcontroller through a Cargo feature and glossing over the peripheral differences between parts, while implementing part of the embedded-hal traits on top of the stm32f4 register crate. Peripheral drivers live in separate crates and are switched on by feature, and the current release is 0.23.0.

**stm32-rs/stm32f4xx-hal** — A Rust embedded-hal HAL for all MCUs in the STM32 F4 family

- Repository: https://github.com/stm32-rs/stm32f4xx-hal
- Stars: 703 · Forks: 222
- Language: Rust
- License: 0BSD
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/stm32-rs-stm32f4xx-hal

## One crate, seventeen part numbers

stm32f4xx-hal is described as a multi device hardware abstraction on top of the peripheral access API for the STMicro STM32F4 series, and the selection of the microcontroller is done by feature gates, typically specified by board support crates. The list of supported configurations is long: stm32f401, stm32f405, stm32f407, stm32f410, stm32f411, stm32f412, stm32f413, stm32f415, stm32f417, stm32f423, stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469 and stm32f479. The rationale is stated plainly. The idea behind the crate is to gloss over the slight differences in the peripherals available on those MCUs, so a HAL can be written for all chips in that same family without having to cut and paste crates for every single model. For a product that ships on an F407 and later moves to an F429 or an F469, that is the whole value proposition, and it is also the reason the crate exists as a single project rather than as a family of small ones.

## Register definitions come from stm32f4, traits come from embedded-hal

The layering is worth being precise about, because it explains what the crate does and does not do. The README says the crate relies on Adam Greig's stm32f4 crate to provide the appropriate register definitions, and that it implements a partial set of the embedded-hal traits. So the register map, the bit definitions and the memory layout of the peripherals are not written in this repository, they come from a separate crate that keeps them in sync with the reference manual, and this project sits one level up, turning those registers into timers, GPIOs, SPI, I2C and the rest. The partial implementation is the part that needs attention. Some of the implementation was adapted from the stm32f1xx-hal crate originally started by Jorge Aparicio, which is how a large part of the F1 family experience was carried across. The consequence for a user is simple: if a driver library you want requires a trait that this HAL does not implement, you will need to drop down to the raw registers.

## Peripherals are separate crates behind optional features

The optional feature list shows a clear architectural habit: this crate does not implement every peripheral itself, it enables the ecosystem crate that does. The can feature brings bxCAN support through the bxcan crate. The i2s feature points at stm32_i2s_v12x. USB OTG FS and HS support comes from synopsys-usb-otg, and LCD support over the FMC and FSMC peripherals comes from display-interface. SDIO host support is sdio-host, DSI host support is embedded-display-controller, and defmt support is an implementation of the Format trait for the crate's public enums and structures. There are also two framework features, rtic1 for the RTICv1 framework and rtic2 for RTICv2, and the README is explicit that the two are incompatible and that rtic2 requires a nightly compiler. The cost of this design is that your dependency tree grows with the peripherals you turn on, and each of those crates has its own version and MSRV.

## Setting up a project by hand means three files

The recommended path is to check whether a board support crate for your board already exists in the stm32-rs organisation, since the HAL is then already included and you can use the BSP directly. Otherwise you create a Rust project with cargo init, and the dependencies go into the Cargo.toml:

```toml
[dependencies]
embedded-hal = "1.0"
nb = "1"
cortex-m = "0.7"
cortex-m-rt = "0.7"
# Panic behaviour, see https://crates.io/keywords/panic-impl for alternatives
panic-halt = "1.0"

[dependencies.stm32f4xx-hal]
version = "0.23.0"
features = ["stm32f407"] # replace the model of your microcontroller here
                         # and add other required features
```

The feature you select is the model, stm32f407 in this example, with a comment telling you to replace it. Then there is the link and memory layout, which is where embedded Rust trips people up. You copy .cargo/config.toml and memory.x from the repository into your project and make sure the sizes match the datasheet, and the README adds a warning that there may be different kinds of memory which are not equal, so on the safe side you specify only the size of the first block at the specified address. If you would rather not do this by hand, the README points to a project template driven by cargo generate, which needs the full chip name:

```
$ cargo generate --git https://github.com/burrbull/stm32-template/
```

## Twenty six examples stand in for the reference manual

The examples directory is the best documentation in the repository, and it covers a lot more than blinking. There are the basic ones, blinky.rs, blinky-timer-irq.rs, delay-syst-blinky.rs, delay-timer-blinky.rs and dwt-blinky.rs, the last of which uses the data watchpoint timer as a timebase. There is dynamic-gpio.rs for pins whose direction changes at runtime, i2c_scanner.rs for bus discovery, can-send.rs for the CAN peripheral, and a family of PWM examples: pwm.rs, pwm-sinus.rs, pwm-input.rs and pwm-dead-time.rs, which covers the advanced timer feature where two outputs are gated against each other. The display side is well served, with hd44780.rs, display-touch.rs, f413disco-lcd-ferris.rs, f469disco-lcd-test.rs, fmc-sdram.rs and a ltdc-screen directory. Audio and storage appear through i2s-audio-out.rs, a cs43l22 directory and qspi-w25q.rs, and the rest covers quadrature encoder input, the random number generator display, an IST7920 touch controller and an analogue stopwatch driving an SSD1306 over SPI. For a crate where the API is partly in the traits and partly in the examples, that directory is the reference.

## Toolchain and release state, including a gap in the tags

The manifest in the repository root sets edition 2021 and rust-version 1.95, categorises the crate as embedded, hardware-support and no-std, and names the thumbv7em-none-eabihf target that the documentation is built for. The README badge states a minimum supported Rust version of rustc 1.62+, which is looser than the manifest value, so the manifest is the number to trust. The docs.rs metadata lists the feature set used to build the API documentation, including stm32f429, usb_fs, can, i2s, fsmc_lcd, rtic1, defmt and sdio-host, which is a useful map of the combination that is known to compile together. The release history is the part to look at twice. v0.19.0 and v0.20.0 were both published on 2024-01-14, v0.23.0 followed on 2025-09-23, and the last push was on 2026-08-12 with no tag in between. The repository is not archived, so work continues, but if you pin a version you are pinning to September 2025, not to the current source.

## 0BSD is about as permissive as a licence gets

The crate is released under the 0-clause BSD licence, with the text in the LICENSE-0BSD.txt file at the repository root and the licence field in the manifest set to 0BSD. That is the most permissive of the licences in common use: it grants use, modification, distribution and sublicensing without the attribution clause that the usual two clause BSD licence carries, and without a patent grant. For an embedded crate that teams tend to vendor into a firmware repository rather than depend on from a registry, that matters less than it would for a library, but it does mean you can take this code, adapt it to your board, and ship it without publishing your own modifications. This is a statement about the licence terms and not legal advice, and the same question applies to the peripheral crates you pull in through the feature flags, since those are separate projects with separate licences.

## Conclusion

Adopt stm32f4xx-hal if you are writing Rust firmware for an STM32F4 part and want one codebase across several models, with the peripheral differences absorbed by feature gates rather than by duplicated crates. Do not adopt it if you need the complete embedded-hal trait surface, because the README states that only a partial set of the traits is implemented, and a driver that requires a missing trait will not compile against it. Before you start, check the trait coverage for the drivers you intend to use, copy .cargo/config.toml and memory.x and set the memory sizes from your datasheet, and note that the newest published release is v0.23.0 from 2025-09-23 while the last push was on 2026-08-12, so you may be building on unreleased work.

## FAQ

### How do I select the STM32F4 model in stm32f4xx-hal?

The MCU is chosen with a Cargo feature, typically specified by a board support crate, and the README lists seventeen supported configurations from stm32f401 through stm32f479. The dependency block shows the pattern, with features = ["stm32f407"] and a note to replace it with your own model.

### What do I need besides the stm32f4xx-hal dependency to build a project?

The README says to copy .cargo/config.toml and memory.x from the repository into your project and make sure the sizes match the datasheet, specifying only the size of the first memory block at the given address. The dependencies also include embedded-hal, nb, cortex-m, cortex-m-rt and panic-halt.

### Does stm32f4xx-hal implement all of the embedded-hal traits?

No. The README states that the crate implements a partial set of the embedded-hal traits, on top of the register definitions provided by the stm32f4 crate. If a driver you need depends on a trait that is not implemented, you will have to use the raw registers instead.

### How do I enable CAN, USB or LCD support?

Each peripheral is an optional feature that pulls in a separate crate: can uses bxcan, usb_fs and usb_hs use synopsys-usb-otg, fsmc_lcd uses display-interface, i2s uses stm32_i2s_v12x, sdio-host and dsihost cover SDIO and DSI host support, and defmt adds the Format implementation.

### What licence is stm32f4xx-hal released under and what is the current version?

It is released under the 0-clause BSD licence, with the text in the LICENSE-0BSD.txt file. The current published release is v0.23.0, and the README's setup instructions use version 0.23.0 in the dependency block.

## Sources

- [Issues](https://github.com/stm32-rs/stm32f4xx-hal/issues)
- [License: 0BSD](https://github.com/stm32-rs/stm32f4xx-hal/blob/master/LICENSE)
- [README](https://github.com/stm32-rs/stm32f4xx-hal/blob/master/README.md)
- [Releases](https://github.com/stm32-rs/stm32f4xx-hal/releases)
- [stm32-rs/stm32f4xx-hal on GitHub](https://github.com/stm32-rs/stm32f4xx-hal)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/stm32-rs-stm32f4xx-hal
