(stm32之HAL库)UART工作在DMA模式要打开串口中断吗?

这篇具有很好参考价值的文章主要介绍了(stm32之HAL库)UART工作在DMA模式要打开串口中断吗?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题引入

最近学习了stm32(F4xx)的串口在DMA模式下的使用,期间以ST官方提供的例程进行参考学习,发现其初始化过程中是打开了UART的中断的,而且HAL库中stm32f4xx_hal_uart.c文件中的DMA模式使用说明里也有这么一句话:

(+++) Configure the USARTx interrupt priority and enable the NVIC USART IRQ handle
     (used for last byte sending completion detection in DMA non circular mode)

即在非循环模式下(也就是发完一次数据就停止的常用模式)需要配置串口中断,以使DMA发送完毕后能够触发中断,告诉CPU自己发完了。
那么问题就来了,使用DMA就是为了解放CPU,为了达到这个目的,DMA发送完毕常采用中断模式而非轮询模式,而中文参考手册里也说DMA的每个数据流都配有中断处理函数,那发送结束时直接由DMA产生中断不就行了,为何还要打开UART的中断呢?而且如果打开了UART中断,是否会导致每发送一个字节就会触发一次发送完成中断?那不就帮倒忙了。
网上搜索暂没找到满意的解答,希望这篇文章能为有同样困惑的uu解解惑。

实用结论

先直接上结论,急着用的uu请放心使用这个结论:
如果是在HAL库基础上编程的话,DMA模式下的UART是需要开中断的,但是并不全开。
具体而言,
一、其中要打开的部分指的是:

  1. 在NVIC上使能对应串口中断源,并设定抢占优先级和子优先级,比如使用USART1的话:
		HAL_NVIC_EnableIRQ(USART1_IRQn);				//使能USART1中断通道
		HAL_NVIC_SetPriority(USART1_IRQn,0,0);			//抢占优先级0,子优先级0	
  1. 写中断处理函数和回调函数(这里针对传输完毕回调函数)
//传输完毕回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance==USART1)
	{
		//实现个性化的内容
	}
}
//中断处理函数
void USART1_IRQHandler(void)
{
	HAL_UART_IRQHandler(&UART1_Handler);
}

二、 不要打开的部分指的是:
不要使能UART的硬件中断,在这里也就是不要给UART的USART_CR1的TCIE位置1,即你的初始化代码里不应该出现:

SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);

这类代码。
到这里,如果你不感兴趣具体原因的话就可以跑路了,祝食用愉快。

推理过程

正式推理之前,先梳理一下你将能在这个推理过程中收获什么:

  1. 对UART中断过程更深入的理解;
  2. 通览HAL库中UART在DMA工作模式下的代码结构框架;
  3. 对DMA和底层硬件合作的逻辑有更深的认识,这可以举一反三到SPI、IIC的DMA模式编程中;

Let’s begin the journey!

回到最开始的疑虑,在DMA数据流配有发送完毕中断的前提下,为何还需要UART中断来实现传输完成中断?打开串口中断,是否会导致发送过程中UART每发送完一个字节就触发一次传输完成中断?

在本例中,采用的是USART1,其发送引脚对应的数据流是DMA2_Stream7,通道是DMA_CHANNEL_4
因此对于UART,其中断入口是:

void USART1_IRQHandler(void)
{
	HAL_UART_IRQHandler(&UART1_Handler);
}

对于DMA,其中断入口是:

void DMA2_Stream7_IRQHandler(void)
{
	HAL_DMA_IRQHandler(&UART1TxDMA_Handler);
}

两者发送完的回调函数分别是:

//UART传输完成回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
//DMA传输完成回调函数
void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma);

而DMA传输完成回调函数会调用

//UART传输完成回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);

因此代码结构可以表示为:为什么dma串口接收还要开中断,stm32,单片机,嵌入式硬件
我们个性化的代码,正是在HAL_UART_TxCpltCallback中实现的;

因此,为了知道两者的中断是否都触发了,触发了多少次,可以先在中断处理函数和回调函数处加入LED翻转代码来协助判断。

