第一幕:时钟与中断统一配置
2026/5/9大约 1 分钟嵌入式开发STM32Embassy
所有外设共享同一个时钟树,所有中断注册到同一个 Irqs 结构体。统一配置是整合的第一步。
时钟树
let mut rcc_config = Config::default();
rcc_config.hsi = true;
rcc_config.pll_src = PllSource::HSI;
rcc_config.pll = Some(Pll {
prediv: PllPreDiv::DIV16,
mul: PllMul::MUL336,
divp: Some(PllPDiv::DIV2), // 168 MHz SYSCLK
divq: Some(PllQDiv::DIV7), // 48 MHz SDIO/USB
divr: None,
});
rcc_config.sys = Sysclk::PLL1_P;
rcc_config.ahb_pre = AHBPrescaler::DIV1;
rcc_config.apb1_pre = APBPrescaler::DIV4;
rcc_config.apb2_pre = APBPrescaler::DIV2;不同外设挂在 APB1 和 APB2 两条总线上,预分频器让它们各自运行在规范频率内。
中断聚合绑定
用一个宏注册全部 DMA 流和外部中断:
bind_interrupts!(
struct Irqs {
SDIO => sdmmc::InterruptHandler<peripherals::SDIO>;
DMA2_STREAM3 => dma::InterruptHandler<peripherals::DMA2_CH3>;
DMA2_STREAM6 => dma::InterruptHandler<peripherals::DMA2_CH6>;
DMA2_STREAM0 => dma::InterruptHandler<peripherals::DMA2_CH0>;
USART1 => usart::BufferedInterruptHandler<peripherals::USART1>;
EXTI9_5 => exti::InterruptHandler<interrupt::typelevel::EXTI9_5>;
}
);| 中断 | 用途 |
|---|---|
| SDIO | SD 卡命令/响应 |
| DMA2_CH3 | SPI1 TX(VS1053 数据发送) |
| DMA2_CH6 | SDIO 数据块 DMA |
| DMA2_CH0 | SPI1 RX |
| USART1 | 串口接收命令 |
| EXTI9_5 | VS1053 DREQ 信号 |
串口初始化
BufferedUart 用 DMA + 环形缓冲接收数据:
let mut usart_config = usart::Config::default();
usart_config.baudrate = 115200;
let mut tx_buf: [u8; 256] = [0u8; 256];
let mut rx_buf: [u8; 256] = [0u8; 256];
let mut usart = BufferedUart::new(
p.USART1, p.PA10, p.PA9,
&mut tx_buf, &mut rx_buf,
Irqs, usart_config,
).unwrap();为什么用 BufferedUart?
普通 Uart::read() 没数据时阻塞等待。BufferedUart 内部用 DMA + 环形缓冲,read_exact 在有数据时才返回。
