2026-05-08 1:01 AM
I've been struggling with a strange ADC problem for a while, and have now made some interesting observations.
The scenario
I'm using an STM32G474, where HRTIM directly controls a peltier driver for temperature regulation. Temperatures are measured by ADC4 (12 bit resolution), running in DMA circular mode, triggered by TIM7, at 1 kHz. This works. Temperatures are coming in, and are being used for PID regulation.
The problem
Quite often – perhaps always – some of the temperature readings are being disturbed, but only at certain temperatures. At first, I thought that it was random noise, but in a graph the noise looks strange. Not random at all.
After monitoring the raw ADC values that the DMA has thrown into memory, I discovered something that might be a clue – or it might just be a source of confusion. Every time a noisy sequence occurs, the ADC readout jumps to a lower nearby value where the five least significant bits are all 1, i.e. xxxx xxx1 1111. This is not random noise. It is if as the values are rounded down to nearest 0x001F.
A single spurious readout once in a while can be handled. But when this occurs, it happens so much that the PID regulation is disturbed.
The disturbances are visible in this chart. The orange trace are raw ADC samples, copied directly from the array that the DMA dumps the ADC values in. ADC values are on the right hand axis (decimal). The blue trace is the converted temperature readout, which is where I first noticed the problem.
The disturbing ADC values in this example are 0x073F, 0x07BF, 0x083F and 0x08BF. All ending with the 11111 bit pattern, and exactly 128 ADC counts apart. I have also run tests where the spacing was 64 counts. This also tells me that this isn't random noise.
Some zoomed-in examples:
Apparently, it doesn't matter if the temperature is slowly moving up or down:
During other tests, I have observed this behaviour at other values – but always with the xxxx xxx1 1111 pattern in the ADC value. I have watched the sampled values in RAM, by using STM32Programmer through the SWD interface. This is where I first spotted the recurring bit pattern.
I've checked my code (obviously), to see that the ADC value array isn't overwritten before is is handled in the interrupt function. The only thing that overwrites this array is the DMA channel.
What does the errata sheet say about this? The only section I've found that might be relevant, is this one:
I'm using all five ADCs for different purposes, all using the same clock source, with prescalers set to 1. Perhaps ADC4 is being disturbed by one of the other ADCs. If this is the case, I may be able to make a work-around.
But again, these aren't random disturbances. They only happen in certain windows, hitting very specific values.
I am unsure about what to show you, regarding setup and code. There is a lot of code in this project. But here is how ADC4 is setup in CubeMX:
Sampling time and offset is the same for all channels.
The function that initialises DMA, and starts ADC4:
void adcInitADC4(void)
{
ADC4Handle->Instance->CR = ADC_CR_ADVREGEN; // ADC disable
ADC4Handle->Instance->CR |= ADC_CR_ADCAL; // Start calibration
ADC4DMAHandle->Instance->CCR &=~ DMA_CCR_EN; // DMA channel off
ADC4DMAHandle->Instance->CCR |= DMA_CCR_TCIE; // Turn on DMA interrupt
ADC4DMAHandle->Instance->CNDTR = 10; // Ten transfers to memory
ADC4DMAHandle->Instance->CPAR = (uint32_t)&ADC4->DR; // Set peripheral address (ADC data register)
ADC4DMAHandle->Instance->CMAR = (uint32_t)&ADC4Buffer[0]; // Set memory address
ADC4DMAHandle->Instance->CCR |= DMA_CCR_EN; // Enable DMA
while (ADC4Handle->Instance->CR & ADC_CR_ADCAL) __asm("NOP");
ADC4Handle->Instance->CFGR |= ADC_CFGR_DMAEN; // DMA transfer enable
ADC4Handle->Instance->ISR = ADC_ISR_ADRDY; // Clear ADC ready Flag
ADC4Handle->Instance->CR |= ADC_CR_ADEN; // Enable ADC
while (!(ADC4Handle->Instance->ISR & ADC_ISR_ADRDY)); // Wait for ADC ready
ADC4Handle->Instance->CR |= ADC_CR_ADSTART; // Start ADC
TIM7->CR1 |= TIM_CR1_CEN;
}Can anyone help shed some light on this weirdness?
Solved! Go to Solution.
2026-05-09 10:26 AM
Correct. But 340 MHz / 6 is 56.6667 MHz.
However, you are pointing out something I hadn't noticed before:
When using more than one ADC, 56.6667 MHz is too fast. And I am using all five, all single ended. Thanks @Mikk Leini
Yeeh, the errata sheet is full of ADC stuff. And lots more. If one reads the entire errata sheet before attempting to use the microcontroller, one would seriously doubt that it will even power up.
Now I'll slow down the ADC clock a bit, and see if the issue changes.
2026-05-09 12:36 PM
Changing the ADC clocks to synchronous divided by 4 didn't solve the problem, but the timing of the issue definitely changed. Also, the problem persists even when the TEC drivers are off (meaning that all potentially noisy stuff is off).
So I am more and more inclined to believe that the problem is caused by ADCs disturbing other ADCs. I'm not quite sure what I can do about it, as some of these ADCs are quite busy. But to begin with, I guess I can disable one at a time, and see if it makes a difference.
2026-05-09 3:07 PM
My Goodness – it just dawned on me. I am starting two different ADCs with the same timer event. That is probably pretty unclever, given that they are prone to disturb each other.
I think I'll come up with a scheme where the different ADCs are started in a sequence where they don't overlap. This should be doable.
Thanks for all your assistance gentlemen (and, possibly, ladies). I'll let you know once I have a breakthrough.
2026-05-10 7:35 AM
Indeed, the problem was caused by ADCs disturbing each other. And in a particularly nasty way, as the disturbances manifested as SAR bit-decision errors. That is why the patterns were so distinct.
To overcome this, I have completely changed the way the ADCs are triggered. In my main timer interrupt, I've made a sequence, so ADCs 1, 2, 4 and 5, are triggered at specific times, where they never collide.
I couldn't do this with ADC3, as it runs at a much higher sampling frequency. But I moved it to be triggered by update events from a different timer, which runs at a slightly odd frequency, not in sync with the main timer interrupt. In addition, I've set that timer to dither, so the exact sampling time wobbles. I believe this should randomise disturbances even further.
The result is this, which is a stark contrast to the first graph I uploaded:
Thanks to all of you for your assistance! Should any of you find yourselves in Jutland some day, beer is on me!
2026-05-10 12:18 PM
I'm glad you found the solution and share it, so other people (and AI bots) can solve their issues also.
2026-05-11 1:20 AM
@EThom.3 great you found it share the solution!
Also kudos for the really good documentation of the problem.
But I'd like to understand this a little better - what's the theory for that noise source?
Looking at the G4 ref manual (I only ever played with G431, and only used 1 ADC), it seems that the hardware the ADCs share are the power supply, the VREF pin, and the input muxes. Which is already a lot... but my guess would have been it's good enough for 12 bit resolution.
Is this the cause of noise, that the simultaneously timed ADCs draw the most current / power at the same time, probably mostly influencing each other's sample & hold stage ?
Could this be reduced with using better input driving, or at least some bigger input caps ?
2026-05-11 1:26 AM
Errata sheet of G431:
Interesting, never heard of "bulb sampling".
2026-05-11 2:45 AM - edited 2026-05-11 2:57 AM
@LCE wrote:@EThom.3 great you found it share the solution!
Also kudos for the really good documentation of the problem.
But I'd like to understand this a little better - what's the theory for that noise source?
Looking at the G4 ref manual (I only ever played with G431, and only used 1 ADC), it seems that the hardware the ADCs share are the power supply, the VREF pin, and the input muxes. Which is already a lot... but my guess would have been it's good enough for 12 bit resolution.
Is this the cause of noise, that the simultaneously timed ADCs draw the most current / power at the same time, probably mostly influencing each other's sample & hold stage ?
Could this be reduced with using better input driving, or at least some bigger input caps ?
Good question. The errata sheet dosn't say why it happens, but in my opinion they downplay the problem.
"(...) the worst case (a few LSBs) being when all the ADCs on the device operate synchronously."
A few LSBs??? No, rather big-time SAR bit-decision errors! However, it is possible that the decoupling on my prototypes isn't good enough. On the new version, which I'm about to order, I have improved this greatly.
In fact, when I get the new boards, I think I'll first install an older version of the firmware, to see if the layout made a difference, and then I'll post my findings here.
Edit to add: I actually hope that my main issue is caused by insufficient decoupling, because that will make the ADCs so much easier to use on properly designed boards.
2026-05-11 2:54 AM
@LCE wrote:Errata sheet of G431:
Interesting, never heard of "bulb sampling".
I hadn't either, until I began to use these micrcontrollers. I haven't tried using that mode, as it isn't relevant for my application.
Also, "BULB" seems to be an ST term. I haven't been able to find it anywhere else in relation to ADCs, but the term may originate from photography, as the "bulb" can be used to keep the shutter open: