Skip to main content
Tim Goll
Associate II
April 25, 2022
Solved

STM32 ADC DMA problems

  • April 25, 2022
  • 11 replies
  • 11785 views

I hope someone can help me with my problem. In a recent post I talked about my problems getting DMA work with the ADC. This does work, sort of.

Now to my problem: The ADC is triggered by a timer update event. Then the data is transferred via DMA to a buffer. The problem is, that the values in the DMA buffer are random (?) values. I verified with an osilloscope that the timings of the measurements are correct:

0693W00000LyvckQAB.pngThe yellow line is toggled after the buffer is filled completely, the blue line is the signal to be measured. The sampling frequency (and the frequency of the timer) is 500kHZ, so well within the ADC spec (event the slow ones have a sample rate of 1MHz). The buffer has a size of 256, so the frequency of the yellow line fits this as well.

This is what the first 100 values in the ADC buffer actually look like:

0693W00000LyvdEQAR.png 

Looks like a sine wave with a really low sample rate, doesn't it? But if the 

HAL_ADC_ConvCpltCallback-interrupt is called at the right time, then this should be the first sine wave. So it makes no sense.

The DAC is working though, this is what a constant 3.2V looks like:

0693W00000LyvddQAB.png 

And this happens if I leave the input floating:

0693W00000LyvdnQAB.png 

I'm a bit lost at the moment. I tried so many different things in the last two days, but nothing worked. If someone has any idea, I'd highly appreciate it.

Some more info:

- the mcu: STM32H743ZI (on a nucleo board)

- cubeIDE 1.7.0 (1.9.0 completely breaks the ADC/DMA combo)

- the timer, dma and adc setup:

0693W00000Lyve2QAB.png0693W00000Lyve7QAB.png0693W00000LyveHQAR.png 

- I don't think my code is that relevant here, but here in this line is the setup of the DMA/ADC: https://github.com/TimGoll/masterthesis-lcr_driver/blob/main/Core/Code/Logic/AnaRP.c#L14 (the remaining adc/dma logic is in this file as well and here is the timer setup: https://github.com/TimGoll/masterthesis-lcr_driver/blob/main/Core/Code/Threads/AnalogIn.c#L10

- the autogenerated setup can be found in the main.c: https://github.com/TimGoll/masterthesis-lcr_driver/blob/main/Core/Src/main.c

---

I posted the same question on Reddit: https://www.reddit.com/r/embedded/comments/ubh04v/stm32_adc_dma_problems/

There a helpful commenter noticed that there is nothing in the auto-generated code that links the ADC to the DMA. Maybe the timings are completely off? However I'm not so sure about this because the interrupt timing is right.

-----

UPDATE [solved]:

 There was no bug at all. Thanks to everyone and their great ideas I learned today that a breakpoint does not stop DMA and interrupts. Therefore the data that the debugger got was a random mess from multiple cycles. Here is how it looks now:

0693W00000Lz1yrQAB.png

This topic has been closed for replies.
Best answer by TDK

Real data? Yes. Data from the same capture? No, not if the DMA is continuously refreshing data. Timers don't stop by default when the system is paused. Debugger accesses to read data on the chip are not particularly fast, especially in the context of your ~250us buffer update time. Again, very easy to confirm this by slowing down the frequency and observing.

(Seems you are aware, but your call to HAL_ADC_Start_DMA is fine.)

11 replies

Javier1
Principal
April 25, 2022

Try this out:

HAL_ADC_Start_DMA(hadc, (uint32_t *) dev->buffer[0], dev->size);

HAL_ADC_Start_DMA(&hadc, dev->buffer[0], dev->size);

play a bit with how youre passing the dev->buffer , use the debugger and make sure the ADC readings are stored where you wanted them and double check youre not just displaying random flash garbage(does that ADC plot change each time¿)

hit me up in https://www.linkedin.com/in/javiermuñoz/
Tim Goll
Tim GollAuthor
Associate II
April 25, 2022

I tried this already. But it doesn't matter because the function expects a 32bit int and then it is casted implicitly

Javier1
Principal
April 25, 2022

>But it doesn't matter

You do you

isnt dev->buffer[0] a double pointer¿

hit me up in https://www.linkedin.com/in/javiermuñoz/
TDK
April 25, 2022

As you said, the ADC is working, so this has to be a program logic error of some sort. If you use a DC signal, it works. So likely the buffer values that you're reading are from different captures.

> This is what the first 100 values in the ADC buffer actually look like:

How specifically are you reading these values? I don't see anything in your HAL_ADC_ConvCpltCallback call which shifts out data. Possibly I'm missing it somewhere in the threads.

Could also slow down the input frequency by orders of magnitude to confirm this.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Tim Goll
Tim GollAuthor
Associate II
April 25, 2022

I've set a breakpoint and then took a look at the buffer. This should show the real data, shouldn't it?

TDK
TDKBest answer
April 25, 2022

Real data? Yes. Data from the same capture? No, not if the DMA is continuously refreshing data. Timers don't stop by default when the system is paused. Debugger accesses to read data on the chip are not particularly fast, especially in the context of your ~250us buffer update time. Again, very easy to confirm this by slowing down the frequency and observing.

(Seems you are aware, but your call to HAL_ADC_Start_DMA is fine.)

"If you feel a post has answered your question, please click ""Accept as Solution""."
Piranha
Principal III
April 25, 2022

> the function expects a 32bit int

No, the function expects a pointer to uint32_t, but you are passing an uint16_t value (array element). And the GCC compiler warning tells it exactly - you just didn't read it!

HAL_ADC_Start_DMA(hadc, (uint32_t*)&dev->buffer[0], dev->size);

Spot the difference!

Tim Goll
Tim GollAuthor
Associate II
April 25, 2022

dev->buffer is two dimensional. So yours would return a double pointer which won't work. Also `&dev->buffer[0]` is the same as `dev->buffer`

Piranha
Principal III
April 26, 2022

Ahh, indeed it's 2-dimensional. But then the array element of the first dimension is also an array and adding & will not change anything. So in this case all of those versions are the same.

https://stackoverflow.com/questions/2528318/how-come-an-arrays-address-is-equal-to-its-value-in-c

The & operator by itself cannot create a double pointer. One has to create an intermediate pointer variable for storing the second level pointer.

https://stackoverflow.com/questions/30057128/why-isnt-it-possible-to-address-a-pointer-using-double-ampersand