Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
DMA
Serial
USART
rt-thread-4.0.2串口DMA模式使用过程中的问题总结
发布于 2022-06-16 10:36:59 浏览:1440
订阅该版
[tocm] ## 一、环境 rt-thread V4.0.2 STM32 ## 二、遇到的问题 应用层使用串口DMA,伪代码如下: ```C ... rt_device_t dev = rt_device_find(name); ... rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_TX | RT_DEVICE_FLAG_DMA_RX); ... rt_device_set_tx_complete(dev, uart_tx_done); rt_device_set_rx_indicate(dev, uart_rx_ind); ... // do something. ... rt_device_close(dev); ``` 两个问题都是发生在用DMA模式再次打开串口的情况下,有: - 收到若干数据0,并提示`Warning: There is no enough buffer for saving data` - 内存泄漏 ### 2.1、收到若干数据0 这是驱动问题。首先要知道的是当前的驱动使用DMA循环模式进行数据接收 ```C // $RTT_ROOT/bsp/stm32/libraries/HAL_Drivers/drv_usart.c static void stm32_dma_config(struct rt_serial_device *serial, rt_ubase_t flag) { ... if (RT_DEVICE_FLAG_DMA_RX == flag) { DMA_Handle->Init.Direction = DMA_PERIPH_TO_MEMORY; DMA_Handle->Init.Mode = DMA_CIRCULAR; // <---- 循环模式 } ... /* enable interrupt */ if (flag == RT_DEVICE_FLAG_DMA_RX) { rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; /* Start DMA transfer */ if (HAL_UART_Receive_DMA(&(uart->handle), rx_fifo->buffer, serial->config.bufsz) != HAL_OK) { /* Transfer error in reception process */ RT_ASSERT(0); } CLEAR_BIT(uart->handle.Instance->CR3, USART_CR3_EIE); __HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_IDLE); } ... } ``` 这样启用DMA接收时的缓冲区`rx_fifo->buffer`就是环形的。需要有个变量去记录上次读取结束的地方,如下: ```C uart->dma_rx.last_index = recv_total_index; ``` 此行出现在DMA完成中断和串口空闲中断。**但是关闭串口时,并没有将此全局变量置为零。会造成下一次进行串口DMA接收时,接收到若干0,因为`rx_fifo->buffer`被初始化为零**。 #### 解决办法 串口关闭时,会清空DMA接收中断,在这个过程中重置`uart->dma_rx.last_index`。 ```C // $ROOT_ROOT/components/drivers/serial/serial.c static rt_err_t rt_serial_close(struct rt_device *dev) { ... serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *) RT_DEVICE_FLAG_DMA_RX); ... } // $RTT_ROOT/bsp/stm32/libraries/HAL_Drivers/drv_usart.c static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg) { ... /* disable interrupt */ case RT_DEVICE_CTRL_CLR_INT: if(RT_DEVICE_FLAG_INT_RX == ctrl_arg){ /* disable rx irq */ NVIC_DisableIRQ(uart->config->irq_type); /* disable interrupt */ __HAL_UART_DISABLE_IT(&(uart->handle), UART_IT_RXNE); } else if(RT_DEVICE_FLAG_DMA_RX == ctrl_arg){ /* disable DMA irq */ ... uart->dma_rx.last_index = 0; // <--- 这里 } break; ... } ``` 注意:因为是驱动层面的问题,不排除其他BSP驱动也存在类似问题。 ### 2.2、内存泄漏问题 从设备打开到关闭,会有76字节的内存泄漏。不说排查过程,直接说结论。 串口框架在DMA发送时,使用到了数据队列(data queue),其主要作用应该是用于重发机制,在`rt_serial_open`中初始化,但是没有地方去初始化。这就导致了内存泄漏。 ```C // $ROOT_ROOT/components/drivers/serial/serial.c static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) { ... rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL); ... } ``` #### 解决办法 v4.0.2版本的data queue没有deinit接口,可以在后续版本中移植此函数。然后在`rt_serial_close`时调用它,释放内存。 ```C // $ROOT_ROOT/components/drivers/serial/serial.c static rt_err_t rt_serial_close(struct rt_device *dev, rt_uint16_t oflag) { ... else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX) { struct rt_serial_tx_dma* tx_dma; tx_dma = (struct rt_serial_tx_dma*)serial->serial_tx; RT_ASSERT(tx_dma != RT_NULL); rt_data_queue_deinit(&tx_dma->data_queue); // <--- 这里,注意要在tx_dma释放前调用 rt_free(tx_dma); serial->serial_tx = RT_NULL; dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX; } ... } ``` ## 三、最后 以上是个人的分析和理解,解决方法也并非最佳,请各位斧正。 欢迎贴内评论回复。
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
RemyShi
这家伙很懒,什么也没写!
文章
1
回答
4
被采纳
1
关注TA
发私信
相关文章
1
串口DMA发送数据时,数据被覆盖
2
关于串口DMA模式下rt_device_close问题
3
stm32L4 lpuart1DMA下不能打开的问题
4
UART驱动开启DMA后编译报错,UART DMA配置中加入了没有定义的域
5
UART DMA 设计问题
6
UART DMA 拆包问题
7
串口如何有效的清除掉接收缓冲,而不必一个一个的去读取
8
串口接收使用方式问题
9
在studio中打开串口的DMA后,编译出错
10
官方DMA串口例程,使用时数据打印错误
推荐文章
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组件
热门标签
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
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部