tpgf 发表于 2021-12-1 08:50

DMA 导致 SPI 异常停止的原因分析、DMA 配置的那些坑

缘起  在最近的项目测试中发现,SPI 通信总是莫名其妙的失败,查看寄存器发现 SPI 已经被停止了。根据手册,SPI 在异常情况下会被强制停止(SPI 的使能为被清零),而根据波形显示通信过程没有问题。下图是我实际中的 DMA 及 SPI 使用情况:
[*]SPI1 仅使用发送功能,SPI2 仅使用接收功能,两者均使用 DMA。由于 SPI 没有仅发送模式,因此 SPI2 必须要配置一个 TX,否则导致 SPI 报错(实际并不配置 SPI 的发送引脚)。
[*]在初始化时,先初始化了 SPI2(含 DMA),然后再初始化的 SPI1(含DMA),这里是关键。
[*]在初始化之后,SPI 立刻开始工作(有数据通信)。其中,SPI2 大约以 8MHz 的速率不停的接收数据,SPI1 则以 1MHz 的速率在需要的时候才会发送数据。
[*]问题是在以上流程中,在配置 SPI2 时,有概率导致 SPI2 异常停止!


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

tpgf 发表于 2021-12-1 08:51

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


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

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

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

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


tpgf 发表于 2021-12-1 08:52

配置  根据手册,使用 DMA 时需要先写寄存器将 DMA 控制器使能,使能方法是写 DMA 使能寄存器 DMA_EN.EN 位。 如下图所示:我试了一下,不先使能貌似也没法发现啥问题啊!不知道为啥!?
无法获取当前传出数据长度  先来说一下需求:在串口驱动中,串口的接收使用 DMA 来实现,DMA 配置为循环模式,在指定缓冲区中循环存放收到的数据,通过读写指针来标记数据的读和写位置。  然而,驱动库中 DMA 接口并没有能获取当前 DMA 传输了多少字节的接口!!!无奈只能选择修改驱动库,添加一些指定的接口,如下图所示:
 后来,为了不修改驱动库,我直接把接口放到了自己的驱动里面,然后使用寄存器直接读取:M4DMA1->MONRPT0_f.DRPT,这样的话,需要注意与通道号的对应关系,如 MONRPT0 即通道 0。

tpgf 发表于 2021-12-1 08:53

中断的使用  在华大的 DMA 中,中断默认都是开启的,这点在配置 DMA 的时候需要特殊注意。我们需要使用 DMA 的屏蔽中断寄存器来屏蔽不使用的中断。如下图示:
在实际写代码时,需要调用 en_result_t DMA_DisableIrq(M4_DMA_TypeDef* pstcDmaReg, uint8_t u8Ch, en_dma_irq_sel_t enIrqSel); 来关闭不需要的中中断。例如,DMA 的块传输完成中断 和 传输完成中断 通常不会一起使用!这点对于用惯了 ST MCU 的人来说需要特殊注意!

结论在使用中,发现华大 MCU 的外设配置中,有不少的坑,尤其是对于我这种用惯了 STM32 的人来说。例如之前说的 SPI、中断、这里说的 DMA 等等。千万不要完全相信华大 MCU 驱动库中给出的示例,里面是丢三落四各种错误!在用户手册中一些比较重要的点,手册往往是一笔带过,在我们实际使用中容易被忽略,而往往忽略的就是问题的关键。而且对于异常情况,手册中没有很详细的描述,导致真正出现问题时,从手册中不能很快分析出原因。对于某些外设,有很多用来观察外设工作的寄存器(ST 没有这部分寄存器),我们在实际使用中,往往需要等待这些寄存器中的某些位被置位之后才可以继续操作,否则会出现各种错误

华大单片机 发表于 2021-12-1 09:32

您好,毕竟国产要跟国外来区别。华大的DMA确实是有些不同,如果可以最好有工程师来协助处理。

sadicy 发表于 2021-12-1 13:47

用惯了一种片子,换其他的话,总会不由自主的对比
然后觉得现在用的为什么和之前不一样
就好像用惯了安捷伦的万用表示波器,在用其他的,界面都别扭一样~~~

不过,现在国产芯片确实好很多了,发展也快了~~一些方面,优势也有了

caigang13 发表于 2021-12-3 08:35

谢谢楼主分享避坑经验

两只袜子 发表于 2021-12-6 09:29

学习下楼主分享的闭坑经验

andygirl 发表于 2021-12-8 17:03

学习一下,DMA不是 很熟

duo点 发表于 2021-12-9 16:18

学习学习

xing650721 发表于 2021-12-10 00:25

DMA还是很有用处的

daichaodai 发表于 2021-12-10 07:53

谢谢分享经验

麻花油条 发表于 2021-12-13 14:37

学习学习

alxd 发表于 2021-12-20 14:59

哈哈,挺好,感谢楼主分享

Allison8859 发表于 2021-12-20 15:01

能早点看到就好了能少走不少弯路

guijial511 发表于 2021-12-21 08:10

哈哈,楼主是踩了多少坑啊?

littlelida 发表于 2022-1-18 15:14

确实有一些点很简单的带过了,但是感觉总体来说,还可以,
华大甚至其他一些国产品牌的片子,还是有很多不错的。
其实ST也会有一些坑,只是踩的人多了,人家一点点的改了而已。

感谢楼主分享采坑经验 ,分享还是很好的

热任务人 发表于 2024-4-3 11:15

那需要同时对同一个dma不同通道进行设置,这怎么解决

xdvca 发表于 2024-7-31 22:34

要生成 38.4kHz 的红外信号,你可以使用定时器模块来产生 PWM 信号。
页: [1]
查看完整版本: DMA 导致 SPI 异常停止的原因分析、DMA 配置的那些坑