Cortex-M7 DCache 数据一致性 STM32H743 SD卡 SDMMC1

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函数如法炮制就好了。

发布了7 篇原创文章 · 获赞 9 · 访问量 2266

猜你喜欢

转载自blog.csdn.net/wait_for_STM32/article/details/103628141