华大MCU之七:DMA 导致 SPI 异常停止的原因分析、DMA 配置的那些坑

cathy的头像

缘起

在最近的项目测试中发现,SPI 通信总是莫名其妙的失败,查看寄存器发现 SPI 已经被停止了。根据手册,SPI 在异常情况下会被强制停止(SPI 的使能为被清零),而根据波形显示通信过程没有问题。下图是我实际中的 DMA 及 SPI 使用情况:

“华大MCU之七:DMA

1、SPI1 仅使用发送功能,SPI2 仅使用接收功能,两者均使用 DMA。由于 SPI 没有仅发送模式,因此 SPI2 必须要配置一个 TX,否则导致 SPI 报错(实际并不配置 SPI 的发送引脚)。

2、在初始化时,先初始化了 SPI2(含 DMA),然后再初始化的 SPI1(含DMA),这里是关键。

3、在初始化之后,SPI 立刻开始工作(有数据通信)。其中,SPI2 大约以 8MHz 的速率不停的接收数据,SPI1 则以 1MHz 的速率在需要的时候才会发送数据。

4、问题是在以上流程中,在配置 SPI2 时,有概率导致 SPI2 异常停止!

问题分析
  
最初怀疑是 SPI 的问题,因为在初始实现这部分功能时就遇到了很多坑,我也写过博文华大MCU之五:SPI从机DMA模式配置(不能正常接收问题处理)来专门记录遇到的问题。但是再一次整理了一下 SPI 的配置流程,并没有发现啥问题。在测试中发现,将 SPI2 使用的 DMA 停止,则不会出现问题,于是开始调查 DMA 的问题。

DMA 的坑

最开始将问题重点放到了 DMA 的配置上,怀疑是不是 DMA 部分配置项不正确。但是,读数情况下 SPI 是工作正常的,如果是配置不对,应该是一个必出现的问题。转而又开始怀疑是不是配置时序(寄存器的配置的先后顺序)不对,反复查看代码也没有发现问题。正在一筹莫展之时,有同事提出了手册中 DMA 章节给出的一个注意事项:

“华大MCU之七:DMA

其实,最开始实现 SPI 驱动时就关注过该注意事项,只是开始的理解是,这条注意事项是针对同一通道而言的,同一通道在工作时不能再次配置上面说的这些寄存器,不同 DMA 通道之间应该互不影响。然而实际情况是,只要 DMA 有任意一个通道在传输数据,其他所有通道都不可以配置!

这就导致了一个很大的问题,外设在工作中不可避免的要重新配置 DMA。例如,SPI 的 DMA 发送,由于发送数据长度是动态变化的,必须每次重新进行配置,则根据上面这一条,必须把该 DMA 下的其他通道(例如上面我的 SPI1 使用的通道)也都全部停止,这样就可能导致其他外设丢失数据。

最麻烦的是,这个问题没有找到任何其他的解决方法,只能是停止该 DMA 下的所有通道,进而来配置自己需要的那个通道参数。起初在寻找解决方法的时候,也考虑是不是可以用下图所示的寄存器位来进行一下判断,而是实际是下面的位根本没有任何用处。

“华大MCU之七:DMA

还是以我上面的使用示例来说,SPI2 作为从机接收,由于使用了 DMA,MCU 并不能确定数据何时到来。即使 MCU 检测 DMAACT 未动作,可能在实际配置通道时,DMA 又变为了动作状态。

配置

根据手册,使用 DMA 时需要先写寄存器将 DMA 控制器使能,使能方法是写 DMA 使能寄存器 DMA_EN.EN 位。 如下图所示:

“华大MCU之七:DMA

我试了一下,不先使能貌似也没法发现啥问题啊!不知道为啥!?

无法获取当前传出数据长度

先来说一下需求:在串口驱动中,串口的接收使用 DMA 来实现,DMA 配置为循环模式,在指定缓冲区中循环存放收到的数据,通过读写指针来标记数据的读和写位置。

然而,驱动库中 DMA 接口并没有能获取当前 DMA 传输了多少字节的接口!!!无奈只能选择修改驱动库,添加一些指定的接口,如下图所示:

“华大MCU之七:DMA

后来,为了不修改驱动库,我直接把接口放到了自己的驱动里面,然后使用寄存器直接读取:M4DMA1->MONRPT0_f.DRPT,这样的话,需要注意与通道号的对应关系,如 MONRPT0 即通道 0。

中断的使用

在华大的 DMA 中,中断默认都是开启的,这点在配置 DMA 的时候需要特殊注意。我们需要使用 DMA 的屏蔽中断寄存器来屏蔽不使用的中断。如下图示:

“华大MCU之七:DMA

在实际写代码时,需要调用 en_result_t DMA_DisableIrq(M4_DMA_TypeDef* pstcDmaReg, uint8_t u8Ch, en_dma_irq_sel_t enIrqSel); 来关闭不需要的中中断。例如,DMA 的块传输完成中断 和 传输完成中断 通常不会一起使用!这点对于用惯了 ST MCU 的人来说需要特殊注意!

结论

1、在使用中,发现华大 MCU 的外设配置中,有不少的坑,尤其是对于我这种用惯了 STM32 的人来说。例如之前说的 SPI、中断、这里说的 DMA 等等。

2、千万不要完全相信华大 MCU 驱动库中给出的示例,里面是丢三落四各种错误!

3、在用户手册中一些比较重要的点,手册往往是一笔带过,在我们实际使用中容易被忽略,而往往忽略的就是问题的关键。而且对于异常情况,手册中没有很详细的描述,导致真正出现问题时,从手册中不能很快分析出原因。

4、对于某些外设,有很多用来观察外设工作的寄存器(ST 没有这部分寄存器),我们在实际使用中,往往需要等待这些寄存器中的某些位被置位之后才可以继续操作,否则会出现各种错误

参考

HC32F460系列用户手册Rev1.21.pdf

相关阅读:
华大MCU之一:HC32F460 替换 STM32F411 移植记录
华大MCU之二:USB 驱动 + FatFs 的移植使用详解
华大MCU之三:时钟控制器(CMU)配置记录
华大MCU之四:使用问题记录
华大MCU之五:SPI从机DMA模式配置(不能正常接收问题处理)
华大MCU之六:SEGGER Embedded Studio及Ozone使用Jlink调试

版权声明:本文为CSDN博主「ZC·Shou」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ZCShouCSDN/article/details/121414394
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。