/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file sd_diskio.c * @brief SD Disk I/O driver ****************************************************************************** * @attention * *

© Copyright (c) 2021 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* USER CODE END Header */ /* Note: code generation based on sd_diskio_dma_rtos_template_bspv1.c v2.1.4 as FreeRTOS is enabled. */ /* USER CODE BEGIN firstSection */ /* can be used to modify / undefine following code or add new definitions */ /* USER CODE END firstSection*/ /* Includes ------------------------------------------------------------------*/ #include "ff_gen_drv.h" #include "sd_diskio.h" #include #include /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ #define QUEUE_SIZE (uint32_t) 10 #define READ_CPLT_MSG (uint32_t) 1 #define WRITE_CPLT_MSG (uint32_t) 2 /* ================================================================== enable the defines below to send custom rtos messages when an error or an abort occurs. Notice: depending on the HAL/SD driver the HAL_SD_ErrorCallback() may not be available. See BSP_SD_ErrorCallback() and BSP_SD_AbortCallback() below ================================================================== #define RW_ERROR_MSG (uint32_t) 3 #define RW_ABORT_MSG (uint32_t) 4 */ /* * the following Timeout is useful to give the control back to the applications * in case of errors in either BSP_SD_ReadCpltCallback() or BSP_SD_WriteCpltCallback() * the value by default is as defined in the BSP platform driver otherwise 30 secs */ #define SD_TIMEOUT 30 * 1000 #define SD_DEFAULT_BLOCK_SIZE 512 /* * Depending on the use case, the SD card initialization could be done at the * application level: if it is the case define the flag below to disable * the BSP_SD_Init() call in the SD_Initialize() and add a call to * BSP_SD_Init() elsewhere in the application. */ /* USER CODE BEGIN disableSDInit */ /* #define DISABLE_SD_INIT */ /* USER CODE END disableSDInit */ /* * 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 */ /* * Some DMA requires 4-Byte aligned address buffer to correctly read/write data, * in FatFs some accesses aren't thus we need a 4-byte aligned scratch buffer to correctly * transfer data */ /* USER CODE BEGIN enableScratchBuffer */ /* #define ENABLE_SCRATCH_BUFFER */ /* USER CODE END enableScratchBuffer */ /* Private variables ---------------------------------------------------------*/ #if defined(ENABLE_SCRATCH_BUFFER) #if defined (ENABLE_SD_DMA_CACHE_MAINTENANCE) ALIGN_32BYTES(static uint8_t scratch[BLOCKSIZE]); // 32-Byte aligned for cache maintenance #else __ALIGN_BEGIN static uint8_t scratch[BLOCKSIZE] __ALIGN_END; #endif #endif /* Disk status */ static volatile DSTATUS Stat = STA_NOINIT; #if (osCMSIS <= 0x20000U) static osMessageQId SDQueueID = NULL; #else static osMessageQueueId_t SDQueueID = NULL; #endif /* Private function prototypes -----------------------------------------------*/ static DSTATUS SD_CheckStatus(BYTE lun); DSTATUS SD_initialize (BYTE); DSTATUS SD_status (BYTE); DRESULT SD_read (BYTE, BYTE*, DWORD, UINT); #if _USE_WRITE == 1 DRESULT SD_write (BYTE, const BYTE*, DWORD, UINT); #endif /* _USE_WRITE == 1 */ #if _USE_IOCTL == 1 DRESULT SD_ioctl (BYTE, BYTE, void*); #endif /* _USE_IOCTL == 1 */ const Diskio_drvTypeDef SD_Driver = { SD_initialize, SD_status, SD_read, #if _USE_WRITE == 1 SD_write, #endif /* _USE_WRITE == 1 */ #if _USE_IOCTL == 1 SD_ioctl, #endif /* _USE_IOCTL == 1 */ }; /* USER CODE BEGIN beforeFunctionSection */ /* can be used to modify / undefine following code or add new code */ /* USER CODE END beforeFunctionSection */ /* Private functions ---------------------------------------------------------*/ static int SD_CheckStatusWithTimeout(uint32_t timeout) { uint32_t timer; /* block until SDIO peripheral is ready again or a timeout occur */ #if (osCMSIS <= 0x20000U) timer = osKernelSysTick(); while( osKernelSysTick() - timer < timeout) #else timer = osKernelGetTickCount(); while( osKernelGetTickCount() - timer < timeout) #endif { if (BSP_SD_GetCardState() == SD_TRANSFER_OK) { return 0; } } return -1; } static DSTATUS SD_CheckStatus(BYTE lun) { Stat = STA_NOINIT; if(BSP_SD_GetCardState() == SD_TRANSFER_OK) { Stat &= ~STA_NOINIT; } return Stat; } /** * @brief Initializes a Drive * @param lun : not used * @retval DSTATUS: Operation status */ DSTATUS SD_initialize(BYTE lun) { Stat = STA_NOINIT; /* * check that the kernel has been started before continuing * as the osMessage API will fail otherwise */ #if (osCMSIS <= 0x20000U) if(osKernelRunning()) #else if(osKernelGetState() == osKernelRunning) #endif { #if !defined(DISABLE_SD_INIT) if(BSP_SD_Init() == MSD_OK) { Stat = SD_CheckStatus(lun); } #else Stat = SD_CheckStatus(lun); #endif /* * if the SD is correctly initialized, create the operation queue * if not already created */ if (Stat != STA_NOINIT) { if (SDQueueID == NULL) { #if (osCMSIS <= 0x20000U) osMessageQDef(SD_Queue, QUEUE_SIZE, uint16_t); SDQueueID = osMessageCreate (osMessageQ(SD_Queue), NULL); #else SDQueueID = osMessageQueueNew(QUEUE_SIZE, 2, NULL); #endif } if (SDQueueID == NULL) { Stat |= STA_NOINIT; } } } return Stat; } /** * @brief Gets Disk Status * @param lun : not used * @retval DSTATUS: Operation status */ DSTATUS SD_status(BYTE lun) { return SD_CheckStatus(lun); } /* 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) { 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 */ 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