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

© Copyright (c) 2020 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 cachable 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 /* USER CODE END enableSDDmaCacheMaintenance */ /* * Some DMA requires 4-Byte aligned address buffer to correctly read/wite 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 #define FORCE_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] @ "DTCMRAM" __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 */ /** * @brief Finds the SD card SCR register value. * @param hsd: Pointer to SD handle * @param pSCR: pointer to the buffer that will contain the SCR value * @retval error state */ static uint32_t SD_FindSCR_NEW(SD_HandleTypeDef *hsd, uint32_t *pSCR) { SDMMC_DataInitTypeDef config; uint32_t errorstate; uint32_t tickstart = HAL_GetTick(); uint32_t index = 0U; uint32_t tempscr[2U] = {0U, 0U}; uint32_t *scr = pSCR; /* Set Block Size To 8 Bytes */ errorstate = SDMMC_CmdBlockLength(hsd->Instance, 8U); if(errorstate != HAL_SD_ERROR_NONE) { return errorstate; } /* Send CMD55 APP_CMD with argument as card's RCA */ errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)((hsd->SdCard.RelCardAdd) << 16U)); if(errorstate != HAL_SD_ERROR_NONE) { return errorstate; } config.DataTimeOut = SDMMC_DATATIMEOUT; config.DataLength = 8U; config.DataBlockSize = SDMMC_DATABLOCK_SIZE_8B; config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; config.DPSM = SDMMC_DPSM_ENABLE; (void)SDMMC_ConfigData(hsd->Instance, &config); /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */ errorstate = SDMMC_CmdSendSCR(hsd->Instance); if(errorstate != HAL_SD_ERROR_NONE) { return errorstate; } while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND)) { if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL)) { *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance); index++; } //********************************************************** // hier Timeout neu max. 100ms !!! //********************************************************** if((HAL_GetTick() - tickstart) >= 100) { return HAL_SD_ERROR_TIMEOUT; } } if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) { __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); return HAL_SD_ERROR_DATA_TIMEOUT; } else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) { __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); return HAL_SD_ERROR_DATA_CRC_FAIL; } else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) { __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); return HAL_SD_ERROR_RX_OVERRUN; } else { /* No error flag set */ /* Clear all the static flags */ __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); *scr = (((tempscr[1] & SDMMC_0TO7BITS) << 24) | ((tempscr[1] & SDMMC_8TO15BITS) << 8) |\ ((tempscr[1] & SDMMC_16TO23BITS) >> 8) | ((tempscr[1] & SDMMC_24TO31BITS) >> 24)); scr++; *scr = (((tempscr[0] & SDMMC_0TO7BITS) << 24) | ((tempscr[0] & SDMMC_8TO15BITS) << 8) |\ ((tempscr[0] & SDMMC_16TO23BITS) >> 8) | ((tempscr[0] & SDMMC_24TO31BITS) >> 24)); } return HAL_SD_ERROR_NONE; } /** * @brief Enables the SDMMC wide bus mode. * @param hsd: pointer to SD handle * @retval error state */ static uint32_t SD_WideBus_Enable_NEW(SD_HandleTypeDef *hsd) { uint32_t scr[2U] = {0U, 0U}; uint32_t errorstate; if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) { return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; } /* Get SCR Register */ errorstate = SD_FindSCR_NEW(hsd, scr); if(errorstate != HAL_SD_ERROR_NONE) { return errorstate; } /* If requested card supports wide bus operation */ if((scr[1U] & SDMMC_WIDE_BUS_SUPPORT) != SDMMC_ALLZERO) { /* Send CMD55 APP_CMD with argument as card's RCA.*/ errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); if(errorstate != HAL_SD_ERROR_NONE) { return errorstate; } /* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */ errorstate = SDMMC_CmdBusWidth(hsd->Instance, 2U); if(errorstate != HAL_SD_ERROR_NONE) { return errorstate; } return HAL_SD_ERROR_NONE; } else { return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; } } /** * @brief Disables the SDMMC wide bus mode. * @param hsd: Pointer to SD handle * @retval error state */ static uint32_t SD_WideBus_Disable_NEW(SD_HandleTypeDef *hsd) { uint32_t scr[2U] = {0U, 0U}; uint32_t errorstate; if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) { return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; } /* Get SCR Register */ errorstate = SD_FindSCR_NEW(hsd, scr); if(errorstate != HAL_SD_ERROR_NONE) { return errorstate; } /* If requested card supports 1 bit mode operation */ if((scr[1U] & SDMMC_SINGLE_BUS_SUPPORT) != SDMMC_ALLZERO) { /* Send CMD55 APP_CMD with argument as card's RCA */ errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); if(errorstate != HAL_SD_ERROR_NONE) { return errorstate; } /* Send ACMD6 APP_CMD with argument as 0 for single bus mode */ errorstate = SDMMC_CmdBusWidth(hsd->Instance, 0U); if(errorstate != HAL_SD_ERROR_NONE) { return errorstate; } return HAL_SD_ERROR_NONE; } else { return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; } } /** * @brief Enables wide bus operation for the requested card if supported by * card. * @param hsd: Pointer to SD handle * @param WideMode: Specifies the SD card wide bus mode * This parameter can be one of the following values: * @arg SDMMC_BUS_WIDE_8B: 8-bit data transfer * @arg SDMMC_BUS_WIDE_4B: 4-bit data transfer * @arg SDMMC_BUS_WIDE_1B: 1-bit data transfer * @retval HAL status */ HAL_StatusTypeDef HAL_SD_ConfigWideBusOperation_NEW(SD_HandleTypeDef *hsd, uint32_t WideMode) { SDMMC_InitTypeDef Init; uint32_t errorstate; /* Check the parameters */ assert_param(IS_SDMMC_BUS_WIDE(WideMode)); /* Change State */ hsd->State = HAL_SD_STATE_BUSY; if(hsd->SdCard.CardType != CARD_SECURED) { if(WideMode == SDMMC_BUS_WIDE_8B) { hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; } else if(WideMode == SDMMC_BUS_WIDE_4B) { errorstate = SD_WideBus_Enable_NEW(hsd); hsd->ErrorCode |= errorstate; } else if(WideMode == SDMMC_BUS_WIDE_1B) { errorstate = SD_WideBus_Disable_NEW(hsd); hsd->ErrorCode |= errorstate; } else { /* WideMode is not a valid argument*/ hsd->ErrorCode |= HAL_SD_ERROR_PARAM; } } else { /* MMC Card does not support this feature */ hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; } if(hsd->ErrorCode != HAL_SD_ERROR_NONE) { /* Clear all the static flags */ __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); hsd->State = HAL_SD_STATE_READY; return HAL_ERROR; } else { /* Configure the SDMMC peripheral */ Init.ClockEdge = hsd->Init.ClockEdge; Init.ClockBypass = hsd->Init.ClockBypass; Init.ClockPowerSave = hsd->Init.ClockPowerSave; Init.BusWide = WideMode; Init.HardwareFlowControl = hsd->Init.HardwareFlowControl; Init.ClockDiv = hsd->Init.ClockDiv; (void)SDMMC_Init(hsd->Instance, Init); } /* Change State */ hsd->State = HAL_SD_STATE_READY; return HAL_OK; } /* USER CODE END beforeFunctionSection */ /* Private functions ---------------------------------------------------------*/ static int SD_CheckStatusWithTimeout(uint32_t timeout) { uint32_t timer; /* block until SDIO peripherial 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) for (int errorcounter = 0; errorcounter < 3; errorcounter++) { extern SD_HandleTypeDef hsd1; /* Check if the SD card is plugged in the slot */ if (BSP_SD_IsDetected() != SD_PRESENT) break; /* HAL SD initialization */ /* Configure SD Bus width (4 bits mode selected) */ if (HAL_SD_Init(&hsd1) == MSD_OK) { /* Enable wide operation */ if (HAL_SD_ConfigWideBusOperation_NEW(&hsd1, SDMMC_BUS_WIDE_4B) == HAL_OK) break; } } #endif Stat = SD_CheckStatus(lun); /* * 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 /* * ensure the SDCard is ready for a new operation */ if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0) { return res; } #if !defined(FORCE_SCRATCH_BUFFER) #if defined(ENABLE_SCRATCH_BUFFER) if (!((uint32_t)buff & 0x3)) { #endif #if defined(ENABLE_SD_DMA_CACHE_MAINTENANCE) const uint32_t alignedAddr = (uint32_t)buff & ~0x1F; const uint32_t alignedSize = count * BLOCKSIZE + ((uint32_t)buff & 0x1F); /* additional check if data cache is enabled indeed */ if (SCB->CCR & SCB_CCR_DC_Msk) { /* Clean whole aligned buffer from data cache */ SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, alignedSize); } #endif /* Fast path cause destination buffer is correctly aligned */ if (BSP_SD_ReadBlocks_DMA((uint32_t*)buff, (uint32_t)(sector), count) == MSD_OK) { #if (osCMSIS < 0x20000U) /* wait for a message from the queue or a timeout */ event = osMessageGet(SDQueueID, SD_TIMEOUT); if ((event.status == osEventMessage) && (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) { #if defined(ENABLE_SD_DMA_CACHE_MAINTENANCE) /* additional check if data cache is enabled indeed */ if (SCB->CCR & SCB_CCR_DC_Msk) { /* the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address, adjust the address and the D-Cache size to invalidate accordingly. */ SCB_CleanInvalidateDCache_by_Addr((uint32_t*)alignedAddr, alignedSize); } #endif res = RES_OK; break; } } } } #endif /* !defined(FORCE_SCRATCH_BUFFER) */ #if defined(ENABLE_SCRATCH_BUFFER) #if !defined(FORCE_SCRATCH_BUFFER) } else { #endif /* !defined(FORCE_SCRATCH_BUFFER) */ /* Slow path, fetch each sector a part and memcpy to destination buffer */ uint8_t ret = MSD_OK; int i; for (i = 0; i < count; i++) { ret = BSP_SD_ReadBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1); if (ret != MSD_OK) break; /* 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) && (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 defined(ENABLE_SD_DMA_CACHE_MAINTENANCE) /* additional check if data cache is enabled indeed */ if (SCB->CCR & SCB_CCR_DC_Msk) { /* * * 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; if (ret != MSD_OK) break; } if ((i == count) && (ret == MSD_OK)) res = RES_OK; #if !defined(FORCE_SCRATCH_BUFFER) } #endif /* !defined(FORCE_SCRATCH_BUFFER) */ #endif return res; } /* USER CODE BEGIN beforeWriteSection */ /* can be used to modify previous code / undefine following code / add new code */ /* USER CODE END beforeWriteSection */ /** * @brief Writes Sector(s) * @param lun : not used * @param *buff: Data to be written * @param sector: Sector address (LBA) * @param count: Number of sectors to write (1..128) * @retval DRESULT: Operation result */ #if _USE_WRITE == 1 DRESULT SD_write(BYTE lun, const 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 /* * ensure the SDCard is ready for a new operation */ if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0) { return res; } #if !defined(FORCE_SCRATCH_BUFFER) #if defined(ENABLE_SCRATCH_BUFFER) if (!((uint32_t)buff & 0x3)) { #endif #if defined(ENABLE_SD_DMA_CACHE_MAINTENANCE) /* additional check if data cache is enabled indeed */ if (SCB->CCR & SCB_CCR_DC_Msk) { const uint32_t alignedAddr = (uint32_t)buff & ~0x1F; const uint32_t alignedSize = count * BLOCKSIZE + ((uint32_t)buff & 0x1F); /* the SCB_CleanDCache_by_Addr() requires a 32-Byte aligned address adjust the address and the D-Cache size to clean accordingly. */ SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, alignedSize); } #endif /* Fast path cause destination buffer is correctly aligned */ if (BSP_SD_WriteBlocks_DMA((uint32_t*)buff, (uint32_t)(sector), count) == MSD_OK) { #if (osCMSIS < 0x20000U) /* wait for a message from the queue or a timeout */ event = osMessageGet(SDQueueID, SD_TIMEOUT); if ((event.status == osEventMessage) && (event.value.v == WRITE_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 == WRITE_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; break; } } } } #endif /* !defined(FORCE_SCRATCH_BUFFER) */ #if defined(ENABLE_SCRATCH_BUFFER) #if !defined(FORCE_SCRATCH_BUFFER) } else { #endif /* !defined(FORCE_SCRATCH_BUFFER) */ /* Slow path, fetch each sector a part and memcpy to destination buffer */ int32_t ret = MSD_OK; int i; for (i = 0; i < count; i++) { memcpy((void *)scratch, buff, BLOCKSIZE); buff += BLOCKSIZE; #if defined(ENABLE_SD_DMA_CACHE_MAINTENANCE) /* additional check if data cache is enabled indeed */ if (SCB->CCR & SCB_CCR_DC_Msk) { /* * clean the scratch buffer before the next write to get the actual data instead of the cached one */ SCB_CleanDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE); } #endif ret = BSP_SD_WriteBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1); if (ret != MSD_OK) break; /* 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) && (event.value.v == WRITE_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 == WRITE_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 ((i == count) && (ret == MSD_OK)) res = RES_OK; #if !defined(FORCE_SCRATCH_BUFFER) } #endif /* !defined(FORCE_SCRATCH_BUFFER) */ #endif return res; } #endif /* _USE_WRITE == 1 */ /* USER CODE BEGIN beforeIoctlSection */ /* can be used to modify previous code / undefine following code / add new code */ /* USER CODE END beforeIoctlSection */ /** * @brief I/O control operation * @param lun : not used * @param cmd: Control code * @param *buff: Buffer to send/receive control data * @retval DRESULT: Operation result */ #if _USE_IOCTL == 1 DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff) { DRESULT res = RES_ERROR; BSP_SD_CardInfo CardInfo; if (Stat & STA_NOINIT) return RES_NOTRDY; switch (cmd) { /* Make sure that no pending write process */ case CTRL_SYNC: res = RES_OK; break; /* Get number of sectors on the disk (DWORD) */ case GET_SECTOR_COUNT: BSP_SD_GetCardInfo(&CardInfo); *(DWORD*)buff = CardInfo.LogBlockNbr; res = RES_OK; break; /* Get R/W sector size (WORD) */ case GET_SECTOR_SIZE: BSP_SD_GetCardInfo(&CardInfo); *(WORD*)buff = CardInfo.LogBlockSize; res = RES_OK; break; /* Get erase block size in unit of sector (DWORD) */ case GET_BLOCK_SIZE: BSP_SD_GetCardInfo(&CardInfo); *(DWORD*)buff = CardInfo.LogBlockSize / SD_DEFAULT_BLOCK_SIZE; res = RES_OK; break; default: res = RES_PARERR; } return res; } #endif /* _USE_IOCTL == 1 */ /* USER CODE BEGIN afterIoctlSection */ /* can be used to modify previous code / undefine following code / add new code */ /* USER CODE END afterIoctlSection */ /* USER CODE BEGIN callbackSection */ /* can be used to modify / following code or add new code */ /* USER CODE END callbackSection */ /** * @brief Tx Transfer completed callbacks * @param hsd: SD handle * @retval None */ void BSP_SD_WriteCpltCallback(void) { /* * No need to add an "osKernelRunning()" check here, as the SD_initialize() * is always called before any SD_Read()/SD_Write() call */ #if (osCMSIS < 0x20000U) osMessagePut(SDQueueID, WRITE_CPLT_MSG, 0); #else const uint16_t msg = WRITE_CPLT_MSG; osMessageQueuePut(SDQueueID, (const void *)&msg, NULL, 0); #endif } /** * @brief Rx Transfer completed callbacks * @param hsd: SD handle * @retval None */ void BSP_SD_ReadCpltCallback(void) { /* * No need to add an "osKernelRunning()" check here, as the SD_initialize() * is always called before any SD_Read()/SD_Write() call */ #if (osCMSIS < 0x20000U) osMessagePut(SDQueueID, READ_CPLT_MSG, 0); #else const uint16_t msg = READ_CPLT_MSG; osMessageQueuePut(SDQueueID, (const void *)&msg, NULL, 0); #endif } /* USER CODE BEGIN ErrorAbortCallbacks */ /* void BSP_SD_AbortCallback(void) { #if (osCMSIS < 0x20000U) osMessagePut(SDQueueID, RW_ABORT_MSG, 0); #else const uint16_t msg = RW_ABORT_MSG; osMessageQueuePut(SDQueueID, (const void *)&msg, NULL, 0); #endif } */ /* USER CODE END ErrorAbortCallbacks */ /* USER CODE BEGIN lastSection */ /* can be used to modify / undefine previous code or add new code */ /* USER CODE END lastSection */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/