打印
[PIC32/SAM]

cache 对 flash操作的影响 分享

[复制链接]
1125|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Vansm|  楼主 | 2020-5-9 14:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近在做一个项目,用到SAMV71 系列芯片,遇到一个关于FLASH读写的问题,跟大家分享一下,开发工具用的是MPLABX  5.30 , 调试工具用的是开发板上自带的调试芯片。

发现问题:本来计划在SAMV71的Internal Flash区域开辟一块程序没有用到的空间作为数据存储区域。可以在设备上电或者掉电的时候加载保存一些数据。在尝试调试芯片的FLASH读写的时候发现一个问题,芯片上电后写入数据正常,读取数据的时候偶会会发生错误。写入和读取都是调用Harmony3生成的plib_efc.c驱动。

写入函数:bool EFC_PageWrite( uint32_t *data, uint32_t address )
读取函数:bool EFC_Read( uint32_t *data, uint32_t length, uint32_t address )
扇区擦除函数:bool EFC_SectorErase( uint32_t address )

以下是发生FLASH读取错误的操作步骤:

1. 利用 EFC_SectorErase擦除一个扇区的flash
2. 利用 EFC_Read 读取扇区是否被擦除,如果被擦除,区域内数据应为0xFFFF FFFF, 结果出来正确
3. 利用 EFC_PageWrite 写入一块FLASH内容
4. 利用 EFC_Read 读取扇区是否被写入,结果正确
5. 利用 EFC_SectorErase再次擦除扇区
6. 利用 EFC_Read 读取目标扇区数据,观察是否被擦除,结果错误,读出来的数据还是刚才写入的数据

尝试解决:为了验证第6步骤的错误是否因为没有扇区擦除没有成功导致的,利用MPLAB工具中的 Execution memory窗口观察了目标FLASH区域,结果发现FLASH区域已经被成功擦除,只是读取出来的结果不正确,又怀疑是程序被优化,没有直接从FLASH中读取数据,把程序优化等级从1调到0,在变量前加入volatile修饰,结果还是一样,读取出来的数据仍然和Execution memory观察窗口看到的结果不一致。百思不得其解,没办法只能去看程序编译出来的汇编,汇编显示就是从flash区域直接把数据读取出来,可是结果就是不正确。
    又换了种方式验证,不通过EFC_PageWrite写入数据,直接通过AHB总线写入,像写入SRAM一样,*(unsigned int*)0x00500000 = 0x12345678; ,写入完成后,发现虽然在Execution memory中观察没有写入成功,但是通过EFC_Read函数读取,或者通过强制转换指针的方式读取,却可以读出刚才写入的数据,可是印象中FLASH不是只能通过FLASH controler才能操作么? 为何Execution memory窗口中看到的数据和通过程序读取出来的不一致?

问题原因:经过一番思考,终于找到问题原因,原因就出在 dcache上,这里就要先普及以下什么是cache,cache是一种缓存机制,由于芯片上的FLASH IP虽然可以做到空间很大,价格便宜,但是读取速度终究不能和CPU匹配,所以我们在大多的FLASH控制器中都会发现一个程序取指等待周期寄存器,当CPU工作频率到达几十MHz或者上百MHz的时候,就没有办法每个时钟周期对Flash进行一次取指了,需要n个周期取一次,受限于FLASH的读取,于是某工程师就发明出了cache这种东西,它的本质是一块靠近CPU的高速缓存,速度可以匹敌SRAM,照寄存器可能差一些,但是比FLASH快多了,这样每次从FLASH中取内容时,可以多取一些放到缓存中,或者最近访问过的FLASH内容也放到缓存中,等待下次再想访问同样的FLASH位置时,就可以不需要花费n个时钟周期去读取FLASH,直接从缓存中拿,这样就可以提高CPU取指令或者取数据的速度,但是由于cache的尺寸限制,并不是每次都可以从cache中拿数据,所以cache有个性能指标叫做命中率,如果刚好你CPU下一条要用的指令在cache中,就命中cache, 反之就是没有命中,说到这里,那有人可能会问,这么好用的东西为什么不制作大一点呢,好让cache的命中率提高一些,原因就是因为这个东西它虽然速度快,但是贵。  我们平时用的电脑CPU介绍上的1级缓存多大多大,2级缓存多大多大,说的就是多级的cache尺寸大小。
      回到问题上来,之所以FLASH擦除后读取出来的数据仍然是之前的数据,就是因为命中了cache,虽然FLASH中的数据已经擦除,但是cache中的数据没有更新,通过程序读取时,CPU发现程序要访问的数据cache中已经有了,不需要再费劲从FLASH中读,所以还给了我们cache中的没有更新的数据,至于为什么操作FLASH后不同步触发更新以下cache,这个就不得而知了(需要问数字设计工程师了)。但是还有一个问题,虽然程序读取出来的数据错误能解释通了,但是为什么Execution memory窗口确能准确的反映出当前FLASH的内容,而不受到cache的影响呢。 这个就涉及到内核中调试接口的问题了,ARM核中的调试模块叫做SWD调试模块,SWD访问数据与CPU读取数据走的不是一条路,是另外一条路,而Execution memory窗口里的数据正是SWD调试模块读取出来的,所以不受到cache的影响。(这里解释的有点通俗,因为不是专业芯片设计,只是懂大概原理),这样就解释了之前碰到的一些列问题。

解决方法:有了之前的分析,解决方法当然是在操作FLASH的时候关闭cache了,虽然会造成CPU读取指令或者数据效率下降,但是没有想到其他更好的办法,如果哪位大神有更好的办法可以回帖留言。经过亲自实验,关闭cache后,之前遇到的问题都能顺利解决,FLASH读取出来的数据内容也全部正确。

另外SAMV71 Harmony3生成的工程的cache默认是开启的,在startup_xc32.c文件的复位函数中,如下所示:

    /* Enable Instruction Cache */
    ICache_Enable();


    /* Enable Data Cache    */
    DCache_Enable();


分为指令cache和数据cache,像之前的操作都属于数据cache,注释掉数据cache的enable 函数后,问题解决。


PS: 分享一些平时开发单片机时遇到的问题与解决方法,如果哪位工程师正巧碰到同样问题看了帖子还可以快速的从坑里爬出来。如果有不同见解或者更好的解决方法,欢迎留言交流   By  Vansm


使用特权

评论回复
沙发
wakayi| | 2020-6-2 17:25 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
板凳
wowu| | 2020-6-2 17:36 | 只看该作者
宝贵的经验啊

使用特权

评论回复
地板
xiaoqizi| | 2020-6-2 17:36 | 只看该作者
这个芯片是什么系列的啊

使用特权

评论回复
5
木木guainv| | 2020-6-2 17:37 | 只看该作者
太感谢楼主的热心了

使用特权

评论回复
6
磨砂| | 2020-6-2 17:37 | 只看该作者
以后我也能避免犯这个错误了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

187

帖子

3

粉丝