Skip to main content
Explorer
October 21, 2024
Solved

STM32F411 multi-channel DMA + software trigger, VREFINT VBAT two can not collect at the same time

  • October 21, 2024
  • 1 reply
  • 668 views

After using cubemx, I tested the single channel round-robin acquisition and there was no problem.
After changing to DMA acquisition, as long as VREFINT and VBAT exist at the same time, the data of the first channel is wrong. The following is the correct code:

uint16_t data[256]; 
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
}
int main{
...
...
while(1){
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)data, hadc1.Init.NbrOfConversion*2);
printf("adc: %d %d %d %d %d %d \n",data[0],data[1],data[2],data[3],data[4],data[5]);
HAL_Delay(1000);
}
}
static 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 */

/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}

/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_VREFINT;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}

/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
// sConfig.Channel = ADC_CHANNEL_VBAT;
// sConfig.Rank = 2;
// if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
// {
// Error_Handler();
// }

/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */

/* USER CODE END ADC1_Init 2 */

}
correct result:
adc:1497 378 1497 382 0 0
adc:1497 378 1498 382 0 0
adc:1497 377 1497 381 0 0
adc:1497 378 1498 382 0 0
adc:1497 378 1497 382 0 0

The following is the error code:

 

uint16_t data[256]; 
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
}
int main{
...
...
while(1){
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)data, hadc1.Init.NbrOfConversion*2);
printf("adc: %d %d %d %d %d %d \n",data[0],data[1],data[2],data[3],data[4],data[5]);
HAL_Delay(1000);
}
}
static 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 */

/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}

/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_VREFINT;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}

/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_VBAT;
sConfig.Rank = 2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}

/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
// sConfig.Channel = ADC_CHANNEL_0;
// sConfig.Rank = 2;
// if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
// {
// Error_Handler();
// }
/* USER CODE BEGIN ADC1_Init 2 */

/* USER CODE END ADC1_Init 2 */
}
error result:
adc: 10 919 10 920 0 0
adc: 10 920 10 919 0 0
adc: 11 919 10 920 0 0
adc: 10 919 10 919 0 0
adc: 11 919 10 919 0 0
adc: 11 919 9 919 0 0
adc: 11 920 10 919 0 0


The only difference above is whether Vbat and channel 0 are turned on or not. I have no idea why the number of the first channel is around 10. I tested it for a long time and finally found the smallest error code. Please help me check it. Thank you.

 

 

    This topic has been closed for replies.
    Best answer by waclawek.jan

    You cannot measure both VREFINT and VBAT in one go.

    Thing is, for some weird reason, VBAT and TEMP measuremets are connected to a single input ADC1_IN18 (*); and, for another weird reason, the switch which toggles between VBAT and TEMP (ADC_CCR.TSVREFE) also switches off VREFINT.

    (*) RM0383 mentions that TEMP is connected also to ADC1_IN16 but still, ADC_CCR.TSVREFE either allows VBAT or VREFINT measurement, not both.

    Btw. don't forget to switch off VBAT measurement after taking the measurement, to avoid discharging the battery.

    JW

    1 reply

    Super User
    October 21, 2024

    You cannot measure both VREFINT and VBAT in one go.

    Thing is, for some weird reason, VBAT and TEMP measuremets are connected to a single input ADC1_IN18 (*); and, for another weird reason, the switch which toggles between VBAT and TEMP (ADC_CCR.TSVREFE) also switches off VREFINT.

    (*) RM0383 mentions that TEMP is connected also to ADC1_IN16 but still, ADC_CCR.TSVREFE either allows VBAT or VREFINT measurement, not both.

    Btw. don't forget to switch off VBAT measurement after taking the measurement, to avoid discharging the battery.

    JW

    Explorer
    October 22, 2024

    thank you so much!