2020-12-31 05:54 AM
Hello!
Configured 3 input channels to be checked by two ADCs in fast mode. First ADC request works perfectly, but all next request ADC2 data is not synchronized with ADC1. It seems, ADC2 stops incorrectly and continues to change the channels.
Here is an initialization:
#define ADC_CONV (3) // Activated ADC Ranks Number (hadc*.Init.NbrOfConversion)
#define ADC_LOOPS (1) // Number of ADC conversion loops. Should be even
#define ADC_BUFF_SZ (2*ADC_CONV*ADC_LOOPS) // Both ADCs are checking input channels
volatile static uint16_t adc_buff[ADC_BUFF_SZ];
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 3;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_DUALMODE_INTERLFAST;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
/**
* @brief ADC2 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC2_Init(void)
{
/* USER CODE BEGIN ADC2_Init 0 */
/* USER CODE END ADC2_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC2_Init 1 */
/* USER CODE END ADC2_Init 1 */
/** Common config
*/
hadc2.Instance = ADC2;
hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc2.Init.ContinuousConvMode = DISABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 3;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC2_Init 2 */
/* USER CODE END ADC2_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
Here is the DMA callback. The highlighted line is a break point:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if (hadc->Instance != ADC1) return;
HAL_ADC_Stop(&hadc2);
HAL_ADCEx_MultiModeStop_DMA(&hadc1);
volatile uint8_t ok = 1;
for (uint8_t l = 0; l < ADC_LOOPS; ++l) {
for (uint8_t i = 0; i < ADC_CONV; ++i) {
if (abs(adc_buff[2*i] - adc_buff[2*i+1]) > 5) {
ok = 0;
break;
}
}
}
}
Here is a main loop. Here you can see two commented out lines to re-initialize the both ADCs:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//MX_ADC1_Init();
//MX_ADC2_Init();
HAL_ADC_Start(&hadc2);
HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)adc_buff, ADC_CONV*ADC_LOOPS);
HAL_Delay(500);
}
First iteration at the break point shows the following values for adc_buff array:
37,38, 329,329, 646,649
But in the second iteration the values shuffled:
40,645, 327,38, 644,329
In the third iteration:
37,645, 328,39, 645,327
If the two lines MX_ADC1_Init(); & MX_ADC2_Init(); activated, the result become correct:
first iteration:
36,41, 331,329, 652,653
second iteration:
42,39, 338,339, 665,665
Perhaps, it is not good idea to initialize ADCs before each measurement? Does anybody know another way to get correct ADC readings?
2020-12-31 06:55 AM
Try dont call
HAL_ADC_Stop(&hadc2);
HAL_ADCEx_MultiModeStop_DMA(&hadc1);
when you dont start continuos , stop isnt necessary.
2020-12-31 02:39 PM
Now, both ADC initialized with continous mode disabled:
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
Callback now without stop code.
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if (hadc->Instance != ADC1) return;
// HAL_ADC_Stop(&hadc2);
// HAL_ADCEx_MultiModeStop_DMA(&hadc1);
volatile uint8_t ok = 1;
for (uint8_t l = 0; l < ADC_LOOPS; ++l) {
for (uint8_t i = 0; i < ADC_CONV; ++i) {
if (abs(adc_buff[2*i] - adc_buff[2*i+1]) > 5) {
ok = 0;
break;
}
}
}
}
And start code without ADC_init():
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// MX_ADC1_Init();
// MX_ADC2_Init();
HAL_ADC_Start(&hadc2);
HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)adc_buff, ADC_CONV*ADC_LOOPS);
HAL_Delay(500);
}
And the result is the same.
First iteration works correctly:
36,37, 313,316, 620,621
Second iteration. Perhaps, ADC2 started with channel 2, 3, and 3.
35,308, 311,613, 615,613
Third iteration:
616,616, 35,306, 305,601. ADC1 - 3,1,2; ADC2 - 3,2,3.
I think the HAL_ADCEx_MultiModeStop_DMA(&hadc1); should be in the callback.
2021-01-01 02:03 AM
In my F4 adc init have this lines try add to yourboth configs
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;