Search code examples
csd-cardxilinxvivado

initializing and using SD card after migration from vivado 2015.2 to 2016.4 does not work


--------------- EDIT: Additional Note -----------------------------------------

We just tried only migrating to Vivado 2016.1. With that version the SD card is working with the new functions, even if it destroys the audio codec somehow. Which is pretty interesting because we looked up every patch note from 2015.2 to 2016.4 and the only thing mentioned is that they added an additional data type for sd card I/O whoch is taken out again in the next version.

----------------END EDIT--------------------------------------------------------

We just migrated our robot project from vivado 2015.2 to 2016.4, after the upgrade the sd image is flashed when the fpga (zynq 7020) ist started but the processor code will not be executed. After some debugging we found out, that we have to create a new SDK project with new FSBL and BSP and include the source files with an new empty application. After this the program got stuck in a loop so we had to debug further. We then found out we had to replace our actual SD card functions ( those recommended in TRM UG585 ) with our old ones.

New SD functions:

        void readBlock(unsigned char sd_id, unsigned int sector, unsigned int* buf){
            unsigned int baseaddress = sd_id == 0 ? SD0_BASEADDRESS : SD1_BASEADDRESS;                          //        Choose baseaddress based on the desired SD-slot
                                                                                                                //        START
            TO_REG(baseaddress + SD_BLOCK_SIZE_REG_OFFSET) = SD_BLOCKCOUNT1_BLOCKSIZE512;                       // (1)    Set Block Size Reg -> 512 Bytes, (2) Set Block Count Reg -> 1 Block
            TO_REG(baseaddress + SD_ARGUMENT_REG_OFFSET) = sector;                                              // (3)    Set Argument Reg -> Readaddress
            TO_REG(baseaddress + SD_TRANSFER_MODE_COMMAND_REG_OFFSET) = SD_SINGLEBLOCK_READ;                    // (4/5)  Set Transfer Mode / Command Reg -> CMD17, Normal, Data Present, Enable Index-Check, Enable CRC-Check, Response length 48, Single Block, Read, Disable Auto CMD12, Disable Block Count, Disable DMA

                while(!SD_CMD_COMPLETE_INTERRUPT(baseaddress));                                                     // (6)    Wait for Command Complete Interrupt
                TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_CMD_COMPLETE_MASK;       // (7)    Clear Command Complete Status
        // (8)    Get Response Data -> ignored, maybe checked for errors and retry                                                                                                  
        // (9)    Write or Read -> Read

        while(!SD_BUFFER_READ_RDY_INTERRUPT(baseaddress));                                                  // (10-R) Wait for Buffer Read Ready Interrupt
        TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_BUFFER_READ_RDY_MASK;    // (11-R) Clear Buffer Read Ready Status

        for(unsigned char i = 0; i< 128; i++)                                                               // (12-R) Get Block Data
            buf[i] = TO_REG(baseaddress + SD_BUFFER_DATA_PORT_REG_OFFSET);
    // (13-R) More Blocks? -> No
                                                                                                            // (14)   Single/Multi/Infinite Block Transfer? -> Single

    while(!SD_TRANSFER_COMPLETE_INTERRUPT(baseaddress));                                                // (15)   Wait for Transfer Complete Interrupt
        TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_TRANSFER_COMPLETE_MASK;  // (16)   Clear Transfer Complete Status
                                                                                                            //        END
    }

    void writeBlock(unsigned char sd_id, unsigned int sector, unsigned int* buf){
        unsigned int baseaddress = sd_id == 0 ? SD0_BASEADDRESS : SD1_BASEADDRESS;                          //        Choose baseaddress based on the desired SD-slot
                                                                                                            //        START
        TO_REG(baseaddress + SD_BLOCK_SIZE_REG_OFFSET) = SD_BLOCKCOUNT1_BLOCKSIZE512;                       // (1)    Set Block Size Reg -> 512 Bytes, (2) Set Block Count Reg -> 1 Block
        TO_REG(baseaddress + SD_ARGUMENT_REG_OFFSET) = sector;                                              // (3)    Set Argument Reg -> Readaddress
        TO_REG(baseaddress + SD_TRANSFER_MODE_COMMAND_REG_OFFSET) = SD_SINGLEBLOCK_WRITE;                   // (4/5)  Set Transfer Mode / Command Reg -> CMD24, Normal, Data Present, Enable Index-Check, Enable CRC-Check, Response length 48, Single Block, Write, Disable Auto CMD12, Disable Block Count, Disable DMA

        while(!SD_CMD_COMPLETE_INTERRUPT(baseaddress));                                                     // (6)    Wait for Command Complete Interrupt
        TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_CMD_COMPLETE_MASK;       // (7)    Clear Command Complete 

    Status
        // (8)    Get Response Data -> ignored, maybe checked for errors and retry                                                                                                          
    // (9)    Write or Read -> Write

        while(!SD_BUFFER_WRITE_RDY_INTERRUPT(baseaddress));                                                 // (10-W) Wait for Buffer Write Ready Interrupt
        TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_BUFFER_WRITE_RDY_MASK;   // (11-W) Clear Buffer Write Ready Status

        for(unsigned char i = 0; i< 128; i++)                                                               // (12-W) Set Block Data
            TO_REG(baseaddress + SD_BUFFER_DATA_PORT_REG_OFFSET) = buf[i];
    // (13-W) More Blocks? -> No
                                                                                                            // (14)   Single/Multi/Infinite Block Transfer? -> Single

    while(!SD_TRANSFER_COMPLETE_INTERRUPT(baseaddress));                                                // (15)   Wait for Transfer Complete Interrupt
        TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_TRANSFER_COMPLETE_MASK;  // (16)   Clear Transfer Complete Status
                                                                                                            //        END
    }

