初级会员

- 积分
- 62
- 金钱
- 62
- 注册时间
- 2024-4-27
- 在线时间
- 9 小时
|
50金钱
大家好,我在 ESP32 上做一个高速 SPI 发送测试,目标只是连续发送固定长度数据
## 环境
- MCU:ESP32
- SDK:ESP-IDF 6.0.1
- SPI 时钟:30 MHz
- SPI mode:3
- 使用两个 SPI host 同时发送
- 每个 host 每次发送 44 bytes 一直连续发送
- 两个 SPI host 共用一个软件 GPIO CS
- 不能关中断,因为系统还要维持 Wi-Fi 通信
## GPIO
- SPI host 1:
- data0:GPIO33
- data1:GPIO32
- CLK:GPIO27
- SPI host 2:
- data0:GPIO17
- data1:GPIO16
- CLK:GPIO19
- shared CS:GPIO21,软件手动拉低/拉高
## 目标
连续发送 transaction,每个 transaction:
- host1 发送 44 bytes
- host2 发送 44 bytes
- 两个 host 尽量同步启动
- transaction 之间“上一帧最后一个 SCLK 上升沿到下一帧第一个 SCLK 上升沿”的间距间隔希望压到 0.4us 以内
- 发送内容不重要,只要求每次 44B 完整稳定发出
我当前最好只能做到约 0.9us,进一步改动会引发稳定性问题。
## 已尝试方案
### 1. ESP-IDF SPI master driver
常规 `spi_device_transmit` / queued transaction 开销太大,不适合这种 44B 小包连续发送。
### 2. 直接 LL / 寄存器控制 SPI + DMA
目前主要使用:
- 手动配置 SPI host
- 手动配置 MOSI bit length
- 使用 DMA descriptor
- 手动启动 DMA out link
- 手动置位 `SPI_CMD_REG.USR`
- 软件 GPIO 控制 shared CS
大致流程:
```c
cs_low();
start_dma(host1, desc1);
start_dma(host2, desc2);
spi_ll_user_start(host2);
spi_ll_user_start(host1);
/* wait target CS-low time or wait done */
cs_high();
为了减少间隔,我做过双 descriptor slot:
当前 slot 正在发送
同时准备 next slot descriptor
当前发送结束后,切换到 next slot
这样 transaction 间隔可以到约 0.9us。
3. 等 trans_done
如果每次启动前清 trans_done,然后拉高 CS 前等待两个 host 的 trans_done,发送边界更可靠,但 transaction 间隔明显变长,接近优化前。
4. 只等 cmd.usr == 0
如果只等 SPI_CMD_REG.USR 清零,间隔较短,但担心 DMA/FIFO 还没有完全稳定,可能存在边界风险。
5. CPU FIFO
因为每次只发 44B,小于 ESP32 SPI FIFO 64B,我尝试不用 DMA,直接:
spi_ll_write_buffer(host1, buf1, 44 * 8);
spi_ll_write_buffer(host2, buf2, 44 * 8);
spi_ll_user_start(host1);
spi_ll_user_start(host2);
结果 transaction 间隔变成约 6.8us,明显更差。推测是每次写 44B FIFO 的 CPU 成本进入了热路径。
希望各位大佬帮帮忙,如果能解决问题愿意有偿。
|
|