0%

S32K344 Cache 调试记录

Cache概述

在嵌入式系统中,缓存(Cache)是一种重要的存储器,位于CPU和主存储器(如SRAM、DRAM)之间。它用于存储经常访问的数据和指令,以减少访问主存的时间,从而提高系统的整体性能。缓存可以显著减少CPU等待数据的时间,提高系统的响应速度和处理能力。

Cache工作原理

缓存通过存储从主存储器中读取的常用数据或指令来加快访问速度。当CPU需要访问某个数据或指令时,会首先检查缓存。如果缓存中存在所需数据(称为缓存命中),则直接从缓存中读取。如果缓存中不存在(称为缓存未命中),则从主存储器中读取数据,并将其存储到缓存中,以备后续访问。

S32K344 Cache资源情况

NXP S32K344拥有8KB I-Cache 和 8KB D-Cache,从系统框图看这个芯片,对于锁步核的应用,两个核的Cache无法共用,而TCM内存是可以共用的,锁步情况下TCM内存容量是不锁步的2倍。在Memory table里还能看到存在672Bytes的I-Cache tag和800Bytes的D-Cache tag,缓存需要一种机制来管理哪些数据当前存储在缓存中,这就是tag的作用。S32K344的RAM和ROM都有ECC校验,Cache也包含了ECC校验,RAM和ROM每64位数据有8位是存ECC校验值,这意味着实际设计的Cache资源还要更大一些用于存ECC校验值。

Cache维护

在缓存管理中,无效化(Invalidate)和清除(Clean)是两个不同的操作。这两个操作帮助维持缓存一致性,确保系统性能和数据正确性。

无效化(Invalidate)

作用:使缓存中的数据无效,但不写回主存。
使用场景:当你确定缓存中的数据已经过期或不再需要时,可以无效化缓存来避免使用陈旧数据。

清除(Clean)

作用:将缓存中的数据写回主存,但不使数据无效。
使用场景:当需要确保缓存中的最新数据已经同步到主存时,可以进行清除操作,特别是在DMA操作前后。

实际使用问题

开启Cache后Flash读写擦

S32K344,MCAL的INFLS代码可以配置开启Mem Synchronize Cache选项用于确保缓存与Flash存储之间的数据一致性。

功能:在每次Flash高电压操作(写入、擦除)后,通过调用MCL(Memory Control Layer)缓存API函数来无效化缓存,以确保缓存与修改后的Flash存储同步。但也存在缺点,如果要无效化的区域大于缓存的一半,则整个缓存会被无效化。

在实际使用中如果开启Cache,没开这个选项部分代码擦写Flash不生效,写入异常

代码加载到RAM运行

S32K344,MCAL的INFLS代码可以配置开启Mem Clean Cache After Load Access Code选项用于确保加载到RAM中的Access Code函数与缓存一致。

如果该选项启用,在将Access Code函数加载到RAM后,清除缓存,将缓存数据写入实际RAM内存。此操作可确保缓存和RAM之间的数据同步,避免缓存数据不一致的问题。在实际使用中遇到了开启这个选项但没开Cache功能,有概率会在加载RAM代码缓存操作时卡死问题

DMA 搬运到 Cache 区域

在使用 DMA 将 UART 收到的数据搬运到 Cache 区域前,必须先 Invalidate 那片区域的 Cache。这是为了确保在 DMA 操作过程中,该区域的 Cache 中不会有未写入内存的脏数据。这些脏数据如果存在,可能会在 DMA 写入数据时被覆盖,导致数据不一致的问题。

虽然在 DMA 搬运前也可以使用 Clean 操作,但相较于 Invalidate 操作,效率较低。Clean 操作会将 Cache 中的脏数据写回到内存,而 Invalidate 直接使 Cache 无效,避免了写回的开销,因此通常更高效。

数据搬运完成后,也需要 Invalidate 那片区域的 Cache。这一步是为了防止在接下来的数据访问过程中,Cache 中的陈旧数据被直接读取,而不是从内存中读取 DMA 搬运来的新数据。

内存区域配置不使用Cache

不同MCU实现不一样,有使用MPU(内存保护单元),配置MPU区域属性,将指定内存区域设置为不可缓存,设置MPU的Region属性,使该区域不可缓存。也有配置MMU(内存管理单元),如果使用MMU,可以通过设置页表条目属性将内存区域设置为不可缓存。或者是芯片特定的寄存器,参考芯片手册进行配置。

S32K344如何配置目前还没了解到,在链接脚本中看到有一块 SRAM 没有被缓存。顺着链接脚本中定义的变量应该能查到程序中哪里配置的不缓存,也有可能那块区域就是不缓存区域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MEMORY
{
int_pflash : ORIGIN = 0x00440000, LENGTH = 0x00394000 /* 4096KB - 176KB (sBAF + HSE) - 256KB(boot) = 3664KB*/
int_dflash : ORIGIN = 0x10000000, LENGTH = 0x00020000 /* 128KB */
int_itcm : ORIGIN = 0x00000000, LENGTH = 0x00010000 /* 64KB */
int_dtcm : ORIGIN = 0x20000000, LENGTH = 0x0001F000 /* 124KB */
int_stack_dtcm : ORIGIN = 0x2001F000, LENGTH = 0x00001000 /* 4KB */
int_sram : ORIGIN = 0x20400000, LENGTH = 0x0002FF00 /* 184KB, needs to include int_sram_fls_rsv */
int_sram_fls_rsv : ORIGIN = 0x2042FF00, LENGTH = 0x00000100
int_sram_no_cacheable : ORIGIN = 0x20430000, LENGTH = 0x0000FF00 /* 64KB, needs to include int_sram_results */
int_sram_results : ORIGIN = 0x2043FF00, LENGTH = 0x00000100
int_sram_shareable : ORIGIN = 0x20440000, LENGTH = 0x00004000 /* 16KB */
ram_rsvd2 : ORIGIN = 0x20444000, LENGTH = 0 /* End of SRAM */
}