一、实验目标学会配置STM32的SPI寄存器和DMA寄存器,实现STM32的SPI1与SPI2通信功能,每次发送一字节数据,并可多次发送,如果接收的数据正确,则点亮LED灯。
二、实验目的加入DMA的SPI通信相对于普通SPI通信有什么好处?ST给SPI加了DMA功能出于什么目的?我觉得这是很重要的一个问题,一直边学习边想。以下是我的看法:
减少CPU负荷?我想这应该是DMA最主要的功能,可是对于SPI通信来说,其实大部分时候我们需要根据发送的指令->目标器件的应答来决定下一个指令,所以此时CPU还是需要一直等待每次通信的结束。而且像SD卡的操作,是一个顺序流的指令操作过程,用中断也不容易控制。那到底加入了DMA有什么好处?仔细查看了STM32F10xxx的用户手册,发现这么一行字“连续和非连续传输:当在主模式下发送数据时,如果软件足够快,能够在检测到每次TXE的上升沿(或TXE中断),并立即在正在进行的传输结束之前写入SPI_DR寄存器,则能够实现连续的通信;此时,在每个数据项的传输之间的SPI时钟保持连续,同时BSY位不会被清除。如果软件不够快,则会导致不连续的通信;这时,在每个数据传输之间会被清除”
也就是说如果连续传输而不使用DMA的话,需要CPU不停检测TXE并很快地置入SPI->DR的值,对于复杂程序的话这是很难达到的,而如果使用DMA,就可以轻易实现连续传输,CPU只需等待其完成就好。我想到的一个应用就是在写SD卡的时候,每次写一个块512字节,就可以用到,能提高SD卡的写入数据速率。
其次还可以降低功耗,记得数字集成电路老师说过一句话“软件上降低数字电路功耗的一个方法就是减少电平转换。”那么连续通信的时候,像SPI的BSY电平转换会大大减少!
最后一点,虽然效果不大,就是如果不是用DMA,那么CPU的工作就是搬运工,把SPI->DR的内容搬到内存存储起来,而如果使用DMA,就省略了这个环节!
我想,为什么实现同一个功能,有的执行起来很流畅,有的却很卡,应该和这些小细节的减载有关吧。
这次先把SPI基本通信写出来,然后再写SPI的连续通信,并看能不能用到SD卡读写上。
四、实验结果利用SPI1和SPI2进行两次数据传输,并比较SPI1_RX与SPI2_TX,SPI2_RX与SPI1_TX,数据相同点亮LED灯。
在某个论坛看到有人说把SPI的速度设置为2分频传输数据不正确,分析原因是DMA反应不过来。我也试了一下,传输正常,数据正确。(SPI传输速率是用JLINK仿真查看寄存器的)
哦,对了,期间还吃过一个亏,害我调了好久,就是下面的语句:
while( ( DMA1->ISR & (1<<17) ) == 0 ) ; //等待通道5传输完成
我写成:
while( DMA1->ISR & (1<<17) == 0 ) ; //等待通道5传输完成
由于“==”的优先级比“&”高,所以会先执行“(1<<17) == 0”,结果是0,再与上DMA1->ISR,那么相当于while直接跳过了,读不到数据!很低级的错误!所以提醒后来者,看起来可加可不加的括号,还是要加上去的好!
还有一个问题,一直在想DMA传输,那么硬件怎么认为一次传输的结束而停止以及怎样才能开启新一次的传输。我觉得最关键就是DMA的传输数量计数器以及DMA的传输完成标志。只要DMA的计数器不为零,就能响应请求传输,此时就算传输完成标志置位,也能进行DMA响应,只不过你不知道什么时候完成罢了。所以每次传输开始前,程序需要清除标志位并检测到该标志位置位,才知道一次传输是否完成!
续:终于把SPI的DMA弄完了,实现了连续发送和读取的功能,DMA开辟512字节的数组作为内存存储数据(所以连续发送最大的数据量也是512,当然可以在宏定义里面更改),通过num控制要写入或读入的数据量,源代码中有3个函数,一个函数是读写一体的,一个函数是只发送模式,一个函数是只接收模式,都通过测试。唯一的缺陷就是没有进行错误检测,特别说明一下,我把清标志位是放在函数前面而不是函数后面,就是想函数执行完,标志位依然还在,我们可以以此来判断是否有错误。在这里和大家分享一下小经验。
(1) 怎么测试?最好的测试方法我觉得就是双机通讯了,由于实验室资源比较好,所以我得以有两个STM32(非MiniSTM32,用的是AG嵌入式开发板)进行测试,所以以上代码都是通过双击测试的,不过我只整理了SPI1主机源代码,需要的自己稍微改一下就可以,程序中有注释!
(2) 用双机测试的时候,刚开始我没有共地,导致数据可以接收,但是数据错误!所以紧记,当你使用两个器件通讯或交互时,一定要先检查两个器件是否共地,甚至共源!
(3) 如果只有一个STM32其实也可以测试,就是把MISO和MOSI短接,但这个测试方法,用来测试SPI1_ReceiveSendByte(u16 num)就比较方便,用来测试只发送和只接收模式就需要改一下函数咯。
(4) 弄了这么久的SPI_DMA,也不知道用处大不大,总之弄完了,呵呵,也算比较了解SPI总线和DMA了,接下来想试试原子哥的新的SD卡函数,原来AG嵌入式开发板也是移植原子哥的旧版,也是有些卡初始化失败,我还以为是我的卡有问题呢?还有就是文件系统,前阵子只弄了基本的读写,准备把FATFS文件系统写得完善一点~
最后,附上源代码。(使用的不是MiniSTM32,所以大家在测试时只需要改一下LED驱动。)
第一个源代码是基础的,实现一个字节在SPI1&SPI2的传送;
第二个是函数化的代码咯,发送随意数量的8bit数据,数量小于512;
专营STM8/32
QQ 940436962
http://y-ec.taobao.com
银洋出品 必是精品
ST专业代理
SPI1_DMA(发送随意数量的8bit数据,数量小于512).zip
(1.09 MB)
SPI_DMA.zip
(1.11 MB)
|