小试验

  1. 试验一
    1.1 试验描述
    USART1_IRQHandler,DMA2_Stream7_IRQHandler两个中断处理函数中分别加入LED翻转程序,主程序进行USART1DMA模式下的传输。
    1.2 试验结果
    发现无论在哪一个中断处理函数中加灯泡翻转程序,LED等均会在DMA传输结束时刻点亮,也就是两个中断处理函数都在DMA发送结束时调用了一次。
  2. 试验二
    2.1 试验描述
    仅在传输完成回调函数HAL_UART_TxCpltCallback中添设LED翻转程序,主程序不变。
    2.2 试验结果
    在DMA传输结束时LED点亮,并不熄灭,也即该回调函数之调用了一次。
  3. 试验结论
    两个中断函数都调用了一次,而回调函数却只调用了一次,那么必有一个中断处理函数是没有直接调用回调函数的。

再看HAL库

经过一番折腾,我确定了调用回调函数的支路是UART这一支,而DMA这一支虽然调用了中断处理函数,但并没有调用回调函数。
可见, 猫腻就藏在HAL库提供的DMA中断处理函数UART_DMATransmitCplt上,其实现代码如下:

static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
//...处省略非重要代码
 ...
  /* DMA Normal mode*/
  ...
  //关闭DMA模式
    CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
  //使能UART的TC中断
    SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
...
  /* DMA Circular mode */
...
    /*Call registered Tx complete callback*/
    //调用HAL_UART_TxCpltCallback
    huart->TxCpltCallback(huart);
    ...
 }

原来只有在循环模式下,它才会调用HAL_UART_TxCpltCallback,在非循环模式下,会关闭UART的DMA模式,并使能硬件层面上的UART传输完成中断。这就解释了为什么中断处理函数两者都调用了,但是干实事的中断回调函数只有UART这条支路调用了,这就是为什么最开始有必要打开UART的中断,否则将无法在传输完毕时调用我们想让程序执行的代码。正呼应了HAL库中的

(+++) Configure the USARTx interrupt priority and enable the NVIC USART IRQ handle
     (used for last byte sending completion detection in DMA non circular mode)

刨根

现在仍有两个小问题有待解决:

  1. 为什么传输过程中每次UART发送完单个字节后没有触发传输完成中断;
  2. 在发送完毕的最后一小段时间里,程序是如何达到如上的效果的;

为了解决这两个问题,需要回顾一下UART传输完毕中断发生的过程:

UART传输完成中断产生过程

图片:
为什么dma串口接收还要开中断,stm32,单片机,嵌入式硬件
如图为UART中断映射图,只看上面部分(对应发送中断),常用的有TC(发送完成)和TXE(发送数据寄存器为空)
而中文参考手册里也对它们硬件置1的条件予以说明:
为什么dma串口接收还要开中断,stm32,单片机,嵌入式硬件
为什么dma串口接收还要开中断,stm32,单片机,嵌入式硬件
结合下图进行解释:
为什么dma串口接收还要开中断,stm32,单片机,嵌入式硬件
当UART在中断模式下发送时:

  1. 对于TXE,每当发送数据寄存器内的内容传输给移位寄存器(由硬件自己完成),并开始从移位寄存器一位一位通过TC引脚往外送,TXE就会置1;此时如果TXEIE为1(即TXE中断使能),就会调用中断,中断处理的内容是将下一个待传输的数据内容放到数据寄存器里,并清零TXE标志位(HAl库里是这么写都),这样循环往复,直到要发送的内容都发完;
  2. 对于TC,当发送完最后一个数据内容之后,如果此时TXE为1(也即数据寄存器里不再有新的内容),说明传输结束了,TC置1,如果TCIE为1(即TC中断使能),就会调用传输完成中断,告诉CPU说可以进行后续操作。

UART在DMA模式下