Old SD functiony:

DRESULT readBlock(unsigned char sd_id, unsigned long sector, unsigned char* buff){

    unsigned int count = 1;

        if(sd_id > 1) return RES_ERROR; //only id = 0 or id = 1 is valid

        s32 Status;
        DWORD LocSector = sector;

        /* Convert LBA to byte address if needed */
        if ((SdInstance[sd_id].HCS) == 0U) {
            LocSector *= (DWORD)XSDPS_BLK_SIZE_512_MASK;
        }

        Status = XSdPs_ReadPolled(&SdInstance[sd_id], (u32)LocSector, count,(unsigned char *) buff);
        if (Status != XST_SUCCESS) {
            return RES_ERROR;
        }

        return RES_OK;
}


DRESULT writeBlock(unsigned char sd_id, unsigned long sector, unsigned char* buff){

        unsigned int count = 1;
        if(sd_id > 1) return RES_ERROR; //only id = 0 or id = 1 is valid

        s32 Status;
        DWORD LocSector = sector;

        /* Convert LBA to byte address if needed */
        if ((SdInstance[sd_id].HCS) == 0U) {
            LocSector *= (DWORD)XSDPS_BLK_SIZE_512_MASK;
        }

        Status  = XSdPs_WritePolled(&SdInstance[sd_id], (u32)LocSector, count,buff);
        if (Status != XST_SUCCESS) {
            return RES_ERROR;
        }

        return RES_OK;
    }

This fixed the problem with the processor code in general but we are still not able to initialize or do IO operations on the SD card. Additionally we found out that when initializing the SD the function getBusWidth (bsp) failes when it tries to call XSdPs_CmdTransfer() -> XSdPs_ReadReg(). Which also seems to be the case when we try to do IO ops on the SD card with our old functions.

SD init function:

unsigned char initSD(unsigned char sd_id){

    if(sd_id > 1) return 0xFF; //only id = 0 or id = 1 is valid

    DSTATUS s = 0;
    s32 Status;
    u8 SCR[8] = {0U};
    u8 ReadBuff[64] = {0U};

    XSdPs_Config *SdConfig = NULL;

    /*
     * Initialize the host controller
     */
    SdConfig = &XSdPs_ConfigTable[sd_id];

    Status = XSdPs_CfgInitialize(&SdInstance[sd_id], SdConfig, SdConfig->BaseAddress);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }

    Status = XSdPs_SdCardInitialize(&SdInstance[sd_id]);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }

    Status = XSdPs_Change_ClkFreq(&SdInstance[sd_id], SD_CLK_25_MHZ);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }

    Status = XSdPs_Select_Card(&SdInstance[sd_id]);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }

    Status = XSdPs_Get_BusWidth(&SdInstance[sd_id], SCR);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }

    Status = XSdPs_Get_BusSpeed(&SdInstance[sd_id], ReadBuff);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }

    if((ReadBuff[13] & HIGH_SPEED_SUPPORT) != 0U){
        Status = XSdPs_Change_BusSpeed(&SdInstance[sd_id]);
        if (Status != XST_SUCCESS) {
            s |= STA_NOINIT;
            return s;
        }
    }

    Status = XSdPs_Pullup(&SdInstance[sd_id]);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }

    if ((SCR[1] & WIDTH_4_BIT_SUPPORT) != 0U) {
        Status = XSdPs_Change_BusWidth(&SdInstance[sd_id]);
        if (Status != XST_SUCCESS) {
            s |= STA_NOINIT;
            return s;
        }
    }

    Status = XSdPs_SetBlkSize(&SdInstance[sd_id], (u16)XSDPS_BLK_SIZE_512_MASK);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }

After this quite short description of our problem ;), now to my question. Has anyone of you encountered a similar problem and knows a workaround or can point us in a direction where we may find a solution?

Thanks in advance :).

Delet0r


Solution

  • So it worked before, which means your SD configuration seems to be right.

    Have you tried the build in XSdPs_CardInitialize(...) function, instead of your customized initSD(...) function? The XSdPs_CardInitialize(...) is inside the xsdps.c of your sdps driver. This function is doing a lot more checks and also a few things in different order, as you are in your initSD(...).

    So try this one:

    unsigned char initSD(unsigned char sd_id){
    
    if(sd_id > 1) return 0xFF; //only id = 0 or id = 1 is valid
    
    DSTATUS s = 0;
    s32 Status;
    
    XSdPs_Config *SdConfig = NULL;
    
    /*
     * Initialize the host controller
     */
    SdConfig = &XSdPs_ConfigTable[sd_id];
    
    Status = XSdPs_CfgInitialize(&SdInstance[sd_id], SdConfig, SdConfig->BaseAddress);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }
    
    Status = XSdPs_CardInitialize(&SdInstance[sd_id]);
    if (Status != XST_SUCCESS) {
        s |= STA_NOINIT;
        return s;
    }
    
    return Status;
    }