Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
DMA
串口
20
新的STM32串口DMA驱动的一点疑问?
发布于 2020-11-26 17:01:09 浏览:2728
订阅该版
之前一直使用的是rt-thread 2.x版本,想升级到rt-thread 4.x版本;硬件平台STM32F767;串口接收使用DMA方式;串口DMA驱动主要涉及: 1) 硬件串口的IDLE中断; 2) DMA传输完成TC中断;其中TC中断主要是处理DMA CIRCULAR模式缓冲区数据指针从零计数的问题,以前的TC中断处理的代码如下: ```c level = rt_hw_interrupt_disable(); recv_len = serial->config.bufsz - uart->dma.last_index; uart->dma.last_index = 0; rt_hw_interrupt_enable(level); if (recv_len) { rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); } ``` 这个串口驱动的DMA使用下来没有问题; 最新的针对STM32串口DMA接收的驱动代码,IDLE中断处理时一样的,针对TC中断的处理有一些小的更改: ```c if ((__HAL_DMA_GET_IT_SOURCE(&(uart->dma_rx.handle), DMA_IT_TC) != RESET) || (__HAL_DMA_GET_IT_SOURCE(&(uart->dma_rx.handle), DMA_IT_HT) != RESET)) { level = rt_hw_interrupt_disable(); recv_total_index = serial->config.bufsz - __HAL_DMA_GET_COUNTER(&(uart->dma_rx.handle)); if (recv_total_index == 0) { recv_len = serial->config.bufsz - uart->dma_rx.last_index; } else { recv_len = recv_total_index - uart->dma_rx.last_index; } uart->dma_rx.last_index = recv_total_index; rt_hw_interrupt_enable(level); if (recv_len) { rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); } } ``` 和之前的代码相比, 1) 增加了对缓冲区半满的处理,这部分和串口IDLE中断的处理类似,就是对应 (recv_total_index != 0)的情况; 2) 从代码上看, if (recv_total_index == 0)这个条件应该对应的是TC(传输完成)的情况,由于工作在CIRCULAR模式(STM32的数据手册上说,TC完成时,NDTR会自动装载初始设定的值),__HAL_DMA_GET_COUNTER()得到的是初始设定时的config.bufsz,得到recv_total_index == 0; uart->dma_rx.last_index = 0正常复位; 现在的问题是,因为DMA工作在CIRCULAR模式,数据的传输是连续不断的,在针对TC中断处理的时候,串口有可能有新的数据,这样__HAL_DMA_GET_COUNTER()得到的就不是config.bufsz。比如在处理TC时新收到了一个字节,recv_total_index = serial->config.bufsz - __HAL_DMA_GET_COUNTER(&(uart->dma_rx.handle))得到的值为1,这样的结果并不符合实际情况,相当于漏掉了针对缓冲区满指针回零的处理。 个人感觉之前的DMA驱动针对TC的处理更合理一些, ``` recv_len = serial->config.bufsz - uart->dma.last_index; uart->dma.last_index = 0; ``` 就是把uart->dma.last_index到config.bufsz的数全部读出来,在TC处理时新进来的数据会在下一次IDLE中断时通过__HAL_DMA_GET_COUNTER()的调用处理而不会遗漏。 不知道有没有使用过STM32平台新的串口DMA驱动的同学,大家针对这个问题有没有什么建议?还是说在针对TC的处理完成前,串口DMA在CIRCULAR模式时也不会进行新的传输?
查看更多
4
个回答
默认排序
按发布时间排序
我夏了夏天
认证专家
2020-11-26
Life isn't about finding yourself, life is about creating yourself.
要解决这个问题,你需要搞清楚 DMA 中断的触发条件,把断点加载串口中断处理函数和 DMA 中断处理函数上,观察这两个中断的触发顺序,以及 DMA 中断触发时的情况,可能会对你理解这个问题有帮助。 基本上使用串口 DMA 的流程是这样的,配置时将串口设备与某个通道的 DMA 中断绑定起来,此时如果发生串口中断,则会触发 DMA 传输,DMA 完成后将会回调我们在串口驱动中编写的中断处理函数,更新串口 device 的缓冲区 index。
Acuity
2020-11-26
这家伙很懒,什么也没写!
1、之前的DMA实质上是不合理,只使用了TC中断,即是DMA 单buf接收;如果有持续数据进来,将可能覆盖数据;不过,串口这种低速总线,怎么整都很难丢数据; 2、新的STM32串口DMA接收做的很好,用了半满中断(之前没去细看,一直想提交个老STM32的DMA 串口接收补丁,原来已经实现了,哈哈。。);关于你的TC中断处理疑问:TC中断后,CPU介入将DMA buf后半部拷贝数据到内存中,这个时候即使有串口数据来,DMA只是将数据搬运到buf的前半部分,在DMA将buf前半部分填满并触发HT中断前,CPU早就把后半部分数拷贝走了(如果CPU还没拷贝完成,就要考虑整个系统设计问题了,是否有过于频繁的中断资源占用CPU等等,或者增大DMA buf);HT中断也与之同理; 3、ST高系列,支持DMA 双buf(乒乓缓存),这个就好使多了;当然半断也够用了。 参考,STM32F0/F1 DMA收发实现,实测1.5Mbps波特率不翻车: [文章](https://acuity.blog.csdn.net/article/details/108367512) [代码仓库](https://github.com/Prry/stm32-uart-dma)
whj467467222
认证专家
2021-05-25
开源,分享,交流,共同进步
https://github.com/RT-Thread-Studio/sdk-bsp-stm32h750-realthread-artpi/pull/201 https://github.com/RT-Thread-Studio/sdk-bsp-stm32h750-realthread-artpi/tree/lab_serial 试试这个呢?
07lhluo
2021-11-26
这家伙很懒,什么也没写!
@softwind, 既然全满中断有DMA持续搬运数据修改__HAL_DMA_GET_COUNTER()数值的嫌疑,那其实半满中断也有同样的嫌疑。 我有一计如下,分开处理则不需要调用__HAL_DMA_GET_COUNTER(),可消除疑虑,请大家一起斟酌讨论。 ``` static void dma_isr(struct rt_serial_device *serial) { struct stm32_uart *uart; rt_size_t recv_total_index, recv_len =0;//recv_len初始化为0; rt_base_t level; RT_ASSERT(serial != RT_NULL); uart = rt_container_of(serial, struct stm32_uart, serial); //既然进入此dma_isr()中断函数,DMA持续搬运数据导致可能调用__HAL_DMA_GET_COUNTER(&(uart->dma_rx.handle))取得的数值有被修的嫌疑, //分开中断类型分别处理,则不需要调用 __HAL_DMA_GET_COUNTER(&(uart->dma_rx.handle)),可避免嫌疑; if (HAL_DMA_GET_IT_SOURCE(&(uart->dma_rx.handle), DMA_IT_TC) != RESET) { level = rt_hw_interrupt_disable(); //既然为全满中断,那recv_total_index必定为rx_bufsz的一半; recv_total_index = 0; recv_len = serial->config.rx_bufsz - uart->dma_rx.last_index; uart->dma_rx.last_index = recv_total_index; rt_hw_interrupt_enable(level); } else if (HAL_DMA_GET_IT_SOURCE(&(uart->dma_rx.handle), DMA_IT_HT) != RESET) { level = rt_hw_interrupt_disable(); //既然为半满中断,那recv_total_index必定为rx_bufsz的一半; recv_total_index = serial->config.rx_bufsz >> 1; recv_len = recv_total_index - uart->dma_rx.last_index; uart->dma_rx.last_index = recv_total_index; rt_hw_interrupt_enable(level); } if (recv_len)//省略了中断类型的判断,recv_len初始化为0, 如果没有中断,recv_len一定为0; { rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); } } #endif ```
撰写答案
登录
注册新账号
关注者
3
被浏览
2.7k
关于作者
softwind
这家伙很懒,什么也没写!
提问
41
回答
153
被采纳
0
关注TA
发私信
相关问题
1
串口DMA发送数据时,数据被覆盖
2
关于串口DMA模式下rt_device_close问题
3
利用stm32f427实现usb转串口,电脑端什么也没有识别到
4
finsh 控制台 适配 RS 485请大神指点????
5
uart_sample.c 中,读串口设备时偏移量pos要设置为-1而不是0?
6
【结贴】at_device软件包中对串口接收数据缺少判断导致数据接收异常
7
串口无法接受数据,但可以发送
8
串口如何有效的清除掉接收缓冲,而不必一个一个的去读取
9
串口接收使用方式问题
10
雅特力FINSH问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
【RT-Thread】【ci】【scons】将ci.attachconfig.yml和scons结合使用
2
Rt-thread中OTA下载后,bootloader不搬程序
3
ulog 日志 LOG_HEX 输出时间改为本地日期时间
4
在RT-Thread Studio中构建前执行python命令
5
研究一了一段时间RTT,直接标准版上手太难,想用nano,但又舍不得组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
出出啊
1518
个答案
343
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
813
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
5
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部