硬汉嵌入式论坛

 找回密码
 立即注册
查看: 4429|回复: 17
收起左侧

[STM32H750] [经验分享]纯硬件实现SPI接口驱动外部ADC以800KSps速度连续采样

  [复制链接]

2

主题

9

回帖

20

积分

新手上路

积分
20
发表于 2021-12-21 18:34:47 | 显示全部楼层 |阅读模式
本帖最后由 archon 于 2021-12-22 19:52 编辑

最近做一个项目需要使用STM32H7驱动一个外置16bit ADC进行高速连续采样,设计采样速度为800KSps。ADC使用SPI接口,接口时序如下图。
timing.png
单片机使输出CNV信号,ADC在上升沿开启采样,在固定的采样时间后,即可通过SPI接口读取2字节的采样转换结果。ADC内部会在每一次转换之后自动切换到内部设定好的通道转换序列中的下一个通道。因此要实现对这样的ADC的驱动,操作循环如下:
1、单片机输出CNV上升沿。
2、等待固定时间或等待BUSY信号出现下降沿。
3、SPI输出2字节空数据,读取2字节转换结果。

很容易想到的就是使用定时器的OC输出CNV信号,然后在OC中断中调用SPI读写函数。但这个思路存在很大的问题,即800KSps的采样频率已经相对较高,每秒产生80万次中断,简单计算可知STM32H7最大主频为480MHz,因此每一次中断间隔仅有600个时钟周期。考虑到HAL库的中断调用开销,假如以这种频率触发中断,光进出中断服务函数本身就已经消耗了单片机15%以上的性能,更不要提还需要在中断服务函数中进行SPI读写了。H750这么强的单片机不是拿来这样用的。因此就需要使用一套尽可能不引入任何软件操作的驱动方式。而这个方式的核心则是H750中的DMAMUX。可以说任何人如果需要用H750进行一些相对复杂的通讯或者数据管理,DMAMUX是一定要好好研究的。

具体实现思路如下。首先使用TIM12产生CNV驱动波形。为何使用TIM12,这是因为DMAMUX1的限制导致的,因为DMAMUX1的定时器触发源只能选择TIM12_TRGO。但实际上也并不完全必须要用TIM12直接驱动ADC,尤其是考虑到PCB布局的缘故,也可以用其他的定时器驱动,只要把它配置为和TIM12产生同样频率的波形即可,这样两个定时器以伪同步的方式工作,也可以实现稳定触发。但这里有两个小问题需要注意。

第一个问题:由于软件代码的执行顺序问题,实现上不可能做到同步启用两个定时器,总有一个会比另外一个晚一点,因此为了对齐OC事件的时序,需要把后启动的那个定时器的OC比较值调小一些,具体可以靠试验得出。当然,H750本身也支持用一个定时器通过触发的方式启动其他定时器,但靠调节延迟可以解决问题也就没必要做这么复杂了。

第二个问题:由于HAL库比较臃肿,调用HAL_TIM_Start_OC()函数的开销过大,可能导致后启动的定时器需要设置成负OC比较值才可以匹配的情况,因此需要对HAL库进行修改,把前述函数中的__HAL_TIM_ENABLE()宏单独提取出来放在外面执行。

我们假设直接使用TIM12驱动ADC,在配置好频率和占空比后,将TIM12的TRGO配置为对应通道的OC事件。这样TIM12就会在OC匹配的时候产生一个正脉冲,用于触发DMAMUX1。

下一步需要做的就是用TIM12的OC事件触发SPI通讯,在每一次TIM12 OC事件发生时,让SPI接口输出2个字节。这里需要用到DMAMUX的同步功能。这个功能可以在仅仅收到同步信号的时候,再“放行”堵塞在DMAMUX通道输入端口上的外设DMA请求。按照常规方式配置SPI的发送DMA通道,然后对这个通道启用事件同步,同步源为TIM12_TRGO,即可实现由TIM12_TRGO触发SPI DMA发送。那么如何保证发送的是2个字节,这需要用到DMAMUX的另外一个功能,即每次同步后产生的请求数量。DMAMUX支持在一次同步事件后产生1~32个请求,因此假设我们配置的SPI发送DMA模式为2字节或半字,则把同步请求数量设置为1即可。如果SPI发送DMA模式为1字节,则把同步请求数量设置为2,甚至如果需要发送的是奇数个字节比如24bit,通过将SPI发送DMA模式设置为1字节,再将请求数量设置为3也可以实现。

至此即可实现由TIM12 OC事件驱动SPI接口自动发送指定字节数据的功能。发送的数据可以通过修改SPI发送DMA对应的发送缓冲区实现,如果只需要读取,发送全0或者全1均可。这时甚至可以关闭SPI发送DMA的内存地址自增功能,仅需几个字节的缓冲区即可。

