在之前的ST测评活动中,体验过使用DMA的方式采集ADC1的通道数据,今天分享一下在STM32U3系列中,使用该方式的采集。
一:STM32u385的ADC基础知识
STM32U385xx设备内嵌多达2个ADC,即ADC1和ADC2。这两个ADC紧密耦合,并可工作在双模式(ADC1为主)。每个ADC模块由一个12位逐次逼近式模数转换器组成。每个ADC最多支持19个多路复用通道。各个通道的A/D转换可以以单通道、连续、扫描或非连续模式进行。ADC的结果被存储在左对齐或右对齐(默认配置)的32位数据寄存器中。
ADC被映射到AHB总线上,以实现快速数据处理。
模拟看门狗功能允许应用程序检测输入电压是否超出用户定义的高或低值。
内置硬件过采样器可以在卸载相关计算负担的同时提高模拟性能。
内部电压参考(VREFINT)
VREFINT为ADC和比较器提供稳定的(带隙)电压输出。VREFINT与ADC1和ADC2的输入通道内部相连
VREFINT的确切电压由意法半导体在生产测试期间为每个部件单独测量,并存储在系统内存区域中。它处于只读模式,可供访问。
二:STM32 GPDMA的基础知识
通用直接内存访问控制器(GPDMA)
通用直接内存访问(GPDMA)控制器是一个总线主设备和系统外围设备。
GPDMA用于在卸载的CPU的控制下,通过链接列表在内存映射的外设和/或存储器之间执行可编程的数据传输。
这个起到的作用和ST产品中的DMA功能类似。具体的还没有研究清楚。
三:STM32 cube MX 软件配置
3.1 这里我使用的引脚是PA0,ADC1通道中的IN3
3.2 GPDMA的配置过程:
这里配置的时候需要注意下,字节的宽度,DMA的通道,使能DMA等等。
四:软件编写过程:
4.1 基本思路:
首先开启PA口时钟和ADC1时钟,设置PA0为模拟输入模式,否则AD不能正常读数
程序开启之前复位ADC1,同时设置ADC1分频因子和ADC的位数等相关信息。
初始化ADC1参数,配置规则通道参数:
开启软件转换:软件自校准,DMA开启转换,然后打开定时器2计时功能。
等待转换完成,读取ADC值
4.2 ADC初始化:
- void MX_ADC1_Init(void)
- {
- /* USER CODE BEGIN ADC1_Init 0 */
- /* USER CODE END ADC1_Init 0 */
- ADC_ChannelConfTypeDef sConfig = {0};
- /* USER CODE BEGIN ADC1_Init 1 */
- /* USER CODE END ADC1_Init 1 */
- /** Common config
- */
- hadc1.Instance = ADC1;
- hadc1.Init.Resolution = ADC_RESOLUTION_12B;
- hadc1.Init.GainCompensation = 0;
- hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
- hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
- hadc1.Init.LowPowerAutoWait = DISABLE;
- hadc1.Init.ContinuousConvMode = DISABLE;
- hadc1.Init.NbrOfConversion = 1;
- hadc1.Init.DiscontinuousConvMode = DISABLE;
- hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T2_TRGO;
- hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
- hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
- hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
- hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
- hadc1.Init.OversamplingMode = DISABLE;
- if (HAL_ADC_Init(&hadc1) != HAL_OK)
- {
- Error_Handler();
- }
- /** Configure Regular Channel
- */
- sConfig.Channel = ADC_CHANNEL_3;
- sConfig.Rank = ADC_REGULAR_RANK_1;
- sConfig.SamplingTime = ADC_SAMPLETIME_246CYCLES_5;
- sConfig.OffsetNumber = ADC_OFFSET_NONE;
- sConfig.Offset = 0;
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN ADC1_Init 2 */
- /* USER CODE END ADC1_Init 2 */
- }
主函数中,开启ADC校准,使能DMA如下:
- if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK)
- {
- /* Calibration Error */
- Error_Handler();
- }
- /* Start ADC group regular conversion */
- if (HAL_ADC_Start_DMA(&hadc1,
- (uint32_t *)uhADCxConvertedData,
- ADC_CONVERTED_DATA_BUFFER_SIZE
- ) != HAL_OK)
- {
- /* Error: ADC conversion start could not be performed */
- Error_Handler();
- }
- if (HAL_TIM_Base_Start(&htim2) != HAL_OK)
- {
- /* Starting Error */
- Error_Handler();
- }
实物验证如下所示:
转动电位器可以看到采集的adc 数据的变化:
可以看到ADC采集的数据很稳定,个人感觉可以直接用到工业控制中的数据采集。
在调试中遇到的问题和解决的办法:
由于自己调试过ST的 使用DMA采集ADC的功能,发现U385系列在使用该方式时候还是与其他芯片有些区别的,首先就是DMA的配置,需要一些具体的配置,字节长度和模式,开始配置字节长度出现问题,导致采集的ADC的数据不会超过255(FF),翻看手册也是12位ADC,搞了半天也不清楚是哪里的问题,后来打开的ST提供的库函数,才发现是字节长度的问题。看来,从事嵌入式的工作,某个配置的错误,会让自己怀疑人生的。
|