Missing D-Cache clean in "sd_diskio.c" SD_Read() causes SD card FATFS libraries to fail
I've been working with an F7 processor, using RTOS with the FATFS and an SD card in 4bit mode on SDMMC1.
STM32CubeIDE V1.8
STM32CubeMX V6.4.0
Within the sd_diskio.c file there is the following option to enable D-Cache maintenance when D-Cache is used:
/*
* when using cacheable memory region, it may be needed to maintain the cache
* validity. Enable the define below to activate a cache maintenance at each
* read and write operation.
* Notice: This is applicable only for cortex M7 based platform.
*/
/* USER CODE BEGIN enableSDDmaCacheMaintenance */
#define ENABLE_SD_DMA_CACHE_MAINTENANCE 1
/* USER CODE END enableSDDmaCacheMaintenance */However, there seems to be a D-Cache clean missing within SD_read(), this is the generated code:
/* USER CODE BEGIN beforeReadSection */
/* can be used to modify previous code / undefine following code / add new code */
/* USER CODE END beforeReadSection */
/**
* @brief Reads Sector(s)
* @param lun : not used
* @param *buff: Data buffer to store read data
* @param sector: Sector address (LBA)
* @param count: Number of sectors to read (1..128)
* @retval DRESULT: Operation result
*/
DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
uint8_t ret;
DRESULT res = RES_ERROR;
uint32_t timer;
#if (osCMSIS < 0x20000U)
osEvent event;
#else
uint16_t event;
osStatus_t status;
#endif
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
uint32_t alignedAddr;
#endif
/*
* ensure the SDCard is ready for a new operation
*/
if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
{
return res;
}
#if defined(ENABLE_SCRATCH_BUFFER)
if (!((uint32_t)buff & 0x3))
{
#endif
/* Fast path cause destination buffer is correctly aligned */
ret = BSP_SD_ReadBlocks_DMA((uint32_t*)buff, (uint32_t)(sector), count);
if (ret == MSD_OK) {
#if (osCMSIS < 0x20000U)
/* wait for a message from the queue or a timeout */
event = osMessageGet(SDQueueID, SD_TIMEOUT);
if (event.status == osEventMessage)
{
if (event.value.v == READ_CPLT_MSG)
{
timer = osKernelSysTick();
/* block until SDIO IP is ready or a timeout occur */
while(osKernelSysTick() - timer <SD_TIMEOUT)
#else
status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
if ((status == osOK) && (event == READ_CPLT_MSG))
{
timer = osKernelGetTickCount();
/* block until SDIO IP is ready or a timeout occur */
while(osKernelGetTickCount() - timer <SD_TIMEOUT)
#endif
{
if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
{
res = RES_OK;
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
/*
the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
adjust the address and the D-Cache size to invalidate accordingly.
*/
alignedAddr = (uint32_t)buff & ~0x1F;
SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
#endif
break;
}
}
#if (osCMSIS < 0x20000U)
}
}
#else
}
#endif
}
#if defined(ENABLE_SCRATCH_BUFFER)
}
else
{
/* Slow path, fetch each sector a part and memcpy to destination buffer */
int i;
for (i = 0; i < count; i++)
{
ret = BSP_SD_ReadBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1);
if (ret == MSD_OK )
{
/* wait until the read is successful or a timeout occurs */
#if (osCMSIS < 0x20000U)
/* wait for a message from the queue or a timeout */
event = osMessageGet(SDQueueID, SD_TIMEOUT);
if (event.status == osEventMessage)
{
if (event.value.v == READ_CPLT_MSG)
{
timer = osKernelSysTick();
/* block until SDIO IP is ready or a timeout occur */
while(osKernelSysTick() - timer <SD_TIMEOUT)
#else
status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
if ((status == osOK) && (event == READ_CPLT_MSG))
{
timer = osKernelGetTickCount();
/* block until SDIO IP is ready or a timeout occur */
ret = MSD_ERROR;
while(osKernelGetTickCount() - timer < SD_TIMEOUT)
#endif
{
ret = BSP_SD_GetCardState();
if (ret == MSD_OK)
{
break;
}
}
if (ret != MSD_OK)
{
break;
}
#if (osCMSIS < 0x20000U)
}
}
#else
}
#endif
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
/*
*
* invalidate the scratch buffer before the next read to get the actual data instead of the cached one
*/
SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
#endif
memcpy(buff, scratch, BLOCKSIZE);
buff += BLOCKSIZE;
}
else
{
break;
}
}
if ((i == count) && (ret == MSD_OK ))
res = RES_OK;
}
#endif
return res;
}I have added a cache clean prior to the BSP_SD_ReadBlocks_DMA call which resolved my connection issues:
#if defined(ENABLE_SCRATCH_BUFFER)
if (!((uint32_t)buff & 0x3))
{
#endif
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
alignedAddr = (uint32_t)buff & ~0x1F;
// Clean whole aligned buffer from data cache
SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
#endif
/* Fast path cause destination buffer is correctly aligned */
ret = BSP_SD_ReadBlocks_DMA((uint32_t*)buff, (uint32_t)(sector), count);
if (ret == MSD_OK) {
#if (osCMSIS < 0x20000U)
/* wait for a message from the queue or a timeout */
event = osMessageGet(SDQueueID, SD_TIMEOUT);
if (event.status == osEventMessage)
{
if (event.value.v == READ_CPLT_MSG)
{
timer = osKernelSysTick();
/* block until SDIO IP is ready or a timeout occur */
while(osKernelSysTick() - timer <SD_TIMEOUT)
#elseThis is working for me, without this I can't use SD library with D-Cache enabled.
