1. 介绍
主控: STM32H743VIH6
软件:STM32CubeMX + STM32CubeIDE
由于此型号H7没有内置的HS USB PHY, 所以使用了外置芯片: USB3300
STM32H7的选型我是根据下帖进行选择的,需要注意的是 1. 不同封装对应的最高采样速率不同;
2. 不同通道所能达到的最高采样率也不同。
STM32H7中ADC功能被ST玩出花,现在分直接通道,快速通道和慢速通道,不同封装最高速不同, LQFP封装速度最低 - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!
根据数据手册 和 参考手册:
可以看出 此型号H7的14bit最高采样率为单通道4M, 同时高速通道为每个ADC的 channel0 ~ 5;
本来我是打算通过3 个ADC交替达到12M的, 但是ADC3仅有的高速通道还都被 USB的ULPI接口占用了,所以退而使用 2个ADC交替, 刚好 ADC1 和 ADC2 可以使用H7自带的 interleaved mode。
所以,接下来的实现方案为使用 STM32H7 自带的 交替采样模式来实现。
2. CubeMX配置
首先是M7 内核的配置, 这个我也不是很懂, 在我的试验中,就是一定要打开DCache, 无论是USB 还是 ADC, 如果不打开DChache,就会出现各种各样的问题。
时钟配置, 主频480M, ADC 72M, USB 48M:
ADC配置:
ADC1 和 ADC2 选择同一引脚, 我这里选择了PA6, 同时对应ADC1和ADC2 的 通道3
ADC1 配置为:
主要配置为:
Mode: Dual interleaved mode only, 这个是配置为双重交替采样
DMA Access Mode 启动 ,因为使用了 DMA
Delay between 2 sampling phases 是两次交替之间的延时,这个的选用可以看一下这篇文章:STM32G474 CubeMX + CLion双重ADC交替采样实现2M+2M = 4M_delay between 2 sampling phases-CSDN博客
但是我按照此文思路应该配置为 72M /8M = 9 cycle, 实际测出来却是3.5cycle分隔最正常,我猜这个的选用可能是按照 采样时间 + 转换时间 +Delay between 2 = 9 cycle 来计算(以我这个来看);但是从手册看, 光是采样+转换就用了9个周期了。。。
然后是 Clock prescaler 时钟预分配,这个是最抽象的, 从手册来看 ADC时钟最高是36M,但是我配置的72M时钟,在2分频得到的最高采样率只有4M, 反而在1分频下达到了理论上的最高8M,这点我到现在都很懵逼
其他就是常规配置, 我这边用的是连续转换和DMA 循环, 因为其他方法都发生了奇怪的问题,这个放最后说。
DMA配置如下:只需要开启ADC1的就可以了, ADC2在interleaved mode 下作为 从ADC 是跟随ADC1的
ADC2: 与 ADC1 保持一致
顺便提一下USB的配置, USB的配置非常简单,一点都不需要改动,只需要打开USB_OTG_HS
选择为Device, 再打开USB_Device选择为虚拟串口即可。
3. 代码
因为整体没什么功能,代码很简单, 基本就是启用ADC 和 USB 即可
USB: 包含头文件 "usbd_cdc_if.h", 就可以在 文件中使用CDC_Transmit_HS() 发送数据了, 接受到的数据可以到" usbd_cdc_if.c "里的 CDC_Receive_HS() 函数处理。
代码可以看看stm32Cubemx USB虚拟串口_stm32f407 usb虚拟串口 cubemx-CSDN博客
整体非常简单, 一个函数搞定。
ADC的启用: 前两段 ADCEx_Calibration 函数用来 校准ADC, 启动的时候, 需要先启动从ADC,再通过HAL_ADCEx_MultiModeStart_DMA() 来启动 主ADC。
HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_FACTOR_LINEARITY_REGOFFSET, ADC_SINGLE_ENDED);
HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_FACTOR_LINEARITY_REGOFFSET, ADC_SINGLE_ENDED);
HAL_ADC_Start(&hadc2);
HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t* )dmabuffer, data_len);
由于之前DMA配置的size是 word(32位, 将ADC1和ADC2 的两个 14bit数据,存到1个word里了), 所以在传输完成后,还需要加一步,将ADC1与ADC2的数据分离开。 在处理数据之前,需要使用SCB_InvalidateDCache_by_Addr() 这个函数的作用是把DChache中的现有数据无效化,保证我们读到的是重新加载的新数据。 这个貌似是H7系列带有DChache而特需的步骤。
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
SCB_InvalidateDCache_by_Addr((uint32_t *) dmabuffer, 2048);
for( i=0, j=0;j<data_len && i<data_len*2;i++)
{
adc_data=(dmabuffer[j] & 0x0000FFFF) ;
i++;
adc_data=((dmabuffer[j] >>16)) ;
j++;
}
CDC_Transmit_HS((uint8_t* )adc_data, 2048);
}
4. 试验结果
1. ADC为72M, 1分频, delay between 2 为 3.5 cycle
测试波形: 400k 正弦波
测试波形1M 正弦波:
2. ADC为72M, 1分频, delay between 2 为 9 cycle
测试波形 400K 正弦波
3. ADC为72M, 2分频, delay between 2 为 3.5 cycle
测试波形:400K 正弦波
从上面的试验来看, 配置为 ADC时钟72M 1分频, 2次采样间隔为3.5 cycle, 可以跑出比较好看的波形, 问题就是ADC时钟远超于手册给的最大时钟36M, 这点难以理解, 希望有大佬可以解解惑。
5. 其他
此外,还有一种方式为定时器作为触发源来触发ADC,相关文章:STM32H743/H723 三ADC交替触发采样,理论速度可达14MSPS+ - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!
我最开始采用的就是这个方法,设置定时器两个触发源为4M,上升沿触发,示波器测出如下:
但是在最终测试时, 波形在好与不好之间切换,以500K 正弦波测试,结果如图:
我已尽可能的减少ADC1和ADC2 的dma冲突,采取的DMA配置为 Normal, 即DMA采集完后停止,直到我代码重新启动ADC_DMA, 即便这样仍然是这样的现象; 给我的感觉像是 ADC1和ADC2的先后顺序时不时在改变,一直没有解决,最后换成使用H7自带的交替采样模式勉强跑起来。
这篇在ADC部分有很多的bug和没搞懂的东西,希望有懂的大佬能指点指点/(ㄒoㄒ)/~~
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/2404_88276917/article/details/143108040
|