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

📄 sdspi.c

📁 Tried to make CAN logger on AT91sam7X-ek, but have no idea how to implement FATFs... -( I m just a
💻 C
📖 第 1 页 / 共 2 页
字号:
//------------------------------------------------------------------------------
/// Get response after send data.
/// Return 0 if no error, otherwise indicate an error.
/// \param pSdSpi Pointer to the SD SPI instance.
/// \param pCommand  Pointer to the SD command
//------------------------------------------------------------------------------
unsigned char SDSPI_GetDataResp(SdSpi *pSdSpi, SdSpiCmd *pCommand)
{
    unsigned char resp = 0;  // response 
    unsigned char error;
    unsigned int respRetry = 18; //NCR max 8, refer to card datasheet

    // Wait for response start bit. 
    do {
        error = SDSPI_Read(pSdSpi, &resp, 1);
        if (error) {
            return error;
        }
        if (((resp & 0x11) == 0x1) || ((resp & 0xf0) == 0))
            break;

        respRetry--;
    } while(respRetry > 0);
    //TRACE_DEBUG("SDSPI_GetDataResp 0x%X\n\r",resp);
    return resp;
}

//------------------------------------------------------------------------------
/// Starts a SPI master transfer. This is a non blocking function. It will
/// return as soon as the transfer is started.
/// Returns 0 if the transfer has been started successfully; otherwise returns
/// error.
/// \param pSdSpi  Pointer to a SdSpi instance.
/// \param pCommand Pointer to the SPI command to execute.
//------------------------------------------------------------------------------
unsigned char SDSPI_SendCommand(SdSpi *pSdSpi, SdSpiCmd *pCommand)
{
    AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
    unsigned char CmdToken[6];
    unsigned char *pData;
    unsigned int blockSize;
    unsigned int i;
    unsigned char error;
    unsigned char dataHeader;
    unsigned int dataRetry1 = 100;
    unsigned int dataRetry2 = 100;
    unsigned char crc[2];
    unsigned char crcPrev = 0;
    unsigned char crcPrev2 = 0;

    SANITY_CHECK(pSdSpi);
    SANITY_CHECK(pSpiHw);
    SANITY_CHECK(pCommand);

    CmdToken[0] = pCommand->cmd & 0x3F;
    pData = pCommand->pData;
    blockSize = pCommand->blockSize;

    SDSPI_MakeCmd((unsigned char *)&CmdToken, pCommand->arg);

    // Command is now being executed
    pSdSpi->pCommand = pCommand;
    pCommand->status = SDSPI_STATUS_PENDING;

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

        for(i = 0; i < 6; i++) {
            error = SDSPI_Write(pSdSpi, &CmdToken[i], 1);
            if (error) {
                TRACE_DEBUG("Error: %d\n\r", error);
                return error;
            }
        }
        // Specific for Cmd12()
        if ((pCommand->cmd & 0x3F) == 12) {
            if( 1 == SDSPI_Wait(pSdSpi, 2) ) {
                TRACE_DEBUG("Pb Send command 12\n\r");
            }
        }
        if (pCommand->pResp) {
            error = SDSPI_GetCmdResp(pSdSpi, pCommand);
            if (error) {
                TRACE_DEBUG("Error: %d\n\r", error);
                return error;
            }
        }
    }

    if( (blockSize > 0) && (pCommand->nbBlock == 0) ) {
        pCommand->nbBlock = 1;
    }

    // For data block operations
    while (pCommand->nbBlock > 0) {

        // If data block size is invalid, return error
        if (blockSize == 0) {
            TRACE_DEBUG("Block Size = 0\n\r");
            return 1;
        }

        // DATA transfer from card to host
        if (pCommand->isRead) {
            do {
                SDSPI_Read(pSdSpi, &dataHeader, 1);
                dataRetry1 --;
                if (dataHeader == SDSPI_START_BLOCK_1) {
                    break;
                }
                else if((dataHeader & 0xf0) == 0x00) {
                    pCommand->status = SDSPI_STATUS_ERROR;
                    TRACE_DEBUG("Data Error 0x%X!\n\r", dataHeader);
                    return 1;
                }
            } while(dataRetry1 > 0);

            if (dataRetry1 == 0) {
                TRACE_DEBUG("Timeout dataretry1\n\r");
                return 1;
            }

            SDSPI_Read(pSdSpi, pData, blockSize);

            // Specific for Cmd9()
            if ((pCommand->cmd & 0x3f) != 0x9) {

                SDSPI_Read(pSdSpi, crc, 2);
#ifdef SDSPI_CRC_ON
                // Check data CRC
                TRACE_DEBUG("Check Data CRC\n\r");
                crcPrev = 0;
                crcPrev2 = 0;
                if (crc[0] != ((crc_itu_t(crcPrev, pData, blockSize) & 0xff00) >> 8 )
                 || crc[1] !=  (crc_itu_t(crcPrev2, pData, blockSize) & 0xff)) {
                    TRACE_ERROR("CRC error 0x%X 0x%X 0x%X\n\r", \
                        crc[0], crc[1], crc_itu_t(pData, blockSize));
                    return 1;
                }
#endif
            }
        }

        // DATA transfer from host to card
        else {
            SDSPI_NCS(pSdSpi);
            if ((pCommand->conTrans == SPI_CONTINUE_TRANSFER) || ((pCommand->cmd & 0x3f) == 25)) {
                dataHeader = SDSPI_START_BLOCK_2;
            }
            else {
                dataHeader = SDSPI_START_BLOCK_1;
            }

            crcPrev = 0;
            crc[0] = (crc_itu_t(crcPrev, pData, blockSize) & 0xff00) >> 8;
            crcPrev2 = 0;
            crc[1] = (crc_itu_t(crcPrev2, pData, blockSize) & 0xff);
            SDSPI_Write(pSdSpi, &dataHeader, 1);
            SDSPI_Write(pSdSpi, pData, blockSize);
            SDSPI_Write(pSdSpi, crc, 2);

            // If status bits in data response is not "data accepted", return error
            if ((SDSPI_GetDataResp(pSdSpi, pCommand) & 0xe) != 0x4) {
                TRACE_ERROR("Write resp error!\n\r");
                return 1;
            }

            do {
                if (SDSPI_WaitDataBusy(pSdSpi) == 0) {
                    break;
                }
                dataRetry2--;
            } while(dataRetry2 > 0);
        }
        pData += blockSize;
        pCommand->nbBlock--;
    }

    if (pCommand->status == SDSPI_STATUS_PENDING) {
        pCommand->status = 0;
    }

    //TRACE_DEBUG("end SDSPI_SendCommand\n\r");
    return 0;
}
//!

