在Cortex-M7系列的芯片中,存在DCache与ICache用于加速单片机访问内存与flash。在使用DCache的过程中,需要小心内核与外设同时访问一块ram时,内存信息可能不一致的问题。典型的场景为DMA发送与接收时,需要调用SCB_InvalidateDCache_by_Addr与SCB_CleanDCache_by_Addr进行处理,这俩个函数的用途为:
SCB_InvalidateDCache_by_Addr:将指定地址与指定大小的Ram的内容同步到Cache中,典型使用场景为DMA接收。
SCB_CleanDCache_by_Addr:将指定地址与指定大小的Cache的内容同步到Ram中,典型使用场景为DMA发送。
在使用这两个函数时,需要注意调用参数的限制,如图为SCB_InvalidateDCache_by_Addr的具体定义:
可以看到,在该函数的注释处,明确规定了其addr参数,应该为32字节对齐的地址,(所谓32字节对齐的意思就是addr%32==0)。并且观察源代码还可以发现,dsize也最好设置为32字节对齐的,这个结论是如何得出的呢?举个例子,假设输入的addr=0,dsize=11,观察源代码可以发现,其执行情况和addr=0,dsize=32是一样的,因此可以大胆猜测,执行该函数后,只要dsize<=32,那么DCache中地址0~32范围的内存都会被Ram中的内存覆盖掉。如果在使用中,地址12~31中定义了其它变量的话,那么该变量的值就会莫名其妙发生改变,影响程序的稳定性。
为了解决上述问题,这里针对DMA接收处理给出一种相对稳妥的使用方法,DMA发送同理:
[C] 纯文本查看 复制代码 #define DATA_SIZE 100
#define _ALIGN_UP(data,align_byte) ((((size_t)data) + (size_t)(align_byte) - 1)&~((size_t)(align_byte) - 1))
#define _ALIGN_DOWN(data,align_byte) (((size_t)data)&~((size_t)(align_byte) - 1))
static __ALIGNED(32) uint8_t data_rec_buf[_ALIGN_UP(DATA_SIZE,32)];
//rec_len为DMA接收的数据个数
void dma_recieve_process(uint16_t rec_len){
//对起始地址进行下对齐,对数据大小进行上对齐,确保能覆盖到想要无效化的内存
SCB_InvalidateDCache_by_Addr((uint8_t*)_ALIGN_DOWN(data_rec_buf,32),_ALIGN_UP(rec_len,32));
//
// 数据接收处理
//
}
以上仅为个人看法,欢迎讨论。
|