优化方案:DMA 中断 + 回调机制
核心思路是用 DMA 传输完成中断替代阻塞等待,让 CPU 在 DMA 传输期间可处理其他任务,传输完成后通过中断通知 CPU 收尾。
1. 中断相关配置代码(关键补充)
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)rx_buf;
dma_init(DMA1, DMA_CHANNEL_RX, &dma_init_struct);
// 拉低 NSS,使能 DMA 通道
gpio_bit_reset(SPI_NSS_GPIO_PORT, SPI_NSS_GPIO_PIN);
dma_channel_enable(DMA1, DMA_CHANNEL_TX);
dma_channel_enable(DMA1, DMA_CHANNEL_RX);
}
// DMA1_TX(CH1)中断服务函数
void DMA1_Channel1_IRQHandler(void) {
if(dma_interrupt_flag_get(DMA1, DMA_CHANNEL_TX, DMA_INT_FLAG_FTF) != RESET) {
// 1. 关闭 TX 通道,清除中断标志
dma_channel_disable(DMA1, DMA_CHANNEL_TX);
dma_interrupt_flag_clear(DMA1, DMA_CHANNEL_TX, DMA_INT_FLAG_FTF);
// 2. 标记 TX 完成
dma_tx_done = 1;
// 3. 若 RX 也完成,拉高 NSS(避免单独操作导致时序错误)
if(dma_rx_done == 1) {
gpio_bit_set(SPI_NSS_GPIO_PORT, SPI_NSS_GPIO_PIN);
}
}
}
// DMA1_RX(CH3)中断服务函数
void DMA1_Channel3_IRQHandler(void) {
if(dma_interrupt_flag_get(DMA1, DMA_CHANNEL_RX, DMA_INT_FLAG_FTF) != RESET) {
dma_channel_disable(DMA1, DMA_CHANNEL_RX);
dma_interrupt_flag_clear(DMA1, DMA_CHANNEL_RX, DMA_INT_FLAG_FTF);
dma_rx_done = 1;
if(dma_tx_done == 1) {
2. 主函数调用示例(非阻塞逻辑)
dma_spi0_interrupt_init(); // 初始化 DMA 中断
// 启动非阻塞 DMA 传输
spi0_dma_start_nonblock(tx_buf, rx_buf, 100);
// 传输期间,CPU 可处理其他任务(如 LED 闪烁、UART 接收)
while(1) {
// 检查 DMA 是否完成(非阻塞查询,仅占极少 CPU 资源)
if(dma_tx_done && dma_rx_done) {
// 处理接收数据(如校验、解析)
process_rx_data(rx_buf, 100);
// 重新启动下一轮传输
spi0_dma_start_nonblock(tx_buf, rx_buf, 100);
}
// 其他任务:LED 闪烁
led_toggle();
delay_ms(100);
}
}
|