cancel
Showing results for 
Search instead for 
Did you mean: 

Putting ADC data via DMA to upper 16 bit of 32 bit variable.

DRums.1
Associate II

Hi

I sample analog data with the STM32F401CE ADC. 12 bit resolution. This data is stored via DMA in an array.

If I use a 16 bit array, everythin works fine.

I now want to shift the whole data 16 bit to the left.

Therefore I switched to a 32 bit data array to store the data. Also I changed the Data width in the DMA settings from "Half Word" to "Word". This also works fine, now the data is stored in 32 bit values. But it is not shifted.

Therefore I try to pass the DMA init function the starting address shifted by 16 bit, so the data is always stored in the "upper" 16 bit of the 32 bit values. It looks like:

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)(((uint16_t*)adc_buf)+1), (uint32_t)FFT_LENGTH*2);

The "+1" however has no effect. Changing to "+2" has the expected effect, that the first value of the adc_buf remains zero.

Here come my questions:

  • how do I pass the starting address of the 32 bit write values to ensure writing to the upper value 16 bit of 32 bit values?
  • Is there another solution to my problem, like shifting the ADC value by <<16 during DMA writing?
  • Looping over the complete buffer after the data has beew written (and DMA IR has been triggered) and shifting every single value <<16 does not seem like a good solution as it takes too long - do you agree?

Thanks for your help,

BR Donald

PS: I added one value to the adc_buf length to not unintentionally overwrite some other data in the RAM.

2 REPLIES 2

> how do I pass the starting address of the 32 bit write values to ensure writing to the upper value 16 bit of 32 bit values?

You can't. The DMA does not support unaligned accesses.

> Is there another solution to my problem, like shifting the ADC value by <<16 during DMA writing?

Generally, no.

You can try to use PINCOS with halfword transfers, but that's certainly not something you just click in CubeMX.

https://community.st.com/s/question/0D53W00000Mg1Nb/helloi-have-been-working-with-a-stm32f4-where-i-use-two-channels-of-tim8-to-trigger-data-transfers-from-two-gpio-ports-to-memory-using-two-dma2-streams-i-would-like-to-have-these-dma-streams-write-16bit-data-interleaved-to-32bit-memory-addresses

As I wrote there, you'd need to turn around the direction, and I still don't know if PINCOS would not require word-aligned addresses, anyway.

In that same thread, a half-solution is proposed, with using a second DMA to rearrange the data.

> Looping over the complete buffer after the data has beew written (and DMA IR has been triggered)

I don't know what is "DMA IR". (Interrupt Routine? ISR is then the commonly used acronym, for Interrupt Service Routine.)

> shifting every single value <<16 does not seem like a good solution as it takes too long - do you agree?

Not necessarily.

At the end of the day, you'd need to process the data somehow anyway. You can add the shift to that processing; it may turn out it's not that expensive after all.

As you've already noticed, shift is not really necessary, it can be replaced by misaligned reads/writes. The processor is capable of that even if it's at the cost of extra memory/bus cycle, it's certainly faster than to read-shift-write back.

JW

DRums.1
Associate II

Thanks for the fast reply.

So I will stick to 16 bit data for the ADC buffer (called adc_buf below). Afterwards, I loop over the array once and copy the 16 bit values to the upper most 16 bit of a 32 bit array (called fft_input_buf below).

 for (uint16_t i = 0; i < FFT_LENGTH; ++i){

 *((int16_t*)fft_input_buf+1+2*i) = adc_buf[i];

 }

As I execute the code in the HAL_ADC_ConvHalfCpltCallback() and HAL_ADC_ConvCpltCallback(), I would like to set the priority of these interrupts to be quite low. Should I set the priority in the the DMA2 stream0 global IR priority in the NVIC? If so, what means the priority that can be set in the ADC DMA Settings (there I can choose "low" ... "very high").

Cheers,

Donald