2018-05-09 11:02 PM
Hi ALL,
I develop an application based on STM32F04. There are 3 ADC channels and I used DMA to collect data from these 3 channels.
It can get correct data from ADC, but there is a problem.
If I call the HAL_ADC_Start_DMA before main loop to trigger DMA convert, the HAL_ADC_ConvCpltCallback does not get called. If I call HAL_ADC_Start_DMA in my main loop in every 1 second, the HAL_ADC_ConvCpltCallback takes age to be called (3-4 second later).
If I configure the ADC as continual and DMA as circular mode, then it is OK, I can see the HAL_ADC_ConvCpltCallback get called very often. But I really cannot use this mode for my application.
Many thanks
The ADC configure is:
static __IO uint16_t aADCxConvertedData[3*8];
//below code is used to collect data from 3 ADC channel, and take average of 8 to reduce the noise.
HAL_ADC_Start_DMA( &hadc, (uint32_t *)aADCxConvertedData, 3*8);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.LowPowerAutoWait = ENABLE;
hadc.Init.LowPowerAutoPowerOff = ENABLE;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_6;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
DMA configures as :
hdma_adc.Instance = DMA1_Channel1;
hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc.Init.Mode = DMA_NORMAL;
hdma_adc.Init.Priority = DMA_PRIORITY_LOW;
My interrupt handler is:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
if (__HAL_ADC_GET_FLAG(AdcHandle, ADC_FLAG_EOS))
{
//do read the ADC data here
}
}
The system clock is configured as blow: HSI14 should be used for ADC.
void SystemClock_Config(void)
{ RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_PeriphCLKInitTypeDef PeriphClkInit; /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI14|RCC_OSCILLATORTYPE_HSI48 |RCC_OSCILLATORTYPE_LSI; RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; RCC_OscInitStruct.HSI14State = RCC_HSI14_ON; RCC_OscInitStruct.HSI14CalibrationValue = 16; RCC_OscInitStruct.LSIState = RCC_LSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB|RCC_PERIPHCLK_USART1 |RCC_PERIPHCLK_RTC; PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1; PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);}