in portable/STM32F4xx/stm32f4xx_hal_sd.c [679:912]
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks( SD_HandleTypeDef * hsd,
uint32_t * pWriteBuffer,
uint64_t WriteAddr,
uint32_t BlockSize,
uint32_t NumberOfBlocks )
{
SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
/*SDIO_DataInitTypeDef sdmmc_datainitstructure; */
HAL_SD_ErrorTypedef errorstate = SD_OK;
uint32_t totalnumberofbytes, bytesRemaining;
uint32_t tmpreg;
uint32_t last_sta;
uint32_t * tempbuff = ( uint32_t * ) pWriteBuffer;
uint8_t cardstate = 0;
__IO uint32_t * pulFIFO = &( hsd->Instance->FIFO );
uint32_t ulEndFags;
uint32_t ulHasHWFlowControl;
/* Initialize data control register */
hsd->Instance->DCTRL = 0;
if( hsd->CardType == HIGH_CAPACITY_SD_CARD )
{
BlockSize = 512;
WriteAddr /= 512;
}
/* Set Block Size for Card */
sdmmc_cmdinitstructure.Argument = ( uint32_t ) BlockSize;
sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN;
sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );
/* Check for error conditions */
errorstate = SD_CmdResp1Error( hsd, SD_CMD_SET_BLOCKLEN );
if( errorstate != SD_OK )
{
return errorstate;
}
if( NumberOfBlocks > 1 )
{
/* Send CMD25 WRITE_MULT_BLOCK with argument data address */
sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_MULT_BLOCK;
/* Test for DATAEND : Data end (data counter, SDID count) is zero) */
ulEndFags = SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_FLAG_STBITERR;
}
else
{
/* Send CMD24 WRITE_SINGLE_BLOCK */
sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK;
/* Test for DBCKEND : Data Block Sent/Received (CRC check passed) */
ulEndFags = SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR;
}
ulEndFags |= SDIO_FLAG_TXUNDERR;
sdmmc_cmdinitstructure.Argument = ( uint32_t ) WriteAddr;
SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );
/* Check for error conditions */
errorstate = SD_CmdResp1Error( hsd, sdmmc_cmdinitstructure.CmdIndex );
if( errorstate != SD_OK )
{
return errorstate;
}
ulHasHWFlowControl = ( hsd->Instance->CLKCR & SDIO_HARDWARE_FLOW_CONTROL_ENABLE ) != 0;
/* Set total number of bytes to write */
totalnumberofbytes = NumberOfBlocks * BlockSize;
bytesRemaining = 4 * ( ( totalnumberofbytes + 3 ) / 4 );
/* Configure the SD DPSM (Data Path State Machine) */
/*
* sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT;
* sdmmc_datainitstructure.DataLength = NumberOfBlocks * BlockSize;
* sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
* sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_CARD;
* sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
* sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE;
* SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure);
*/
/* Set the SDIO Data Timeout value */
hsd->Instance->DTIMER = SD_DATATIMEOUT;
/* Set the SDIO DataLength value */
hsd->Instance->DLEN = NumberOfBlocks * BlockSize;
tmpreg = hsd->Instance->DCTRL & ~( DCTRL_CLEAR_MASK );
/* Set the SDIO data configuration parameters */
tmpreg |= ( uint32_t ) ( SDIO_DATABLOCK_SIZE_512B | SDIO_TRANSFER_DIR_TO_CARD | SDIO_TRANSFER_MODE_BLOCK | SDIO_DCTRL_DTEN );
/* Write to SDIO DCTRL */
hsd->Instance->DCTRL = tmpreg;
for( ; ; )
{
last_sta = hsd->Instance->STA;
if( ( last_sta & ( SDIO_FLAG_TXFIFOHE | SDIO_FLAG_TXFIFOE ) ) != 0 )
{
/* SDIO_FLAG_TXFIFOHE: Transmit FIFO Half Empty
* May write 32 bytes. */
if( bytesRemaining < 32 )
{
/* Write data to SDIO Tx FIFO */
while( bytesRemaining > 0 )
{
*pulFIFO = *( tempbuff++ );
bytesRemaining -= 4;
}
}
else
{
/* Write data to SDIO Tx FIFO */
*pulFIFO = tempbuff[ 0 ];
*pulFIFO = tempbuff[ 1 ];
*pulFIFO = tempbuff[ 2 ];
*pulFIFO = tempbuff[ 3 ];
*pulFIFO = tempbuff[ 4 ];
*pulFIFO = tempbuff[ 5 ];
*pulFIFO = tempbuff[ 6 ];
*pulFIFO = tempbuff[ 7 ];
tempbuff += 8;
bytesRemaining -= 32;
if( ( last_sta & SDIO_FLAG_TXFIFOE ) != 0 )
{
/* SDIO_FLAG_TXFIFOE: Transmit FIFO empty
* May write 24 or 32 extra bytes, depending on
* ulHasHWFlowControl. */
*pulFIFO = tempbuff[ 0 ];
*pulFIFO = tempbuff[ 1 ];
*pulFIFO = tempbuff[ 2 ];
*pulFIFO = tempbuff[ 3 ];
*pulFIFO = tempbuff[ 4 ];
*pulFIFO = tempbuff[ 5 ];
if( ulHasHWFlowControl != 0 )
{
tempbuff += 6;
bytesRemaining -= 24;
}
else
{
*pulFIFO = tempbuff[ 6 ];
*pulFIFO = tempbuff[ 7 ];
tempbuff += 8;
bytesRemaining -= 32;
}
}
}
}
if( ( last_sta & ulEndFags ) != 0 )
{
break;
}
}
if( ( ( last_sta & SDIO_FLAG_TXUNDERR ) != 0 ) || ( bytesRemaining != 0 ) )
{
FF_PRINTF( "TX underflow %lu < %lu\n", bytesRemaining, totalnumberofbytes );
}
/* Send stop transmission command in case of multiblock write */
if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DATAEND ) && ( NumberOfBlocks > 1 ) )
{
if( ( hsd->CardType == STD_CAPACITY_SD_CARD_V1_1 ) || ( hsd->CardType == STD_CAPACITY_SD_CARD_V2_0 ) || \
( hsd->CardType == HIGH_CAPACITY_SD_CARD ) )
{
/* Send stop transmission command */
errorstate = HAL_SD_StopTransfer( hsd );
}
}
/* Get error state */
if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DTIMEOUT ) )
{
__HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DTIMEOUT );
errorstate = SD_DATA_TIMEOUT;
return errorstate;
}
else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DCRCFAIL ) )
{
__HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DCRCFAIL );
errorstate = SD_DATA_CRC_FAIL;
return errorstate;
}
else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_TXUNDERR ) )
{
__HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_TXUNDERR );
errorstate = SD_TX_UNDERRUN;
return errorstate;
}
else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_STBITERR ) )
{
__HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_STBITERR );
errorstate = SD_START_BIT_ERR;
return errorstate;
}
else
{
/* No error flag set */
}
/* Clear all the static flags */
__HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );
/* Wait till the card is in programming state */
do
{
errorstate = SD_IsCardProgramming( hsd, &cardstate );
} while( ( errorstate == SD_OK ) && ( ( cardstate == SD_CARD_PROGRAMMING ) || ( cardstate == SD_CARD_RECEIVING ) ) );
return errorstate;
}