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

📄 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 页
字号:
/* ----------------------------------------------------------------------------
 *         ATMEL Microcontroller Software Support 
 * ----------------------------------------------------------------------------
 * Copyright (c) 2008, Atmel Corporation
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Atmel's name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ----------------------------------------------------------------------------
 */

//------------------------------------------------------------------------------
//         Headers
//------------------------------------------------------------------------------

#include "sdspi.h"
#include <utility/assert.h>
#include <utility/trace.h>
#include <board.h>
#include <crc7.h>
#include <crc-itu-t.h>
#include <crc16.h>
#include <crc-ccitt.h>
#include <string.h>

//------------------------------------------------------------------------------
//         Macros
//------------------------------------------------------------------------------

/// Transfer is pending.
#define SDSPI_STATUS_PENDING      1
/// Transfer has been aborted because an error occured.
#define SDSPI_STATUS_ERROR        2

/// SPI driver is currently in use.
#define SDSPI_ERROR_LOCK    1

// Data Tokens
#define SDSPI_START_BLOCK_1 0xFE  // Single/Multiple read, single write
#define SDSPI_START_BLOCK_2 0xFC  // Multiple block write
#define SDSPI_STOP_TRAN     0xFD  // Cmd12

//------------------------------------------------------------------------------
//         Exported functions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
/// Initializes the SD Spi structure and the corresponding SPI hardware.
/// \param pSpid  Pointer to a Spid instance.
/// \param pSpiHw  Associated SPI peripheral.
/// \param spiId  SPI peripheral identifier.
//------------------------------------------------------------------------------
void SDSPI_Configure(SdSpi *pSdSpi,
                     AT91PS_SPI pSpiHw,
                     unsigned char spiId)
{
    // Initialize the SPI structure
    pSdSpi->pSpiHw = pSpiHw;
    pSdSpi->spiId = spiId;
    pSdSpi->semaphore = 1;

    // Enable the SPI clock
    AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
    
    // Execute a software reset of the SPI twice
    pSpiHw->SPI_CR = AT91C_SPI_SWRST;
    pSpiHw->SPI_CR = AT91C_SPI_SWRST;

    // Configure SPI in Master Mode with No CS selected !!!
    pSpiHw->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS  | AT91C_SPI_PCS;

    // Disables the receiver PDC transfer requests
    // Disables the transmitter PDC transfer requests.
    pSpiHw->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;

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

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

//------------------------------------------------------------------------------
/// Configures the parameters for the device corresponding to the cs.
/// \param pSdSpi  Pointer to a SdSpi instance.
/// \param cs  number corresponding to the SPI chip select.
/// \param csr  SPI_CSR value to setup.
//------------------------------------------------------------------------------
void SDSPI_ConfigureCS(SdSpi *pSdSpi, unsigned char cs, unsigned int csr)
{
    unsigned int spiMr;
    AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;

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

    //TRACE_DEBUG("CSR[%d]=0x%8X\n\r", cs, csr);
    pSpiHw->SPI_CSR[cs] = csr;

//jcb to put in sendcommand
    // Write to the MR register
    spiMr = pSpiHw->SPI_MR;
    spiMr |= AT91C_SPI_PCS;
    spiMr &= ~((1 << cs) << 16);
    pSpiHw->SPI_MR = spiMr;

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

//------------------------------------------------------------------------------
/// Use PDC for SPI data transfer.
/// Return 0 if no error, otherwise return error status.
/// \param pSdSpi  Pointer to a SdSpi instance.
/// \param pData  Data pointer.
/// \param size  Data transfer byte count.
//------------------------------------------------------------------------------
unsigned char SDSPI_PDC(SdSpi *pSdSpi, unsigned char *pData, unsigned int size)
{
    AT91PS_SPI pSpiHw = pSdSpi->pSpiHw;
    unsigned int spiIer;

    if (pSdSpi->semaphore == 0) {
        TRACE_DEBUG("No semaphore\n\r");
        return SDSPI_ERROR_LOCK;
    }
    pSdSpi->semaphore--;

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

    // Disable transmitter and receiver
    pSpiHw->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;

    // Receive Pointer Register
    pSpiHw->SPI_RPR = (int)pData;
    // Receive Counter Register
    pSpiHw->SPI_RCR = size;
    // Transmit Pointer Register
    pSpiHw->SPI_TPR = (int) pData;
    // Transmit Counter Register
    pSpiHw->SPI_TCR = size;

    spiIer = AT91C_SPI_RXBUFF;

    // Enable transmitter and receiver
    pSpiHw->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;

    // Interrupt enable shall be done after PDC TXTEN and RXTEN
    pSpiHw->SPI_IER = spiIer;

    return 0;
}

//! Should be moved to a new file
//------------------------------------------------------------------------------
/// Read data on SPI data bus; 
/// Returns 1 if read fails, returns 0 if no error.
/// \param pSdSpi  Pointer to a SD SPI driver instance.
/// \param pData  Data pointer.
/// \param size Data size.
//------------------------------------------------------------------------------
unsigned char SDSPI_Read(SdSpi *pSdSpi, unsigned char *pData, unsigned int size)
{
    unsigned char error;

    // MOSI should hold high during read, or there will be wrong data in received data.
    memset(pData, 0xff, size);

    error = SDSPI_PDC(pSdSpi, pData, size);

    while(SDSPI_IsBusy(pSdSpi) == 1);

    if( error == 0 ) {
        return 0;
    }
    else {
        TRACE_DEBUG("PB SDSPI_Read\n\r");
        return 1;
    }
}

//------------------------------------------------------------------------------
/// Write data on SPI data bus; 
/// Returns 1 if write fails, returns 0 if no error.
/// \param pSdSpi  Pointer to a SD SPI driver instance.
/// \param pData  Data pointer.
/// \param size Data size.
//------------------------------------------------------------------------------
unsigned char SDSPI_Write(SdSpi *pSdSpi, unsigned char *pData, unsigned int size)
{
    unsigned char error;

    error = SDSPI_PDC(pSdSpi, pData, size);

    while(SDSPI_IsBusy(pSdSpi) == 1);

    if( error == 0 ) {
        return 0;
    }
    else {
        TRACE_DEBUG("PB SDSPI_Write\n\r");
        return 1;
    }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
unsigned char SDSPI_WaitDataBusy(SdSpi *pSdSpi)
{
    unsigned char busyData;

    SDSPI_Read(pSdSpi, &busyData, 1);

    if (busyData != 0xff) {
        return 1;
    }
    else {
        return 0;
    }
}

//------------------------------------------------------------------------------
/// Convert SD MCI command to a SPI mode command token.
/// \param pCmdToken Pointer to the SD command token.
/// \param arg    SD command argument
//------------------------------------------------------------------------------
void SDSPI_MakeCmd(unsigned char *pCmdToken, unsigned int arg)
{
    unsigned char sdCmdNum;
    unsigned char crc = 0;
    unsigned char crcPrev = 0;

    sdCmdNum = 0x3f & *pCmdToken;
    *pCmdToken = sdCmdNum | 0x40;
    *(pCmdToken+1) = (arg >> 24) & 0xff;
    *(pCmdToken+2) = (arg >> 16) & 0xff;
    *(pCmdToken+3) = (arg >> 8) & 0xff;
    *(pCmdToken+4) = arg & 0xff;

    crc = crc7(crcPrev, (unsigned char *)(pCmdToken), 5);

    *(pCmdToken+5) = (crc << 1) | 1;
}

//------------------------------------------------------------------------------
/// Get response after send SD command.
/// 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_GetCmdResp(SdSpi *pSdSpi, SdSpiCmd *pCommand)
{
    unsigned char resp[8];  // response 
    unsigned char error;
    unsigned int  respRetry = 8; //NCR max 8, refer to card datasheet

    memset(resp, 0, 8);

    // Wait for response start bit. 
    do {
        error = SDSPI_Read(pSdSpi, &resp[0], 1);
        if (error) {
            TRACE_DEBUG("\n\rpb SDSPI_GetCmdResp: 0x%X\n\r", error);
            return error;
        }
        if ((resp[0]&0x80) == 0) {
            break;
        }
        respRetry--;
    } while(respRetry > 0);

    switch (pCommand->resType) {
        case 1:
        *(pCommand->pResp) = resp[0];
        break;

        case 2:
        error = SDSPI_Read(pSdSpi, &resp[1], 1);
        if (error) {
            return error;
        }
        *(pCommand->pResp) = resp[0]
                          | (resp[1] << 8);
        break;

        // Response 3, get OCR
        case 3:
        error = SDSPI_Read(pSdSpi, &resp[1], 4);
        if (error) {
            return error;
        }
        *(pCommand->pResp) = resp[0] 
                          | (resp[1] << 8) 
                          | (resp[2] << 16)
                          | (resp[3] << 24);
        *(pCommand->pResp+1) = resp[4];
        break;

        case 7:
        TRACE_DEBUG("case 7\n\r");
        error = SDSPI_Read(pSdSpi, &resp[1], 4);
        if (error) {
            return error;
        }
        *(pCommand->pResp) = resp[0]
                          | (resp[1] << 8) 
                          | (resp[2] << 16)
                          | (resp[3] << 24);
        *(pCommand->pResp+1) = resp[4];
        break;

        default:
        TRACE_DEBUG("PB default\n\r");
        break;
    }

    return 0;
}

⌨️ 快捷键说明

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