请稍侯

K60 SPI触发DMA数据传输

22 November 2014

  这段时间一直在折腾K60的DMA和SPI,希望通过DMA将数据通过SPI发送出去。这篇博客介绍的功能是实现了SPI0和SPI1的回环测试,然后通过SPI0触发DMA,将数据从内存A通过SPI0发送到SPI1,SPI1再次触发DMA,将数据存储到内存B。下面介绍下如何实现的。

1 SPI的工作原理

  基本知识大家直接谷歌就可以搜到一大堆,分为主机和从机,需要MISO、MOSI、SCK和SS四根线等等。主要介绍下K60的SPI的一些特性:
  (1)支持4个字的FIFO
  (2)速度大概可以达到总线时钟的一半
  (3)每二个SPI模块可以接多个从机(最多6个)
  (4)发送和接收可以通过中断或者DMA方式,中断源只有一个,需要在中断服务例程中判断中断标志位。
1
  从上面这张图中可以清楚地看到SPI的结构,数据可以通过DMA和中断发送和接收,发送和接收分别对应一个FIFO,大小为4个字,和发送相关的寄存器PUSHR是一个32位的寄存器,高16位代表命令字,表明发送到哪一个从机以及发送完片选的状态等等,这就意味着每次发送最大发送16字节的数据,超过可能要分次发送;和接收相关的寄存器POPR寄存器为32位,里面就是SPI收到的数据,对这个寄存器按照8位和16位方式的访问等效于32位访问。

2 DMA的工作原理

  DMA(Direct Memory Access)的作用就是为了减少CPU的负担,将数据的传输使用DMA总线进行,K60的DMA也成为eDMA,意思就是enhanced,增强型DMA。可以实现内存到内存,外设到内存,内存到外设,外设到外设的数据传输。可以指定传输数据的宽度以及大小,有许多触发源(触发源的作用就是触发DMA传输,我理解为类似于中断的概念)。可以配置中断(传输完成中断和半传输完成中断,同样对应一个中断源,需要判断中断标志位),除了通过触发源触发DMA传输,还可以配置为软件触发,功能还是比较强大的。

3 寄存器简要说明及配置

  下面分别对SPI和DMA的寄存器进行介绍。

3.1 SPI相关寄存器

  其实大部分通信模块的寄存器都很类似,肯定会有控制寄存器和数据寄存器,想要实现基本功能只需要配置控制寄存器的几个位即可。第一个介绍的寄存器是MCR寄存器,如下所示。

(1)SPI配置寄存器 (SPIx_MCR)

2

(2)时钟和传输属性寄存器-主机(SPIx_CTARn)

3

(3)时钟和传输属性寄存器-从机(SPIx_CTAR_SLAVE)

4

(4)状态寄存器(SPIx_SR)

5

(5)DMA/中断请求选择和使能寄存器(SPIx_RSER)

6
  在发送数据时需要向数据寄存器PUSHR写数据,之前有讲到,PUSHR是一个32位的寄存器,高16位代表命令字,表明发送到哪一个从机以及发送完片选的状态等等,比如说,需要发送的数据字节是0x1234,命令字节0x8001(片选信号保持拉低,使用CTAS0配置传输,拉低pcs0),那么需要发送的数据为0x8001_1234,这就需要你先将数据进行预处理(加上命令字段)再进行发送,传输完成时TCF标志被置位。
  接收数据时只要等RFDF被置位(RXFIFO不空)读取POPR寄存器即可。

3.2 DMA相关寄存器

  DMA涉及的寄存器较多,其实理解了它是如何工作的也就指导需要设置哪些寄存器了。首先需要设置DMA多路复用器(Channel Configuration Register (DMAMUX_CHCFGn)),设置DMA的触发源(触发源参考芯片手册3.3.9.1章节,因为表的内容太多放不下),最后设置使能DMA。
  接着就是对DMA的具体属性进行设置了,原理如下图所示:
7
  DMA中有主循环(major loop)和次循环(minor loop),其实就是我们写程序时的嵌套循环一个意思。只不过需要注意的是两个循环的单位不一样,major loop的单位是次,也就是minor loop发生了多少次,minor loop的单位是字节,也就是每次minor loop传输的字节数。举例来说:一块大小为96个字节的内存,我可以设置为major loop为24,minor loop为4,也就是说minor loop每次传输4个字节,每次minor loop结束时major loop的计数器减1,同时源地址偏移指定的字节数(目的地址也可以偏移),如此循环直到减为0,传输完成标志置位,可以配置结束时是否产生中断。
  理解了原理之后,我们就直到需要设置:使用DMA的通道号、DMA触发源、源地址和目的地址、每次minor loop结束源地址和目的地址的偏移、major loop次数、minor loop的字节数、源地址和目的地址的数据宽度、major lopp结束之后是否禁用DMA请求。这些设置参照DMA相关寄存器设置就好。设置完之后使能DMA了,并且使能DMA请求。

4 功能实现

  SPI模块中有两个标志可以出发DMA请求,如下图所示,TFFF标志和RFDF标志,由DMA完成时自动清除标志位。程序流程是这样的:首先TFFF标志是被置位的(TXFIFO为空),触发DMA0将数据由数组A拷贝至SPI0的PUSHR(记得要预处理加上命令字节),SPI0发送至SPI1,此时SPI1的RXFIFO不为空,RFDF标志被置位,触发DMA1将数据从SPI1的POPR寄存器拷贝至数组B。
8

5 遇到问题

5.1 接线问题

  SPI0和SPI1回环测试时需要将SPI0的MISO和SPI1的MOSI相连,SPI0的MOSI和SPI1的MISO相连,SCK和PCS0分别连到对方的SCK和PCS0。

5.2 TXFIFO和RXFIFO必须使能

  如果不使能,那么TFFF和RFDF可能不会被置位。

5.3 发送的数据必须加上命令字

  未使用DMA收发数据时,测试时主机的TCF标志已经被置,说明数据已经传输出去,可是从机一直没有收到,后来看到网上代码在发送数据时都是要将前面的命令字加上(主要就是片选字段要选中),测试时发现只向PUSHR寄存器写数据时数据不能接收到,加上命令字之后就可以了。

5.4 DMA速度较快

  DMA传输数据速度较快,本来在从机端使用RFDF触发中断,在中断中打印出POPR中的数据,发现数据值拷贝了前面的几个,调试一直找不出什么原因,以为数据没有全部发出,加了DMA传输完成中断,发现DMA传输已经完成,便猜测有可能数据传输太快,来不及触发中断打印出来,后来在从机也使用DMA接收数据,发现数据其实以及全部发送过来了。