你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

HAL库的串口DMA操作方法很难理解,非常的不好用

[复制链接]
tempchar 提问时间:2016-6-12 10:22 /
阅读主题, 点击返回1楼
收藏 2 评论21 发布时间:2016-6-12 10:22
21个回答
斜阳 回答时间:2017-5-8 14:11:34
  1. 打开DMA接收:HAL_UART_Receive_DMA(&guiSerial,guiRcvBuf,guiRcvBufLen);
复制代码
下面是中断处理;guiDataRcvCallBack是我自己定义的接收完成的回调
  1.                 uint32_t temp;
  2.                 if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE)!=RESET)
  3.                 {
  4.                         __HAL_UART_CLEAR_IDLEFLAG(&huart2);
  5.                         temp = huart2.Instance->SR;
  6.                         temp = huart2.Instance->DR;
  7.                         HAL_UART_DMAStop(&huart2);
  8.                         temp=hdma_usart2_rx.Instance->NDTR;
  9.                         guiDataRcvCallBack(guiRcvBufLen-temp);
  10.                 }

复制代码

涛哥2035 回答时间:2017-5-8 15:17:55
二楼说的很好,原因就是如此。其实在STM32官网公众号有文章介绍了该问题,主要是先启动了串口再启动DMA就会容易引起该问题。因此为了防止该问题要不每次开DMA都清ORE寄存器;要不按规矩先开DMA再开串口,不用了先关串口再关DMA
喜欢吃青椒麽 回答时间:2018-1-26 11:35:28
斜阳__ 发表于 2016-6-15 10:21
我刚做过用串口DMA接收不定长数据,使能空闲中断,在空闲中断触发的时候停止DMA,取出数据,之后使用HAL_UA ...

正常方法是这样。
但是使用空闲中断也有一个问题,就是的发送端发送一帧数据不能被打断。不然stm32就会触发空闲中断,只接收到一帧的一部分数据。
空闲中断就是这个串口线有一个字节的时间没有数据传输就触发空闲中断吧。
那么假设我发送端要发送一帧数据,共20个字节,那么假设在发送到第10个字节的时候,被中断打断了,打断了之后恢复发送,那么打断到恢复发送这段时间超过了传输一个字节的时间,则就会触发接收端的空闲中断。
则接收端只接收到了10个字节,这个时候在中断里面关闭DMA再开启已经来不及接收后面的了?
这个问题怎么解决的阿?
龙吟风独恋云 回答时间:2018-5-11 17:04:22
本帖最后由 龙吟风独恋云 于 2018-5-11 17:05 编辑

针对第2点,串口DMA接收不能单独停止。

HAL_UART_DMAStop()函数的确是uart接收和发送同时关闭,找了好久终于找到只关闭接收的函数了。
只关闭接收的函数。HAL_UART_AbortReceive()

下面看一下函数具体实现:
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)
{
  uint32_t dmarequest = 0x00U;
  /* The Lock is not implemented on this API to allow the user application
     to call the HAL UART API under callbacks HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback():
     when calling HAL_DMA_Abort() API the DMA TX/RX Transfer complete interrupt is generated
     and the correspond call back is executed HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback()
     */
  /* Stop UART DMA Tx request if ongoing */
  dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT);
  if((huart->gState == HAL_UART_STATE_BUSY_TX) && dmarequest)
  {
    CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
    /* Abort the UART DMA Tx channel */
    if(huart->hdmatx != NULL)
    {
      HAL_DMA_Abort(huart->hdmatx);
    }
    UART_EndTxTransfer(huart);
  }
  /* Stop UART DMA Rx request if ongoing */
  dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
  if((huart->RxState == HAL_UART_STATE_BUSY_RX) && dmarequest)
  {
    CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    /* Abort the UART DMA Rx channel */
    if(huart->hdmarx != NULL)
    {
      HAL_DMA_Abort(huart->hdmarx);
    }
    UART_EndRxTransfer(huart);
  }
  return HAL_OK;
}

主要分为2大部分,处理标志,关闭发送和接收DMA。

HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart)
{
  /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
  CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
  CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
  /* Disable the UART DMA Rx request if enabled */
  if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
  {
    CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    /* Abort the UART DMA Rx channel : use blocking DMA Abort API (no callback) */
    if(huart->hdmarx != NULL)
    {
      /* Set the UART DMA Abort callback to Null.
         No call back execution at end of DMA abort procedure */
      huart->hdmarx->XferAbortCallback = NULL;
      HAL_DMA_Abort(huart->hdmarx);
    }
  }
  /* Reset Rx transfer counter */
  huart->RxXferCount = 0x00U;
  /* Restore huart->RxState to Ready */
  huart->RxState = HAL_UART_STATE_READY;
  return HAL_OK;
}

也是分为2部分,处理标志和关闭接收DMA。

最简单的实现:
1. 先关闭接收DMA,HAL_DMA_Abort(huart->hdmarx);
2. 置位RX ready状态,huart->RxState = HAL_UART_STATE_READY;
忽略了错误标志和IT标志处理,最保险的方式还是使用HAL_UART_AbortReceive()函数。

评分

参与人数 1蝴蝶豆 +4 收起 理由
zero99 + 4

查看全部评分

any012 回答时间:2018-11-23 11:30:07
任风吹吹 发表于 2016-6-15 11:28
当你将接收DMA关闭后,此时串口还是激活的,若此时串口来数据,无法触发DMA传输,此时产生上溢错误(ORE) ...

正好遇到了这个问题。
群里朋友帮找到了这个帖子,收益匪浅。
any012 回答时间:2018-11-23 12:01:40
龙吟风独恋云 发表于 2018-5-11 17:04
针对第2点,串口DMA接收不能单独停止。

HAL_UART_DMAStop()函数的确是uart接收和发送同时关闭,找了好久终 ...

HAL_UART_AbortReceive()代替HAL_DMA_STOP()挺好的。
pkoko 回答时间:2019-12-27 22:38:24
喜欢吃青椒麽 发表于 2018-1-26 11:35
正常方法是这样。
但是使用空闲中断也有一个问题,就是的发送端发送一帧数据不能被打断。不然stm32就会触 ...

采用缓冲区接收N次IDLE中断接收到的数据,然后再处理。N根据实际情况来定。也可采用环形缓冲区
12

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版