我们在做SPI应用时,有时希望通过定时器来定时地触发SPI的收发,并利用DMA完成数据的传输。这里,以STM32L476芯片为例来做个演示,以供参考。
本示例的大致过程是这样的:
片内SPI1做Master,SPI2做Slave,均工作在全双工模式。
这里使用片内定时器TIM3,通过它的更新事件触发DMA请求,通过DMA将数据给到SPI1的数据寄存器并发送出去,同时也开启SPI1接收事件的DMA传输。总之,SPI2的收、发事件都启用DMA完成。
TIM3的更新事件周期控制两个SPI的收发节奏,即定时器每产生一次更新事件,SPI1/SPI2这两个主从通信模块就进行一个数据的收发。我们可以通过调整定时器的计时周期来调整数据收发的快慢。
好,先基于STM32CubeMx进行初始化配置。
1. 对TIM3做基本配置。选择时钟源,先大致估算个定时器计时周期,调试时我们可以自行灵活调整。
开启基于TIM3更新事件的DMA配置。传输方向是从Memory 到 外设SPI1,即将内存数据传输到SPI1的数据寄存器进行数据发送,这里选用循环模式,以便测试。
2. 对SPI1/SPI2进行基本配置。细节请参看下面三幅截图。
3、DMA的配置情况。
在TIM3和SPI1/SPI2外设配置中,开启了相关事件的DMA请求,汇总如下图。
4、准备用户代码。
当完成基于STM32CubeMx的初始化配置并生产初始化代码后,我们准备相应的用户代码。这里准备了4个内存数组,分别用于存放SPI1/SPI2的收发数据。
在定时器的触发下,Master SPI1逐字的向Slave SPI2发送“Hello! I AM STM32!”,Slave SPI2也逐字的向Master回应“HI,MASTER,ME TOO!”,这样循环操作。下面两幅截图是本示例中使用到的用户代码,是基于STM32Cube固件库而编写的。应该说简单明了,无须过多解释。
5、结果验证。
下面的截图是两个不同时刻SPI通信时的信号波形图。其中,紫色的是时钟信号,绿色、黄色是数据信号。两个数据信号间的时间间隔由定时器的更新周期决定。
下面的截图是在调试状态下的通过观察窗口得到的SPI1/SPI2分别从对方收到的数据,即SPI2收到的数据是“HELLO,I AM STM32!”,SPI1收到的数据则是“HI,MASTER,ME TOO!”
整体上讲,上述应用的实现不难,可能稍微有点综合性。
要实现上述应用,首先要求我们对DMA传输的原理有清晰的了解,触发事件,传输源、传输目标几个概念及关系要弄清楚。
另外,即使我们基于STM32固件库开发,不一定能找到完整的现存例程,我们可能需要基于现有驱动代码自行组织用户程序。
还有,在上面示例代码中,我没有开启DMA的中断事件,我们在具体应用中可以根据情况来决定是否启用DMA中断,比方开启传输完成中断等。
最后顺便提醒下,这里我们基于定时器事件的DMA请求而自行指定DMA的源端和目的端,一定要保证是该触发事件所请求的DMA可以到达的地方。建议编程设计前最好查看下相关芯片数据手册里的芯片模块及总线框架图,不然的话,有时你可能遇到你指定的DMA根本就不正常运作的情况。