在 ESP32-S3 上,SPI 主机驱动(spi_master)本身已基于 GDMA,但默认的 spi_device_transmit 是阻塞式且会做数据拷贝。要实现零拷贝高速采集,核心是绕过高层 API,直接操作 SPI 外设的 DMA 链表。步骤:1) 用 heap_caps_malloc(size, MALLOC_CAP_DMA) 分配对齐的接收缓冲区,避免 PSRAM 非 DMA 可达问题;2) 调用 spi_bus_add_device 后,通过 spi_device_get_transaction 或直接配置 SPI_DMA_IN_LINK 寄存器,构建 dma_descriptor_t 链,每个描述符指向一块缓冲区,用 owner/eof 位串联;3) 将描述符链首地址写入 SPI_DMA_IN_LINK_ADDR,设置 SPI_DMA_IN_SUC_EOF_ENA,启动 SPI 传输;4) 传输完成由 DMA 中断触发,在 ISR 中只更新链表尾指针,实现乒乓缓冲。注意:描述符必须 4 字节对齐,缓冲区大小建议 4KB 以内以降低中断延迟;若用 PSRAM,需确认 GDMA 可访问且开启 cache 一致性维护。实测在 40MHz SPI 下可稳定达到 5MB/s 以上零拷贝吞吐。
mcuku 阿沐 · 2026-09-25