Skip to main content
Associate
July 9, 2026
Question

ADC stuck at constant code for while ISR shows no error — looking for root cause hints

  • July 9, 2026
  • 4 replies
  • 61 views

Setup

  - MCU: STM32U595VITxQ (Cortex-M33)
  - ADC: ADC4, 57Mhz,12-bit, 7 channels, 6400 Hz sample rate, triggered by TIM1
  - Data path: GPDMA1 in linked-list circular mode, double-buffered with half/complete callbacks (128 samples per half-buffer). DMA writes directly into a static INT16U s_adc4_result[256][7] buffer in normal SRAM.
  - Signal chain: external current/voltage sensors → signal conditioning board (op-amps, anti-alias filter, DC bias) → ADC4 input pins
  - Firmware: FreeRTOS, half-callback copies 128 samples per channel into a ring buffer (PF_TOTAL_WAVE_NUM = 40 slots × 128 samples), pf_task consumes from queue

  Symptom

  Most of time, everything works fine. But some times something wrong happened,in a log file we captured, channels simultaneously read byte-identical constant values.

Questions:

  1. Has anyone seen an STM32U5 ADC report "healthy" (no OVR, no error, ADSTART set) while consistently delivering a constant code per channel? Are there silicon errata I should check?
  2. Are there known ADC4 / GPDMA1 quirks on STM32U595 (linked-list circular mode, TIM-triggered regular conversions) that could produce a "freeze the last good sample and keep DMA-cycling it" behavior?
  3. Could a VREF+/VDDA glitch cause the ADC to digitize a fixed code without setting any error flag? c
  4. Any other diagnostic register / signal I should capture next time it happens to definitively separate "ADC digitizing a clamped analog input" from "ADC/DMA digital block misbehaving"? I can add logging on the next firmware build.

 

 

4 replies

Ozone
Principal
July 9, 2026

> Most of time, everything works fine. But some times something wrong happened,in a log file we captured, channels simultaneously read byte-identical constant values.

This sounds like a race condition is involved.
Either another interrupt, or a task change in FreeRTOS.
The ADC is probably not the cause, I would look at the DMA, involved routines/handlers, and neighboring memory (map file).

You could try to set a write access breakpoint in the debugger, assuming a DMA access would not trigger it.
Or perhaps a stack overflow.

 

Edward_kAuthor
Associate
July 9, 2026

Thanks, i will check this situation carefully. But i think this is not the only case, some people meet this issue in other chips either.
 

 

Ozone
Principal
July 9, 2026

I have no specific experience with STM32U devices, but used ADC+DMA frequently on some F, C and L devices.

Another option would be that the DMA configuration gets corrupted at runtime, i.e. overwriting the ADCn.DR as source register. Although this seems not very likely.

Devices that have dual (or triple) modes have special configuration and result registers in the ADC register interface, perhaps this plays a role here.


On a loosely related note, a common “race condition” bug with RTOSes is stack allocation, at least in RTOSes that implement RT functionality in cyclically called sequential functions, not endless loops.
Pointers to local (stack) variables become invalid when once a cycle finishes.
If you access this pointer in subsequent cycles, you destroy other variables.

Edward_kAuthor
Associate
July 10, 2026

Thank you. I have already checked all the possibilities mentioned above and found no issues. Moreover, I am unable to reproduce this problem in the lab, but it does occur at the actual field site. I suspect it might be due to ESD (electrostatic discharge) interference. see this. 

 

Ozone
Principal
July 10, 2026

> I am unable to reproduce this problem in the lab, but it does occur at the actual field site. I suspect it might be due to ESD (electrostatic discharge) interference. see this. 

Possibly, but AFAIK such kind of behavior is normal and allowed for certain ESD tests, requiring a power cycle afterwards to get the device under test back to normal operation.

You could review the schematics and improve EMI protection of relevent inputs if this turns out to be the case.

Since there is no code shared, some general thoughts and ideas …

First, how many channels are affected, and is the error pattern consistent ?

Second, have you checked the time budget of your sampling chain ?
By that I mean, are the conversions definitely finished and transferred by DMA when the timer triggers the next sequence ?

For reproducing it in the lab, you could increase the load caused by other channels and tasks, especially those which involve interrupts and / or DMA.
Perhaps instrumenting the code to visualize events and tasks, create a (scope) trigger for the error event, and store/output relevant status information.

Philippe Cherbonnel
ST Employee
July 10, 2026

Hello,

As mentioned in users comments, root cause is uncertain: ADC ? DMA ? System IRQ overhead ?

To debug ADC activity:

Can place this code somewhere in your code, run periodically:

  if (LL_ADC_IsActiveFlag_EOS(ADC4) == 1UL)
  {
    LL_ADC_ClearFlag_EOS(ADC4);
    adc_eos_count++;
  }  
  //(or LL_ADC_IsActiveFlag_EOC(ADC4) but take care: EOC is read-clear, therefore access during debug will impact flag state)

  conv_data = LL_ADC_REG_ReadConversionData32(ADC4);

If flag EOS and conv_data are updated periodically, it means ADC is alive.

To debug DMA transfers:

Can you check periodically:

LL_ADC_IsActiveFlag_OVR(ADC4);

Try to disable DMA transfer:

LL_ADC_REG_SetDMATransfer(ADC4, LL_ADC_REG_DMA_TRANSFER_NONE_ADC4);

To debug system IRQ overhead:

Try to disable all ADC interrupts:

ADC4->IER = 0UL;

and DMA interrupts

  LL_DMA_DisableIT_TO(GPDMA1, LL_DMA_CHANNEL_1);
  LL_DMA_DisableIT_USE(GPDMA1, LL_DMA_CHANNEL_1);
  LL_DMA_DisableIT_ULE(GPDMA1, LL_DMA_CHANNEL_1);
  LL_DMA_DisableIT_DTE(GPDMA1, LL_DMA_CHANNEL_1);
  LL_DMA_DisableIT_HT(GPDMA1, LL_DMA_CHANNEL_1);
  LL_DMA_DisableIT_TC(GPDMA1, LL_DMA_CHANNEL_1);
 

waclawek.jan
Super User
July 10, 2026

> in a log file we captured, channels simultaneously read byte-identical constant values.

Infinitely?

And where is the adc_dr value from, in that log? Reading out ADC_DR by processor, while it’s being handled by DMA, is a bad idea.

JW