📄 sdspi.c
字号:
/* ----------------------------------------------------------------------------
* 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 + -