下一步是同步接收SPI数据。这里有一个不大不小的坑,折腾了我好几天。首先可以明确的是,SPI接收DMA并不需要主动提供触发,当SPI硬件接收到对应长度数据时它会自动产生DMA请求。因此我们只需要控制好发送,对于接收,直接打开SPI接收DMA通道就行了,也不需要进行DMAMUX同步,当然要同步也不会出错。但当配置好以后发现收到的数据在每一个DMA传输周期后会产生一个偏移,导致数据对不齐。这问题弄得我百思不得其解,尤其是在单步调试的时候DMA其实还在继续工作,导致连数据都看不清。最后发现问题出在SPI的接收FIFO上。通过将TIM12配置为单脉冲模式分析发现,只有当SPI的接收FIFO满了以后它才会开始产生DMA请求,而一般来说都会建议将SPI接收FIFO阈值设置为不超过16字节的最大值,之前初始化的时候我设置成了7,才会出现在第八次SPI发送DMA请求之后,才产生第一个SPI接收DMA请求。将SPI接收FIFO的大小设置为1,即可解决数据对齐问题。

至此就已经完成了纯靠硬件的SPI驱动ADC连续采样。工作流程是:TIM12产生CNV信号发送给ADC,并在CNV信号下降沿产生触发信号给DMAMUX1,DMAMUX1接到触发信号后,放行1次SPI发送DMA请求,发送2个字节。发送完成后SPI硬件自动产生接收DMA请求,最终将数据转移至内存缓冲区。当然,为了安全处理数据,可以启用SPI接收DMA的硬件双缓冲功能,或通过半传输中断来实现。通过这样的设计,可以把产生的中断次数从每秒80万次降低到每秒25次,M7核心就可以随便去做任何其他事了。
补充一个后来发现的额外的问题,那就是在这种速度不高但频率很高的连续DMA调用时,这个DMA最好完全给SPI外设使用,而不要再分配其它通道。在半传输中断中要把数据从SRAM搬运到SDRAM,我尝试了用DMA2(SPI收发我也用的DMA2)的MEM2MEM通道,结果发现会导致严重的不稳定现象,40KB数据复制完成的速度最慢需要接近半秒,后来想想其实也很容易理解就是,毕竟SPI接口的收发占空比几乎达到了50%,而DMA2负责TX和RX DMA就基本已经占满了工作时间,已经没什么资源可以分配给其它任务了。而我的应用里,DMA1负责了3个内置ADC的连续采样,所以连DMA1也没法用,最后测试下来,用MDMA来完成SRAM到SDRAM的数据搬运是很稳定的选择,因此如果需要用某一个DMA来完成高频率SPI通讯,那么这个DMA非常建议配置为SPI外设独占,而对应的缓冲区搬运就改用其它的DMA来实现。SRAM1、SRAM2、SRAM3也都可以,但考虑到总线性能,还是建议把SPI的DMA接收缓冲开在AXI SRAM里。

希望分享经验能对大家有所帮助。

评分

参与人数 2金币 +110 收起 理由
missfox + 10 赞一个!
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

747

主题

1049

回帖

3295

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3295
发表于 2021-12-21 22:21:11 | 显示全部楼层
好贴,谢谢分享。这是将H750的SPI硬件功能用到极致。
回复

使用道具 举报

0

主题

31

回帖

31

积分

新手上路

积分
31
发表于 2021-12-21 23:49:36 | 显示全部楼层
这么强悍
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2021-12-22 00:49:09 | 显示全部楼层
非常感谢楼主分享,码字不易。

楼主的思路当前应该是没有BUSY反馈,用BUSY反馈,确实会更繁琐一些。我画个框图,方便其他人了解楼主的思路,跟我之前SPI DMA驱动DAC8563差不多,区别的地方是我的仅输出就行。

QQ截图20211222005336.png


PS:
1。这个地方描述,楼主应该是想表达24bit吧,“甚至如果需要发送的是奇数个字节比如24字节,通过将SPI发送DMA模式设置为1字节,再将请求数量设置为3也可以实现 ”

2、关于DMA和SPI FIFO的大小,这个非常考究,补充一个帖子,方便后来的人了解:

STM32H7的SPI DMA配置时,SPI硬件FIFO,DMA突发设置等几个重要注意事项
https://www.armbbs.cn/forum.php?mod=viewthread&tid=102944

回复

使用道具 举报

23

主题

1403

回帖

1472

积分

至尊会员

