⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mci.c

📁 FreeRTOS is a portable, open source, mini Real Time Kernel - a free to download and royalty free RTO
💻 C
📖 第 1 页 / 共 2 页
字号:

    // Set PDC data transfer direction
    if(pCommand->blockSize > 0) {
        if(pCommand->isRead) {
            WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTEN);
        }
        else {
            WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_TXTEN);
        }
    }
    // Disable transmitter and receiver
    WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);

    mciMr = READ_MCI(pMciHw, MCI_MR) & (~(AT91C_MCI_BLKLEN | AT91C_MCI_PDCMODE));

    // Command with DATA stage
    if (pCommand->blockSize > 0) {
        // Enable PDC mode and set block size
        if(pCommand->conTrans != MCI_CONTINUE_TRANSFER) {

            WRITE_MCI(pMciHw, MCI_MR, mciMr | AT91C_MCI_PDCMODE | (pCommand->blockSize << 16));
        }

        // DATA transfer from card to host
        if (pCommand->isRead) { 
            WRITE_MCI(pMciHw, MCI_RPR, (int) pCommand->pData);

            // If Multiblock command set the BLKR register
            /* if (pCommand->nbBlock > 1) { 
                WRITE_MCI(pMciHw, MCI_BLKR, pCommand->nbBlock | (pCommand->blockSize << 16));
            }
            else {
                WRITE_MCI(pMciHw, MCI_BLKR, (pCommand->blockSize << 16));        		
            }*/

            // Sanity check
            if (pCommand->nbBlock == 0)
                pCommand->nbBlock = 1;
            ////////
            if ((pCommand->blockSize & 0x3) != 0) {
                WRITE_MCI(pMciHw, MCI_RCR, (pCommand->nbBlock * pCommand->blockSize) / 4 + 1);
            }
            else {
                WRITE_MCI(pMciHw, MCI_RCR, (pCommand->nbBlock * pCommand->blockSize) / 4);
            }

            WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTEN);
            mciIer = AT91C_MCI_ENDRX | STATUS_ERRORS;
            // mciIer = AT91C_MCI_RXBUFF | STATUS_ERRORS;
        }

        // DATA transfer from host to card
        else {
            // Sanity check
            if (pCommand->nbBlock == 0)
                pCommand->nbBlock = 1;
            WRITE_MCI(pMciHw, MCI_TPR, (int) pCommand->pData);
            // Update the PDC counter
            if ((pCommand->blockSize & 0x3) != 0) {
                WRITE_MCI(pMciHw, MCI_TCR, (pCommand->nbBlock * pCommand->blockSize) / 4 + 1);
            }
            else {
                WRITE_MCI(pMciHw, MCI_TCR, (pCommand->nbBlock * pCommand->blockSize) / 4);
            }
            // MCI_BLKE notifies the end of Multiblock command
            mciIer = AT91C_MCI_BLKE | STATUS_ERRORS;
        }
    }
    // No data transfer: stop at the end of the command
    else {
        WRITE_MCI(pMciHw, MCI_MR, mciMr);
        mciIer = AT91C_MCI_CMDRDY | STATUS_ERRORS;
    }
    // Enable MCI clock
    MCI_Enable(pMci, ENABLE);

    // Send the command
    if((pCommand->conTrans != MCI_CONTINUE_TRANSFER) 
        || (pCommand->blockSize == 0)) {

        WRITE_MCI(pMciHw, MCI_ARGR, pCommand->arg);
        WRITE_MCI(pMciHw, MCI_CMDR, pCommand->cmd);
    }

    // In case of transmit, the PDC shall be enabled after sending the command
    if ((pCommand->blockSize > 0) && !(pCommand->isRead)) {
        WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_TXTEN);
    }

    // Ignore data error
//    if (pCommand->blockSize == 0) {
    {
        mciIer &= ~(AT91C_MCI_UNRE | AT91C_MCI_OVRE \
            | AT91C_MCI_DTOE | AT91C_MCI_DCRCE);
    }

    // Interrupt enable shall be done after PDC TXTEN and RXTEN
    WRITE_MCI(pMciHw, MCI_IER, mciIer);

    return 0;
}

//------------------------------------------------------------------------------
/// Check NOTBUSY and DTIP bits of status register on the given MCI driver.
/// Return value, 0 for bus ready, 1 for bus busy
/// \param pMci  Pointer to a MCI driver instance.
//------------------------------------------------------------------------------
unsigned char MCI_CheckBusy(Mci *pMci)
{
    AT91S_MCI *pMciHw = pMci->pMciHw;
    unsigned int status;

    // Enable MCI clock
    MCI_Enable(pMci, ENABLE);

    status = READ_MCI(pMciHw, MCI_SR);
    // trace_LOG(trace_DEBUG, "status %x\n\r",status);


    if(((status & AT91C_MCI_NOTBUSY)!=0)
        && ((status & AT91C_MCI_DTIP)==0)) {

        // Disable MCI clock
        MCI_Enable(pMci, DISABLE);

        return 0;
    }
    else {
        return 1;
    }
}

