📄 mmc.c
字号:
/*-----------------------------------------------------------------------*/
/* MMC/SDC (in SPI mode) control module (C)ChaN, 2006 */
/*-----------------------------------------------------------------------*/
/* Only rcvr_spi(), xmit_spi(), disk_timerproc(), disk_initialize () and */
/* some macros are platform dependent. */
/*-----------------------------------------------------------------------*/
#include "AT91SAM7S64.h"
#include "lib_AT91SAM7S64.h"
#include "SAMspi.h"
#include "diskio.h"
#define SPI_CSR_SD 1
#define SD_NPCS PCS_1
#define SD_CS_PIN AT91C_PA31_NPCS1
/* SPI CLK = (MCK / SPI_DIV) */
#define SPI_DIV 6
//#define USE_DMA
/* MMC/SD command (in SPI) */
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND */
#define CMD9 (0x40+9) /* SEND_CSD */
#define CMD10 (0x40+10) /* SEND_CID */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
#define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */
static volatile BYTE Timer = 0; /* 100Hz decrement timer */
/*-----------------------------------------------------------------------*/
/* Module Private Functions */
/*-----------------------------------------------------------------------*/
/*-------------------------------------*/
/* HW Interface config */
/*-------------------------------------*/
/*------------------*/
/* SET SPI Baudrate */
static void if_spiSetSpeed(unsigned char speed)
{
SAMspiSetSCBR(SPI_CSR_SD, speed);
}
/*------------------*/
/* Init AT91SAM SPI */
static void init_spi(void)
{
//SAMspiInit();
//SAMspiCfgCH(SPI_CSR_SD, (AT91C_SPI_NCPHA | AT91C_SPI_BITS_8));
}
/*-------------------------------------*/
/* Power & CS control */
/*-------------------------------------*/
/*--------------------- */
/* MMC disable : CS = 1 */
void DESELECT(void)
{
//AT91C_BASE_SPI->SPI_MR |= ((0x0F << 16) & AT91C_SPI_PCS ); // disable all PCS
AT91C_BASE_PIOA->PIO_PER = SD_CS_PIN; // enable PIO of CS-pin
AT91C_BASE_PIOA->PIO_SODR = SD_CS_PIN; // set
AT91C_BASE_PIOA->PIO_OER = SD_CS_PIN; // output
}
/*---------------------*/
/* MMC enable : CS = 0 */
void SELECT(void)
{
//AT91C_BASE_SPI->SPI_MR &= ~(AT91C_SPI_PCS ); // CLEAR PCS
//AT91C_BASE_SPI->SPI_MR |= ((SD_NPCS << 16) & AT91C_SPI_PCS ); // set PCS
AT91C_BASE_PIOA->PIO_PER = SD_CS_PIN; // enable PIO of CS-pin
AT91C_BASE_PIOA->PIO_CODR = SD_CS_PIN; // set
AT91C_BASE_PIOA->PIO_OER = SD_CS_PIN; // output
}
/*--------------*/
/* MMC Power ON */
static void power_on(void)
{
}
/*---------------*/
/* MMC Power OFF */
static void power_off(void)
{
}
/*-------------------------------------*/
/* MMC Operation */
/*-------------------------------------*/
/*--------------------------------*/
/* Transmit a byte to MMC via SPI */
static BYTE xmit_spi(BYTE dat)
{
BYTE rcv = 0;
#if 0
AT91PS_SPI pSPI = AT91C_BASE_SPI;
while( !( pSPI->SPI_SR & AT91C_SPI_TDRE ) ); // transfer compl. wait
pSPI->SPI_TDR = dat;
while( !( pSPI->SPI_SR & AT91C_SPI_RDRF ) ); // wait for char
rcv = (BYTE)( pSPI->SPI_RDR ); // it's important to read RDR here!
#else
rcv = SAMspiSend(SD_NPCS, dat);
#endif
return (BYTE)rcv;
}
/*---------------------------------*/
/* Receive a byte from MMC via SPI */
static BYTE rcvr_spi(void)
{
BYTE rcv = 0;
#if 0
AT91PS_SPI pSPI = AT91C_BASE_SPI;
while( !( pSPI->SPI_SR & AT91C_SPI_TDRE ) ); // transfer compl. wait
pSPI->SPI_TDR = 0xFF;
while( !( pSPI->SPI_SR & AT91C_SPI_RDRF ) ); // wait for char
rcv = (BYTE)( pSPI->SPI_RDR );
//iprintf("r: %x\n", dat);
#else
rcv = SAMspiSend(SD_NPCS, 0xff);
#endif
return (BYTE)rcv;
}
/*---------------------------------*/
/* Receive a byte from MMC via SPI */
static void rcvr_spi_m(BYTE *dest)
{
BYTE dat = 0;
AT91PS_SPI pSPI = AT91C_BASE_SPI;
while( !( pSPI->SPI_SR & AT91C_SPI_TDRE ) ); // transfer compl. wait
pSPI->SPI_TDR = 0xFF;
while( !( pSPI->SPI_SR & AT91C_SPI_RDRF ) ); // wait for char
dat = (BYTE)( pSPI->SPI_RDR );
*dest = dat;
}
/*---------------------*/
/* Wait for card ready */
static BYTE wait_ready ()
{
BYTE res = 0;
Timer = 50; /* Wait for ready in timeout of 500ms */
rcvr_spi();
do
{
res = rcvr_spi();
} while ((res != 0xFF) && Timer);
return res;
}
/*--------------------------------*/
/* Receive a data packet from MMC */
static BOOL rcvr_datablock (
BYTE *buff, /* Data buffer to store received data */
BYTE wc /* Word count (0 means 256 words) */
)
{
BYTE token;
#ifdef USE_DMA
/* TODO: deuglyfy */
static const BYTE dummy_ff_block[512] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#endif
Timer = 10;
do
{ /* Wait for data packet in timeout of 100ms */
token = rcvr_spi();
} while ((token == 0xFF) && Timer);
//iprintf("token: %x\n", token);
if (token != 0xFE) return FALSE; /* If not valid data token, retutn with error */
#ifdef USE_DMA
// enable DMA transfer
*AT91C_SPI_RPR = (unsigned long)buff;
*AT91C_SPI_RCR = 2 * (wc == 0 ? 256 : wc);
*AT91C_SPI_TPR = (unsigned long)dummy_ff_block;
*AT91C_SPI_TCR = 2 * (wc == 0 ? 256 : wc);
*AT91C_SPI_PTCR = AT91C_PDC_RXTEN;
*AT91C_SPI_PTCR = AT91C_PDC_TXTEN;
/*while(i++ < 512)
*AT91C_SPI_TDR = 0xFF; // start transfer*/
while(! (*AT91C_SPI_SR & AT91C_SPI_ENDRX));
*AT91C_SPI_PTCR = AT91C_PDC_RXTDIS;
*AT91C_SPI_PTCR = AT91C_PDC_TXTDIS;
#else
do
{ /* Receive the data block into buffer */
rcvr_spi_m(buff++);
rcvr_spi_m(buff++);
} while (--wc);
#endif
rcvr_spi(); /* Discard CRC */
rcvr_spi();
//puts("rcvr_datablock success");
return TRUE; /* Return with success */
}
/*---------------------------*/
/* Send a data packet to MMC */
#if _READONLY == 0
static BOOL xmit_datablock (
const BYTE *buff, /* 512 byte data block to be transmitted */
BYTE token /* Data/Stop token */
)
{
#ifdef USE_DMA
AT91PS_SPI pSPI = AT91C_BASE_SPI;
#else
BYTE wc = 0;
#endif
BYTE resp = 0;
if (wait_ready() != 0xFF) return FALSE;
xmit_spi(token); /* Xmit data token */
if (token != 0xFD)
{ /* Is data token */
#ifdef USE_DMA
// enable DMA transfer
*AT91C_SPI_TPR = (unsigned int)buff;
*AT91C_SPI_TCR = 512;
*AT91C_SPI_PTCR = AT91C_PDC_TXTEN;
while(! (*AT91C_SPI_SR & AT91C_SPI_ENDTX));
*AT91C_SPI_PTCR = AT91C_PDC_TXTDIS;
(BYTE)( pSPI->SPI_RDR ); // it's important to read RDR here!
#else
do
{ /* Xmit the 512 byte data block to MMC */
xmit_spi(*buff++);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -