在i.MXRTxxx芯片上如何实现DMA链式传输以使SPI从设备接收速率达到50Mbps上限?
摘要:大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRT下使能DMA链式传输可达到SPI从设备接收速率上限50Mbps。 最近痞子衡在帮一个 RT600 的 AR 眼镜客户优化 SPI 从设备接收数据的速率,我们知道 S
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRT下使能DMA链式传输可达到SPI从设备接收速率上限50Mbps。
最近痞子衡在帮一个 RT600 的 AR 眼镜客户优化 SPI 从设备接收数据的速率,我们知道 SPI 从设备接收数据方法一般有三种:1) 轮询模式,2) 中断模式,3) DMA 模式。前两种模式都会受到 CPU 性能的限制,而 DMA 模式则可以最大程度地降低 CPU 负载,提高数据传输效率以及速率。
然而使用 DMA 传输也会有潜在问题,单次 DMA 传输数据长度有上限(受限于 DMA 通道缓冲区长度),如果在一次 DMA 传输结束之后才开始手动启动下一次 DMA 传输,中间的延迟则有可能导致漏收数据,这时我们就需要使用 DMA 链式传输(Linked Transfer)来解决潜在漏收数据问题。这便是今天我们要讨论的话题:
Note1:本文方法主要针对 RT500/600 上的 DMA(又称LPC_DMA),其来自于恩智浦 LPC 系列。
Note2:RT700/RT4digits 上的 eDMA 与 LPC_DMA 完全不同,其来自于原飞思卡尔 Kinetis 系列(KL25 DMA是第一代,K60 eDMA算第二代)。
一、Flexcomm SPI速率
在讨论这个话题之前,我们先来看一下 RT500/600 上的 SPI 外设本身速率。我们知道 RT3digits 上有一个非常神奇的外设 Flexcomm(与之对应的是 RT4digits 上的 FlexIO),这个外设可以按照用户需求被配置成 USART, SPI, I2C 或者 I2S 外设功能之一。
RT3digits 内部一般会有多个 Flexcomm,而其本身又分为普通和专用两种类型:普通 Flexcomm 内部结构复杂,因为外设功能配置灵活性而稍稍放弃了一点传输性能;专用 Flexcomm 则限定用于特定外设功能,放弃了灵活性,但是传输性能更高。下面是芯片数据手册里找到的 SPI 速率:
芯片系列
普通SPI
Master/Slave:TX/RX - 25Mbps
高速SPI
Master:TX/RX - 50Mbps
Slave:RX - 50Mbps, TX - 35Mbps
RT500
Flexcomm 0-8, 10-12
专用 Flexcomm 14,16
RT600
Flexcomm 0-7
专用 Flexcomm 14
二、为什么必须要用DMA?
下图是 Flexcomm 模块简图,其内部对于收发均配置了一个深度为 8 entries 的 FIFO(对于 SPI frame 长度硬件上能直接支持 4-16 bits,所以这里 entries 是以 frame 长度为单位。如果配置为最常用的 8bits frame,那 FIFO 就能缓存 8bytes 数据),有一定的数据缓存能力,不至于因 CPU 响应不及而立即漏数据。
文章开头说了 SPI 从设备接收数据方法有三种,我们来一一具体分析:
轮询方式: CPU 每隔一段时间就来读一次 SPI RX FIFO 状态寄存器,一旦有数据就立刻取走,这种方法能够达到速率上限 50Mbps,但是代价是 275/300MHz 的 CPU 需要付出相当大的负载地在这轮询 SPI RX FIFO 寄存器状态,这对于应用程序设计太不友好,稍稍不慎就会漏数据,显得匆匆忙忙,一般不会这么用。
中断方式: 预先设置一下 SPI RX FIFO 的 level trigger point(1-8 entries),当 RX FIFO 中数据达到这个水平时就触发中断,在 ISR 里把数据取走。这种方法可以降低 CPU 负载,但是由于 Cortex-M33 中断延迟较大,再加上 ISR 代码执行时间消耗导致可能达不到速率上限 50Mbps(理想情况下需要 FIFO 触发设 4 entries,然后一次 ISR 读取 4 个 entries 数据),ISR 加点代码都需要谨慎,显得小心翼翼,因此也不太推荐。