//------------------------------------------------------------------------------
/// The SPI_Handler must be called by the SPI Interrupt Service Routine with the
/// corresponding Spi instance.
/// The SPI_Handler will unlock the Spi semaphore and invoke the upper application 
/// callback.
/// \param pSdSpi  Pointer to a SdSpi instance.
//------------------------------------------------------------------------------
void SDSPI_Handler(SdSpi *pSdSpi)
{
    SdSpiCmd *pCommand = pSdSpi->pCommand;
    AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
    volatile unsigned int spiSr;

    // Read the status register
    spiSr = pSpiHw->SPI_SR;
    if(spiSr & AT91C_SPI_RXBUFF) {

        if (pCommand->status == SDSPI_STATUS_PENDING) {
            pCommand->status = 0;
        }
        // Disable transmitter and receiver
        pSpiHw->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;

        // Disable the SPI clock
        AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);

        // Disable buffer complete interrupt
        pSpiHw->SPI_IDR = AT91C_SPI_RXBUFF | AT91C_SPI_ENDTX;

        // Release the SPI semaphore
        pSdSpi->semaphore++;
    }

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

//------------------------------------------------------------------------------
/// Returns 1 if the given SPI transfer is complete; otherwise returns 0.
/// \param pCommand  Pointer to a SdSpiCmd instance.
//------------------------------------------------------------------------------
unsigned char SDSPI_IsTxComplete(SdSpiCmd *pCommand)
{
    if (pCommand->status != SDSPI_STATUS_PENDING) {
        if (pCommand->status != 0){
            TRACE_DEBUG("SPI_IsTxComplete %d\n\r", pCommand->status);
        }
        return 1;
    }
    else {
        return 0;
    }
}

//------------------------------------------------------------------------------
/// Close a SPI driver instance and the underlying peripheral.
/// \param pSdSpi  Pointer to a SD SPI driver instance.
//------------------------------------------------------------------------------
void SDSPI_Close(SdSpi *pSdSpi)
{
    AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;

    SANITY_CHECK(pSdSpi);
    SANITY_CHECK(pSpiHw);

    // Enable the SPI clock
    AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);

    // Disable the PDC transfer    
    pSpiHw->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;

    // Enable the SPI
    pSpiHw->SPI_CR = AT91C_SPI_SPIDIS;

    // Disable the SPI clock
    AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);

    // Disable all the interrupts
    pSpiHw->SPI_IDR = 0xFFFFFFFF;
}

//------------------------------------------------------------------------------
/// Returns 1 if the SPI driver is currently busy programming; 
/// otherwise returns 0.
/// \param pSdSpi  Pointer to a SD SPI driver instance.
//------------------------------------------------------------------------------
unsigned char SDSPI_IsBusy(SdSpi *pSdSpi)
{
    if (pSdSpi->semaphore == 0) {
        return 1;
    }
    else {
        return 0;
    }
}

//------------------------------------------------------------------------------
/// Wait several cycles on SPI bus; 
/// Returns 0 to indicates no error, otherwise return 1.
/// \param pSdSpi  Pointer to a SD SPI driver instance.
/// \param cycles  Wait data cycles.
//------------------------------------------------------------------------------
unsigned char SDSPI_Wait(SdSpi *pSdSpi, unsigned int cycles)
{
    unsigned int i = cycles;
    unsigned char data = 0xff;

    for (; i > 0; i--) {
        if (SDSPI_Read(pSdSpi, &data, 1)) {
            return 1;
        }
    }
    return 0;
}

//------------------------------------------------------------------------------
/// Send stop transfer data token;
/// Returns 0 to indicates no error, otherwise return 1.
/// \param pSdSpi  Pointer to a SD SPI driver instance.
//------------------------------------------------------------------------------
unsigned char SDSPI_StopTranToken(SdSpi *pSdSpi)
{
    unsigned char stopToken = SDSPI_STOP_TRAN;

    TRACE_DEBUG("SDSPI_StopTranToken\n\r");
    return SDSPI_Write(pSdSpi, &stopToken, 1);
}

//------------------------------------------------------------------------------
/// Wait, SD card Ncs cycles; 
/// Returns 0 to indicates no error, otherwise return 1.
/// \param pSdSpi  Pointer to a SD SPI driver instance.
//------------------------------------------------------------------------------
unsigned char SDSPI_NCS(SdSpi *pSdSpi)
{
    unsigned int i;
    unsigned char ncs;

    for(i = 0; i < 15; i++) {
        ncs = 0xff;
        if (SDSPI_Write(pSdSpi, &ncs, 1)) {
            return 1;
        }
    }
    return 0;
}


⌨️ 快捷键说明

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