инициализация и использование SD-карты после перехода с vivado 2015.2 на 2016.4 не работает

------------------------------ РЕДАКТИРОВАТЬ: Дополнительное примечание ----------------- ----------

Мы только что попытались перейти только на Vivado 2016.1. В этой версии SD-карта работает с новыми функциями, даже если каким-то образом разрушает аудиокодек. Что довольно интересно, потому что мы просмотрели все примечания к патчу с 2015.2 по 2016.4, и единственное, что упоминалось, это то, что они добавили дополнительный тип данных для ввода-вывода SD-карты, который снова будет удален в следующей версии.

----------------КОНЕЦ РЕДАКТИРОВАТЬ-------------------------------- ------------------------

Мы только что перенесли наш проект робота с vivado 2015.2 на 2016.4, после обновления образ SD мигает, когда запускается fpga (zynq 7020), но код процессора не будет выполняться. После некоторой отладки мы обнаружили, что нам нужно создать новый проект SDK с новыми FSBL и BSP и включить исходные файлы с новым пустым приложением. После этого программа зациклилась, и нам пришлось отлаживать дальше. Затем мы узнали, что нам пришлось заменить наши фактические функции SD-карты (те, которые рекомендованы в TRM UG585) нашими старыми.

Новые функции SD:

        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
    }

Старый функционал SD:

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

Это устранило проблему с кодом процессора в целом, но мы по-прежнему не можем инициализировать или выполнять операции ввода-вывода на SD-карте. Кроме того, мы обнаружили, что при инициализации SD функция getBusWidth (bsp) дает сбой при попытке вызвать XSdPs_CmdTransfer() -> XSdPs_ReadReg(). Это также похоже на тот случай, когда мы пытаемся выполнять операции ввода-вывода на SD-карте с нашими старыми функциями.

Функция инициализации SD:

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

После этого довольно краткого описания нашей проблемы ;), теперь к моему вопросу. Кто-нибудь из вас сталкивался с подобной проблемой и знает обходной путь или может указать нам направление, в котором мы можем найти решение?

Заранее спасибо :).

Удалить0r


person Delet0r    schedule 13.03.2017    source источник


Ответы (2)


Так что это работало раньше, что означает, что ваша конфигурация SD кажется правильной.

Пробовали ли вы сборку в функции XSdPs_CardInitialize(...) вместо настраиваемой функции initSD(...)? XSdPs_CardInitialize(...) находится внутри xsdps.c вашего драйвера sdps. Эта функция выполняет гораздо больше проверок, а также несколько вещей в другом порядке, как вы это делаете в своем initSD(...).

Итак, попробуйте этот:

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;
}
person user7815288    schedule 04.04.2017
comment
Большое спасибо :) . Как только у меня снова будет доступ к оборудованию, я попробую. - person Delet0r; 05.04.2017

Мы также попробовали его с Vivado 2016.3, который работает с SD-картами, даже если мы не знаем, почему. Мы еще не проверяли, работает ли все остальное, но пока это похоже на обходной путь.

Надеюсь, это будет исправлено в 2017.1.

person Delet0r    schedule 23.03.2017