Skip to main content
TBuls
Associate II
March 5, 2023
Solved

STM32G0: Stoppping/Starting ADC with DMA for re-calibration

  • March 5, 2023
  • 1 reply
  • 2527 views

To avoid the best accuracy when using the ADC it is advised to re-calibrate the ADC when environment temperature changes "too much"

The ADC calibration can only be done when the ADC is disabled, so to re-calibrate the ADC has to be stopped, disabled, calibrated, then enabled and started again.

I'm using the ADC with DMA in circular buffer mode, using only the LL API.

I can see however that stopping and then starting the ADC this way results is strange intermittent inaccuracies in the ADC values read (offsets). This happens also when i'm not re-calibrating, so its not that im reading the calibration factor or something like that.

What is the advised way of stopping and then restarting the ADC when using DMA/circular mode?

This topic has been closed for replies.
Best answer by Piranha
  1. Disable the DMA.
  2. Disable the ADC.
  3. Do the ADC calibration.
  4. Enable the ADC.
  5. Reinitialize the NDTR and enable the DMA.

1 reply

Piranha
PiranhaBest answer
Principal III
March 11, 2023
  1. Disable the DMA.
  2. Disable the ADC.
  3. Do the ADC calibration.
  4. Enable the ADC.
  5. Reinitialize the NDTR and enable the DMA.
TBuls
TBulsAuthor
Associate II
March 12, 2023

Piranha,

Thanks for your response, it triggered me to check and check again my sequence because it was actually pretty much the same as you propose, except for the fact that i disabled the ADC before disabling the DMA. (Im assuming with stopping DMA you mean disabling it?).

That however doesn't seem to make much difference because...

It seems to be working now .... but i don't for the life of me know what was wrong before.

In any case, thanx for your support, maybe if i find time i will backtrace what i did wrong...

For whomever this may be of interest, the i code i have now is pretty much this (warning LL code ahead):

// Disable DMA
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
while (LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1))
 ;
 
// Stop ADC
if (LL_ADC_REG_IsConversionOngoing(ADC1) && !LL_ADC_REG_IsStopConversionOngoing(ADC1)) {
 LL_ADC_REG_StopConversion(ADC1);
}
while (LL_ADC_REG_IsStopConversionOngoing(ADC1))
 ;
 
// Disable ADC
if (LL_ADC_IsEnabled(ADC1) && !LL_ADC_IsDisableOngoing(ADC1)) {
 LL_ADC_Disable(ADC1);
}
while (LL_ADC_IsEnabled(ADC1))
 ;
LL_ADC_REG_SetDMATransfer(ADC1, LL_ADC_REG_DMA_TRANSFER_NONE);
 
// Calibrate
LL_ADC_StartCalibration(ADC1);
while (LL_ADC_IsCalibrationOnGoing(ADC1) or (!LL_ADC_IsActiveFlag_EOCAL(ADC1)))
 ;
 
DelayMs(2);
 
// Enable ADC
LL_ADC_REG_SetDMATransfer(ADC1, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
 
if (!LL_ADC_IsEnabled(ADC1)) {
 LL_ADC_ClearFlag_ADRDY(ADC1);
 LL_ADC_Enable(ADC1);
}
while ((!LL_ADC_IsEnabled(ADC1)) or (!LL_ADC_IsActiveFlag_ADRDY(ADC1)))
 ;
 
// Start the ADC
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_1, LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA), reinterpret_cast<uint32_t>(m_channels), LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, ADC_CHANNEL_COUNT);
 
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
while (!LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1))
 ;
 
LL_ADC_REG_StartConversion(ADC1);