Cache-应用(第二篇)

本文探讨了嵌入式系统中由于Cache引发的数据不一致问题,包括DMA操作、芯片对Flash的读写以及代码烧录过程中的挑战。介绍了常见的解决办法,如关闭Cache、使用Write-Through策略以及局部Cache操作来确保内存与Cache数据同步。同时,针对特定场景,如DMA读写前后对Cache的操作,以及在Flash操作和代码烧录时的Cache管理,提供了具体的解决方案。
摘要由CSDN通过智能技术生成

一、应用中不一致问题

上一节讲了cache的基本原理,实际应用中虽然cache给我们带来了处理性能的提升,但是也因为cache的与内存的一致性问题给我们带来不少烦恼。实际应用中主要是D-cache的write back策略方式问题多些。

1.常用接口

关于cache的处理接口,一般会提供常用的开/关cache接口,Invalidate接口和clean(有的是flush)接口。以stm32F7为例,其关于cache操作的接口有如下:
1)SCB_EnableICache() 和 SCB_EnableDCache():使能 I-cache 或 D-cache。
2)SCB_DisableICache() 和 SCB_DisableDCache():禁用 I-cache 或 D-cache。
3)SCB_InvalidateICache():使 I-cache 无效
4)SCB_InvalidateDCache():使 D-cache 无效
5)SCB_InvalidateDCache_by_Addr():根据地址信息无效其对应的 cache-line。
6)SCB_CleanDCache_by_Addr():根据地址信息 clean 其对应的 cache-line。

这里说明下这些接口实质上实现了什么:
开关cache接口这里就不多解释了,就是将cache打开或者关闭了。
结合上节的流程图:
Invalidate的实质就是将cache line的相应valid标志置为无效,关于valid其作用就是表示当前cache line是否启用,如果valid为无效,那么无论哪种cache 策略,其读cache的Cache hit判定肯定不会通过,也就是读就转而从实际的内存进行读取数据,而不是使用cache中的数据。(当然读之后,cache也获得了内存的数据)
Clean(或者flush)的实质就是将cache的数据更新到内存中,实现内存数据与cache数据的同步。在write back策略下,也就实现了将dirty标志清0的操作。
带不带Addr后缀就是操作的是整个cache还是部分地址域对应的cache line了

2.发生不一致一般解决办法

当由于cache与内存的不一致影响到程序的正常执行,一般解决办法有以下方式:
法1:整个代码关闭cache,这种办法显然cache不使用牺牲了其性能。
法2:将使用的内存区域转移到write through 区域。write back区域由于策略的不同,可将内存使用的空间转移到write through 区域。
法3:局部针对cache进行操作,实现cache与内存数据的同步。

二、应用

以下均指在开启cache条件下,且是采用write back策略才存在这种问题

1.DMA:

因为DMA是直接内存访问,而cache是cpu专用的,DMA和CPU都会使用内存数据则要保证其一致性问题。

DMA读取一段内存空间:
首先要调用Clean(有的是flush接口),将cache中的数据更新到内存中。
再开启DMA访问内存数据。完成DMA操作

DMA写一段内存空间:
再开启DMA写内存数据。完成DMA操作
调用Invalidate,这样cpu访问内存数据会发现cahe不能hit而从实际的内存取数据。(放在DMA开启前执行也可)

2.某型号芯片操作flash:

比如下图为某MCU的Cache可访问区域分布。

在这里插入图片描述
简单叙述该MCU内部与flash之间的内部框图如下:
在这里插入图片描述
这个芯片比较特别的是其读取flash数据是可cacheable的,走的是AHB总线,但是其擦写操作flash是通过flash控制器走的APB总线,这是不通过cache的。这就带来一个问题,当开启D-cache时,如果先读flash数据,执行了相同地址flash擦或者写操作,那么再读flash的数据,由于实际访问时cache可以hit,所以直接获取的是cache中的数据而导致flash数据写或者擦失败的假象。

解决办法:每次擦写之前将对应内存区域设置为Invalid状态。
Invalidate()指定flash区域;
执行erase/program()flash操作;

3.某芯片向flash烧录代码程序

在测试一个芯片通过上位机通过ICE仿真器(JTAG接口)烧录执行代码到flash的过程中,发现一旦烧录程序开启D-cache那么烧录就无法进行。经调试,发现是上位机软件在通过JTAG接口直接修改烧录程序的cmd后(不知道JTAG具体怎么通过什么指令操作的内存。。。),会执行读cmd进行校验cmd是否执行,不匹配程序就停止运行了。大致流程如下:(不需要太了解了,其实就是知道其写是通过cpu访问修改cmd,实际修改的是cache,而读是通过直接访问的内存)。

在这里插入图片描述

解决办法,在每次读cmd命令调用之前,调用之前flush一下cache数据到内存。
flushDCache_Addr( (unsigned long)cmdarr,((unsigned long)(cmdarr+sizeof(cmdarr)) );
xxx…读cmd

4.指令cache的数据一致性问题:

当前嵌入式系统采用独立的指令cache和数据cache,当获取内存指令到I-cache后,如果内存对应的空间发生了指令更新(典型的比如代码升级),那么对于指令cache是未知的。简而言之就是读取内存的code至I-cache后,cpu通过D-cache或者直接更新了code,导致CPU再执行与实际最新的内存不一致。实际上也是读和写一个操作了cache(I-cache),一个直接操作的内存,导致的不一致。

在这里插入图片描述

总结:Cache的不一致问题从根本上都可以说成是由于读和写操作一个通过cache,一个未通过cache导致的(这里的cache是指读写共用的cache)
参考:
添加链接描述

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值