今天项目里用到了DMA相关的技术,调了比较长的时间的,特地来记录一下。

DMA是直接存储器存取,它的主要功能是用来搬数据, 但是不需要占用CPU。对于F103芯片来说,DMA控制器包含DMA1和DMA2,其中DMA1有7个通道,DMA2有5个通道。下图为DMA1的通道配置情况。

图 21‑2 DMA1各个通道的请求映像

本次使用的主要是DMA1中的通道5,即使能USART1_RX功能。具体设置的时候就是把USART1->DR初始化为外设地址,自定义一块内存地址为USART1_Rx_Buffer。在数据读取的时候,外设地址是不变的,一直是USART1->DR,而内存地址因为一直在写入所以需要递增。有一个值得注意的配置是DMA_Mode,有DMA_Mode_Normal和DMA_Mode_Circular两种模式可以选择,后文细说。

从中断的角度,由于开启DMA单帧接收中断USART_IT_IDLE,DMA接收中断USART_DMAReq_Rx,同时关闭串口的单字节接收中断USART_IT_RXNE。当串口接收到数据的时候会进入到USART1_IRQHandler函数。此时值得注意的是,需要用USART_GetITStatus函数来判断USART_IT_IDLE的状态,用法如下:

1
if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET)

如果函数进入if判断,说明接收到一帧数据。

此时首先要解除IDLE的中断状态,解除方法是调用USART1->SR和USART1->DR两个寄存器。然后关闭DMA,用下式计算本次USART传输的数据量

1
usart1_this_time_rx_len = USART_DMA_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);

然后再将需要传输的数据总数填入DMA1_Channel5->CNDTR寄存器中,再打开DMA。

这时需要做一个判断,如果刚才传输的数据量等于我需要的数据量,比如协议规定单次传输数据量为264字节,则说明本次数据长度有效。此步骤非常重要,因为并不是每一次接收到的数据量均为需求的长度(原因不确定),因此需要在此做一个筛选。

1
if(usart1_this_time_rx_len == SIT_BUFFER_SIZE)

此时还需要判断包头是否正确,如果包头正确则把数据拷贝至一块单独的内存做备份。这块内存就可以用来进行数据处理操作了。

这里值得提到的就是,当我准备把USART1_Rx_Buffer的数据拷贝到另一块单独内存时出现的bug。当时我用keil调试时,USART1_Rx_Buffer的数据是正常的,即可以看到正确的包头,而且内部的数据变化也比较明显,但是我不论是用memcpy还是用for循环来复制都不能把USART1_Rx_Buffer的数据拷贝出来,新内存地址的数据是不正确的。

经过很多尝试后,我把DMA_Mode_Circular改为DMA_Mode_Normal,突然新内存地址的数据就正常了。我查了相关资料,解释如下。

参考https://blog.csdn.net/weixin_45362275/article/details/119544121

https://blog.csdn.net/qq_40831436/article/details/115071656?spm=1001.2014.3001.5502

https://blog.csdn.net/qq_40831436/article/details/119566869?spm=1001.2014.3001.5502

https://blog.csdn.net/qq_40831436/article/details/123665418?spm=1001.2014.3001.5502

DMA_Mode_Normal是正常模式,当一次DMA数据传输完成后就停止DMA传送;而DMA_Mode_Circular是循环模式,当一次DMA数据传输完成后继续传输

在普通模式下,接收完一次数据后,CNDTR自动清0,需要先关闭DMA,重置CNDTR,然后再开启DMA。

在循环模式下,接收超过DMA剩余内存的数据时,首先接受完剩下空间所能容纳的数据,此时CNDTR=0,然后DMA自动装载初始化时的配置,下一步接收数据时的地址指向RxBuff[0],CNDTR重置为DMA内存空间长度,最后DMA在RxBuff[0]处继续接收剩下的数据。

相比较而言,循环模式主要用于AD采样等需要循环队列的场景。本次我的使用场景是下位机通过20ms频率的速度发送坐垫压力传感数据给板子,每次发送的数据量是固定为264字节的。由于循环模式的读取过于复杂,所以我最终没有采用循环模式,而是就采用了普通模式。