【问题标题】:L1-cache behaviour of STM32H7STM32H7 的 L1 缓存行为
【发布时间】:2019-12-05 15:59:08
【问题描述】:

我在玩 STM32H753 的 L1-cache。

我想要做的是故意挑起缓存和 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。变量 write 是通过 STR 完成的(我的意思是:据我所知,没有奇怪的 CPU 优化)。

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

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

编辑:修复 MPU 配置

【问题讨论】:

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

标签: c caching stm32


【解决方案1】:

您正在尝试启用/禁用 DTCMRAM 的缓存,该缓存从地址 0x200000000 开始。但是,DTCMRAM 是紧密耦合的存储器。它直接连接到 Cortex-M7 内核,并且位于缓存后面。 您可以在 (Reference Manual) 的图 1 中看到这一点。(系统架构)。 因此,缓存操作不会影响此内存。

如果要进行此测试,则必须使用另一个内存区域,例如 AXI SRAM(从地址 0x24000000 开始)。这可以通过修改链接描述文件(可能还有启动代码)来完成,或者通过使用指针变量直接写入固定的内存地址来完成。

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

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

【讨论】:

    猜你喜欢
    • 2015-02-07
    • 1970-01-01
    • 2013-02-07
    • 2013-01-20
    • 2021-09-30
    • 2017-08-12
    • 1970-01-01
    • 2012-07-02
    • 2010-10-27
    相关资源
    最近更新 更多