请选择 进入手机版 | 继续访问电脑版
搜索
查看: 28426|回复: 27

[原创] HAL库UART按DMA方式发送和接收函数简析及测试

  [复制链接]

该用户从未签到

5

主题

146

帖子

4

蝴蝶豆

论坛元老

最后登录
2021-5-7
发表于 2018-1-24 13:29:00 | 显示全部楼层 |阅读模式
个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑
不管什么芯片,当我们遇到问题时,通过查阅datasheet上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道(我就是用有道划的)
C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。
程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。
鄙人浅见,请大家不吝赐教。
进入正题:UART以DMA方式接收和发送的函数调用顺序
循环模式接收:HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)==》DMA1_Channelx_IRQHandler(void)==》HAL_DMA_IRQHandler(&hdma_usartx_rx)==》UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)==》HAL_UART_RxCpltCallback(huart)
当然这当中还会调用传输 Half 中断,这里就不讨论了。

正常模式发送:HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)==》DMA1_Channelx_IRQHandler(void)==》HAL_DMA_IRQHandler(&hdma_usartx_tx)==》UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)==》USART3_IRQHandler(void)==》HAL_UART_IRQHandler(&huart3)==》UART_EndTransmit_IT(huart)==》HAL_UART_RxCpltCallback(huart)

这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析:
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
UART以DMA方式接收指定长度数据到指定缓冲区
{
  uint32_t *tmp;

  /* Check that a Rx process is not already ongoing */
  if(huart->RxState == HAL_UART_STATE_READY)   检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。
  {
    if((pData == NULL) || (Size == 0U))
    {
      return HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;

    /* Set the UART DMA transfer complete callback */
    huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxStateREADY,并调用
UART接收完成中断的回调函数。所以,
不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数
    /* Set the UART DMA Half transfer complete callback */
    huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;

    /* Set the DMA error callback */
    huart->hdmarx->XferErrorCallback = UART_DMAError;

    /* Set the DMA abort callback */
    huart->hdmarx->XferAbortCallback = NULL;

    /* Enable the DMA channel */
    tmp = (uint32_t*)&pData;
    HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改

    /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */
    __HAL_UART_CLEAR_OREFLAG(huart);

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    /* Enable the UART Parity Error Interrupt */
    SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);

    /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    SET_BIT(huart->Instance->CR3, USART_CR3_EIE);

    /* Enable the DMA transfer for the receiver request by setting the DMAR bit
    in the UART CR3 register */
    SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}
下面上我做的测试:一、Cube配置
1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。
2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。
以上两点大家可以自己改改测试。
2.png
3.png
1.png

二、Keil例程编写
4.png
6.png
5.png

三、测试
可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。
7.png

最后,奉上测试工程: uart_dma_test.rar (3.7 MB, 下载次数: 2136)

评分

参与人数 2ST金币 +11 收起 理由
buffoon51 + 1 很给力!
zero99 + 10 谢谢分享

查看全部评分

回复

使用道具 举报

  • TA的每日心情
    开心
    2018-2-6 09:20
  • 签到天数: 1 天

    [LV.1]初来乍到

    1182

    主题

    4967

    帖子

    1

    蝴蝶豆

    论坛元老

    最后登录
    2020-3-17
    发表于 2018-2-1 09:25:49 | 显示全部楼层
    感谢支持,已汇总到1月技术原创
    https://www.stmcu.org.cn/module/forum/thread-614550-1-1.html
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    82

    主题

    718

    帖子

    121

    蝴蝶豆

    版主

    最后登录
    2021-1-2
    发表于 2018-2-1 13:59:04 | 显示全部楼层
    心得分享,谢谢了
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    3

    主题

    971

    帖子

    176

    蝴蝶豆

    论坛元老

    最后登录
    2021-4-1
    发表于 2018-2-2 09:13:13 | 显示全部楼层
    分享经验,共同进步,谢谢楼主
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    11

    帖子

    0

    蝴蝶豆

    初级会员

    最后登录
    2018-5-13
    发表于 2018-2-3 22:03:44 | 显示全部楼层
    感谢分享
    回复

    使用道具 举报

    该用户从未签到

    0

    主题

    4

    帖子

    0

    蝴蝶豆

    新手上路

    最后登录
    2018-8-19
    发表于 2018-2-4 20:16:50 | 显示全部楼层
    学习下
    回复

    使用道具 举报

    该用户从未签到

    0

    主题

    3

    帖子

    0

    蝴蝶豆

    初级会员

    最后登录
    2019-12-5
    发表于 2018-2-8 15:11:46 | 显示全部楼层
    谢谢分享,正在捣鼓这一块,很有帮助
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    2

    帖子

    0

    蝴蝶豆

    中级会员

    最后登录
    2021-3-12
    发表于 2018-3-29 21:03:55 | 显示全部楼层
    敬佩楼主的奉献精神!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    3

    帖子

    0

    蝴蝶豆

    初级会员

    最后登录
    2019-9-20
    发表于 2018-4-25 08:38:11 | 显示全部楼层
    谢谢分享,参考一下
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    1

    主题

    944

    帖子

    6

    蝴蝶豆

    论坛元老

    最后登录
    2021-8-19
    发表于 2018-4-25 08:40:34 | 显示全部楼层
    谢谢分享
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

    GMT+8, 2024-3-29 19:56 , Processed in 1.189658 second(s), 45 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

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