問題描述:
使用STM32H7+ThreadX+FileX,之前使用swissbit牌的存儲卡可正常使用,最近項目用了金士頓的存儲卡,發(fā)現(xiàn)無法掛載文件系統(tǒng)。
原因分析:
調(diào)試過程發(fā)現(xiàn),關(guān)閉D-Cache可以掛載使用exfat文件系統(tǒng)。
FileX對SD卡讀寫接口全部位于fx_stm32_sdio_driver.c中,查看該文件可以發(fā)現(xiàn)在讀寫函數(shù)中已經(jīng)考慮到使用Cache與DMA的情況,如下代碼所示。
SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, DEFAULT_SECTOR_SIZE);
SCB_InvalidateDCache_by_Addr((uint32_t*)media_ptr->fx_media_driver_buffer, num_sectors * DEFAULT_SECTOR_SIZE);
SCB_InvalidateDCache_by_Addr()函數(shù)用于將該地址D-Cache無效化,無效化的意思是將Cache Line 標(biāo)記為無效,等同于刪除操作。這樣下次讀寫該地址數(shù)據(jù)時,D-Cache中無此數(shù)據(jù),CPU直接對SRAM讀寫數(shù)據(jù),保證CPU讀取到的數(shù)據(jù)是真實的。
源碼分析:
以讀取函數(shù)為例:
case FX_DRIVER_READ:
{
media_ptr->fx_media_driver_status = FX_IO_ERROR;
//TX_DISABLE /* disable interrupts */
if ((ULONG)(media_ptr->fx_media_driver_buffer) & 0x03)
{
if (sd_read_data(media_ptr, media_ptr->fx_media_driver_logical_sector + media_ptr->fx_media_hidden_sectors,
media_ptr->fx_media_driver_sectors, 1) == FX_SUCCESS)
{
media_ptr->fx_media_driver_status = FX_SUCCESS;
}
}
……
if ((ULONG)(media_ptr->fx_media_driver_buffer) & 0x03)
判斷讀取地址是否4字節(jié)對齊,因為使用MDMA讀寫SD卡需要地址4字節(jié)對齊,并對sd_read_data()函數(shù)傳入相應(yīng)值。
sd_read_data()函數(shù)如下:
static UINT sd_read_data(FX_MEDIA *media_ptr, ULONG start_sector, UINT num_sectors, UINT use_scratch_buffer)
{
INT i = 0;
UINT status;
if (use_scratch_buffer)
{
memset(scratch, '\0', DEFAULT_SECTOR_SIZE);
for (i = 0; i < num_sectors; i++)
{
status = BSP_SD_ReadBlocks_DMA((uint32_t*)scratch, start_sector++, 1);
if (status != BSP_ERROR_NONE)
{
status = FX_IO_ERROR;
break;
}
if(tx_semaphore_get(&transfer_semaphore, DEFAULT_TIMEOUT) != TX_SUCCESS)
{
status = FX_BUFFER_ERROR;
break;
}
else
{
#if (ENABLE_CACHE_MAINTENANCE == 1)
SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, DEFAULT_SECTOR_SIZE);
#endif
_fx_utility_memory_copy(scratch, media_ptr->fx_media_driver_buffer, DEFAULT_SECTOR_SIZE);
media_ptr->fx_media_driver_buffer += DEFAULT_SECTOR_SIZE;
}
}
if (i == num_sectors)
{
status = FX_SUCCESS;
}
}
else
{
status = BSP_SD_ReadBlocks_DMA((uint32_t*)media_ptr->fx_media_driver_buffer, start_sector, num_sectors);
if (status == BSP_ERROR_NONE)
{
if(tx_semaphore_get(&transfer_semaphore, DEFAULT_TIMEOUT) == TX_SUCCESS)
{
#if (ENABLE_CACHE_MAINTENANCE == 1)
SCB_InvalidateDCache_by_Addr((uint32_t*)media_ptr->fx_media_driver_buffer, num_sectors * DEFAULT_SECTOR_SIZE);
#endif
status = FX_SUCCESS;
}
else
{
status = FX_BUFFER_ERROR;
}
}
}
return status;
}
根據(jù)傳入?yún)?shù)判斷,若傳輸?shù)刂凡皇?字節(jié)對齊,則使用內(nèi)部定義的一塊32字節(jié)對齊的地址作為中轉(zhuǎn)站,先用MDMA讀取到數(shù)據(jù),再將數(shù)據(jù)拷貝到用戶提供地址。else分支若地址已經(jīng)是4字節(jié)對齊,則直接使用用戶提供的地址進行MDMA傳輸。
然而else分支的代碼存在一個bug,當(dāng)用戶傳入的地址為4字節(jié)對齊時,進入else分支,在MDMA傳輸完成后,進行SCB_InvalidateDCache_by_Addr()操作。但是該函數(shù)要求傳入的地址為32字節(jié)對齊,因為Cortex-M7內(nèi)核的Cache line大小為8個字。所以當(dāng)傳入的地址為4字節(jié)對齊但非32字節(jié)對齊時,SCB_InvalidateDCache_by_Addr()調(diào)用傳入的參數(shù)不符合要求,D-Cache緩存清除錯誤,使CPU讀取到緩存中錯誤的值。文章來源:http://www.zghlxwxcb.cn/news/detail-861304.html
解決方案:
在判斷地址是否4字節(jié)對齊的地方,改成判斷地址是否32字節(jié)對齊(即0x03改成0x1f),共修改2行代碼,在代碼中搜索media_ptr->fx_media_driver_buffer即可找到。文章來源地址http://www.zghlxwxcb.cn/news/detail-861304.html
if ((ULONG)(media_ptr->fx_media_driver_buffer) & 0x1f)
到了這里,關(guān)于STM32H7使用FileX庫BUG,SD卡掛載失敗的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!