HAL库DMA使用异常问题

探讨了串口DMA接收溢出导致数据丢失的问题,分析了串口DMA接收与发送不能单独停止的原因,并提供了通过HAL_UART_AbortReceive()函数解决串口DMA接收溢出的实践方法。

问题描述:

1.串口接收一旦溢出就会丢数据。
串口接收满了,稍等几秒再重新启动DMA接收函数HAL_UART_Receive_DMA()时,就会丢失数据,而且此时串口接收空闲中断启动正常,打印出来会发现全是’\0’。如果接满后马上启动就没此问题。

2.串口DMA接收与发送不能单独停止。
如果串口同时进行DMA发送和DMA接收,在DMA接收到一半我要终止DMA时,只能调用HAL_UART_DMAStop()把接收DMA和发送DMA都停止,不能单独停止DMA接收。

原因分析:

当你将接收DMA关闭后,此时串口还是激活的,若此时串口来数据,无法触发DMA传输,此时产生上溢错误(ORE),由于串口数据寄存器里的数据不能及时转移走,后面来的数据就进不来。一旦出现这种错误后,就不会再触发DMA请求,即使再开启DMA也不行。

解决方案:

官方示例是deinit后再重新初始化串口,或者使用read接口直接将数据寄存器中的数据读走后,后面的数据才能正常进入,从而正常产生DMA请求,这个DMA请求是指硬件请求。
亲测解决方法:将HAL_UART_DMAStop()替换成HAL_UART_AbortReceive(),此函数是只关闭DMA接收的函数。

### STM32 HALDMA使用教程及错误排查 #### DMA的基础概念 直接内存访问(Direct Memory Access, DMA)是一种硬件机制,允许外部设备与存储器之间或者存储器与存储器之间的数据传输不经过CPU干预[^1]。通过这种方式可以显著提高系统的效率并减少CPU负载。 #### 初始化DMA控制器 在STM32 HAL中,初始化DMA控制器通常涉及配置DMA通道、方向、优先级以及数据宽度等参数。以下是典型的DMA初始化过程: ```c // 创建DMA句柄 DMA_HandleTypeDef hdma; void MX_DMA_Init(void) { __HAL_RCC_DMA2_CLK_ENABLE(); // 启用DMA时钟 hdma.Instance = DMA2_Stream0; // 配置使用DMA流 hdma.Init.Channel = DMA_CHANNEL_0; // 设置DMA通道 hdma.Init.Direction = DMA_PERIPH_TO_MEMORY; // 数据传输方向 hdma.Init.PeriphInc = DMA_PINC_DISABLE; // 外设地址固定不变 hdma.Init.MemInc = DMA_MINC_ENABLE; // 存储器地址自动增加 hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // 外设数据对齐方式 hdma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; // 存储器数据对齐方式 hdma.Init.Mode = DMA_CIRCULAR; // 循环模式 hdma.Init.Priority = DMA_PRIORITY_HIGH; // 高优先级设置 if (HAL_DMA_Init(&hdma) != HAL_OK) { // 初始化DMA Error_Handler(); } } ``` 上述代码展示了如何配置一个用于循环缓冲区操作的DMA实例。 #### 堆栈溢出问题及其解决方案 当编写复杂的嵌入式应用程序时,可能会遇到堆栈溢出的情况,这可能导致程序运行不稳定甚至崩溃。如果发现程序无明显逻辑错误却频繁卡死或出现其他异常现象,则应考虑是否存在堆栈空间不足的问题[^3]。可以通过调整向量表偏移量来增大可用堆栈大小;另外,在定义局部变量尤其是大型数组时要格外小心,尽量将其声明为全局变量或将它们分配到动态内存区域以规避潜在风险。 #### 结合ADC实现高速采样 为了利用DMA技术提升模数转换速度,需先完成相应外设资源准备动作后再启动两者联动工作流程。下面给出一段关于启用ADC并通过DMA读取结果寄存器内容的例子: ```c ADC_HandleTypeDef hadc; uint16_t adcValue[NUMBER_OF_CHANNELS]; void Start_ADC_DMA_Conversion(ADC_HandleTypeDef* hadc, uint16_t* pData, uint32_t Length){ if(HAL_ADC_Start_DMA(hadc, (uint32_t*)pData, Length)!= HAL_OK){ /* Conversion start error */ Error_Handler(); } } int main(){ ... MX_ADC_Init(); // ADC初始化函数调用 MX_DMA_Init(); // DMA初始化函数调用 Start_ADC_DMA_Conversion(&hadc, adcValue, NUMBER_OF_CHANNELS); while (1){ // 主循环处理其它任务... } } ``` 此部分演示了怎样借助于之前提到过的DMA功能加速来自模拟输入端口的数据采集进程。 #### 注意事项 - 确认所选DMA请求映射至目标外设上。 - 正确设定源/目的地址增长属性以防越界访问。 - 对中断事件做出适当响应以便及时获取最新状态更新信息。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值