简体   繁体   中英

L1-cache behaviour of STM32H7

I'm playing with the L1-cache of STM32H753.

What I am trying to do is to provoke -on purpose- an inconsistency between the cache and the RAM as follows:

  • set up the SRAM region as write-through cacheable
  • enable the data cache
  • write something to a variable in RAM -> data will be written to both cache and RAM
  • disable the cache without invalidating it
  • write something else to the same variable -> only the RAM will be modified, not the cache
  • enable back the cache, again without invalidating it
  • read the RAM -> I expect to read the old value and not the new one, because at this point there should be a hit in the cache as the cache line should still be valid and it should still contain the old value?

Here is the code:

volatile uint32_t someDummyVariable ;
int main(void)
{
    MPU_Region_InitTypeDef MPU_InitStruct;

    HAL_Init();

    /* Configure the MPU attributes as Write-through for SRAM */
    HAL_MPU_Disable();
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress = 0x20000000;
    MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;    // -> means write through ?
    MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number = MPU_REGION_NUMBER0;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /* Configure the MPU attributes as WT for the Flash */
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress = 0x08000000;
    MPU_InitStruct.Size = MPU_REGION_SIZE_16MB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
    MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number = MPU_REGION_NUMBER1;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;  
    HAL_MPU_ConfigRegion(&MPU_InitStruct);  

    HAL_MPU_Enable(MPU_HARDFAULT_NMI);


    SCB_EnableDCache();

    // write something in a variable in RAM -> thanks to write-through attribute 
    // it will be copied to real RAM, not only to the cache
    someDummyVariable = 0x12345678;

    // disable cache without invalidating it
    SCB->CSSELR = 0U;                       /* select Level 1 data cache */
    __DSB();
    SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk;  /* disable D-Cache */
    __DSB();
    __ISB();

    // write something else to RAM -> will NOT be written to cache
    someDummyVariable = 0xAAAAAAAA;

    // enable cache again (without invalidating or cleaning it)
    __DSB();
    SCB->CCR |=  (uint32_t)SCB_CCR_DC_Msk;  /* enable D-Cache */
    __DSB();
    __ISB();

    // now we should read the old value that is still in the cache
    if ( someDummyVariable != 0x12345678 )
    {
        __NOP();
    }

Compiled with Keil 5, -O0. The variable write is done through a STR (I mean: no weird CPU optimisation, as far as I understood).

I checked the MPU registers values, the address of the RAM variable (indeed inside the MPU region).

Is there something wrong in the algorithm and/or in the code ?

EDIT: fixed the MPU config

You're trying to enable/disable the cache for the DTCMRAM, which starts at address 0x200000000. However, the DTCMRAM is tightly coupled memory. It is directly connected to the Cortex-M7 core and is not behind the cache. You can see this in Figure 1. (System architecture) of the ( Reference Manual ). Consequently, cache operations do not have effect on this memory.

If you want to do this test, you would have to use another memory region, for example the AXI SRAM (starting at address 0x24000000). This can be done by modifying your linker script (and possibly the startup code), or by directly writing to a fixed memory address using a pointer variable.

Note that another possibility to create a mismatch between RAM and cache, without disabling the cache, is by using a DMA controller to access the same memory as the MCU. The DMA controllers do not use the cache, so if a DMA controller writes to the memory that is already in cache, your application would read the old cached version instead of the newly written data. Your test would then be something like this:

  • Software writes a value to AXI SRAM. It is now in cache.
  • DMA action writes data to the same address. This is not "seen" by the core.
  • Normally you would have to perform a cache invalidate operation before reading the data now. For your test you would not do this.
  • Now read the variable from AXI SRAM. If cache is enabled you will probably get the old value (the value that was written by the software, not by the DMA).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM