Инициализация и использование 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;
    }

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

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

Delet0r

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

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

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

Другие вопросы по тегам