而在DMA工作模式下,仍旧结合图片:
为什么dma串口接收还要开中断,stm32,单片机,嵌入式硬件
DMA模式下,每当TXE置1后,不会触发中断来打扰CPU,而是给DMA发送请求,让DMA发送下一段数据内容,并给TXE清零,这解释“为什么传输过程中每次UART发送完单个字节后没有触发传输完成中断 ”这个问题;
对于第二个问题“在发送完毕的最后一小段时间里,程序是如何达到如上的效果的 ”,对HAL库里的代码实现消化如下:
通过之前的分析,我们已经知道,当DMA把最后一个数据内容通过总线发送给UART的数据寄存器之后,DMA对应的数据流就会触发传输完成中断,调用UART_DMATransmitCplt ,而在这个回调函数中,采用非循环模式时,会关闭UART的DMA模式,并将对应的UART的传输完成中断使能;
同时UART在收到最后一段数据之后就开始卖力地传输(先从发送数据寄存器复制到移位寄存器,再从移位寄存器一位一位通过TX引脚开始传输),开始传输的时刻TXE就置1了,发送完之后UART回过头来一看,TXE为1,所以也跟着置1了。而前边DMA传输完成回调函数中又把TCIE中断使能位置1了,所以UART就会触发传输完成中断。
接下来就是调用我们熟悉HAL_UART_TxCpltCallback回调函数了。到此,问题解决。

最终重点再呼应前文为什么说UART中断只要打开一部分,即需要在NVIC中使能+配置好中断处理函数和回调函数,而不要使能中断标志位。

  1. 之所以要“在NVIC中使能+配置好中断处理函数和回调函数”,是因为DMA传输完成中断最终其实是通过UART传输完成中断实现的,所以要提前准备好所需的API、打开必要的通道;
  2. 在DMA发送过程中,DMA是不希望UART传输完成中断来添乱的,所以一开始不应该在硬件层面使能TCIE,这个决定权交由DMA,当其传输完毕后再将其打开; 事实上,在开始传输的API“HAL_UART_Transmit_DMA ”里会进行如下操作:
 __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);

即传输前先清除TC标志位,可见DMA多么担心UART在完成工作前就大声嚷嚷打扰到主子啊/捂脸。

总结

本文围绕“用HAL编程时,UART工作在DMA模式下,串口中断是否需要打开”这一问题,经过推理,得出的结论是UART中断要打开,但只开一部分(具体参考文章开头部分)。
在推理的过程中,对HAL实现UART的DMA模式传输、UART发送中断的寄存器变化、DMA模式下的请求过程进行了梳理,这些内容其实可以用来平行地理解SPI和IIC(至少仍是小白的我瞄了一眼例程感觉大差不差),所以可以为我们未来的学习扫除一些障碍。
最后,非常感谢uu能耐心地看到这里,本人能力有限,不免会有不少疏漏,表达上也会存在欠精准的地方,但还是希望能够多多少少帮到你/爱心,我们一起加油,在硬件开发的海洋里遨游!文章来源地址https://www.toymoban.com/news/detail-650544.html

