STM32G系列 HAL串口DMA接收(不定长)2023年5月更新

摘要:

stm32串口的使用,可以说是这个芯片的灵魂了,DMA、IDLE空闲中断、不定长接收,这些都让stm32的串口产生异常强大的力量。如何用好这些特性,并避免踩坑,本文对几点主要配置和逻辑做了整理。感谢CSDN上各位大虾的无偿分享,本文因知识点太零散,所以无法一一做好文章引用,如果哪位大虾发现本文的某些内容是来自您的文章,请私信我添加您的链接,这里先行谢过了。


正文:

先提供一份测试完全没问题的代码,后面详解一下,以下是在中断文件中的回调函数。,2023年5月更新,DMA与IDLE配合的函数为 HAL_UARTEx_ReceiveToIdle_DMA。

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t Size)
{
		if(( Size> 3) && (Size!= USART_RX_MAX)){
        	rx_f = 1;
    	}

		HAL_UARTEx_ReceiveToIdle_DMA(huart,rx_buf,USART_RX_MAX);  //重新打开DMA与IDLE接收
}

下面是串口中断函数配置,2023年5月更新

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

然后,我们从头开始说起。

一、串口配置问题

串口配置属于比较基础的,推荐使用stm32cubeide,简直是懒人神器,配置时注意几个点即可。

1、串口接收引脚要上拉

这个一般不会有什么影响,但是有时485芯片电压不稳的时候,会产生非常多的接收信号干扰,造成程序跑飞,做了上拉,就可以避免这个问题。

2、串口根据波特率设置对应的引脚速度

一般9600及以下选择LOW即可,19200~115200选择MEDIUM, 再往上的直接用HIGH就行。这里要注意,有一个output level,这个是设置GPIO初始电平高低的,串口输入尽量配置LOW。

3、串口驱动方式

用推挽PUSH PULL比较合适,开漏OPEN Drain有时会有问题,这个跟电路设计有关系。

4、采样率分频(对应图中1、2)

SMT32的串口一般使用16倍过采样,这就需要分频要设置合理范围,STM32CUBEIDE一般默认设置为1,在大多数情况下,不需要修改这个数值。

如果实在需要修改,可以参考下面的计算方法来粗略估算一下:

如19200bps,每个bit位约52us,主频64M来说,每次采集间隔为1/64us,16倍过采样,则对应1/4us,对于串口接收的一个bit来说,16倍采样点尽量落在前1/2处,相对应需要1/2us。用52us来除1/2us,得到最大的分频率为104,所以,19200bps如果使用128分频,可能会造成接收信号判断错误,引起串口接收异常。

5、DMA配置

1)接收启用DMA,发送尽量不用DMA。可以使用发送中断的非阻塞函数HAL_UART_Transmit_IT,使用起来也很方便,并且可以释放一部分运算时间。

2)DMA与USART的初始化顺序问题,有时配置串口时,发现接收一直为0,反反复复找不到原因所在,最终找到原因,原来是DMA的初始化放到了USART后面。这里的顺序导致接收不到的原因是,DMA的时钟开启,必须在USART之前,否则USART是无法使用DMA进行数据接收的。所以,遇到DMA串口接收,没有数据进入的情况,首先查一下DMA与USART的初始化顺序是否正确。以下为正确的顺序:

  MX_DMA_Init();
  MX_USART1_UART_Init();

6、串口初始化

使用stm32cubeide有一个优势,它会自动帮你把外设用较好的顺序进行了初始化,这样就不会因为时钟初始化顺序问题,引起一些莫名其妙的问题。

但是串口中断及DMA初始化,一般还是需要单独做的。一般是先使用IDLE,后使能DMA,有很多文章提到要先初始化DMA,后初始化IDLE,以防一上电就产生接收,我觉得这个不是问题,只要做好接收数据判断即可。但是先使能DMA会造成串口干扰导致中断频发。

    __HAL_UART_ENABLE_IT(&USART, UART_IT_IDLE); //使能IDLE中断
    HAL_UARTEx_ReceiveToIdle_DMA(&USART, rx_buf, USART_RX_MAX);

