1.前言
此前在没有FreeRTOS操作系统上实现了在STM32H7平台上,连接SD卡,使用DMA传输并使得D-Cache保持回写模式下正常工作时的笔记如下:
STM32+SDIO+FATFS在带有DMA和CACHE的平台的调试注意要点_Fairchild_1947的博客-CSDN博客
此次加入FreeRTOS实时操作系统,并同样实现上述功能。
2.注意事项
加入FreeRTOS实时操作系统的情况硬件设置同没有操作系统的硬件设置。不过在设置操作系统可使用的堆栈时最好设置的大一些,因为操作系统版本的sd_diskio.h文件中,使用队列进行进程间通信。此处由于STM32H7的内部SRAM非常大,且笔者比较喜欢使用操作系统的内存申请,所以直接给操作系统分配了256KB,内存分配算法选择默认的heap_4即可,这个算法是最优的。
生成代码后,与没有操作系统一样,需要添加使用Cache的宏定义
然而就在编译之后,若使用C99标准编译会发生报错,因为C99标准定义的变量作用范围是顶定义前的一对括号结束,但是在SD_read方法中,源码在else中没有定义ret,所以需要在else情况添加ret变量的定义。编译即可通过。
具体位置请看如下代码,重要位置已经用中文注释写出:
DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
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 & 0x1F))
{
#endif
/* Fast path cause destination buffer is correctly aligned */
//这里是ret第一次定义的位置,作用范围仅在此if条件成立的区域中
uint8_t 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;
//需要在这里添加一个对ret的定义
uint8_t ret;
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;
}
3.测试结果
测试结果同没有操作系统的时候。