In this guide, we shall see how to deal with the cache coherency of STM32H7 when dealing with the DMA.
In this guide, we shall cover the following:
- Project creation.
- DMA transfer without cache handling.
- DMA transfer with cache handling.
8. Project Creation:
First, start STM32CubeIDE and select your workspace.
Select your STM32H7 based MCU, in my case STM32H747XI.
Give a name to the project like cache or any other name.
From System Core, select Cortex_M7 and enable both D and I cache.
Next, from the DMA, add M2M (Memory to Memory) DMA as following:
Keep the setting as default.
Save the project and this will generate the code.
9. DMA Transfer without Cache Handling:
In CM7 (Applied only to dual core based) project, open main.c source file.
In user code begin PV, declare the following variables:
#define dataSize 10 uint8_t txData[dataSize]; uint8_t rxData[dataSize]; uint8_t counter;
The define state to indicate the data size, 10 in this case.
tx and rx data buffer of size 10 so the DMA can read/write to those array.
Counter to keep the data changes.
Within while loop, in user code begin 3:
Fill the tx buffer:
/*CPU writes to SRAM1*/ for (int i=0;i<dataSize;i++) { txData[i]=counter; }
Start the DMA:
/*Start DMA*/ HAL_DMA_Start(&hdma_memtomem_dma1_stream0, (uint32_t)txData, (uint32_t)rxData, dataSize);
wait a little bit before aborting the DMA:
/*Wait a little bit before aborting DMA*/ HAL_Delay(100);
Abort the DMA transfer:
/*Abort the DMA*/ HAL_DMA_Abort(&hdma_memtomem_dma1_stream0);
Increment the counter and delay by 100ms as following:
/*Increment the counter and delay*/ counter++; HAL_Delay(100);
Save the project and start debug session:
Add both tx and rx data to the live expression.
Run the project and notice the rxData, it doesn’t update as shown here:
Due to cache coherency issue, the DMA won’t be able to transfer the correct data.
10. DMA Transfer with Cache Handling:
In order to solve the coherency issue of the cache, we need to clean the data cache of ARM Cortex M7 before the data is read by the DMA and invalidate the cache after the DMA has written the data to the SRAM.
After the buffer is filled with the new data, clean the data cache by address as following:
/*Clean Dcache before the DMA reads from SRAM*/ SCB_CleanDCache_by_Addr((uint32_t*)txData, dataSize);
This will clean the cache related to txData in the cache.
In order to invalidate the cache, we need to do this after the DMA has been aborted as following:
/*Invalidate the DCache after the DMA writes to SRAM1*/ SCB_InvalidateDCache_by_Addr((uint32_t*)rxData, dataSize);
Hence the new while loop:
/*CPU writes to SRAM1*/ for (int i=0;i<dataSize;i++) { txData[i]=counter; } /*Clean Dcache before the DMA reads from SRAM*/ SCB_CleanDCache_by_Addr((uint32_t*)txData, dataSize); /*Start DMA*/ HAL_DMA_Start(&hdma_memtomem_dma1_stream0, (uint32_t)txData, (uint32_t)rxData, dataSize); /*Wait a little bit before aborting DMA*/ HAL_Delay(100); /*Abort the DMA*/ HAL_DMA_Abort(&hdma_memtomem_dma1_stream0); /*Invalidate the DCache after the DMA writes to SRAM1*/ SCB_InvalidateDCache_by_Addr((uint32_t*)rxData, dataSize); /*Increment the counter and delay*/ counter++; HAL_Delay(100);
Build and debug the project and run it, this time, the rxData is being updated using the DMA.
These steps are mandatory when dealing with DMA in ARM Cortex M7.
Clean the cache before the DMA reads the data.
Invalidate the cache after the DMA has written the data to the SRAM.
This is applicable to Memory to Peripheral and vice versa.
happy coding 😉
Add Comment