This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Writing SD card with UDMA

Other Parts Discussed in Thread: CC3200

Hello
I am trying to write data to SD card using DMA on CC3200. I have been using this https://e2e.ti.com/support/wireless_connectivity/simplelink_wifi_cc31xx_cc32xx/f/968/t/394899 forum thread describing DMA reads as reference. I am new to both UDMA and SD so maybe I am missing something obvious.

Basically I have just changed read cmd to CMD_WRITE_MULTI_BLK, RX channel to TX channel and order of buffers.
Write operations seems to complete correctly, but only part of target block is written with data (only last 128 bytes of 512 are written)
So here are my questions:

1) How the  udma transfer should be setup for performing writes/multi block writes

2) How many SDHOST_INT_DMAWR interrupts should I get ?
    -> is it one DMAWR interrupt for whole transfer or one DMAWR for each group of transfers defined by arbitration size
    -> how to setup transfer to actually write multiply blocks (read example also reads just one block with arb size = 1)
    
3) Do you have any helpfull links/examples that may be usefull when working with UDMA and SDHost

Here is the code I have been using:

static void SDIntDmaWriteHndl()
{
	unsigned long ulStatus;

	ulStatus = SDHostIntStatus(SDHOST_BASE);
	
	SDHostIntClear(SDHOST_BASE, 0xffffffff);

	if (ulStatus & SDHOST_INT_DMAWR)
	{
		g_ucSDUdmaWriteCompleted++;
	}
}

unsigned long  SDDmaWriteTest()
{
    unsigned long ulItemsCount = 0;
    unsigned long ulBlockNo = 0;
	
	SDHostIntRegister(SDHOST_BASE, SDIntDmaWriteHndl);
	SDHostIntDisable(SDHOST_BASE, 0xFFFFFFFF);
	SDHostIntEnable(SDHOST_BASE, SDHOST_INT_DMAWR);

    if(g_sdCard.ulCapClass == CARD_CAP_CLASS_SDSC)
    {
    	ulBlockNo = ulBlockNo * 512;
    }

    memset(g_ucSdBuffer, 'a', SD_BLOCK_SIZE);

    SDHostBlockSizeSet(SDHOST_BASE, SD_BLOCK_SIZE);
	SDHostBlockCountSet(SDHOST_BASE, 1);

	SDHostIntClear(SDHOST_BASE,0xFFFFFFFF);

	ulItemsCount = SD_BLOCK_SIZE/4;

    UDMASetupTransfer(UDMA_CH24_SDHOST_TX, UDMA_MODE_BASIC,
    		ulItemsCount, UDMA_SIZE_32,
			UDMA_ARB_1,
			(void *) g_ucSdBuffer, UDMA_SIZE_32,
			(void *)(SDHOST_BASE + MMCHS_O_DATA), UDMA_DST_INC_NONE
			);

    g_ucSDUdmaWriteCompleted = 0;

    if (SDHostCmdSend(SDHOST_BASE, CMD_WRITE_MULTI_BLK|SDHOST_DMA_EN, ulBlockNo) != 0)
    {
    	Report("[SDDmaWrite] SDHostCmdSend failed \n\r");
    	return 1;
    }

    while (g_ucSDUdmaWriteCompleted == 0)
    {
    }

    SDHostCmdSend(SDHOST_BASE, CMD_STOP_TRANS, 0);
	
	return 0;
}


After reading data from block 0, I am gettin following

0000 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0014 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0028 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
003c :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0050 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0064 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0078 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
008c :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00a0 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00b4 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00c8 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00dc :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00f0 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0104 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0118 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
012c :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0140 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0154 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0168 :00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
017c :00 00 00 00 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
0190 :61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
01a4 :61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
01b8 :61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
01cc :61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
01e0 :61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
01f4 :61 61 61 61 61 61 61 61 61 61 61 61

Thanks in advance,

