/******************************************************/
/* SD Card driver using SSP for LPC2148 */
/* by 314forever */
/* spi_mmc.c 2009.1 */
/******************************************************/
#ifndef __SPI_MMC_H__
#define __SPI_MMC_H__
#define SPI_SEL 16
#define SET_MMC_CS FIO0SET = (1 << SPI_SEL);
#define CLR_MMC_CS FIO0CLR = (1 << SPI_SEL);
#define MMC_CMD_SIZE 6 // the SPI data is 8 bit long, the MMC use 48 bits, 6 bytes
#define MMC_DATA_SIZE 512 // data of one sector in byte
#define MAX_TIMEOUT 0xFF // retry times
#define GO_IDLE_STATE 0x00
#define SEND_CSD 0x09
#define SEND_CID 0x0A
#define READ_SINGLE_BLOCK 0x11
#define WRITE_SINGLE_BLOCK 0x18
#define SEND_OP_COND 0x29
#define APP_CMD 0x37
#define CRC_ON_OFF 0x3B
void spiSend(BYTE *buffer, DWORD length);
void spiReceive(BYTE *buffer, DWORD length);
BYTE spiReceiveByte(void);
BYTE mmcInit(void);
BOOL mmcReadSector(DWORD sector, BYTE *buffer, DWORD *SectorInCache);
BOOL mmcWriteSector(DWORD sector, BYTE *buffer);
#endif
/******************************************************/
/* SD Card driver using SSP for LPC2148 */
/* by 314forever */
/* spi_mmc.c 2009.1 */
/******************************************************/
#include <LPC214X.H>
#include "..\type.h"
#include "spi_mmc.h"
#define sspLowSpeed() SSPCPSR = 0x80;
#define sspHighSpeed() SSPCPSR = 0x08;
void sspSend(BYTE *buffer, DWORD length){
BYTE dummy;
while(SSPSR & 0x04)dummy = SSPDR; // clean FIFO
SSPDR = *buffer; // first byte to send
buffer ++;
length --;
while(length){
SSPDR = *buffer; // keep FIFO not empty nor not full
buffer ++;
length --;
while(!(SSPSR & 0x04));
dummy = SSPDR;
}
while(!(SSPSR & 0x04));
dummy = SSPDR;
}
void sspReceive(BYTE *buffer, DWORD length){
BYTE dummy;
while(SSPSR & 0x04)dummy = SSPDR; // clean FIFO
SSPDR = 0xFF;
length --;
while(length){
SSPDR = 0xFF; // keep FIFO not empty nor not full
while(!(SSPSR & 0x04));
*buffer = SSPDR;
buffer ++;
length --;
}
while(!(SSPSR & 0x04)); // last byte to receive
*buffer = SSPDR;
}
BYTE sspReceiveByte(void){
SSPDR = 0xFF;
while(SSPSR & 0x10);
return SSPDR;
}
void sspSendByte(BYTE data){
BYTE dummy;
SSPDR = data;
while(SSPSR & 0x10);
dummy = SSPDR;
}
BYTE mmcSendCommand(BYTE command, DWORD argument){
BYTE R1;
BYTE retry ;
BYTE MMCCmd[MMC_CMD_SIZE + 1];
MMCCmd[0]= command | 0x40;
MMCCmd[1]= argument >> 24;
MMCCmd[2]= argument >> 16;
MMCCmd[3]= argument >> 8;
MMCCmd[4]= argument;
if(!command)MMCCmd[5]= 0x95;
else MMCCmd[5]= 0xFF;
MMCCmd[6]= 0xFF;
sspSend(MMCCmd, MMC_CMD_SIZE + 1);
retry = MAX_TIMEOUT;
do{
R1 = sspReceiveByte();
if(!(retry --))break;
}while(R1 == 0xFF);
sspReceiveByte();
return R1;
}
BYTE mmcInit(void){
BYTE i;
BYTE R1;
BYTE retry;
WORD dummy;
PINSEL1 |= 0x000000A8; // enable SCK(P0.17), MISO(P0.18), MOSI(P0.19)
FIO0DIR |= 1 << SPI_SEL; // use P0.16 as SSEL of SSP port
FIO0SET = 1 << SPI_SEL;
SSPCR0 = 0x0007; // 8bit, SPI format, CPOL = 0, CPHA = 0, and SCR is 0
sspLowSpeed();
SSPCR1 = 0x02; // master mode, SSP enabled, normal operational mode
while(SSPSR & 0x04)dummy = SSPDR; // clear the RxFIFO
retry = MAX_TIMEOUT;
do{
SET_MMC_CS;
for(i = 0; i < 10; i ++)sspReceiveByte();
CLR_MMC_CS;
R1 = mmcSendCommand(GO_IDLE_STATE, 0); // CMD0
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}while(R1 != 0x01);
retry = MAX_TIMEOUT;
do{
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
R1 = mmcSendCommand(APP_CMD, 0); // CMD55
if(R1 != 0x01)continue;
R1 = mmcSendCommand(SEND_OP_COND, 0); // CMD41
}while(R1 != 0x00);
retry = MAX_TIMEOUT;
do{
R1 = mmcSendCommand(1, 0); // send active command
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}while(R1);
sspHighSpeed();
mmcSendCommand(CRC_ON_OFF, 0); // disable CRC
mmcSendCommand(16, 512); // set sector size to 512
SET_MMC_CS;
return 0;
}
BOOL mmcReadSector(DWORD sector, BYTE *buffer, DWORD *SectorInCache){
BYTE R1;
BYTE retry = MAX_TIMEOUT;
if(*SectorInCache == sector)return 0;
else *SectorInCache = sector;
CLR_MMC_CS;
R1 = mmcSendCommand(READ_SINGLE_BLOCK, sector << 9); // read command
if(R1 != 0x00){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
while(sspReceiveByte() != 0xFE){ // wait to start recieve data
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}
sspReceive(buffer, 512);
sspReceiveByte(); // dummy CRC
sspReceiveByte();
SET_MMC_CS;
sspReceiveByte(); // extra 8 CLK
return 0;
}
BOOL mmcWriteSector(DWORD sector, BYTE *buffer){
BYTE R1;
WORD retry = 0xFFFF;
CLR_MMC_CS;
R1 = mmcSendCommand(WRITE_SINGLE_BLOCK, sector << 9); // write command
if(R1 != 0x00){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
sspReceiveByte();
sspReceiveByte();
sspSendByte(0xFE); // start transmit
sspSend(buffer, MMC_DATA_SIZE); // 512 bytes
sspReceiveByte(); // dummy CRC
sspReceiveByte();
R1 = sspReceiveByte();
if((R1 & 0x1F) != 0x05){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
while(!sspReceiveByte()){ // wait until write finish
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}
SET_MMC_CS;
sspReceiveByte();
return 0;
}
与通用的程序相比就是在连续发送和连续接收的地方作了一些简单处理。改动不大,但是提升的效率却很惊人,读取速度提高了能有50%左右。
文章评论(0条评论)
登录后参与讨论