STM32 ADC+DMA多通道转换数据错位求助
开发环境IAR7.50.2,芯片302RCT6,不知道如何解决多通道数据转化错位问题1、需求:adc规则组采样3个通道,对ADC数据每隔不定时间处理一次,在处理函数中读取数组ConvValue,即为ADC采样的值。2、HAL库配置: 扫描模式使能,连续转换模式使能,DMA连续转换请求使能
3、DMA2_CH1中断不使能(目的为了减少进出中断时间)4、while(1)函数进入前开启dma HAL_ADC_Start_DMA(&hadc2,(uint32_t*)ADC2HARDWARE.ConvValue,3); ConvValue数据类型uint16_t5、正常情况: ConvValue存放ADC_CH0 ConvValue存放ADC_CH1 ConvValue存放ADC_CH2
6、异常情况(非常少见)
ConvValue存放ADC_CH2 ConvValue存放ADC_CH0 ConvValue存放ADC_CH1 或者
ConvValue存放ADC_CH1 ConvValue存放ADC_CH2 ConvValue存放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 */
}
软件、硬件都没问题,是脑子出了问题。 估计ADC转换时间太快了,DMA还没读取就覆盖了。。。 还有就是检查一下DMA的数据长度, caoenq 发表于 2020-10-29 08:39
软件、硬件都没问题,是脑子出了问题。
看问题还要付费的:D:D:D 初始化的顺序是啥?有没有其他地方调用了启动函数:D:D:D :D:D:D:D 数码小叶 发表于 2020-10-29 12:45
初始化的顺序是啥?有没有其他地方调用了启动函数
1、先初始化DMA,再初始化ADC2,这个是STM32CUBEMX提供的。
2、然后再发起校准,最后开启DMA
MX_DMA_Init();
MX_ADC2_Init();
HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);//ADC2校准
HAL_ADC_Start_DMA(&hadc2,(uint32_t*)ADC2HARDWARE.ConvValue,3); ts2000 发表于 2020-10-29 09:57
估计ADC转换时间太快了,DMA还没读取就覆盖了。。。 还有就是检查一下DMA的数据长度, ...
ADC转换周期ADC_SAMPLETIME_7CYCLES_5,3个通道都一样。
DMA转换的数据长度是3,类型是Uint_16,有可能是你说的这种转换过快,DMA还没读取就覆盖了,我把转换周期变长试下 小歆-2051663 发表于 2020-10-29 11:19
看问题还要付费的
也许是设置错误,准备支付金币解决问题,设置成收费了。 利用HAL_ADC_Start_DMA这个函数,它会自动强制使能OVR中断,错位的一种可能会是overrun,建议在主程序中,在回调函数HAL_ADC_ErrorCallback中,加个while(1)来调试是否overrun了,因为初始化overrun为ADC_OVR_DATA_OVERWRITTEN,即使出现overrun,adc还会转换,数据会变化;假如设成preserved,一旦overrun,会看到adc就停止转换,数据不变
页:
[1]
2