打印
[STM32F1]

DMA—UART的代码应该怎么设计是最优解?

[复制链接]
1716|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
13400013591|  楼主 | 2020-4-13 09:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
平台是F103
先说下我的理解:

DMA收:
利用的中断是串口总线空闲中断。
DMA在后台(理解上的后台)搬运数据到缓存,当触发总线空闲中断,在中断中取出缓存的数据,这样就实现了按帧处理串口数据,也叫不定长度接收。

__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, rec_buff, BUFF_SIZE_REC);


整个架构是:
1.设置串口中断+DMA接收。
2.对端发送完成后,串口空闲会触发IDLE中断,进入中断后,从缓存取数据
3.在IDLE中断函数中,重设中断,重新开启DMA收。

---------------------------------------------------------------------------------------------------------------------------------

DMA发:
利用的中断是DMA的TC(发送完成)中断
相对于HAL_UART_Transmit的发送堵塞,发送完函数返回不同的是,DMA发送返回快
相当于是把缓存地址告诉DMA,DMA自行发送,发送完成后进入TC中断。

HAL_UART_Transmit_DMA
上述这个函数内部开启了UART_IT_TC


整个架构是:
1.设置DMA TC中断,在需要发送的时候调用DMA发送。
2.DMA发送完成,会进入DMA TC中断,表示发送完成。
3.在中断中重设DMA发送。

请问一下:
1.我上述的理解对吗?
2.为什么接收是用串口的IDLE中断,而发送是用的DMA的TC中断?有没有适用于DMA的接受中断?(我在手册上没有看到合适的寄存器,真的没有嘛?)
3.idle中断进入的标志是对端发送停止吗?我方持续发送,是否会影响这个IDLE?

使用特权

评论回复
沙发
yljon| | 2020-4-13 12:10 | 只看该作者
我平时用RXNE和TC搞定,其它没有试过

使用特权

评论回复
评论
13400013591 2020-4-13 13:57 回复TA
@yljon :好的吧,我以前做Linux的,用read读不定长习惯了,,,,, 
13400013591 2020-4-13 12:42 回复TA
用RXNE的话,那你接收是一个byte一个byte的接收啊? 
板凳
yklstudent| | 2020-4-13 13:06 | 只看该作者
DMA接收也可以TC中断,不过那是定长了,又不实用,除非你的协议特殊,就是固定长度的

使用特权

评论回复
评论
13400013591 2020-4-13 13:56 回复TA
对的啊,今天查了一天的资料。 DMA收的TC,得是达到DMA预设的接收长度才产生TC flag,这就没有意义,想要的是不定长接收。 请教您一下,DMA发的话用中断的意义是不是就在于:发送完成,清掉TC,以便于下一次的DMA发送可以进行? 
地板
pattywu| | 2020-4-13 16:19 | 只看该作者
教你一点,DMA发送完成中断,只是表示DMA把数据搬完了,并不表示UART已经把数据传完,应该还在传送中。

使用特权

评论回复
5
13400013591|  楼主 | 2020-4-13 16:21 | 只看该作者
pattywu 发表于 2020-4-13 16:19
教你一点,DMA发送完成中断,只是表示DMA把数据搬完了,并不表示UART已经把数据传完,应该还在传送中。
...

非常感谢!
这个昨天困扰我很久,,,手册说的有点含糊

使用特权

评论回复
6
jackghl| | 2020-4-14 15:30 | 只看该作者
本帖最后由 jackghl 于 2020-4-14 15:47 编辑

个人认为接收DMA还可以优化一下数据结构,使用双缓冲(内存地址顺序 缓冲B 1024  缓冲A 1024)和环形数组,
DMA循环接收1024BYTE(缓冲A),
整个架构是:
1.设置串口中断+DMA接收(DMA禁止中断)。
2.对端发送完成后,串口空闲会触发IDLE中断,进入中断后,计算当前DMA数据长度HEAD
3.在IDLE中断函数中,memcpy (缓冲B, 缓冲A,1024),缓冲B中从TAIL开始,取数据((HEAD-TAIL)&1023),最后TAIL=HEAD。

优势,
1.只有一个串口中断,不需要DMA中断,不需要重新设置DMA接收;
2.有时候在IDLE中断函数中 停止DMA中断会导致丢数的情况。

使用特权

评论回复
7
pattywu| | 2020-4-14 17:47 | 只看该作者
本帖最后由 pattywu 于 2020-4-15 07:53 编辑

见你的鬼,对方发送的数据长度比整个缓冲区都长,没DMA完成中断,等着错误接收吧。
485通信的时候,DMA发送完成中断之后,还要等UART发送完成之后,才能从发送切换接收,否则,最后1字节是错的,或是丢了。

使用特权

评论回复
8
xenkuo| | 2020-4-14 22:46 | 只看该作者
你的这个架构基于两个假设:
1, 对方发送单包数据不会中断
2,对方发送的最大连续数据不超过你的DMA buffer总大小。

这种假设可能会被满足,但是一个良好的设计应该不会做这种假设。
---------------
DMA发送应该挺好处理,基本也就这样。关于接收,大部分嵌入式系统应该可以接受uart单字节中断这种方式的,这应该是很经典也是比较稳定的方案。如果认为中断太多,定长DMA中断应该是比较经典的选择,可是我忘记怎么处理尾部数据的处理了?主动超时轮训?

使用特权

评论回复
9
jackghl| | 2020-4-15 14:43 | 只看该作者
xenkuo 发表于 2020-4-14 22:46
你的这个架构基于两个假设:
1, 对方发送单包数据不会中断
2,对方发送的最大连续数据不超过你的DMA buffe ...

情况1,只是处理数据的函数需要修改,DMA接收数据过程是没问题的;
情况2,如果使用DMA接收完成中断,难道不需要加大BUFFER来存储?

使用特权

评论回复
10
xenkuo| | 2020-4-15 19:24 | 只看该作者
jackghl 发表于 2020-4-15 14:43
情况1,只是处理数据的函数需要修改,DMA接收数据过程是没问题的;
情况2,如果使用DMA接收完成中断,难 ...

感觉解释不清楚了。
我理解的接收端解决方案是同时是能串口idle和dma接收完成中断,然后软件还要做缓存和分包处理。其他的方式都应该是有漏洞的。

使用特权

评论回复
11
paotangsan| | 2020-5-13 16:37 | 只看该作者
感觉各有优缺点

使用特权

评论回复
12
Prry| | 2020-11-25 23:57 | 只看该作者
使用“双缓存DMA接收”,否则串口数据连续过来时,可能会丢失。参考DMA收发实现,实测高速通信(1.5Mbps)不翻车:https://acuity.blog.csdn.net/article/details/108367512

使用特权

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

本版积分规则

16

主题

56

帖子

1

粉丝