开发者文档:STM32#
原文: https://embassy.dev/book/dev/developer_stm32.html
了解外设元信息(meta-pac)#
当一个项目编译导入embassy-stm32
crate
时,该项目就会使用所用到芯片的功能。根据这个特性,embassy-stm32
会选择芯片所支持的 IP (半导体知识产权),并启用相应的硬件抽象层实现(HAL)。我们支持数百种芯片,但是embassy-stm32
是如何知道哪个芯片包含哪个 IP 呢? 说来话长,这就算一个关于stm32-data-sources
的故事了。
注:半导体知识产权
半导体中的知识产权 (IP) 核心是可重用的逻辑、功能单元或布局设计,通常向多个供应商授权,是按照模块化复用的思想来开发的。
stm32-data-sources#
stm32-data-sources
是一个比较“荒凉”的仓库。它没有说明书,没有文档,关注的人很少,但它是embassy-stm32
成功的关键。在这个仓库里,我们支持的芯片都有一个对应的 XML 文件,比如 STM32F051K4Ux.xml
。在这个文件中,你可以看到如下内容:
<IP InstanceName="I2C1" Name="I2C" Version="i2c2_v1_1_Cube"/>
<!-- snip -->
<IP ConfigFile="TIM-STM32F0xx" InstanceName="TIM1" Name="TIM1_8F0" Version="gptimer2_v2_x_Cube"/> ##
这些内容说明这个芯片有一个 i2c(一种同步串行总线), 它的版本是”v1_1”。同时,说明它还有一个通用的定时器(timer),版本是 “v2_x”。通过这些数据,就可以决定embassy-stm32
应该包含哪些实现。但实际上,做这些工作,就是另一回事了。
stm32-data#
该项目的用户都熟悉embassy-stm32
,但很少有人了解为其提供支持的项目:stm32-data
。这个项目旨在为embassy-stm32
生成其所需要的一些数据(外设、寄存器等信息)。为此,通过组合和解析stm32-data-sources
项目下的多个文件,来得到相关信息,再按所支持芯片的 IP ,来分配寄存器块的实现。这些操作主要在chips.rs
中:
(".*:I2C:i2c2_v1_1", ("i2c", "v2", "I2C")),
// snip
(r".*TIM\d.*:gptimer.*", ("timer", "v1", "TIM_GP16")),
在这种情况下,i2c 的版本对于我们实现的 “v2”版本,通用定时器(timer)版本对应于我们的“v1”版本。因此,i2c_v2.yaml
和timer_v1.yaml
寄存器块实现就对应 i2c v2 和 timer v1 这些 IP。STM32F051K4.json
就是这些内容生的结果:
{
"name": "I2C1",
"address": 1073763328,
"registers": {
"kind": "i2c",
"version": "v2",
"block": "I2C"
},
// snip
}
// snip
{
"name": "TIM1",
"address": 1073818624,
"registers": {
"kind": "timer",
"version": "v1",
"block": "TIM_ADV"
},
// snip
}
除了寄存器块之外,芯片引脚和复位与时钟(RCC)映射的数据也由embassy-stm32
生成和使用。stm32-metapac-gen
用于将数据打包并发布为 crate。
embassy-stm32#
在embassy-stm32
的根目录lib.rs
文件中,您将看到这一行:
#[cfg(i2c)]
pub mod i2c;
在mod.rs
中的 i2c 模块中,您将看到这一行:
#[cfg_attr(i2c_v2, path = "v2.rs")]
由于 STM32F051K4 支持 i2c,并且其版本对应于我们的“v2”,所以将出现i2c
和i2c_v2
配置指令。上述这些文件都在embassy-stm32
中。根据芯片数据,可以生成配置指令和配置表,embassy-stm32
根据这些生成的数据,就可以明确且清晰适配每个芯片所需要的逻辑和实现。与嵌入式生态系统中的其他项目相比,embassy-stm32
是唯一一个项目:可以在整个 stm32 系列中重用代码,并安全的实现了硬件抽象层中困难重重的逻辑。