7、高级特性设置(对应图中3)

之前遇到过一个特殊的现象,串口在板子刚上电启动时,可以正常收发,但是到了一定时间后,就会出现无法完整接收数据的现象,反复很多次,最终发现,是高级特性惹的祸。

串口配置中,Advanced features,有两个是默认enable的,一个是overrun,一个是dma or rx error。这两个本意是好的,意在增强串口的健壮性,但是在串口可能有干扰信号的情况下,这两个特性会造成串口异常。省力的方法就是关闭(disable)这两个特性。麻烦的方法,是在串口中断接收程序中,做overrun和rx error判断,清除对应的错误位,或者重写void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)函数,这样才能让串口不会出现接收异常的情况。

经过试验测试,即使关闭了这个高级特性,串口接收错误仍然有可能发生,并导致串口一直带着错误位在跑,子程序使用串口不当时,就会发生硬件错误使主程序挂掉。

转载一篇对overrun说的比较清楚的文章:STM32串口溢出错误Overrun使用不当导致的串口死机_TrueLink的博客-CSDN博客

但,这里要千万注意,errorCallback中需要重启的中断,必须是你使用的中断。比如使用了IDLE和DMA来配置的,那就__HAL_UART_ENABLE_IT(&huart, UART_IT_IDLE)。如果未使用IDLE和DMA,那就按照上述博客中提到的,HAL_UART_Receive_IT(&huart1,buf,1),否则,轻则程序卡顿,重则串口又出现假死状态。

二、串口DMA接收的配置

很多文章和帖子中都做了配置说明,经过长时间的试错,可以确认以下几件事情,避免让大家进坑。

1,DMA是否需要开中断?

答案是,不需要开中断。 DMA传输只要配置到串口接收端口上,在串口数据(一般会使用IDLE空闲中断)来临会自动调用DMA程序,DMA负责把串口上的数据转移到片上RAM中,记得,DMA转移时不需要DMA中断动作的,如果加了DMA中断,轻则程序不丝滑,重则程序卡死而找不到原因。

2,DMA与串口是否有对应关系?

答案是,看具体芯片而定。对于stm32F系列芯片来说,很多都需要做对应关系,但是对于stm32G系列芯片来说,已经完全不需要做对应关系了。这个前期去芯片手册中查找清楚即可。

3,DMA优先级如何设置?

答案是,一般不需要特殊配置,从LOW到HIGH,配置起来问题都不大。重点是,需要调用DMA的外设,尽量避免同时持续不断的进行数据传输,一般来说,串口或者ADC通过DMA转移到片内RAM的时间,是以指令数来计的,对于48M以上的stm32时间一般在us级以下,所以,优先级在使用少量DMA的时候,完全不是问题。只有在DMA使用超过5个以上,且外设数据持续不停、通信速率又非常高的时候,才会发生抢占优先级的问题。

三、程序解析

1、串口中断,为什么把回调函数放在系统函数后面?,2023年5月更新

  HAL_UART_IRQHandler(&huart1);

// if(0 != __HAL_UART_GET_FLAG(&USART_BUS, UART_FLAG_IDLE))
//	  usart_rx_cb(&USART_BUS);

这里之前对函数理解不到位,多做了一次无用功。实际上,串口中断这里是不需要额外增加回调函数的。

在HAL_UART_IRQHhandler函数中,就已经包含了回调函数HAL_UARTEx_RxEventCallback,在IDLE产生中断并进入HAL_UART_IRQHhandler函数后,可以直接调用HAL_UARTEx_RxEventCallback 函数进行数据处理。

这里只需要在回调函数内增加一个接收标志,并重新启动接收中断即可。

2、串口异常的处理

串口异常处理在HAL_UART_IRQHhandler函数也已经包含,不需要额外再做错误处理了。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值