ADC with DMA and external Trigger on a STM32G431
Hi guys,
I want to use the ADC with DMA and external trigger. Sounds easy, and its working, but not to 100%.
The ADC should measure 2 channels, Channel 3 and Vrefint. Every measurement should be repeated 50 times, that I get 100 values. The external trigger is on PA11, internal PullUp and a falling edge should be detected. I'm using an mixture of HAL functions and direct register access.
Here is the code for the intialization of the ADC:
HAL_StatusTypeDef adc_custom_init(void)
{
/* configure ADC1 */
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.GainCompensation = 0;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_EXT_IT11;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_FALLING;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = ENABLE;
hadc1.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_256;
hadc1.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_8;
hadc1.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
hadc1.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.NbrOfConversion = 2;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
if(HAL_ADC_Init(&hadc1) != HAL_OK)
return HAL_ERROR;
/* Configure the ADC multi-mode */
multimode.Mode = ADC_MODE_INDEPENDENT;
if(HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
return HAL_ERROR;
/* Configure Regular Channel */
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
/* Rank 1 = Channel 4, Rank 2 = Vrefint */
if(HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
return HAL_ERROR;
/* vrefint */
sConfig.Channel = ADC_CHANNEL_VREFINT;
sConfig.Rank = ADC_REGULAR_RANK_2;
if(HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
return HAL_ERROR;
return HAL_OK;
}To start the ADC with DMA I use the following function:
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_results, 100);After firing the external trigger the Transfer Complete Interrupt of the DNA is executed. So far so good. I also get 100 values (value[0] = channel 4, value[1] = vrefint, value[2] = channel 4, ...).
But when I fire the external trigger again, nothing is happening.
What I already tried?
After the Transfer Complete interrupt is set, I clear the pending interrupt and set a flag. I'm checking this flag in the main-loop.
In the main-loop (when the flag is set) I'm clearing the pending exti flag:
EXTI->PR1 |= EXTI_PR1_PIF11; // clear exti flag(For testing I enabled the exti interrupt, and the interrupt is always executed, when I fire the trigger).
Which Bits and Flags in the ADC and DMA registers do I have to set, that I can fire both again?
I compared the ADC and DMA registers, once before I fired the trigger, and one after one successful run.
In the ADC registers are only two register different: ISR and CR (and of course DR).
In the ISR register the EOS bit and the EOSMP bit are set.
In the CR register only the ADSTART bit has changed to 0.
I tried to set the ADSTART bit. The bit is set, but its not working. When I try to clear the EOS and EOSMP bits (by writing 1 to it) the ADRDY bit in the ISR register is cleared (I dont know why?) and its not working. Why is the ADRDY bit cleared?
In the DMA registers only the CNDTR3 (number of data items to transfer) is set to 0, other registers did not change (yeah, the TC interrupt flag is set, but I clear it in the interrupt routine).
So I set the CNDTR3 to 100. But nothing is happening.
My complete "restart" routine:
if(restart_adc == 1)
{
restart_adc = 0;
EXTI->PR1 |= EXTI_PR1_PIF11; // clear exti flag
ADC1->CR |= ADC_CR_ADSTART;
DMA1_Channel3->CNDTR = 100;
}Does anyone here have an idea where my mistake is?
Thank you.