STM32 DMA编程时的一个小技巧:应用提醒

631561cc86ceec1c7dce8619f2360437.jpeg

有人使用STM32H7芯片做些事情,发现基于ST公司的HAL库开发UART1的DMA收发时可以轻松实现,而当使用ST的LL库组织代码时,却没法实现UART的DMA传输。感觉上就是使用HAL库编写代码功能正常而基于LL库则不行。真是这样吗?

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

636e3e9a612a8f532fec83f711765f1f.png

从功能实现上讲,使用HAL库及相应API还是很方便、很简单的。每个API函数就像个黑盒子,对于里面的内容,如果你不点进去阅读是不会知晓的。不过,建议尽可能地多点进去瞧瞧,那里往往别有洞天。

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

268489a263d3d8a664c69b4593eea0c5.png

c9dc4187ba91d3b9219d296f354df4df.png

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

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

3df3806b6d1c729756620f8d3aba88d1.png

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

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

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

后来,根据代码里涉及到的寄存器去跟STM32H7手册里寄存器做比较阅读。在查看DMA各个stream配置控制寄存器【DMA_SxCR】内容时,突然发现并想起了点什么。其实也是之前在别的DMA应用场合也碰到过的类似问题。下面为该寄存器的内容布局截图。

184e14eb1d60dd7a8c348926ec80dae9.png

隐约记得,该DMA Stream或Channel的控制使能位为0时才能做DMA相关其它参数的配置的。我们可以在手册里找到针对该位的明确描述:

78f60da9e055a120e38e5ced4ae289e6.png

这里的意思是说,要想让某DMA stream工作,必须令该EN位为1。不过,当该EN位为1时时,是不允许对DMA及相应FIFO寄存器做配置的。换言之,若要针对某Stream做DMA相关配置,得先让该控制寄存器的EN位保持为0状态。

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

e7fcc60338c30268f0e6992d32f31378.png

28e2beed3f9c86308ad778982df7abe1.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库组织代码和基于汇编指令组织代码实现相同功能时,对我们自身的挑战及相应的收获是不可同日而语的。

==========================

往期话题阅读链接:

1、STM32G4系列存储访问的两个小话题

2、开启Cache后UART无法发送新数据

3、为何STM32H7的ADC数据不变?

4、CubeMx配置顺序与DMA传输异常之提醒

5、基于STM32的TIM+DMA+DAC应用示例

9ee238f374f9fb2b62452394d0708fef.png

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 DMA编程时的一个小技巧:应用提醒

发表评论