Andrzej

  • Andrzej,

    Apologies for the delayed response - I completely missed this thread.
    Could you make it work? Let me know if you still need help w/ this.!

    -/Praneet
  • Hi Prannet

    We weren't able  to make it work. Unfortunately we were on a short deadline and could not spend more time on investigating the issue. We had to stay with standard block read/writes. If you could provide some insights what is going it would be really helpful.

    Thanks in advance

    Andrzej

  • Andrzej,

    Please find attached the modified 'main.c' file of 'sdhost' example of SDKv1.1.0. I've enabled DMA both for read and write - Please take references from the same.

    -/Praneet

    8306.main.c
    //*****************************************************************************
    //
    // Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
    //
    //
    //  Redistribution and use in source and binary forms, with or without
    //  modification, are permitted provided that the following conditions
    //  are met:
    //
    //    Redistributions of source code must retain the above copyright
    //    notice, this list of conditions and the following disclaimer.
    //
    //    Redistributions in binary form must reproduce the above copyright
    //    notice, this list of conditions and the following disclaimer in the
    //    documentation and/or other materials provided with the
    //    distribution.
    //
    //    Neither the name of Texas Instruments Incorporated nor the names of
    //    its contributors may be used to endorse or promote products derived
    //    from this software without specific prior written permission.
    //
    //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    //  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    //  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    //  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    //  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    //  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    //  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    //  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    //  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    //  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    //  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Application Name     - SDHost
    // Application Overview - This application showcases the basic use case of
    //                        initializing the controller to communicate with the
    //                        attached card, reading and writing SD card block using
    //                        the internal controller buffer via DriverLib API(s).
    //                        The demo includes extracting the card capacity,
    //                        capacity class and SD version information and display
    //                        it on the UART terminal.
    // Application Details  -
    // http://processors.wiki.ti.com/index.php/CC32xx_SDHost
    // or
    // docs\examples\CC32xx_SDHost.pdf
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    //! \addtogroup SDHost
    //! @{
    //
    //*****************************************************************************
    
    // Driverlib includes
    #include "hw_common_reg.h"
    #include "hw_types.h"
    #include "hw_memmap.h"
    #include "hw_ints.h"
    #include "sdhost.h"
    #include "rom.h"
    #include "rom_map.h"
    #include "prcm.h"
    #include "pin.h"
    #include "interrupt.h"
    
    #include "hw_mmchs.h"
    #include "udma.h"
    #include "udma_if.h"
    
    // Common interface includes
    #include "uart_if.h"
    
    #include "sdhost_demo.h"
    #include "utils.h"
    #include "pinmux.h"
    #include "stdcmd.h"
    
    #define APPLICATION_VERSION  "1.1.1"
    #define WRITE_TEST_EN        1
    
    #if WRITE_TEST_EN
    #warning Enabling WRITE_TEST_EN will corrupt the existing filesystem on the card
    #endif
    
    #define CARD_BLK_SIZE_IN_BYTES 512
    
    //*****************************************************************************
    //                 GLOBAL VARIABLES -- Start
    //*****************************************************************************
    static unsigned char g_ucDataBuff[512];
    static tBoolean bTransferDone;
    static tBoolean bIsRead;
    static unsigned long ulNofBlocks;
    static unsigned long *pulNxtBuff;
    
    
    #if defined(ccs)
    extern void (* const g_pfnVectors[])(void);
    #endif
    #if defined(ewarm)
    extern uVectorEntry __vector_table;
    #endif
    //*****************************************************************************
    //                 GLOBAL VARIABLES -- End
    //*****************************************************************************
    
    //!
    void SDHostIntHandler()
    {
        //
        // Reduce the number of sectors remaining
        //
        ulNofBlocks = ulNofBlocks - 1;
    
        //
        // Clear the interrupt handler
        //
        MAP_SDHostIntClear(SDHOST_BASE, SDHOST_INT_DMARD|SDHOST_INT_DMAWR);
    
        //
        // Check if all sectors are transfered.
        //
        if( 0 != ulNofBlocks)
        {
            if(true == bIsRead)
            {
                if( UDMA_MODE_STOP == MAP_uDMAChannelModeGet(UDMA_CH23_SDHOST_RX))
                {
                    //
                    // Configure the udma for a transfer
                    //
                    UDMASetupTransfer(UDMA_CH23_SDHOST_RX, UDMA_MODE_PINGPONG,
                                      CARD_BLK_SIZE_IN_BYTES/4, UDMA_SIZE_32,
                                      UDMA_ARB_512, (void *)(SDHOST_BASE + MMCHS_O_DATA),
                                      UDMA_SRC_INC_NONE, pulNxtBuff, UDMA_DST_INC_32);
    
                }
                else
                {
                    //
                    // Configure the udma for a transfer
                    //
                    UDMASetupTransfer(UDMA_CH23_SDHOST_RX|UDMA_ALT_SELECT, UDMA_MODE_PINGPONG,
                                      CARD_BLK_SIZE_IN_BYTES/4, UDMA_SIZE_32,
                                      UDMA_ARB_512, (void *)(SDHOST_BASE + MMCHS_O_DATA),
                                      UDMA_SRC_INC_NONE, pulNxtBuff, UDMA_DST_INC_32);
                }
            }
            else
            {
                if( UDMA_MODE_STOP == MAP_uDMAChannelModeGet(UDMA_CH24_SDHOST_TX))
                {
                    //
                    // Configure the udma for a transfer
                    //
                    UDMASetupTransfer(UDMA_CH24_SDHOST_TX, UDMA_MODE_PINGPONG,
                                      CARD_BLK_SIZE_IN_BYTES/4, UDMA_SIZE_32,
                                      UDMA_ARB_512, pulNxtBuff, UDMA_SRC_INC_32,
                                      (void *)(SDHOST_BASE + MMCHS_O_DATA), UDMA_DST_INC_NONE);
    
                }
                else
                {
                    //
                    // Configure the udma for a transfer
                    //
                    UDMASetupTransfer(UDMA_CH24_SDHOST_TX|UDMA_ALT_SELECT, UDMA_MODE_PINGPONG,
                                      CARD_BLK_SIZE_IN_BYTES/4, UDMA_SIZE_32,
                                      UDMA_ARB_512, pulNxtBuff, UDMA_SRC_INC_32,
                                      (void *)(SDHOST_BASE + MMCHS_O_DATA), UDMA_DST_INC_NONE);
                }
            }
    
            //
            // Set the next buffer pointer
            //
            pulNxtBuff = pulNxtBuff + CARD_BLK_SIZE_IN_BYTES/4;
        }
        else
        {
            //
            // reset uDMA pointer to primary channel
            //
            MAP_uDMAChannelAttributeDisable(UDMA_CH24_SDHOST_TX,UDMA_ATTR_ALTSELECT);
            MAP_uDMAChannelAttributeDisable(UDMA_CH23_SDHOST_RX,UDMA_ATTR_ALTSELECT);
    
            //
            // Indicate transfer complete
            //
            bTransferDone = true;
        }
    }
    
    //*****************************************************************************
    //
    //! Send Command to card
    //!
    //! \param ulCmd is the command to be send
    //! \paran ulArg is the command argument
    //!
    //! This function sends command to attached card and check the response status
    //! if any.
    //!
    //! \return Returns 0 on success, 1 otherwise
    //
    //*****************************************************************************
    static unsigned long
    SendCmd(unsigned long ulCmd, unsigned long ulArg)
    {
        unsigned long ulStatus;
    
        //
        // Clear interrupt status
        //
        MAP_SDHostIntClear(SDHOST_BASE,0xFFFFFFFF);
    
        //
        // Send command
        //
        MAP_SDHostCmdSend(SDHOST_BASE,ulCmd,ulArg);
    
        //
        // Wait for command complete or error
        //
        do{
            ulStatus = MAP_SDHostIntStatus(SDHOST_BASE);
            ulStatus = (ulStatus & (SDHOST_INT_CC|SDHOST_INT_ERRI));
        }while( !ulStatus );
    
        //
        // Check error status
        //
        if(ulStatus & SDHOST_INT_ERRI)
        {
            //
            // Reset the command line
            //
            MAP_SDHostCmdReset(SDHOST_BASE);
            return 1;
        }
        else
        {
            return 0;
        }
    }
    
    //*****************************************************************************
    //
    //! Get the capacity of specified card
    //!
    //! \param ulRCA is the Relative Card Address (RCA)
    //!
    //! This function gets the capacity of card addressed by \e ulRCA paramaeter.
    //!
    //! \return Returns card capacity on success, 0 otherwise.
    //
    //*****************************************************************************
    static unsigned long long
    CardCapacityGet(unsigned short ulRCA)
    {
        unsigned long ulRet;
        unsigned long ulResp[4];
        unsigned long long ullCapacity;
        unsigned long ulBlockSize;
        unsigned long ulBlockCount;
        unsigned long ulCSizeMult;
        unsigned long ulCSize;
    
        //
        // Read the CSD register
        //
        ulRet = SendCmd(CMD_SEND_CSD,(ulRCA << 16));
        if(ulRet == 0)
        {
            //
            // Read the response
            //
            MAP_SDHostRespGet(SDHOST_BASE, ulResp);
        }
        else
        {
            return 0;
        }
    
        //
        // 136 bit CSD register is read into an array of 4 words.
        // ulResp[0] = CSD[31:0]
        // ulResp[1] = CSD[63:32]
        // ulResp[2] = CSD[95:64]
        // ulResp[3] = CSD[127:96]
        //
        if( ((ulResp[3] >> 30) & 0x1) == 1)
        {
            ulBlockSize = CARD_BLK_SIZE_IN_BYTES * 1024;
            ulBlockCount = (ulResp[1] >> 16 | ((ulResp[2] & 0x3F) << 16)) + 1;
        }
        else
        {
            ulBlockSize  = 1 << ((ulResp[2] >> 16) & 0xF);
            ulCSizeMult  = ((ulResp[1] >> 15) & 0x7);
            ulCSize      = ((ulResp[1] >> 30) | (ulResp[2] & 0x3FF) << 2);
            ulBlockCount = (ulCSize + 1) * (1<<(ulCSizeMult + 2));
        }
    
        //
        // Calculate the card capacity in bytes
        //
        ullCapacity = (unsigned long long)ulBlockSize * (ulBlockCount );
    
        //
        // Return the capacity
        //
        return ullCapacity;
    }
    
    //*****************************************************************************
    //
    //! Initializes the card and fills the card attribute structure.
    //!
    //! \param CardAttrib is the pointer to card attribute structure.
    //!
    //! This function initializes the card and fills in the card attribute
    //! structure.
    //!
    //! \return Returns 0 success, 1 otherwise.
    //
    //*****************************************************************************
    static unsigned long
    CardInit(CardAttrib_t *CardAttrib)
    {
        unsigned long ulRet;
        unsigned long ulResp[4];
    
        //
        // Initialize the attributes.
        //
        CardAttrib->ulCardType = CARD_TYPE_UNKNOWN;
        CardAttrib->ulCapClass = CARD_CAP_CLASS_SDSC;
        CardAttrib->ulRCA      = 0;
        CardAttrib->ulVersion  = CARD_VERSION_1;
    
        //
        // Send std GO IDLE command
        //
        if( SendCmd(CMD_GO_IDLE_STATE, 0) == 0)
        {
    
            ulRet = SendCmd(CMD_SEND_IF_COND,0x00000100);
    
            //
            // It's a SD ver 2.0 or higher card
            //
            if(ulRet == 0)
            {
                CardAttrib->ulVersion = CARD_VERSION_2;
                CardAttrib->ulCardType = CARD_TYPE_SDCARD;
    
                //
                // Wait for card to become ready.
                //
                do
                {
                    //
                    // Send ACMD41
                    //
                    SendCmd(CMD_APP_CMD,0);
                    ulRet = SendCmd(CMD_SD_SEND_OP_COND,0x40E00000);
    
                    //
                    // Response contains 32-bit OCR register
                    //
                    MAP_SDHostRespGet(SDHOST_BASE,ulResp);
    
                }while(((ulResp[0] >> 31) == 0));
    
                if(ulResp[0] & (1UL<<30))
                {
                CardAttrib->ulCapClass = CARD_CAP_CLASS_SDHC;
                }
    
            }
            else //It's a MMC or SD 1.x card
            {
    
                //
                // Wait for card to become ready.
                //
                do
                {
                    if( (ulRet = SendCmd(CMD_APP_CMD,0)) == 0 )
                    {
                        ulRet = SendCmd(CMD_SD_SEND_OP_COND,0x00E00000);
    
                        //
                        // Response contains 32-bit OCR register
                        //
                        MAP_SDHostRespGet(SDHOST_BASE,ulResp);
                    }
                }while((ulRet == 0) && ((ulResp[0] >> 31) == 0));
    
                //
                // Check the response
                //
                if(ulRet == 0)
                {
                    CardAttrib->ulCardType = CARD_TYPE_SDCARD;
                }
                else // CMD 55 is not recognised by SDHost cards.
                {
                    //
                    // Confirm if its a SDHost card
                    //
                    ulRet = SendCmd(CMD_SEND_OP_COND,0);
                    if( ulRet == 0)
                    {
                        CardAttrib->ulCardType = CARD_TYPE_MMC;
                    }
                }
            }
        }
    
        //
        // Get the RCA of the attached card
        //
        if(ulRet == 0)
        {
            ulRet = SendCmd(CMD_ALL_SEND_CID,0);
            if( ulRet == 0)
            {
                SendCmd(CMD_SEND_REL_ADDR,0);
                MAP_SDHostRespGet(SDHOST_BASE,ulResp);
    
                //
                //  Fill in the RCA
                //
                CardAttrib->ulRCA = (ulResp[0] >> 16);
    
                //
                // Get tha card capacity
                //
                CardAttrib->ullCapacity = CardCapacityGet(CardAttrib->ulRCA);
            }
        }
    
        //
        // return status.
        //
        return ulRet;
    }
    
    //*****************************************************************************
    //
    //! Select a card for reading or writing
    //!
    //! \param Card is the pointer to card attribute structure.
    //!
    //! This function selects a card for reading or writing using its RCA from
    //! \e Card parameter.
    //!
    //! \return Returns 0 success, 1 otherwise.
    //
    //*****************************************************************************
    static unsigned long
    CardSelect(CardAttrib_t *Card)
    {
        unsigned long ulRet;
    
        //
        // Send select command with card's RCA.
        //
        ulRet = SendCmd(CMD_SELECT_CARD, (Card->ulRCA << 16));
    
        if(ulRet == 0)
        {
            while( !(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC) )
            {
    
            }
        }
    
        //
        // Delay for card to become ready
        //
        MAP_UtilsDelay(80000000/12);
    
        return ulRet;
    }
    
    //*****************************************************************************
    //
    //! Deselects previously selected card.
    //!
    //! This function deselects previously selected card.
    //!
    //! \return None.
    //
    //*****************************************************************************
    static void
    CardDeselect()
    {
        //
        // Send deselect command
        //
        SendCmd(CMD_DESELECT_CARD,0);
    }
    
    //*****************************************************************************
    //
    //! Reads a block of data.
    //!
    //! \param Card is pointer to a valid card attrib structure.
    //! \param pBuffer is pointer to the buffer to be read into.
    //! \param ulBlockNo is stating block number.
    //! \param ulBlockCount is number of block to be read.
    //!
    //! This function reads specified number of block into \e pBuffer. Each block
    //! is of 512 byte.
    //!
    //! \return Returns 0 on success, 1 otherwise.
    //
    //*****************************************************************************
    static unsigned long
    CardReadBlock(CardAttrib_t *Card, unsigned char *pBuffer,
                  unsigned long ulBlockNo, unsigned long ulBlockCount)
    {
    
        //
        // SDSC linear address instead of block address
        //
        if(Card->ulCapClass == CARD_CAP_CLASS_SDSC)
        {
            ulBlockNo = ulBlockNo * CARD_BLK_SIZE_IN_BYTES;
        }
    
        //
        // Set the number of block on the host
        //
        MAP_SDHostBlockCountSet(SDHOST_BASE,ulBlockCount);
    
        //
        // Mark as read
        //
        bIsRead = true;
    
        //
        // Setup DMA Transfer
        //
        UDMASetupTransfer(UDMA_CH23_SDHOST_RX, UDMA_MODE_PINGPONG,
                          CARD_BLK_SIZE_IN_BYTES/4, UDMA_SIZE_32,
                          UDMA_ARB_512, (void *)(SDHOST_BASE + MMCHS_O_DATA),
                          UDMA_SRC_INC_NONE, (void *)pBuffer, UDMA_DST_INC_32);
    
        UDMASetupTransfer(UDMA_CH23_SDHOST_RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG,
                          CARD_BLK_SIZE_IN_BYTES/4, UDMA_SIZE_32, UDMA_ARB_512,
                          (void *)(SDHOST_BASE + MMCHS_O_DATA), UDMA_SRC_INC_NONE,
                          (pBuffer + CARD_BLK_SIZE_IN_BYTES), UDMA_DST_INC_32);
    
        //
        // Set the next buffer pointer
        //
        pulNxtBuff = (unsigned long *)(pBuffer + (CARD_BLK_SIZE_IN_BYTES * 2));
    
        //
        // Set number of sectors;
        //
        ulNofBlocks = ulBlockCount;
    
        //
        // Set the transfer done flag to false
        //
        bTransferDone = false;
    
        //
        // Send multi block read command to the card
        //
        if( SendCmd(CMD_READ_MULTI_BLK|SDHOST_DMA_EN, ulBlockNo) == 0 )
        {
            //
            // Wait for transfer complete
            //
            do
            {
    
            }while(!bTransferDone);
    
            //
            // Send multi block read stop command to the card
            //
            SendCmd(CMD_STOP_TRANS,0);
    
            //
            // return success.
            //
            return 0;
        }
    
        //
        // Return error
        //
        return 1;
    }
    
    //*****************************************************************************
    //
    //! Write a block of data.
    //!
    //! \param Card is pointer to a valid card attrib structure.
    //! \param pBuffer is pointer to the buffer to be written
    //! \param ulBlockNo is stating block number.
    //! \param ulBlockCount is number of block to be read.
    //!
    //! This function write specified number of block into \e pBuffer. Each block
    //! is of 512 byte.
    //!
    //! \return Returns 0 on success, 1 otherwise.
    //
    //*****************************************************************************
    #if WRITE_TEST_EN
    static unsigned long
    CardWriteBlock(CardAttrib_t *Card, unsigned char *pBuffer,
                  unsigned long ulBlockNo, unsigned long ulBlockCount)
    {
        //
        // SDSC linear address instead of block address
        //
        if(Card->ulCapClass == CARD_CAP_CLASS_SDSC)
        {
            ulBlockNo = ulBlockNo * CARD_BLK_SIZE_IN_BYTES;
        }
    
        //
        // Set the number of block on the host
        //
        MAP_SDHostBlockCountSet(SDHOST_BASE,ulBlockCount);
    
    
        //
        // Setup DMA Transfer
        //
        UDMASetupTransfer(UDMA_CH24_SDHOST_TX, UDMA_MODE_PINGPONG,
                          CARD_BLK_SIZE_IN_BYTES/4, UDMA_SIZE_32, UDMA_ARB_512,
                          (void *)pBuffer, UDMA_SRC_INC_32,
                          (void *)(SDHOST_BASE + MMCHS_O_DATA), UDMA_DST_INC_NONE);
    
        UDMASetupTransfer(UDMA_CH24_SDHOST_TX|UDMA_ALT_SELECT, UDMA_MODE_PINGPONG,
                          CARD_BLK_SIZE_IN_BYTES/4, UDMA_SIZE_32, UDMA_ARB_512,
                          (void *)(pBuffer + CARD_BLK_SIZE_IN_BYTES), UDMA_SRC_INC_32,
                          (void *)(SDHOST_BASE + MMCHS_O_DATA), UDMA_DST_INC_NONE);
    
        //
        // Set the next buffer pointer
        //
        pulNxtBuff = (unsigned long *)(pBuffer + CARD_BLK_SIZE_IN_BYTES * 2);
    
        //
        // Set number of sectors;
        //
        ulNofBlocks = ulBlockCount;
    
        //
        // Set the transfer done flag to false
        //
        bTransferDone = false;
    
    
        //
        // Send multi block read command to the card
        //
        if( SendCmd(CMD_WRITE_MULTI_BLK | SDHOST_DMA_EN, ulBlockNo) == 0 )
        {
            //
            // Wait for transfer complete
            //
            do
            {
    
            }while(!bTransferDone);
    
            //
            // Wait for transfer completion.
            //
            while( !(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC) )
            {
    
            }
    
            //
            // Send multi block write stop command to the card
            //
            SendCmd(CMD_STOP_TRANS,0);
    
            //
            // return
            //
            return 0;
        }
    
        //
        // Return error
        //
        return 1;
    }
    #endif
    
    
    //*****************************************************************************
    //
    //! Board Initialization & Configuration
    //!
    //! \param  None
    //!
    //! \return None
    //
    //*****************************************************************************
    static void
    BoardInit(void)
    {
    /* In case of TI-RTOS vector table is initialize by OS itself */
    #ifndef USE_TIRTOS
      //
      // Set vector table base
      //
    #if defined(ccs)
        MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);
    #endif
    #if defined(ewarm)
        MAP_IntVTableBaseSet((unsigned long)&__vector_table);
    #endif
    #endif
        //
        // Enable Processor
        //
        MAP_IntMasterEnable();
        MAP_IntEnable(FAULT_SYSTICK);
    
        PRCMCC3200MCUInit();
    }
    
    
    //****************************************************************************
    //
    //! Main function
    //!
    //! \param none
    //!
    //! \return None.
    //
    //****************************************************************************
    int main()
    {
        CardAttrib_t sCard;
        unsigned long ulCapacity;
        unsigned long ulAddress;
    
        //
        // Initialize Board configurations
        //
        BoardInit();
    
        //
        // Muxing for Enabling UART_TX and UART_RX.
        //
        PinMuxConfig();
    
        //
        // Initializing the Terminal.
        //
        InitTerm();
    
        //
        // Clearing the Terminal.
        //
        ClearTerm();
    
        //
        // Initialize Udma
        //
        UDMAInit();
    
        //
        // Display the Banner
        //
        Message("\n\n\n\r");
        Message("\t\t   *************************************\n\r");
        Message("\t\t        CC3200 SDHost Demo Application  \n\r");
        Message("\t\t   *************************************\n\r");
        Message("\n\n\n\r");
    
        //
        // Set the SD card clock as output pin
        //
        MAP_PinDirModeSet(PIN_07,PIN_DIR_MODE_OUT);
    
        //
        // Enable Pull up on data
        //
        MAP_PinConfigSet(PIN_06,PIN_STRENGTH_4MA, PIN_TYPE_STD_PU);
    
        //
        // Enable Pull up on CMD
        //
        MAP_PinConfigSet(PIN_08,PIN_STRENGTH_4MA, PIN_TYPE_STD_PU);
    
        //
        // Enable SDHOST
        //
        MAP_PRCMPeripheralClkEnable(PRCM_SDHOST,PRCM_RUN_MODE_CLK);
    
        //
        // Reset SDHOST
        //
        MAP_PRCMPeripheralReset(PRCM_SDHOST);
    
        //
        // Configure SDHOST
        //
        MAP_SDHostInit(SDHOST_BASE);
    
        //
        // Register Interrupt
        //
        MAP_SDHostIntRegister(SDHOST_BASE, SDHostIntHandler);
    
        //
        // Interrupt Enable
        //
        MAP_SDHostIntEnable(SDHOST_BASE, SDHOST_INT_DMARD | SDHOST_INT_DMAWR);
    
        //
        // Configure card clock to 15 Mhz
        //
        MAP_SDHostSetExpClk(SDHOST_BASE, MAP_PRCMPeripheralClockGet(PRCM_SDHOST),
                                15000000);
    
        //
        // Initialize the card
        //
        if( CardInit(&sCard) )
        {
            Message("Error : Failed to initialize the card. Check "
                        "if card is properly inserted \n\r");
        }
        else
        {
            //
            // Print Card Details
            //
            ulCapacity = (sCard.ullCapacity/(1024*1024));
            Message("********************\n\r");
            Message("Card Info \n\r");
            Message("********************\n\r");
            Report("Card Type   : %s \n\r",
                        (sCard.ulCardType == CARD_TYPE_MMC)?"MMC":"SD Card");
            Report("Class       : %s \n\r",
                        (sCard.ulCapClass == CARD_CAP_CLASS_SDHC)?"SDHC":"SDSC");
            Report("Capacity    : %d MB \n\r",ulCapacity);
            Report("Version     : Ver %s \n\r",
                            (sCard.ulVersion  == CARD_VERSION_2)?"2.0":"1.0");
    
            //
            // Select the card
            //
            CardSelect(&sCard);
    
            //
            // Set the block size on the controller.
            //
            MAP_SDHostBlockSizeSet(SDHOST_BASE,CARD_BLK_SIZE_IN_BYTES);
    
            Message("\n\rReading first Block.....\n\r");
    
            //
            // Read 1 Block (512 Bytes) from the card
            //
            CardReadBlock(&sCard,g_ucDataBuff,0,1);
    
            //
            // Display the content
            //
            for(ulAddress=0; ulAddress < CARD_BLK_SIZE_IN_BYTES; ulAddress++)
            {
                if(ulAddress%20 == 0)
                {
                    Report("\n\r%0.4x :", ulAddress);
                }
                Report("%2.2x ",g_ucDataBuff[ulAddress]);
            }
    
    #if WRITE_TEST_EN
    
            Message("\n\n\rWriting first Block.....\n\n\r");
            Message("Info : This will corrupt the existing filesystem on the card\n\r");
    
            //
            // Initialize the buffer with pattern
            //
            for(ulAddress = 0; ulAddress < CARD_BLK_SIZE_IN_BYTES; ulAddress++)
            {
              g_ucDataBuff[ulAddress] = ulAddress;
            }
    
            //
            // Write 1 block (512 bytes) to the card
            //
            CardWriteBlock(&sCard,g_ucDataBuff,0,1);
    
    #endif
    
            //
            // de-select the card
            //
            CardDeselect();
        }
    
        //
        // Infinite loop;
        //
        Report("Done\n\r");
        while(1)
        {
    
        }
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************