积分
1472
发表于 2021-12-22 15:38:55 | 显示全部楼层
好帖子,学习下
代码不规范,亲人两行泪!
回复

使用道具 举报

2

主题

9

回帖

20

积分

新手上路

积分
20
 楼主| 发表于 2021-12-22 19:45:12 | 显示全部楼层
eric2013 发表于 2021-12-22 00:49
非常感谢楼主分享,码字不易。

楼主的思路当前应该是没有BUSY反馈,用BUSY反馈,确实会更繁琐一些。我画 ...

是的,打错了,已经修改成24bit了。用BUSY反馈其实也不是不可以,毕竟DMAMUX可以用EXTI0触发,但SAR ADC的转换时间是很稳定且很固定的,所以直接调节OC数值,把时序对准就行了。
回复

使用道具 举报

4

主题

139

回帖

151

积分

初级会员

积分
151
发表于 2021-12-23 11:03:09 | 显示全部楼层
楼主强啊,可否有示例参考学习下呢
回复

使用道具 举报

2

主题

9

回帖

20

积分

新手上路

积分
20
 楼主| 发表于 2021-12-23 13:39:19 | 显示全部楼层
浴火重生 发表于 2021-12-23 11:03
楼主强啊,可否有示例参考学习下呢

纯硬件功能的东西其实大部分只需要在CUBEMX里配置好就行了,实际并不需要做多少软件操作,真正需要自己写的代码也就三行,HAL_SPI_TransmitReceive_DMA()、HAL_TIM_Start_OC(),以及在半传输完成中断和传输完成中断里靠HAL_MDMA_Start_IT()把数据搬走。剩下的配置全都是在CUBEMX里做,然后靠自动生成的代码就行了,重要的是分享实现流程。所以并不需要什么示例,打开CUBEMX按照这个思路配置基本就可以搞定了。
回复

使用道具 举报

2

主题

75

回帖

81

积分

初级会员

积分
81
发表于 2021-12-25 23:19:15 | 显示全部楼层
准备用743连接一个2.5M采样率的ADC,14位,一定要好好参考学习下楼主的方法。
回复

使用道具 举报

4

主题

20

回帖

32

积分

新手上路

积分
32
发表于 2022-11-1 16:13:55 | 显示全部楼层
我看了,,看懂了,,不会写,,我好想要个例程啊。。
回复

使用道具 举报

41

主题

214

回帖

337

积分

高级会员

积分
337
发表于 2023-2-27 20:16:32 | 显示全部楼层
请问是不是只有h7才可以实现后面,  CCxIF出发SPI的DMA读数据的功能。
F103只能实现前面PWM的占空比。
image.png
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2023-2-28 10:36:09 | 显示全部楼层
snakeemail 发表于 2023-2-27 20:16
请问是不是只有h7才可以实现后面,  CCxIF出发SPI的DMA读数据的功能。
F103只能实现前面PWM的占空比。

楼主位这个是DMAMUX做的同步控制,F103不行。
回复

使用道具 举报

41

主题

214

回帖

337

积分

高级会员

积分
337
发表于 2023-2-28 20:45:56 | 显示全部楼层
本帖最后由 snakeemail 于 2023-2-28 20:47 编辑
eric2013 发表于 2023-2-28 10:36
楼主位这个是DMAMUX做的同步控制,F103不行。

那F103对于这种SPI接口的SAR类型ADC。
如果只有mcu,最优的设计,只能产生PWM波,调整占空比,然后在convst的下降沿,产生中断,SPI读取ADC数据。

image.png
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2023-3-1 16:24:16 | 显示全部楼层
snakeemail 发表于 2023-2-28 20:45
那F103对于这种SPI接口的SAR类型ADC。
如果只有mcu,最优的设计,只能产生PWM波,调整占空比,然后在con ...

对,就是这样效率低些。
回复

使用道具 举报

7

主题

22

回帖

43

积分

新手上路

积分
43
发表于 2023-6-12 16:07:24 | 显示全部楼层
太赞了,已在工程中应用成功
回复

使用道具 举报

4

主题

32

回帖

44

积分

新手上路

积分
44
发表于 2023-6-13 08:37:15 | 显示全部楼层
Mark!
回复

使用道具 举报

0

主题

2

回帖

2

积分

新手上路

积分
2
发表于 2023-7-14 14:20:55 | 显示全部楼层
可以求上面大佬的交流方式吗,求代码球球了
回复

使用道具 举报

0

主题

2

回帖

2

积分

新手上路

积分
2
发表于 2023-7-14 14:21:30 | 显示全部楼层
circlegan 发表于 2023-6-12 16:07
太赞了,已在工程中应用成功

求大佬交流
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-28 23:18 , Processed in 0.328498 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表