背景
- 嵌入式开发中遇到问题:将SD卡中某个文件读取到一块内存中,再将该内存地址发送给外设硬件,硬件通过该地址读取数据做处理,处理结果异常,并且现象有以下规律:
- 通过代码实现将SD卡中的文件数据拷贝到新文件中,文件是正常的。
- 外设硬件处理前,先使用代码使用一次该块内存,即使是简单的打印,处理结果也是正常的。
- 使用fopen/fread读取文件数据再拿去外设HW处理会出现异常,但是换成 open/read或者aos_open/aos_read(alios thing文件接口)是正常的,或者使用fopen/fread再调用setbuf(fp,NULL) 设置缓存为NULL现象也是正常的。
问题分析
- 从问题现象很容易会想到和缓存有关,但是应用层/OS创建的DDR缓存还是cpu L1/L2/L3 cache需要确认下,最终该问题测试验证是cpu cache导致的。
- 嵌入式开发中,cpu和外设硬件配合工作,内存和cache使用有以下两种情况。
- cpu cache flush
- 内存 invalid
- 大致模型:
- 注意:该模型和操作系统OS无关,使用任何系统(liunx,rtos)都需要注意这两种情况。
cpu cache flush
- 情况描述:CPU更改DDR内的数据,外设HW使用。
- 该情况就如背景中描述的问题例子,程序代码在cpu中运行,将SD卡中的文件数据读取到DDR中,为了提升性能,cpu会使用cache,外设HW读取该块内存地址时有部分数据可能存在于cache中,而不是DDR中,由于不经过CPU所以获取不到cache的数据,外设HW获取到的DDR数据有部分数据不对,因此会出现异常。
- 这种情况下,通过代码去使用该块内存是正常的,因为代码需要CPU执行,能够获取到cache数据。
- 这种情况要保证正常,外设HW读取该块内存前需要执行cpu cache flush操作将cpu cache flush到DDR上,背景中的问题例子 使用不带缓存的库接口也能解决问题,但是不清楚库中实现,不能保证其它系统的库接口也是ok的。
内存 invaild
- 情况描述:外设HW更改DDR内的数据,CPU使用。
- 这种情况下,外设HW更改了DDR中的数据,代码执行(CPU处理)通过定义好的变量(存在于该块内存中)去读取值,可能会出现异常,原因是若该块内存的数据存在于CPU cache中cpu为了加快性能,可能并不会读取DDR上的数据,而是直接返回cpu cache中的值(与DDR上的值不一样)。
- 这种情况下,C/C++语言需要将该变量加上volatile关键字。