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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章