Rust in Everything
基于 embassy-executor 0.10.0

HAL:embassy-stm32

执行器、时间和同步原语都不碰硬件。真正去读写寄存器、接中断的是 HAL。这一部分只讲一个 HAL:embassy-stm32 0.6.0。它是 embassy 仓库里最大的 crate(.rs 共 86129 行,其中 src/ 83273 行、build.rs 2762 行),Cargo feature 里列了 1525 个芯片型号,靠的是两样东西:stm32-metapac 21.0.0 里每款芯片的元数据,和一个在编译期把元数据变成 Rust 代码的 build.rs。和它配套的 embassy-hal-internal 0.5.0(2330 行)放各个 HAL 共用的零件:Peri、peripherals! 宏、中断的类型层、原子环形缓冲。

  1. 外设单例与 Peri:init 返回一个 0 字节的 Peripherals,每个引脚、每个外设是一个零大小的类型;驱动构造函数吃掉 Peri<'d, T>,借用检查器保证同一个引脚不会落进两个驱动,reborrow 借出去、drop 时还回来,steal 是唯一的后门。
  2. 中断绑定:bind_interrupts! 展开成一个 #[no_mangle] 的中断向量函数加几行 unsafe impl Binding;驱动的 _irq: impl Binding<..> 参数是一份零大小的证明,忘了绑或绑错向量都在编译期报错;优先级的 Priority 一律按 4 个优先级位生成。
  3. 芯片数据与代码生成:芯片 feature 选中 stm32-metapac 里的一份元数据,build.rs 输出 83 个 cfg 和 _generated.rs(L475 上 4434 行)、_macros.rs、memory.x;同一份 USART 驱动用 usart_v1 到 usart_v4 四个 cfg 覆盖 F1、F4、L4、G0。
  4. init 与时钟:init 在一个临界区里依次使能 SYSCFG / PWR / FLASH、GPIO、DMA、EXTI,再配时钟树、最后起时间驱动;HAL 假设每个「等就绪位」的循环都会退出,QEMU 上三处不退出。
  5. GPIO 与 EXTI:中断主线的完整版。ExtiInput 每条线一个 AtomicWaker,处理函数屏蔽 IMR 位再唤醒,future 看 IMR 位判断就绪;QEMU 上用写 SWIER 触发,实测每一步的寄存器状态;GPIO + EXTI 的程序比只点灯多 1 KB 代码。
  6. USART 与 DMA:阻塞、中断 + 环形缓冲、DMA 三种 UART;查清了 QEMU 上 USART 不出字的两个原因(只接受 32 位访问;ICR 写入会清掉 TXE),打了补丁后 BufferedUart 收发都通;DMA 版在 QEMU 上「立刻成功」却什么也没发出去。
flowchart TB
  data["stm32-metapac"] --> build["build.rs"]
  build --> gen["_generated.rs"]
  build --> cfgs["cfg usart_v3 ..."]
  gen --> periph["Peripherals"]
  gen --> irqmod["interrupt::typelevel"]
  init["init"] --> periph
  periph --> drv["驱动 Peri d T"]
  irqmod --> bind["bind_interrupts!"]
  bind --> drv
  drv --> waker["AtomicWaker"]
  waker --> exec["执行器"]

前两页回答「驱动凭什么拿到外设和中断」,第三页回答「一份代码怎么适配上千款芯片」,第四页是启动顺序,后两页是两个具体驱动。中断主线(ExtiInput::wait_for_rising_edge().await)在一次中断唤醒里走过一遍概览,这里第 2 页讲 bind_interrupts! 那一头,第 5 页讲驱动和处理函数那一头。embassy-stm32 自带的 TIM 时间驱动在时间驱动;低功耗执行器在各平台的执行器。

本部分的实验有三种:交叉编译(看 OUT_DIR、编译错误、代码体积);QEMU 11.1.2 的 b-l475e-iot01a(STM32L475VG)上运行,embassy-stm32 打了「注释掉 rcc/bd.rs 里 while !cr.read().dbp() {}」这一行补丁;USART 一页另加了自己的补丁,在那一页写明。QEMU 里 TIM、DMA、PWR、FLASH 都没有模型,凡是 QEMU 上的结果都不代表真实硬件。

💬 关联讨论

发起讨论
加载中...