STM32
直播中

李慎梓

7年用户 1437经验值
私信 关注
[问答]

STM32 ADC+DMA多通道转换数据错位的原因?怎么解决?

开发环境IAR7.50.2,芯片302RCT6,不知道如何解决多通道数据转化错位问题
1、需求:adc规则组采样3个通道,对ADC数据每隔不定时间处理一次,在处理函数中读取数组ConvValue[3]​,即为ADC采样的值。

2、​HAL库配置:​

        ​扫描模式使能,连续转换模式使能,DMA连续转换请求使能

3、DMA2_CH1中断不使能(目的为了减少进出中断时间)​

4、while(1)函数进入前开启dma

        HAL_ADC_Start_DMA( hadc2,(uint32_t*)ADC2HARDWARE.ConvValue,3);

        ConvValue[3]数据类型uint16_t

5、正常情况:

        ConvValue[0]存放ADC_CH0

        ConvValue[1]存放ADC_CH1

        ConvValue[2]存放ADC_CH2

6、异常情况(非常少见)​

        ConvValue[0]存放ADC_CH2

        ​ConvValue[1]存放ADC_CH0

        ConvValue[2]存放ADC_CH1

        或者

        ConvValue[0]存放ADC_CH1

        ConvValue[1]存放ADC_CH2

        ConvValue[2]存放ADC_CH0


  • /* ADC2 init function */
  • static void MX_ADC2_Init(void)
  • {

  •   ADC_ChannelConfTypeDef sConfig;

  •     /**Common config
  •     */
  •   hadc2.Instance = ADC2;
  •   hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  •   hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  •   hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
  •   //hadc2.Init.ContinuousConvMode = DISABLE;
  •   hadc2.Init.ContinuousConvMode = ENABLE;
  •   hadc2.Init.DiscontinuousConvMode = DISABLE;
  •   hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  •   hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  •   hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  •   hadc2.Init.NbrOfConversion = 3;
  •   //hadc2.Init.DMAContinuousRequests = DISABLE;
  •   hadc2.Init.DMAContinuousRequests = ENABLE;
  •   hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  •   hadc2.Init.LowPowerAutoWait = DISABLE;
  •   hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  •   if (HAL_ADC_Init( hadc2) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }

  •     /**Configure Regular Channel
  •     */
  •   sConfig.Channel = ADC_CHANNEL_6;
  •   sConfig.Rank = 1;
  •   sConfig.SingleDiff = ADC_SINGLE_ENDED;
  •   sConfig.SamplingTime = ADC_SAMPLETIME_7CYCLES_5;
  •   sConfig.OffsetNumber = ADC_OFFSET_NONE;
  •   sConfig.Offset = 0;
  •   if (HAL_ADC_ConfigChannel( hadc2,  sConfig) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }

  •     /**Configure Regular Channel
  •     */
  •   sConfig.Channel = ADC_CHANNEL_8;
  •   sConfig.Rank = 2;
  •   if (HAL_ADC_ConfigChannel( hadc2,  sConfig) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }

  •     /**Configure Regular Channel
  •     */
  •   sConfig.Channel = ADC_CHANNEL_12;
  •   sConfig.Rank = 3;
  •   if (HAL_ADC_ConfigChannel( hadc2,  sConfig) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }

  • }



  •   else if(hadc->Instance==ADC2)
  •   {
  •   /* USER CODE BEGIN ADC2_MspInit 0 */

  •   /* USER CODE END ADC2_MspInit 0 */
  •     /* Peripheral clock enable */
  •     HAL_RCC_ADC12_CLK_ENABLED++;
  •     if(HAL_RCC_ADC12_CLK_ENABLED==1){
  •       __HAL_RCC_ADC12_CLK_ENABLE();
  •     }

  •     /**ADC2 GPIO Configuration
  •     PC0     ------> ADC2_IN6
  •     PC2     ------> ADC2_IN8
  •     PB2     ------> ADC2_IN12
  •     */
  •     GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2;
  •     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  •     GPIO_InitStruct.Pull = GPIO_NOPULL;
  •     HAL_GPIO_Init(GPIOC,  GPIO_InitStruct);

  •     GPIO_InitStruct.Pin = GPIO_PIN_2;
  •     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  •     GPIO_InitStruct.Pull = GPIO_NOPULL;
  •     HAL_GPIO_Init(GPIOB,  GPIO_InitStruct);

  •     /* Peripheral DMA init*/

  •     hdma_adc2.Instance = DMA2_Channel1;
  •     hdma_adc2.Init.Direction = DMA_PERIPH_TO_MEMORY;
  •     hdma_adc2.Init.PeriphInc = DMA_PINC_DISABLE;
  •     hdma_adc2.Init.MemInc = DMA_MINC_ENABLE;
  •     hdma_adc2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  •     hdma_adc2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
  •     //hdma_adc2.Init.Mode = DMA_NORMAL;
  •         hdma_adc2.Init.Mode = DMA_CIRCULAR;
  •     hdma_adc2.Init.Priority = DMA_PRIORITY_LOW;
  •     if (HAL_DMA_Init( hdma_adc2) != HAL_OK)
  •     {
  •       Error_Handler();
  •     }

  •     __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc2);

  •     /* Peripheral interrupt init */
  •     HAL_NVIC_SetPriority(ADC1_2_IRQn, 1, 0);
  •     HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
  •   /* USER CODE BEGIN ADC2_MspInit 1 */

  •   /* USER CODE END ADC2_MspInit 1 */
  •   }


回帖(2)

李亦然

2024-4-10 16:26:49
估计ADC转换时间太快了,DMA还没读取就覆盖了。。。 还有就是检查一下DMA的数据长度
举报

京五环以外

2024-4-10 17:42:45
可能导致多通道转换数据错位的原因有以下几种:
1. DMA缓冲区设置错误:确保DMA缓冲区的大小足够容纳所有通道的转换值,每个通道的转换值应该按照通道顺序依次存放。
2. ADC配置错误:检查ADC的通道顺序和对应的GPIO引脚配置是否正确匹配。
3. 代码执行顺序错误:确保在处理函数中读取数组ConvValue[3]之前,DMA传输已经完成。
4. 数据处理函数错误:确保在处理函数中正确处理不同通道的转换值的位置。

解决方法:
1. 确认DMA缓冲区的大小是否足够存放所有通道的转换值,以及各个通道的转换值在数组中的顺序是否正确。
2. 确保ADC通道配置与GPIO引脚配置正确匹配。
3. 在处理函数中,增加等待DMA传输完成的代码,例如使用HAL_DMA_PollForTransfer完成等待。
4. 确保处理函数中正确处理不同通道的转换值,可以通过打印调试信息或者使用断点来检查数据的正确性。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分