/* 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****/