为何STM32H7的ADC数据不变?

a3437ef7ed034b33397ac342dc83c9cb.jpeg

有人使用STM32H7系列的ADC模块,定时器触发ADC,数据通过DMA传输到内存。对某通道连续转换几次后求个平均值。他却发现ADC结果虽没有什么问题,但一批数据出来后就纹丝不动了。DMA传输本来设计成的Circular模式,感觉好像工作在Normal模式,结果显然有点不合理。

鉴于这个现象和所用芯片,估计是因为Cache使用方面的原因,客户也的确使能了Cache。具体怎么回事呢?我们一起来看看。

我这边使用H743Nucleo板和ST免费的STM32CubeIDESTM32H743片内有个Vrefint信号,电压一般在1.2v左右,用它做ADC的输入信号来测试。用LPTIM触发ADC转换,每读到5个数据就求个平均值。

我这里定义了一个6字大小的数组,uint32_t  AdcDataViaDMA [6];5个位置放实时ADC数据,第6个位置即AdcDataViaDMA [5]放换算后的最终Vrefint电压平均值,单位是mv

我们使用STM32CubeMx进行配置。重点看下ADC的配置:[注:ADC16]

a59acfe98fbabb6232a9f2830581c006.png

d9b02669aa7edf29004c4f8ce14cf664.png

生成初始化代码后,添加用户代码。我把数组AdcDataViaDMA【】指定在片内RAM2区域

__attribute__((section(".AdcDataViaDMA")))   uint32_t AdcDataViaDMA [6];

9903efebfdec9998cefd3a447927ea1a.png

eeae04a8345b042e232eeb638123683e.png

HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED );

HAL_ADC_Start_DMA(&hadc3,(uint32_t *)&AdcDataViaDMA [0], 5);

HAL_LPTIM_PWM_Start(&hlptim2, Period, Pulse);

然后编译调试。同样出现数据纹丝不动的现象。我每次在传输完成中断回调函数里做数据处理。相关处理代码如下图所示:

35e7fbe9b5c328126711dd42ab6e1119.png

TIMER不停触发ADCDMA传输也是循环的,按理数据应该动态改变。即使变化不大,也不至于纹丝不动。【除AdcDataViaDMA [5]外,其它均为AD转换值。】

f47ff3ac84cda40de6622abfbf3d8064.png

那是什么原因呢?目前我们是开启了Cache的。

258cb1a6a4dbd9c111c649bbb4a007b7.png

现在数据的大致流程就是,ADC转换结果出来后,DMA将数据写入SRAM,然后CPU读取SRAM里的数据。因为开启了D-Cache,当CPU针对SRAM做读操作时发生读Allocate,相应内存地址的数据被拷贝一份到Cache里。下次CPU再去相应SRAM地址去读取时,因D-Cache里已经有了一份有效数据,即发生Cache命中事件,CPU就直接从Cache读数据,而不读取SRAM了。

18b7633ae204454acdeea6990bbbaf97.png

所以,尽管后面时间里ADCTIMER不停触发而产生新数据并被DMA传输到SRAM,但CPU除了第一次外总是从D-Cache取数据,导致该数据永远就是第一次读到的数据而不变。

既然这样,我们可以在CPU每次针对SRAM做了读操作后,对D-Cache相应内容做无效处理,迫使CPU每次要取数据时因Cache Miss而发生读Allocate操作并更新Cache数据,进而保证CPU读到跟内存SRAM里一致的Cache数据。

我在DMA完成中断回调函数里加上一句针对D-Cache作无效操作的代码。如下图红线标注的代码。

291151f13674055d924065d7ed5ba009.png

然后进行测试,立即可以看到不断实时变化的数据了。【下图我随机截取的几个结果】

24858e5f59241e8714b7b7ea95d64dd1.png

不过,请注意这里针对D-Cache相应地址做了无效化处理的代码要放在最前面。你可以将该句试着放在对AdcDataViaDMA [5]0语句的后面验证下,看看会有什么现象,要看细致点,不然发现不了问题。顺便提醒,目前所用SRAM区域在没有做MPU配置的情况下,默认为write backwrite allocate Cache属性,我在前面贴图时已经圈出来了。有兴趣的话,可以基于上述代码自行进一步探究下,此处就不延伸了。

另外,除了上面的解决办法外,还有就是将上面内存数组所在区域做MPU设置,关闭那部分区域的Cacheable属性

901171898a10094513654a99d2c33a3f.png

当这样配置后,之前那句针对Cache无效化的代码就不需要了。生成代码进行测试,结果跟预期一致,数据保持实时动态变化,结果也正常。

上面主要就开启D-Cache后,发生了主设备数据读取不一致的问题给出了些解决办法及思路,同时也算是给出些应用提醒,以后碰到类似问题时可以参考。当然,有人或许会说,完全不开启芯片的D-Cache功能也可以解决问题。诚然,但我们需要综合考虑开发便利性和芯片的性能发挥,尽量就问题做些针对性的处理以充分发挥芯片性能。

*******************************

往期话题阅读链接:

1、STM32H7 BDMA应用示例

2、让CDC类USB设备批量接收64字节以上数据

3、CubeMx的初始配置顺序与DMA传输异常提醒

4、远程修改STM32 TIMER占空比的方案续1

5、既生瑜,何生亮?

bfbdb01ec011421c4b1f286e2edb6c8d.png

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值