STM32H7的L1缓存行为

问题描述 投票:0回答:1

我正在玩STM32H753的L1缓存。

我想做的是故意引起缓存和 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();
    }

用Keil 5编译,

-O0
。变量写入是通过
STR
指令完成的(我的意思是:据我所知,没有奇怪的 CPU 优化)。

我检查了 MPU 寄存器值、RAM 变量的地址(确实在 MPU 区域内)。

算法和/或代码有问题吗?

c caching embedded stm32 microcontroller
1个回答
3
投票

您正在尝试启用/禁用 DTCMRAM 的缓存,该缓存从地址 0x200000000 开始。然而,DTCMRAM 是紧耦合存储器。它直接连接到 Cortex-M7 内核,并且“不”位于缓存后面。 您可以在(参考手册)的图 1.(系统架构)中看到这一点。 因此,缓存操作不会影响该内存。 如果您想进行此测试,则必须使用另一个内存区域,例如 AXI SRAM(从地址 0x24000000 开始)。这可以通过修改链接器脚本(可能还包括启动代码)或使用指针变量直接写入固定内存地址来完成。

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

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