cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 ADCs with DMA when D-Cache enabled

TA1
Associate III

Dear all,

I am trying to configure ADC1, ADC2 (ADC1 and ADC2 in multimode) and ADC3 running simultaneously with DMA.

I have a running code for STM32F7 series and I assumed that I could use DMA in the same manner but DMA cannot store data taken from ADC1,2 and 3. DMA transfer complete interrupts occur for ADC1 and ADC3 and ADC12_Common and ADC3 Data registers change and there is no overrun error. So, ADCs work fine and DMA looks like working fine. However, the register where DMA supposed to write didn’t change. Therefore, I searched in the community and I found some articles. I realized that when D-cache is enabled, DMA cannot store data to the buffer even it is located to an address which is above 0x24000000. I thought that if DMA stores data to SRAM1, it may solve the problem because SRAM1 and DMA are on the same domain and luckily it worked with one problem.

Pieces of my code is as follows:

HAL_DMA_Start(&hdma_adc1,(uint32_t)&ADC12_COMMON->CDR ,(uint32_t)0x30000000, 6);      // Start DMA.

0693W00000Y9AOMQA3.png0x83F1 is the first ADC result at 0x30000000 and 0x30000001.

0x8354 is the second ADC result at 0x30000002 and 0x30000003 so on.

So, DMA works well when D-cache is enabled. Then I would like to define a variable at 0x30000000 as follows:

volatile uint32_t ADC12_Result[6] __attribute__((section(".ARM.__at_0x30000000")));

HAL_DMA_Start(&hdma_adc1,(uint32_t)&ADC12_COMMON->CDR ,(uint32_t)&ADC12_Result,6);      // Start DMA.

I supposed that it will work because ADC12_Result is located to 0x30000000. However, it didn't work. After that, I disabled D-cache and it worked well.

What is the difference between two different settings? Is there any very clear working examples that I can easily implement. There are some explanations in https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices

However, I am not expert about MPU and I didn't understand well. Cache maintenance functions may help me but I didn't understand how to implement for ADC.

ADC resolution is 16 bits and ADC_Common->DR contains ADC2 and ADC1 result after every conversation. There will be 6 conversations and we need 32 bits array with a size of 6.

Thank you very much for your contribution and help.

5 REPLIES 5
FBL
ST Employee

Hi @TA​ ,

Could you please be more specific about the product you are using? IOC file if possible would help.

To start the conversion process, you may use

 HAL_ADC_Start_DMA(&AdcHandle (uint32_t*)&uhADCxConvertedValue, 1)

instead of

HAL_DMA_Start(&hdma_adc1,(uint32_t)&ADC12_COMMON->CDR ,(uint32_t)0x30000000, 6);      // Start DMA.

It is important to note, in case of using an F7, that you are trying to access a reserved memory ! as mentioned in figure below which is not the case for an H7 for example, So you should try 0x200000C4 for example.0693W00000Y9DmCQAV.png 

You may refer to the example provided on F7 using DMA while enabling DCache.

Hope this helps

Firas

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.


I'm out of offce with limited access to my emails.
Happy New Year!
TA1
Associate III

Dear F.Belaid

Thank you very much for your quick reply. I will answer your question or comment on your message step by step as follows:

1- The MCU is STM32H742VGT revision V. I think you missunderstand me. MCU is not STM32F7 family member. I have a running code for STM32F7 and I assumed that I could set DMA in same way for STM32H7.

2- I can send .ioc file if it is really required. I may need to change few things that takes time. So, if it is really required, I will send later.

3- I don't want to use HAL_ADC_Start_DMA or HAL_ADCEx_MultiModeStart_DMA functions because they also enable overrun (if applicable), DMA half transfer and DMA transfer complete interrupts. I would like to enable only transfer complete interrupt. If I use HAL_ADCEx_MultiModeStart_DMA fuction, I need to write an extra code to disable two other interrupts. (I don't want to change .c file in the library.)

4- Since the MCU is STM32H742, 0x30000000 is not restricted and it is in SRAM1 area in D2.

5- Firstly I didn't specify RAM location and complier assigned it to 0x24002304. However, DMA cannot write to this address when D-cache is enabled.

I did some systematic tests to collect more information to inform you:

For all cases: ADC1 and ADC2 are in simultaneous regular mode, DMA2 Stream 0 is set to transfer 6 results from ADC_Common->DR

1st Try- D-Cache is enabled, ADC results will be stored between at 0x30000000-0x30000017. It worked well and DMA updated the memory correctly and continuously.

HAL_DMA_Start(&hdma_adc1,(uint32_t)&ADC12_COMMON->CDR ,(uint32_t)0x30000000,6);

2nd Try- D-Cache is enabled, ADC12_Result[6] array is defined and its memory space is specified at 0x30000000. DMA didn't update the array. DMA interrupts came every sampling period and ADC 1 and 2 converted channels however ADC12_Result[6] array didn't change.

volatile uint32_t ADC12_Result[6] __attribute__((section(".ARM.__at_0x30000000")));

HAL_DMA_Start(&hdma_adc1,(uint32_t)&ADC12_COMMON->CDR ,(uint32_t)&ADC12_Result,6);

3rd Try- D-Cache is disabled, ADC12_Result[6] array is defined but its memory space is not specified. However, it is at 0x24002304. It worked well and DMA updated the memory correctly and continuously.

volatile uint32_t ADC12_Result[6];

HAL_DMA_Start(&hdma_adc1,(uint32_t)&ADC12_COMMON->CDR ,(uint32_t)&ADC12_Result,6);

4th Try- D-Cache is enabled, ADC12_Result[6] array is defined and its memory space is specified at 0x30000000. However, ADC12_Result register address is not written in HAL_DMA_Start function.

volatile uint32_t ADC12_Result[6] __attribute__((section(".ARM.__at_0x30000000")));

HAL_DMA_Start(&hdma_adc1,(uint32_t)&ADC12_COMMON->CDR ,(uint32_t)0x30000000,6);

I realized from watch and memory window in debug mode that DMA updated memory location one time (or may be two times) and it didn't update any more. This configuration worked at 1st-Try with one difference. HAL_DMA_Start fuction and other settings are same but 4th-Try I also defined ADC12_Result[6] at 0x3000000.

I hope you can help more with above information.

Thanks in advance

Best Regards

FBL
ST Employee

Hello TA,

You can either disable the D-Cache cache or configure the DMA to write to a non-cached memory area. Both workarounds are correct.

Note that, cache is a small and fast memory that stores a copy of data from main memory. So, care must be taken to benefit when using this feature.

You can try a few different things to resolve this issue:

  1. Change the memory location used by the DMA to a non-cached memory area.
  2. Disable the D-Cache before starting the DMA transfer and re-enable it after the transfer is complete.
void SCB_CleanInvalidateDCache (void) 

For more details, you may refer to Level 1 cache on STM32F7 Series and STM32H7 Series

Hope this helps,

Firas

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.


I'm out of offce with limited access to my emails.
Happy New Year!
TA1
Associate III

Dear Firas

Thank you very much your answer. Before I reply to you I would like to make sure everything is fine. However I faced another problem about DMA reading. It may be my mistake or it may be hardware issue. Please read my post as follows: https://community.st.com/s/question/0D53W000026CLyhSAG/possible-dma-reading-problem-from-adcxcdr

By the way, meanwhile I disabled D-cache to complete first version of my code. When I disabled D-cache, DMA continously updates related register where ADC results are stored.

Best Regards