硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3647|回复: 7
收起左侧

[DMA] HAL库关串口DMA的操作疑问

[复制链接]

98

主题

340

回帖

634

积分

金牌会员

积分
634
发表于 2021-7-2 17:19:48 | 显示全部楼层 |阅读模式
本帖最后由 云琴箫龙 于 2021-7-2 17:23 编辑

我是用串口空闲中断和DMA结合的方式去接收不定长帧,调用HAL_UART_Receive_DMA的时候,长度设置一个人特别大的数,然后在串口空闲中断里面读取DMA已接收的数据。
串口接收空闲中断后,先关DMA接收(HAL_UART_DMAStop),然后读取已接收到的数据,然后重新调用HAL_UART_Receive_DMA再次启动接收。
但是发现HAL_UART_DMAStop里面把串口DMA收发都关闭了,如果这个时候正好有DMA数据发送,就会造成数据的丢失,甚至串口发送异常。
请教硬汉哥,为啥HAL库不单独提供一个关闭DMA接收的函数呢?或是我这么使用有问题?
回复

使用道具 举报

1

主题

94

回帖

97

积分

初级会员

积分
97
发表于 2021-7-3 08:48:06 | 显示全部楼层
可以在中断里面判断发送dma有没有完成,没有完成则先死等发送完成,然后在进行接收处理,这种发送和接收同时有数据应该属于少数状况吧,不考虑效率问题简单的死等也是可以的。
回复

使用道具 举报

1

主题

13

回帖

16

积分

新手上路

积分
16
发表于 2021-7-3 09:12:48 | 显示全部楼层
可以使用HAL_UART_AbortReceive这个函数,只关闭串口的接收
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2021-7-3 09:22:33 | 显示全部楼层
函数整的不全面,参考我这个把,可以分别终止
USARTdrv->Control (ARM_USART_ABORT_RECEIVE, 1);

基于V6的CMSIS-Driver串口应用,支持8串口DMA不定长收发,比CubeMX还要省事
http://www.armbbs.cn/forum.php?m ... id=93714&fromuid=58
(出处: 硬汉嵌入式论坛)



回复

使用道具 举报

98

主题

340

回帖

634

积分

金牌会员

积分
634
 楼主| 发表于 2021-7-4 22:25:17 | 显示全部楼层
hexenzhou 发表于 2021-7-3 08:48
可以在中断里面判断发送dma有没有完成,没有完成则先死等发送完成,然后在进行接收处理,这种发送和接收同 ...

9600的发送波特率,在中断里面等它可不行,中断里面就是做些判断和发消息的活儿,在平衡通信规约里面,发送接收同时的情况很常见。
回复

使用道具 举报

98

主题

340

回帖

634

积分

金牌会员

积分
634
 楼主| 发表于 2021-7-4 22:26:02 | 显示全部楼层
xiaopang059 发表于 2021-7-3 09:12
可以使用HAL_UART_AbortReceive这个函数,只关闭串口的接收

试过了,不行,会造成DMA接收异常,实测好像是无法再启动DMA接收。
回复

使用道具 举报

98

主题

340

回帖

634

积分

金牌会员

积分
634
 楼主| 发表于 2021-7-4 22:27:36 | 显示全部楼层
eric2013 发表于 2021-7-3 09:22
函数整的不全面,参考我这个把,可以分别终止
USARTdrv->Control (ARM_USART_ABORT_RECEIVE, 1);

嗯,暂时用的中断发送的方式,那天倒是想着把HAL库改一下仅停止DMA接收,改天查考一下你的例程。
回复

使用道具 举报

5

主题

192

回帖

212

积分

高级会员

积分
212
发表于 2021-7-5 11:23:19 | 显示全部楼层
1.请问你用的是V7开发板吗?
如果不是你可以参考我在V6开发板上的实现方法:

http://www.armbbs.cn/forum.php?m ... d=101377&extra=

2.如果你的开发板是V7,CPU应该是STM32H743系列,无意中看到F7和H7系列,
ST官方对空闲DMA接收做了处理,在 HAL_UART_IRQHandler 里面 代码如下:
  1.   /* Check current reception Mode :
  2.      If Reception till IDLE event has been selected : */
  3.   if ((huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
  4.       && ((isrflags & USART_ISR_IDLE) != 0U)
  5.       && ((cr1its & USART_ISR_IDLE) != 0U))
  6.   {
  7.     __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_IDLEF);

  8.     /* Check if DMA mode is enabled in UART */
  9.     if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
  10.     {
  11.       /* DMA mode enabled */
  12.       /* Check received length : If all expected data are received, do nothing,
  13.          (DMA cplt callback will be called).
  14.          Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
  15.       uint16_t nb_remaining_rx_data = (uint16_t) __HAL_DMA_GET_COUNTER(huart->hdmarx);
  16.       if ((nb_remaining_rx_data > 0U)
  17.           && (nb_remaining_rx_data < huart->RxXferSize))
  18.       {
  19.         /* Reception is not complete */
  20.         huart->RxXferCount = nb_remaining_rx_data;

  21.         /* In Normal mode, end DMA xfer and HAL UART Rx process*/
  22.         if (huart->hdmarx->Init.Mode != DMA_CIRCULAR)
  23.         {
  24.           /* Disable PE and ERR (Frame error, noise error, overrun error) interrupts */
  25.           CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);
  26.           CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);

  27.           /* Disable the DMA transfer for the receiver request by resetting the DMAR bit
  28.              in the UART CR3 register */
  29.           CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);

  30.           /* At end of Rx process, restore huart->RxState to Ready */
  31.           huart->RxState = HAL_UART_STATE_READY;
  32.           huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;

  33.           CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);

  34.           /* Last bytes received, so no need as the abort is immediate */
  35.           (void)HAL_DMA_Abort(huart->hdmarx);
  36.         }
  37. #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  38.         /*Call registered Rx Event callback*/
  39.         huart->RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
  40. #else
  41.         /*Call legacy weak Rx Event callback*/
  42.         HAL_UARTEx_RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
  43. #endif /* (USE_HAL_UART_REGISTER_CALLBACKS) */
  44.       }
  45.       return;
  46.     }
复制代码

3.根据我自己的方式和官方代码的实现可以看出,在空闲中断的判断上要先判断中断是否开启
以及标志位是否置位,最重要的一点就是:不是调用HAL_UART_DMAStop
而是使用 HAL_DMA_Abort。你自己可以查看函数原型。abort是不会关闭串口发送的,
stop是会关闭串口DMA发送和接收的。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-28 11:45 , Processed in 0.181974 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表