STM32H743 数据一致性调试
这几天从0开始学习并调试STM32H743单片机,大家都了解到F7、H7系列采用了ARM Cortex-M7内核,这和我们常用的F1、F4采用的Cortex-M3、Cortex-M4内核最大的区别就是带了一级缓存,一级缓存运行速率是和Cortex-M7内核运行速率是一样的,其他的SRAM段运行在200MHz,如果不开启DCache,性能会有极大的损失,但是开启了DCache就会牵扯到数据一致性问题,这里不阐述这个问题是怎么产生的,建议大家去安富莱电子论坛,去看硬汉的H7教程,里边有详细说明,原子和野火都建议通过直接配置MPU为透写方式避免这个问题,硬汉解决在这个问题时感觉比较积极。
好了,说正题,我是在调试TF卡时遇到的这个问题,根据上述三家教程描述,数据一致性只有在使用可以主动读写内存的外设才会存在,TF卡为什么会存在这个问题呢,一开始我也没太注意,H7的SDMMC外设是自带IDMA的,但是可以不使用,意味着效率降低了不少,再说HAL库都给你封装好了,不用多可惜呀,还需要注意的是SDMM1的这个IDMA只能访问AXISRAM,也就是512K的那块内存,所以缓存数据别定义到别的内存块了,不然打死都搞不出来(这个错误正点原子论坛有,但我没有看到有人给出解决方法),所以这些坑我都没有遇到。
TF卡初始化好之后移植Fat文件系统,在打开文件后一行打断点,全速运行,挂载文件系统OK,运行到断点处,返回0x0D,没有该文件,权限给的是如果没有这个文件则创建该文件,正常情况下应该返回OK的呀,以前我在F4 用SPIFlash读写文件的时候可是正常的,那只能在读取扇区函数上打断点喽,单步调试,哎呀,它又OK了。
先贴读block代码:
static uint8_t TxBuff[2][BLOCKSIZE] = {0};
void TF_ReadBlocks(uint8_t* Buff,uint32_t Sector,uint32_t Count)
{
HAL_SD_ReadBlocks_DMA(&hsd1,TxBuff[0],Sector,1);
while((Tf_Flag & 0x01) == 0x01);
Tf_Flag |= 0x01;
for(uint32_t i = 0;(i < (Count - 1)) && (Count != 1);i ++)
{
HAL_SD_ReadBlocks_DMA(&hsd1,TxBuff[(i + 1) & 0x01],Sector + i + 1,1);
#if UseDCache > 0
SCB_InvalidateDCache_by_Addr((uint32_t*)TxBuff[i & 0x01],BLOCKSIZE / 4);
#endif
memcpy(Buff + 512 * i,TxBuff[i & 0x01],BLOCKSIZE);
while((Tf_Flag & 0x01) == 0x01);
Tf_Flag |= 0x01;
}
#if UseDCache > 0
SCB_InvalidateDCache_by_Addr((uint32_t*)TxBuff[(Count - 1) & 0x01],BLOCKSIZE/4);
#endif
memcpy(Buff + 512 * (Count - 1),TxBuff[(Count - 1) & 0x01],BLOCKSIZE);
}
不要问我为什么没有做while循环超时退出,我也不知道我为啥不想做,虽然这方法不可取,反正调试可用就行。双缓冲,可能做的不好,笑笑就行哈。
根据三家的描述,肯定使用到和DCache相关的函数了,这里就是SCB_InvalidateDCache_by_Addr函数了,简单说一下这个函数功能,让Dache中对应的数据失效,CPU使用该数据的时候从内存中重新加载。我在使用的时候没有看函数原型,只是根据三大家的描述,填写参数就是代码中的那样。实际中还是出了问题,那我们看看函数原型嘛,位置在cm7_core.h大约2300行左右(版本不同,位置稍有偏差)。
/**
\brief D-Cache Invalidate by address
\details Invalidates D-Cache for the given address
\param[in] addr address (aligned to 32-byte boundary)
\param[in] dsize size of memory block (in number of bytes)
*/
__STATIC_INLINE void SCB_InvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
{
#if (__DCACHE_PRESENT == 1U)
int32_t op_size = dsize;
uint32_t op_addr = (uint32_t)addr;
int32_t linesize = 32U; /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */
__DSB();
while (op_size > 0) {
SCB->DCIMVAC = op_addr;
op_addr += linesize;
op_size -= linesize;
}
__DSB();
__ISB();
#endif
}
如上,第三个参数解释上给的是size of memory block (in number of bytes)以字节为单位的,而例程中给的是以字为单位的,把代码中的/4去掉就OK了。
这样就OK了,写block函数如法炮制就好了。