//------------------------------------------------------------------------------
/// Check BLKE bit of status register on the given MCI driver.
/// \param pMci  Pointer to a MCI driver instance.
//------------------------------------------------------------------------------
unsigned char MCI_CheckBlke(Mci *pMci)
{
    AT91S_MCI *pMciHw = pMci->pMciHw;
    unsigned int status;

    status = READ_MCI(pMciHw, MCI_SR);
    // trace_LOG(trace_DEBUG, "status %x\n\r",status);

    if((status & AT91C_MCI_BLKE)!=0) {
        return 0;
    }
    else {
        return 1;
    }
}

//------------------------------------------------------------------------------
/// Processes pending events on the given MCI driver.
/// \param pMci  Pointer to a MCI driver instance.
//------------------------------------------------------------------------------
void MCI_Handler(Mci *pMci)
{
    AT91S_MCI *pMciHw = pMci->pMciHw;
    MciCmd *pCommand = pMci->pCommand;
    unsigned int status;
    unsigned char i;
    #if defined(at91rm9200)
    unsigned int mciCr, mciSdcr, mciMr, mciDtor;
    #endif

    SANITY_CHECK(pMci);
    SANITY_CHECK(pMciHw);
    SANITY_CHECK(pCommand);

    // Read the status register
    status = READ_MCI(pMciHw, MCI_SR) & READ_MCI(pMciHw, MCI_IMR);
    // trace_LOG(trace_DEBUG, "status %x\n\r", status);

    // Check if an error has occured
    if ((status & STATUS_ERRORS) != 0) {

        // Check error code
        if ((status & STATUS_ERRORS) == AT91C_MCI_RTOE) {
        
            pCommand->status = MCI_STATUS_NORESPONSE;
        }
        // if the command is SEND_OP_COND the CRC error flag is always present
        // (cf : R3 response)
        else if (((status & STATUS_ERRORS) != AT91C_MCI_RCRCE)
                  || ((pCommand->cmd != SDCARD_APP_OP_COND_CMD)
                      && (pCommand->cmd != MMC_SEND_OP_COND_CMD))) {

            pCommand->status = MCI_STATUS_ERROR;
        }
    }

    // Check if a transfer has been completed
    if (((status & AT91C_MCI_CMDRDY) != 0)
        || ((status & AT91C_MCI_ENDRX) != 0)
        || ((status & AT91C_MCI_RXBUFF) != 0)
        || ((status & AT91C_MCI_ENDTX) != 0)
        || ((status & AT91C_MCI_BLKE) != 0)
        || ((status & AT91C_MCI_RTOE) != 0)) {

        if (((status & AT91C_MCI_ENDRX) != 0)
            || ((status & AT91C_MCI_RXBUFF) != 0)
            || ((status & AT91C_MCI_ENDTX) != 0)) {

            MCI_Enable(pMci, DISABLE);
        }

        /// On AT91RM9200-EK, if stop transmission, software reset MCI.
        #if defined(at91rm9200)
        if ((pCommand->cmd & AT91C_MCI_TRCMD_STOP) != 0) {
            mciMr = READ_MCI(pMciHw, MCI_MR);
            mciSdcr = READ_MCI(pMciHw, MCI_SDCR);
            mciDtor = READ_MCI(pMciHw, MCI_DTOR);
            WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);
            // trace_LOG(trace_DEBUG, "reset MCI\n\r");

            WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);
            WRITE_MCI(pMciHw, MCI_MR, mciMr);
            WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr);
            WRITE_MCI(pMciHw, MCI_DTOR, mciDtor);
        }
        #endif

        // If no error occured, the transfer is successful
        if (pCommand->status == MCI_STATUS_PENDING) {
            pCommand->status = 0;
        }
#if 0
        if ((status & AT91C_MCI_CMDRDY) != 0)
            trace_LOG(trace_DEBUG, ".");
        if ((status & AT91C_MCI_ENDRX) != 0)
            trace_LOG(trace_DEBUG, "<");
        if ((status & AT91C_MCI_ENDTX) != 0)
            trace_LOG(trace_DEBUG, "-");
        if ((status & AT91C_MCI_BLKE) != 0)
            trace_LOG(trace_DEBUG, ">");
        trace_LOG(trace_DEBUG, "\n\r");
#endif        
        // Store the card response in the provided buffer
        if (pCommand->pResp) {

            for (i=0; i < pCommand->resSize; i++) {

                pCommand->pResp[i] = READ_MCI(pMciHw, MCI_RSPR[0]);
            }
        }

        // Disable interrupts
        WRITE_MCI(pMciHw, MCI_IDR, READ_MCI(pMciHw, MCI_IMR));

        // Release the semaphore
        pMci->semaphore++;

        // Invoke the callback associated with the current command (if any)
        if (pCommand->callback) {
            (pCommand->callback)(pCommand->status, pCommand);
        }
    }
}

//------------------------------------------------------------------------------
/// Returns 1 if the given MCI transfer is complete; otherwise returns 0.
/// \param pCommand  Pointer to a MciCmd instance.
//------------------------------------------------------------------------------
unsigned char MCI_IsTxComplete(MciCmd *pCommand)
{
    if (pCommand->status != MCI_STATUS_PENDING) {
        if (pCommand->status != 0)
            printf("MCI_IsTxComplete %d\n\r", pCommand->status);
        return 1;
    }
    else {
        return 0;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -