HAL库无法实现UART的DMA传输真是这样吗?

发布者:HappyExplorer最新更新时间:2024-03-18 来源: elecfans关键字:UART  DMA传输 手机看文章 扫描二维码
随时随地手机看文章

有人使用STM32H7芯片做些事情,发现基于ST公司的HAL库开发UART1的DMA收发时可以轻松实现,而当使用ST的LL库组织代码时,却没法实现UART的DMA传输。

感觉上就是使用HAL库编写代码功能正常而基于LL库则不行。真是这样吗?

使用STM32CubeMx进行图形化配置,并生成基于HAL库的初始代码,要实现UART收发功能的DMA传输的话,除了安排好的收发缓冲内存外,再就只需调用下面两个HAL库的API函数即可进行功能验证。

a21e7c38-8e71-11ed-bfe3-dac502259ad0.png

从功能实现上讲,使用HAL库及相应API还是很方便、很简单的。每个API函数就像个黑盒子,对于里面的内容,如果你不点进去阅读是不会知晓的。

不过,建议尽可能地多点进去瞧瞧,那里往往别有洞天。

如果基于LL库来组织代码的话,先使用STM32CubeMx进行配置并生成基于LL库的初始化代码。

a230b31c-8e71-11ed-bfe3-dac502259ad0.png

a241dff2-8e71-11ed-bfe3-dac502259ad0.png

基于CubeMx配置完毕后生成初始化工程,准备收发缓冲内存,然后添加用户代码。

刚开始用户代码是这样编写安排的。见下面代码截图。

a2504d94-8e71-11ed-bfe3-dac502259ad0.png

上图中A处代码的作用就是开启两个DMA stream的功能,即对相关DMA Stream的控制寄存器的使能位进行使能置1。

编译无错后运行代码,可是根本没有数据的收发动作发生。看来,跟反馈者的症状一样。

没办法,硬着头皮核查代码。除了核查我添加的用户代码外,还核查UART及DMA的初始化代码。看来看去,似乎该有的都有了,该写的都写了。

后来,根据代码里涉及到的寄存器去跟STM32H7手册里寄存器做比较阅读。

在查看DMA各个stream配置控制寄存器【DMA_SxCR】内容时,突然发现并想起了点什么。

其实也是之前在别的DMA应用场合也碰到过的类似问题。

下面为该寄存器的内容布局截图。

a27c309e-8e71-11ed-bfe3-dac502259ad0.png

隐约记得,该DMA Stream或Channel的控制使能位为0时才能做DMA相关其它参数的配置的。

我们可以在手册里找到针对该位的明确描述:

a28984c4-8e71-11ed-bfe3-dac502259ad0.png

这里的意思是说,要想让某DMA stream工作,必须令该EN位为1。

不过,当该EN位为1时时,是不允许对DMA及相应FIFO寄存器做配置的。

换言之,若要针对某Stream做DMA相关配置,得先让该控制寄存器的EN位保持为0状态。

而在我的用户代码里,对EN位写1操作则放在了对DMA做各种配置的前面,即上面代码截图的A处。

a29a48cc-8e71-11ed-bfe3-dac502259ad0.png

a2a4da3a-8e71-11ed-bfe3-dac502259ad0.png

既然这样,我们把对DMA控制寄存器EN位的置1操作放在其它DMA相关配置之后就应该可以了,即从上面代码截图中的A处拉到B处。

然后,进行测试,结果果真正常了。

其实就是一个配置代码顺序问题,卡了半天。

如果不是用LL库而是用HAL库可能就不太容易碰到这个问题。前面说过了,基于HAL库的API函数像个黑盒子,它帮我们处理了很多细节性、判断性的东西。

基于LL库组织的代码,相比HAL库组织的代码,代码精简、流程清晰、运行高效。不过,使用LL库做开发需要开发者对芯片各个模块的工作原理,操作流程有更清晰、更精准的了解,同时往往还需要开发者对应用相关的寄存器有更细致、深入的把握。

而HAL库往往事先帮我们充分考虑到了基于硬件需求的操作流程、时序,基于软件层面的诸多事件及状态的互斥管理,以及不同STM32系列的代码兼容性,并做了很好、很全面的封装。

所以我们在利用HAL库来实现相应功能时,往往无须对操作流程、时序以及寄存器本身做过多的了解就可以完成。

从开发角度讲,利用HAL库往往比利用LL库能更快地完成任务,同时基于HAL库的代码也有更好的移植性,代价就是代码相对LL库要庞大些。

对应STM32开发者而言,即使基于HAL库开发了一些STM32项目,对于芯片的诸多功能细节以及寄存器的了解往往可能比较有限。当然,这点因人而异吧,不可说死。

对于HAL库和LL库的选用,我们每个人可以根据自身情况来。比方,对芯片软硬件不熟悉时、任务紧急时先使用HAL库,等对芯片及库函数熟悉、任务不紧急时可以切换到LL库。

或者说,只是做些功能性验证确认,使用HAL库组织代码也是非常快捷方便的。

当然,一个工程里HAL库、LL库是可以同时并存的。另外,当我们对芯片寄存器、内核指令系统足够熟悉时,甚至可以尝试使用汇编语言做MCU编程开发。

作为开发人员,基于HAL库组织代码和基于汇编指令组织代码实现相同功能时,对我们自身的挑战及相应的收获是不可同日而语的。


关键字:UART  DMA传输 引用地址:HAL库无法实现UART的DMA传输真是这样吗?

上一篇:存储器映射与寄存器映射的区别 推挽输出和开漏输出的概念
下一篇:开启Cache后UART无法发送新数据

推荐阅读最新更新时间:2024-11-12 07:12

