C STM32H7的一级缓存行为

C STM32H7的一级缓存行为,c,caching,stm32,C,Caching,Stm32,我在玩STM32H753的一级缓存 我试图做的是故意挑起缓存和RAM之间的不一致,如下所示: 将SRAM区域设置为可直写缓存 启用数据缓存 向RAM中的变量写入内容->数据将同时写入缓存和RAM 禁用缓存而不使其无效 将其他内容写入同一变量->只修改RAM,而不修改缓存 再次启用缓存,但不使其无效 读取RAM->我希望读取旧值而不是新值,因为此时缓存中应该有命中,因为缓存线应该仍然有效,并且应该仍然包含旧值 代码如下: volatile uint32_t someDummyVariable

我在玩STM32H753的一级缓存

我试图做的是故意挑起缓存和RAM之间的不一致,如下所示:

  • 将SRAM区域设置为可直写缓存
  • 启用数据缓存
  • 向RAM中的变量写入内容->数据将同时写入缓存和RAM
  • 禁用缓存而不使其无效
  • 将其他内容写入同一变量->只修改RAM,而不修改缓存
  • 再次启用缓存,但不使其无效
  • 读取RAM->我希望读取旧值而不是新值,因为此时缓存中应该有命中,因为缓存线应该仍然有效,并且应该仍然包含旧值
代码如下:

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();
    }
用keil5,-O0编译。变量写入是通过STR完成的(我的意思是:据我所知,没有奇怪的CPU优化)

我检查了MPU寄存器的值,RAM变量的地址(实际上在MPU区域内)

算法和/或代码中是否有错误


编辑:修复了试图启用/禁用DTCMRAM缓存的MPU配置,该缓存从地址0x200000000开始。然而,DTCMRAM是紧密耦合的存储器。它直接连接到Cortex-M7内核,并且在缓存后面。 您可以在图1中看到这一点。(系统架构)的。 因此,缓存操作不会对该内存产生影响

如果要执行此测试,必须使用另一个内存区域,例如AXI SRAM(从地址0x24000000开始)。这可以通过修改链接器脚本(可能还有启动代码)或使用指针变量直接写入固定内存地址来实现

请注意,在不禁用缓存的情况下,在RAM和缓存之间创建不匹配的另一种可能性是使用DMA控制器访问与MCU相同的内存。DMA控制器不使用缓存,因此如果DMA控制器写入已在缓存中的内存,则应用程序将读取旧的缓存版本,而不是新写入的数据。您的测试将是这样的:

  • 软件将值写入AXI SRAM。它现在在缓存中
  • DMA操作将数据写入同一地址。核心没有“看到”这一点
  • 通常,您必须在现在读取数据之前执行缓存失效操作。对于你的测试,你不会这样做
  • 现在从AXI SRAM读取变量。如果启用缓存,您可能会获得旧值(由软件写入的值,而不是由DMA写入的值)

为什么要在运行时禁用缓存?我需要运行缓存的自检。该算法是在上一代产品上实现的(在不同的MCU上),如果可能的话,我们希望在MPU区域设置为写回的情况下保留类似的算法写入内存。将MPU区域更改为不可缓存,然后将其读回。我认为这会造成不一致。如果这不起作用,它是类似的东西,因为我在过去做过,但不能记住确切的细节。基本上,在MPU中使用不同的缓存设置访问相同的内存会导致问题。是的,这实际上是我现在正在尝试的:将RAM设置为写回、写、禁用缓存、读:预期不一致。