一、概述
经过[玩转先楫SPI外设系列之一] 细说SPI主机发送性能最大化实现方案的文章,我们可以照葫芦画瓢来进行一个SPI主机接收性能实现方向的方案,本文基于这个进行说明。
验证条件是:使用SPI四线模式(QSPI),从机器件为华邦flash--W25Q64,读取一页数据256字节。
二、步骤
(一)读取页数据分析
从华邦对应的手册来看,QSPI读取数据的指令之一是Fast Read Quad I/O---EBh,从手册可以看到,该指令操作是:
指令(8 number clock) + 地址(3 * 2 number clock)+ dummy (3 * 2 number clock) + DATA(2 number clock)
(二) 代码实现
从(一)可知,SPI主机需要开启命令段和地址段,地址段是24位并且是QSPI模式发送,读取需要发送三个dummy。那么基于上篇的SPI发送DMA配合一起,可以这样实现:
封装的spi_rx_trigger_dma API如下:
(三) 现象不符合预期
试着烧录代码之后,发现在20M左右的SPI频率,接收时候SPI SCLK波形能够连续,但再高之后的SPI频率,就会出现接收到一定数据量后突然产生间隔,之后会继续连续,这种间隔产生是不符合预期的,也会导致接收速度性能达不到理想速度。时间间隔长达2.41us。
(四)实现预期效果
从上述上看,在接收到20个字节突然SPI主机就不发时钟,待到一段间隔后,才重新开始,这看起来就是DMA还没启动,但是SPI已经开始传输。
从flash角度上看,当接收到对应的指令后,flash这个从机已经准备好数据,等待SPI SCLK时钟;从SPI主机来看,先楫的SPI接收FIFO长达4个字,也就是16个字节。那么会不会是DMA还没配置和启动,SPI就已经开始传输了,然后等到DMA启动之后,才开始从SPI FIFO搬运。
以下做个单步调试,打断点到配置SPI和SPI DMA的API接口spi_setup_dma_transfer上。
进行到下一个语句,逻辑分析仪发现,SPI已经开始在传输,但是这时候DMA尚未配置和启动。可以理解为,由于SPI已经提前配置后开启靠着FIFO接收一定数据量后阻塞了总线,之后配置的DMA这个流程也需要一定的耗时,所以也会造成一定的间隔产生。
由此可知,我们需要先配置好DMA以及开启DMA,再配置SPI启动,这样可以让DMA时刻在等待SPI的事件请求。把spi_setup_dma_transfer 这个API放于spi_rx_trigger_dma这个API之后,从逻辑分析仪可以看到,SPI SCLK以及可以保持连续。
(五)再进一步(使用SPI merge功能)
上述的都是基于数据量为四的整数倍的接收,如果遇到不是整数倍的,如果使用merge功能,会导致数据合并错误的问题。但我们可以从DMA上去入着手点:
1、照样开启SPI的merge功能
2、DMA传输使用四字节宽度,突发传输长度保持不变。
3、遇到不是四的整数倍,强行四的整数倍的数据量,并且这个数据量作为DMA传输长度,但源数据量长度保持不变。比如要接收252字节,给SPI的传输长度是252字节,但是给DMA传输的长度是补满4字节,也就是256字节。
4、SPI传输完毕后,需要再判断下DMA是否传输完成以便复位下DMA,方便下次收发。
通过示波器可以看到,接收到252字节,SPI就停止传输了。与预期的符合。
三、总结
1、先楫的SPI主机无论从发送还是接收角度上看,都可以满足手册所标的SPI频率,并且可以做到SCLK不连续。
2、性能的提升需要借助外设的细节功能以及场景需要,需要开发者从自己的应用角度出发优化。