打印
[APM32F4]

APM32F411 USART-IDLE-DMA不定长数据收发

[复制链接]
1350|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1455555|  楼主 | 2023-11-30 14:24 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 1455555 于 2023-11-30 14:25 编辑

1、DMA简介
DMA(Direct Memory Access:直接存储器存取)在无须 CPU 干预的情况下,可实现外设与存储器或存储器与存储器之间数据的高速传输,从而节省 CPU 资源来做其他操作。
产品一共有两个 DMA 控制器,共 16 个数据流。每个数据流对应 8 个通道,但每个数据流同一时刻只能使用 1 个通道。每个数据流可设置优先级,仲裁器可根据数据流的优先级协调各个数据流对应的DMA 请求的优先级。

2、比较IDLE和TXC两种收发模式
平时我们发送定长数据,我们通常使用发送完成中断TXC进行数据的发送。这次使用串口IDLE中断利用DMA进行不定长数据发送。
优点:
a、使用字节中断的方式去接收,会频繁进入中断,影响系统实时性。使用IDLE中断可以减少进入中断的次数,提高系统的实时性。
b、通过前面对DMA的介绍,可以知道,我们设定好搬运方向,起始地址和目标地址等信息之后,无须CPU的干预。这样就可以减少CPU的负载,让CPU得以空闲处理其他任务。在大批量数据传输时,DMA具有极高的优势。

3、例程用到的知识点补充
A、IDLE中断
这里是为什么选用空闲IDLE中断的呢?
我们处理接收到的数据,需要依靠一定的中断进行处理。DMA每个数据流都有5 种类型的中断事件,分别是半传输、传输完成、传输错误、 FIFO 错误和直接模式错误。通常我们使用半传输,传输完成中断请求,但这两个适用于定长数据传输,也就是说,我们能知道传输多少字长传输完成时,才适用。
怎么在不知道传输长度时,也能知道是否传输完成呢?——串口空闲中断请求。
当一次数据传输完成时,会产生空闲中断。配置好串口和DMA后,等待数据传输完成,IDLE中断产生,DMA实时搬运。下面为用户手册中IDLE中断相关信息。
IDLE标志:
当检测到空闲总线时,由硬件置 1;
由软件清 0:先读取 USART_STS 寄存器,再读 USART_DATA 寄存器完成清0。后续编写代码时,会需要注意到清零有先读STS寄存器再读DATA寄存器的要求。


B、DMA_NDATA寄存器
在代码编写过程中,会多次用到该寄存器中的数据。
在DMA配置时,设定NDATA的初始值,只有禁止数据流时,才允许对此寄存器进行操作,使能数据流后,该寄存器为只读,用来指示要传输的剩余数据项数目。每次 DMA 传输后,该寄存器递减。代码编写中,重新使能数据流,使寄存器自动重载初始值。

4、例程实现
例程实现功能为通过串口IDLE中断与DMA配合,完成串口助手发送数据的回显。
A、代码编写流程图


a、USART_Init

串口配置成波特率115200,收发模式,1位停止位,0位校验位,8位数据位。开启串口空闲中断,同时设置中断优先级。这里只使用到一个中断,所以优先级没有特殊规定。使能串口DMA。

b、USART_DMA_Config
DATA_BUF_SIZE设置成32,使用USART1的收发,对应DMA2channel4的stream4和stream7。如下图所示。
USART接收时,数据由USART_DATA寄存器运输到设置的rxDataBuf数组中,因此传输方向为从外设到内存,外设地址无需自增,内存地址需要设置为增加。以字节形式发送。配置完成后,打开DMA接收数据流。接收数据流保持常开,只有在处理接收数据时关闭。
USART发送时,数据由txDataBuf数组运输到USART_DATA寄存器,由串口发送至PC串口助手端。因此传输方向为从内存到外设。其他与接收时配置保持一致。
配置完成后关闭发送数据流,等到数据接收完成后打开。



c、USART1_IRQHandler

在接收完数据后,产生IDLE中断。在服务函数中,我们按照手册要求,通过读取USART_STS寄存器,再读取DATA寄存器,完成IDLE标志的清除。然后将RecvFlag置1。这个参数就是用来传递传输是否完成信息的。
关闭USART_RX对应的DMA数据流,计算得出接收到的数据长度。这里的DMA_ReadDataNumber函数就是读取DMA_NDATA寄存器里的数据。函数具体内容如下图。NDATA寄存器初始值为我们配置DMA时设置的DATA_BUF_SIZE:32;每接收到一个数据,NDATA就减1。因此使用它的初值减去接收完后的值,就等于接收到的数据长度。
不要忘记DMA接收完成标志的清除。处理完数据后,再次打开DMA接收数据流。重新使能后,NDATA的值会被重新加载为预设值32。
(加粗的部分都来源于手册对该寄存器的描述,这里再次贴一下图,我开始对这个寄存器理解有误,导致我的代码写得很乱



d、USART_SendArray

在main函数里面,一直在判断RecvFlag判断是否置1,当接收完成标志位置1后,进入到数组发送函数。为了保证函数能够单独使用,设置两个输入参数。第一个为需要发送的数组,第二个为需要传输的数据长度。
先要判断需要传输的数据是否有效:要求len不为0,且不能超过txDataBuf的最大值DATA_BUF_SIZE。当传输数据长度len超过DATA_BUF_SIZE时,只传输DATA_BUF_SIZE长度。如过输数据长度len未超过可传输最大值,传输数据长度就为len。
173行:将需要传输的数组COPY到DMA配置的发送地址处。

e、main

完成发送后,再次等待下一次的接收完成,这部分我是将接收到的数据发送出去,也可以进行其他的数据处理。
程序大概执行过程如流程图所示。

5、实验现象
发送的数据可以正常进行回显。实验成功。



使用特权

评论回复
评论
可口可口 2024-7-4 14:48 回复TA
你好,请问你使用串口空闲中断,找到如何去设置其空闲中断的触发时间吗,就是接收完一帧数据后多久会触发空闲中断。 
1455555 2023-11-30 14:28 回复TA
想到例程有个问题。。。第一个是在处理数据时,会关闭DMA接收数据流,那如果这个时候来了新的数据,就会造成数据的丢失。 
沙发
es16| | 2024-3-19 11:33 | 只看该作者
佬,工程代码可以给我看看吗  2640209801@qq.com

使用特权

评论回复
板凳
wxqfhy| | 2024-5-13 22:13 | 只看该作者
你好,参考你的贴子,我是用405,一直调试不成功,启动RX DMA就不能发送数据,工程代码可以给我看看吗  wxqfhy@126com,

使用特权

评论回复
地板
szt1993| | 2024-5-23 17:56 | 只看该作者
开启DMA一般应该就不会关闭了吧

使用特权

评论回复
5
xiyuyu| | 2024-6-26 17:35 | 只看该作者
你好可以给我发一份代码吗
xiyuyu@88.com

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

17

帖子

1

粉丝