到了这里,关于(stm32之HAL库)UART工作在DMA模式要打开串口中断吗?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32—HAL库中断/DMA控制和完成串口通信

    目录 一、解决的问题 二、串口通讯协议和RS-232的介绍以及USB/TTL转232模块的工作原理   1、 串口协议和RS-232标准:  (1)串口协议: (2)RS-232 标准:   2、RS232电平与TTL电平的区别   3、USB/TTL转232“模块(CH340芯片为例)  (1)基本原理:  (2)CH340模块介绍: ​三、搭

    2024年02月02日
    浏览(61)
  • stm32中HAL_UART_Transmit_DMA,串口只能发送一次。

    配置串口+DMA不产生DMA中断方式, 1、HAL_UART_Transmit_DMA中调用HAL_DMA_Start_IT,在HAL_DMA_Start_IT中虽然开启了三个中断:hdma-Instance-CR  |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME,但是没有开DMA总中断,所以这3个不起作用;同时,锁住DMA( __HAL_LOCK(hdma))。如果开启DMA总中断,完成DMA后会调用下

    2024年04月28日
    浏览(35)
  • 【STM32 HAL库实战】串口DMA + 空闲中断 实现不定长数据接收

    STM32CubeMX最新版: 打开STM32CubeMX软件,点击ACCESS TO MCU SELECTOR,在Commercial Part Number 中输入MCU型号,例如我在这里输入了STM32L431RCT6。选中正确型号然后双击进入下一步的配置界面。 1.1 SYS配置如图 1.2 RCC配置如图 开启了外部晶振,若无则都选择Disable 1.3 USART1配置 NVIC Settings 注意

    2024年02月03日
    浏览(67)
  • STM32CubeMX-HAL库-UART串口接收中断回调函数代码分析

            CubeMx中HAL库函数的调用不同于库函数调用,在学习CubeMx串口通信时,不理解HAL库中的回调函数是怎么被调用的,于是查看每个的定义,参考其他人写的博客,总算弄明白了HAL库中断调用与库函数不同之处。写下这篇博客一是加深自己的理解,二是希望对不理解HA

    2024年02月02日
    浏览(44)
  • STM32-HAL库串口DMA空闲中断的正确使用方式+解析SBUS信号

    能够点进这篇文章的小伙伴肯定是对STM32串口DMA空闲中断接收数据感兴趣的啦,今天用这一功能实现串口解析航模遥控器sbus信号时,查阅了很多网友发布的文章(勤劳的搬运工~),包括自己之前写过一篇博客 STM32_HAL库_CubeMx串口DMA通信(DMA发送+DMA空闲接收不定长数据)。本文

    2024年02月09日
    浏览(55)
  • HAL库 STM32运用DMA与IDLE中断实现高效串口通信 (附代码)

    最近想做一个控制电机的项目,其中会用到Pytho与单片机STM32之间的互同,最近也在看一些关于数据通信和拆包的相关知识,所以记录一下这段时间里对两者之间的互通所做的事情和发现的问题,以供自己和大家参考。 单片机的串口是我们常用的与电脑通信的外设,本次与P

    2024年01月22日
    浏览(46)
  • STM32F4_HAL库_串口阻塞/中断/DMA三种方式发送数据的配置

    串口阻塞发送的意思就是,发送一段数据,在没有发送完所有数据之前,一直停留在此发送函数(可设定阻塞时间),这个过程中会阻塞别的程序运行; HAL库的配置分为两个层次,一个是HAL库内部调用的、与MCU硬件相关的初始化xxx_MspInit,一个是我们外部调用的初始化xxx_In

    2023年04月25日
    浏览(43)
  • STM32:串口轮询模式、中断模式、DMA模式和接收不定长数据

           在STM32每个串口的内部都有两个寄存器:发送数据寄存器(TDR)/发送移位寄存器,当我们调用HAL_UART_Transmit 把数据发送出去时,CPU会将数据依次将数据发送到数据寄存器中,移位寄存器中的数据会根据我们设置的比特率传化成高低电平从TX引脚输出。待发送移位寄存器中发

    2024年02月07日
    浏览(42)
  • 【STM32+HAL+Proteus】系列学习教程---ADC(查询、中断、DMA模式下的电压采集)

    1、学会STM32CubeMX软件关于ADC的配置 2、掌握ADC三种模式(查询、中断、DMA)编程 3、具体目标:1、将开发板单片机采集到的电压值上传至上位机串口调试助手显示。 ADC(Analog to Digital Converter)即模数转换器,用来将模拟信号转换为数字信号。 A/D转换过程 分辨率:  A/D转换器对

    2024年04月26日
    浏览(31)
  • 【STM32】HAL库的STOP低功耗模式UART串口唤醒,第一个接收字节出错的问题(已解决)

    【STM32】HAL库的STOP低功耗模式UART串口唤醒,第一个接收字节出错的问题(已解决) 最近做项目时 用到了STOP1停止模式的串口唤醒 唤醒配置如下: 【STM32】HAL库低功耗STOP停止模式的串口唤醒(解决进入以后立马唤醒、串口唤醒和回调无法一起使用、接收数据不全的问题) 我

    2024年01月15日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包