HAL_SD_ErrorTypedef HAL_SD_WriteBlocks()

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;
    }