先楫SPI Data Merge 功能详解和实践

HPM SPI Data Merge 功能详解和使用

一、问题背景

SPI 主机通过 DMA 发送数据时,默认每次 DMA 事务只搬运 1 字节DMA_TRANSFER_WIDTH_BYTE)到 SPI 的 DATA 寄存器。这导致每发送一个字节,DMA 就要完成一次请求→响应→写入的完整握手流程,字节之间产生显著的时间间隔

以 50MHz SCLK 为例,理论吞吐量 25MB/s,但实测字节间隔可能让有效速率大幅下降。

二、Data Merge 的工作原理

Data Merge 是 SPI TRANSFMT 寄存器的 bit7(DATAMERGE_MASK = 0x80):

SPI_TRANSFMT.DATAMERGE = 1 时:
  - DMA 按 32-bit WORD 宽度写入 SPI DATA 寄存器
  - SPI 控制器内部自动将 1 个 WORD拆解为 4 个连续字节串行发出
  - 发送端:4 字节仅触发 1 次 DMA 事务,而非 4 次
  - 接收端:SPI 将 4 个连续字节打包成 1 个 WORD,DMA 按 WORD 宽度一次性搬走

效果:DMA 事务数减少 4 倍,字节间间隔几乎消除,有效吞吐量逼近理论值。

前提条件:Data Merge 仅在 DATALEN=8bit(即 data_len_in_bits=8)时可用。因为 Merge 的本质是将 4 个 8-bit 数据单元合并为 1 个 32-bit WORD,当数据单元本身就是 16/32-bit或者其他bit时,无法再做 4:1 合并。

Data Merge vs 直接 32-bit DATALEN

一个容易混淆的问题:为什么不直接把 DATALEN 设为 32-bit 来获得 WORD 宽度传输?两者有本质区别:

对比项 Data Merge (DATALEN=8bit + DATAMERGE=1) 直接 32-bit DATALEN
SPI 总线帧格式 每个 SCLK 周期传输 1 bit,4 个 8-bit 帧依次发出 每个 SCLK 周期传输 1 bit,1 个 32-bit 帧整体发出
对端设备感知 收到 4 个独立的 8-bit 数据,与普通 SPI 8-bit 传输完全一致 收到 1 个 32-bit 数据帧,需要对端也支持 32-bit 帧格式
适用对象 标准 8-bit SPI 外设(NOR Flash、传感器等) 仅 32-bit SPI 外设(某些 ADC/DAC、并行数据接口)
长度灵活性 可动态开关 merge,非对齐时回退 BYTE 必须 32-bit 对齐,无回退机制
DMA 宽度 WORD(合并 4 个 BYTE) WORD(天然 32-bit)

总结:Data Merge 是在 保持 8-bit SPI 协议不变 的前提下,仅优化 DMA 与 SPI 控制器之间的搬运效率;而 32-bit DATALEN 是真正改变了 SPI 总线上的数据帧长度,对端设备必须能解析 32-bit 帧。大多数 SPI 外设(NOR Flash、显示屏等)只支持 8-bit 帧,此时只能用 Data Merge。

性能对比

模式 DMA Width 128 字节的事务数 字节间隔
无 Merge BYTE 128 次 明显
有 Merge WORD 32 次 几乎消除

实测数据(传输 512 字节):

配置 SCLK Merge 耗时 实测带宽 理论带宽 结论
66M SCLK + Merge 66MHz 15.352μs ~33MB/s 33MB/s 实测与理论值接近
80M SCLK + Merge 80MHz 12.794μs ~40MB/s 40MB/s 实测与理论值接近
无 Merge(任意频率) - - - - 字节间隔显著,有效速率远低于理论值

关键现象:无 Merge 时 SCLK 时钟脉冲不连续,逻辑分析仪实测 SCLK 频率低于配置值(DMA 每字节握手产生间隙);开启 Merge 后时钟连续,实测带宽吻合理论计算。

下图展示了无 Merge 时 SCLK 的不连续现象,60MHz SPI SCLK, 字节之间出现明显间隔:

下图展示了开启 Merge 后 SCLK 连续输出,字节间无间隔:
在66M的SPI SCLK时钟下,逻辑分析仪抓到的SCLK能保持连续,并且数据能对的上。512字节耗时15.352us,合计33MB/S左右,与理论速度33MB/S接近。

三、使用方法

以下代码模式在 SDK 中多处使用,主要参考来源:

来源 路径 说明
Serial NOR Flash 驱动 components/serial_nor/interface/spi/hpm_serial_nor_host_spi.c TX/RX merge 动态开关,最完整的实战示例
SPI 驱动 API drivers/inc/hpm_spi_drv.h spi_enable/disable_data_merge 定义
寄存器定义 soc/HPM5100/ip/hpm_spi_regs.h TRANSFMT_DATAMERGE_MASK(0x80) 定义

3.1 发送(TX)场景

/* 条件:数据长度必须是 4 的整数倍 */
if ((len % 4) == 0) {
    spi_enable_data_merge(SPI_PTR);          // 开启 merge
    data_width = DMA_TRANSFER_WIDTH_WORD;    // DMA 用 WORD 宽度
} else {
    data_width = DMA_TRANSFER_WIDTH_BYTE;    // 不能 merge,回退到 BYTE
}

/* TX DMA 配置时建议降低 FIFO 阈值,减少启动延迟 */
spi_set_tx_fifo_threshold(SPI_PTR, 3);

/* 传输结束后关闭 merge,避免影响下次非对齐传输 */
spi_disable_data_merge(SPI_PTR);

3.2 接收(RX)场景

/* RX DMA 总是开启 merge,提升接收吞吐量 */
spi_enable_data_merge(SPI_PTR);
data_width = DMA_TRANSFER_WIDTH_WORD;

/* 非 4 对齐的长度:DMA 传输尺寸向上取整到 4 字节 */
if ((len % 4) == 0) {
    dma_send_size = len;
} else {
    dma_send_size = ((len >> 2) + 1) << 2;  // 多读几个字节
}

/* DMA RX 以 WORD 宽度搬运 dma_send_size 字节 */
spi_rx_trigger_dma(..., DMA_TRANSFER_WIDTH_WORD, dma_send_size);

3.3 Serial NOR Flash 驱动中的典型模式

参考 hpm_serial_nor_host_spi.c

操作 Data Merge DMA Width 长度限制
写 Flash len%4==0 时开启 WORD 或 BYTE 非 4 对齐用 BYTE
读 Flash 总是开启 WORD DMA 尺寸向上取整到 4

四、注意事项

  1. 数据位宽限制:Data Merge 仅适用于 data_len_in_bits=8(8-bit 数据单元)
  2. 长度对齐:TX 方向数据长度必须 4 字节对齐才能开启 merge;RX 方向可以向上取整(多读几个无效字节不影响正确数据)
  3. 及时关闭:merge 开启后影响后续传输的 DMA 宽度,每次传输结束后必须 spi_disable_data_merge
  4. TX FIFO 阈值:开启 merge 写时建议 spi_set_tx_fifo_threshold(ptr, 3),降低阈值加速 DMA 填充启动
  5. Cache 操作:merge + DMA 使用 WORD 宽度访问 buffer,若 buffer 在可缓存区域需确保 writeback/invalidate 覆盖完整 cache line;若 buffer 放在 .noncacheable 区域(如 AHB SRAM)则无需 cache 操作
0
0

订阅

发表回复 0

Your email address will not be published. Required fields are marked *

captcha
Enter the characters shown in the image:
Reload

This CAPTCHA helps ensure that you are human. Please enter the requested characters.