stm32f103——中断——UART中断服务函数
在程序中,CPU对外界突发事件进行处理的方式又两种: 1》轮询系统:(在main中,使用while循环,进行循环判断外界事物是否发生) while(1){ } 2》前后台系统:(此时main中的while中的程序是在处理其它事务,当中断来到时,就处理中断服务函数) 轮询系统+中断 中断的过程: 在主程序执行的过程中,中断突然发生,此时主程序停止往下执行,并将CPU的当前状态保持在内核栈中(即:现场保护)。然后跳转到中断服务函数的入口,并执行中断服务函数,当中断服务函数执行完后,再将之前保存在内核栈中的状态全部进行出栈,将状态恢复到发生中断之前(即:现场恢复),此时对于CPU来
[单片机]
stm32f103——中断——<font color='red'>UART</font>中断服务函数
STM32F4 UART1 DMA收发的一些问题解决
早些时间写过一篇“STM32F4 UART1 DMA发送和接收不定长度数据”的博文。很多转载的都不注明出处的。后来就没再怎么用过F4的uart 也有朋友反映过会莫名的进接受完成中断,但是实际接受的数据量并没有达到设置的DMA接受长度,应该不会进DMA接收中断,我也没搞明白就不了了之了,可看这个链接:http://www.openedv.com/forum.php?mod=viewthread&tid=76091&extra= 最近有个项目用到了这个功能。之前能接受发送到程序,下载到单片机里面怎么都不行了。很调了很久发现了以下几个问题 1.串口DMA接收中断、DMA发送中断、空闲中断的优先级是有影响。按照以下设置faxi发现
[单片机]
AVR USART(UART)发送中断程序 使用缓冲器
系统功能    使用AVR的USART进行自发自收(将发送引脚RXD短接到接收引脚TXD),发出数据:0,1,2。。。数据,能接收到自己发出的数据:0,1,2。。。使用LED作出简单指示! 硬件设计 AVR主控电路原理图(点击图片放大,不需要放大镜! ) LED控制电路原理图(点击图片放大,不需要放大镜! ) 软件设计 下面部分从TXT拷出,拷到网页,代码部分缺省了很多空格,比较凌乱,请谅解! //目标系统: 基于AVR单片机 //应用软
[单片机]
AVR USART(<font color='red'>UART</font>)发送中断程序 使用缓冲器
UART0串口编程(一):通信协议设计;RS232标准
嵌入式系统之间采用通信方式交换数据,串行通信是一种最基本的通信手段。现在由于各类CPU均集成了UART部件。本节对串口编程时如何设计串口通信协议,以及对RS232接口进行了说明。 1. 通信协议设计 在进行通信时,每次需要传送的信息一般超过1字节。为此,通信双方必须约定通信数据的排列格式,即通信协议。通常把一次通信过程的全部内容称为一个“通信帧”。通信协议设计就是帧结构设计。在一帧内容中,通常包括以下部分。 (1)起始码:由一个或若干个包含特定内容的字节,表示一个通信帧的开始。起始码的内容必须与通信数据内容有明显区别(不能在通信数据里出现与起始码相同的内容)。当通信帧的总长度比较短,信道质量比较高时,为了提高效率,可
[单片机]
<font color='red'>UART</font>0串口编程(一):通信协议设计;RS232标准
SAM4E单片机之旅——11、UART之PDC收发
使用PDC进行数据的收发能减少CPU的开销。这次就使用PDC进行UART数据的接收与发送,同时,也利用TC也实现了PDC的接收超时。 PDC是针对外设的DMA控制器。对比DMA控制器,它更为简便,与相应外设的结合也更为紧密。比如说,要配置PDC时,首先要启用相应的外设的时钟;同时PDC收发的状态是通过外设上的寄存器反映出来的;甚至中断也是通过相应外设产生的。 使用PDC时,只需设置好传输时内存的地址,以及传输长度,就可以在外设和内存之前进行数据传输了。而SAM4的PDC甚至还提供了一个类似FIFO的功能:可以在进行本次传输的同时指定下次传输时的地址和长度,然后在本次传输结束时开始下一次传输。 一、 实现思路 本次会使用两组
[单片机]
MSP430另一种UART实现
1 #include msp430g2553.h 2 3 typedef unsigned char uchar; 4 typedef unsigned int uint; 5 6 #define LED BIT0 7 #define TXD BIT1 // TXD on P1.1 8 #define RXD BIT2 // RXD on P1.2 9 #define POUT P1OUT 10 11 #define BITTIME_1b 13*4 //1bit宽度 12 #define BITTIME_1b5 13*6
[单片机]
STM32CubeIDE 中 HAL库的串口中断接收函数 HAL_UART_Receive_IT
一、代码自动生成以后的项目及代码结构: main.c中,调用了串口初始化 串口初始化函数赋值了串口的参数 相当于底层的初始化,配置引脚、并开启中断。 至此串口1配置完毕 二、库文件stm32f1xx_hal_uart.c内的秘密 2.1 初始化 1.usart.c中,MX_USART1_UART_Init 调用了库的HAL_UART_Init,将结构体传递进该函数中 2.HAL_UART_Init干了些什么事? if (huart- gState == HAL_UART_STATE_RESET) { huart- Lock = HAL_UNLOCKED; HAL_UART_MspInit(huar
[单片机]
STM32CubeIDE 中 <font color='red'>HAL库</font>的串口中断接收函数 HAL_<font color='red'>UART</font>_Receive_IT
STM32 ADC多通道DMA传输
ADC多通道采集是在ADC单通道DMA传输的基础上写的,代码如下: volatile u16 adcconverdata ={0,0}; static void ADC_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2;//添加PA2的GPIO初始化代码 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; GPIO_Init(
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved