STM32 Developer Documentation
Understanding metapac
When a project imports embassy-stm32
for compilation, it selects the feature corresponding to the chip it uses. Based on this feature, embassy-stm32
selects the IP (Intellectual Property core) supported by the chip and enables the corresponding HAL implementation. But how does embassy-stm32
know which IPs are included in each of the hundreds of chips we support? This is a long story starting from stm32-data-sources
.
stm32-data-sources
stm32-data-sources
is a rather rudimentary code repository. It has no README, no documentation, and few followers. But it is the core that makes embassy-stm32
possible. The data for each chip we support comes partly from the corresponding XML file, such as STM32F051K4Ux.xml
. In this file, you will see lines like this:
<IP InstanceName="I2C1" Name="I2C" Version="i2c2_v1_1_Cube"/>
<IP ConfigFile="TIM-STM32F0xx" InstanceName="TIM1" Name="TIM1_8F0" Version="gptimer2_v2_x_Cube"/>
These lines indicate that the chip has an i2c with version "v1_1". It also indicates that the chip has a general-purpose timer with version "v2_x". With this data, we can determine which implementations should be included in embassy-stm32
. But actually performing this process is another matter.
stm32-data
Although all users of this project are familiar with embassy-stm32
, few people know about the project that supports it: stm32-data
. This project is not just for generating data for embassy-stm32
, but for making this data universally usable by machines. To achieve this goal, information from multiple files in the stm32-data-sources
project is combined and parsed to assign register block implementations for each supported IP. The core of this matching is located in chips.rs
:
(".*:I2C:i2c2_v1_1", ("i2c", "v2", "I2C")),
(r".*TIM\\d.*:gptimer.*", ("timer", "v1", "TIM_GP16")),
In this example, the i2c version corresponds to our "v2", and the general-purpose timer version corresponds to our "v1". Therefore, the i2c_v2.yaml
and timer_v1.yaml
register block implementations are assigned to these IPs respectively. The result is that these lines are generated in STM32F051K4.json
:
{
"name": "I2C1",
"address": 1073763328,
"registers": {
"kind": "i2c",
"version": "v2",
"block": "I2C"
},
// 省略
}
// 省略
{
"name": "TIM1",
"address": 1073818624,
"registers": {
"kind": "timer",
"version": "v1",
"block": "TIM_ADV"
},
// 省略
}
In addition to register blocks, pin and RCC mapping data are also generated and used by embassy-stm32
. stm32-metapac-gen
is used to package and publish the data as a crate.
embassy-stm32
In the lib.rs
file in the root directory of embassy-stm32
, you will see lines like this:
#[cfg(i2c)]
pub mod i2c;
And in the mod.rs
of the i2c module, you will see:
#[cfg_attr(i2c_v2, path = "v2.rs")]
Because STM32F051K4 supports i2c, and its version corresponds to our "v2", the i2c
and i2c_v2
configuration directives will exist, and embassy-stm32
will include these files accordingly. These configuration directives and tables are generated from chip data, enabling embassy-stm32
to clearly and explicitly adjust the logic and implementation according to the needs of each chip. Compared to other projects in the embedded ecosystem, embassy-stm32
is the only project that can reuse code across the entire STM32 product line and remove difficult-to-implement insecure logic to the HAL.