Cache in ARM Cortex M7: MPU Configuration

In this guide, we shall configure the MPU to disable cache for certain region in order to get DMA operate normally.

In this guide, we shall configure the following:

  • Creating the project.
  • Modification of linkerscript.
  • Results before MPU configuration.
  • MPU configuration.
  • Results after MPU configuration.

8. Creating the project:

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.

In user code begin PV (Private variable):

#define dataSize 10

uint8_t txData[dataSize]__attribute__ ((section (".Txbuffer")));
uint8_t rxData[dataSize]__attribute__ ((section (".Rxbuffer")));


uint8_t counter;

Declare a symbolic name to hold the data size which is 10 in this.

Tx and Rx data with attribute to push these variable to certain address.

counter to indicate changing the variable over time.

9. Linker Script Modification:

Open STM32H747XIHX_FLASH.ld file.

Add the following after the discard section:

.buffer (NOLOAD):
 {	
  . = ALIGN(1);
  . = ABSOLUTE(0x30000000);
   *(.Txbuffer)
  
  . = ABSOLUTE(0x30000040);
   *(.Rxbuffer)
  
  } > RAM_D2

This will put Tx buffer in address 0x30000000 and Rx buffer into address 0x30000040.

These will be in RAM_D2 region of STM32H747XI.

Save the project.

Build the project and you should see RAM_D2 has ben occupied by 74 Bytes as following:

We have successfully move a variable from RAM_D1 to RAM_D2.

In user code begin 3 while 1 loop:

	  /*CPU writes to SRAM1*/
	  for (int i=0;i<dataSize;i++)
	  {
		  txData[i]=counter;
	  }


	  /*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);

	  counter++;
	  HAL_Delay(100);

10. Results without MPU Configuration:

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:

As you can see, the TX data is updating but not the RX data. This means that we are facing cache coherency issue.

11. MPU Configuration:

Open your .ioc file and select Cortex M7 and enable the MPU as following:

The MPU shall be configured as following:

  • MPU Control Mode: Background Region Privileged accesses only + MPU disabled during hard faults.
  • MPU region to be enabled.
  • Region based address is 0x30000000 (RAM_D2 address).
  • MPU Region size: Since the size used by DMA is 74 bytes, the next available size is 128B.
  • TEX field to 0.
  • All access permitted.
  • Instruction access to enabled.
  • Sharable since both CPU and DMA will access to this region.
  • Disable the cache since it is the source of the problem.
  • Bufferable.

Save the project and this will generate the code.

12. Results with MPU:

Build and debug the project and run it, this time, the rxData is being updated using the DMA.

As you can see, the rx data is updating without the need to manually invalidate nor clean the cache every time.

Happy coding 🙂

Add Comment

Your email address will not be published. Required fields are marked *