📄 mmc.c
字号:
#include "mmc.h"
#include "board.h"
#include "buffer.h"
extern void SPIWait(void);
unsigned char MmcCommand(unsigned char c1,
unsigned char c2,
unsigned char c3,
unsigned char c4,
unsigned char c5){
char c;
/* Note: c1, c2 are used for temporary variables after use! */
//MMC_OFF = NO; //MMC should be powered, but switch power on just-in-case
// MMC_XCS = MMC_NOT_SELECTED; //put MMC on-line.
// Provide clock edges before and after asserting MMC CS
SPI8Clocks(8);
IOCLR0 |= MMC_CS;
SPI8Clocks(8);
c=0;
// If card still seems to be busy, give it some time...
while ((SPIGetChar()!=0xff) && (c<100)){
//ConsolePutChar('.');
c++;
}
// The bus should be stable high now
if (SPI_RESULT_BYTE != 0xff){
//ConsoleWrite("\rUnexpected busy signal from MMC. ");
IOSET0 |= MMC_CS; //drop MMC offline.
return 0x81; //MMC unexpectedly Busy
}
// Send the MMC command
SPIPutCharWithoutWaiting(c1);
SPIPutChar(c2);
SPIPutChar(c3);
SPIPutChar(c4);
SPIPutChar(c5);
if(c1 ==0x40)
{
SPIPutChar(0x95);
}
else
{
SPIPutChar(0xFF);
}
/* Valid CRC for init, then don't care */
SPIWait();
/* Now ok to use c1..c5 as temporaries (dirty but kool) */
// Wait for R1 style response (bit 7 low) from MMC
c1=100;
while((c1--)&&((c2=SPIGetChar())&0x80)) //wait for R1 or timeout
;
return c2; //return the R1 response
}
unsigned char MmcWaitForData(void){
unsigned char c;
// Wait until something else than 0xff is read from the bus
do {
c=SPIGetChar();
} while ((c == 0xff));
// Something was received from the bus? Might it actually be te
// desired 0xFE data start token?
if (c != 0xfe){
// No data start token, read fail. In an OS an error message would display.
// Since we're in an embedded system, it's unclear what we should do now.
// Current approach is to say all ok but make read block return 0xff's.
// It's not disasterous at least as long as we don't WRITE to MMC.
// Flush any data that might be pending from the MMC.
SPI8Clocks(200); /* Flush MMC by sending lots of FF's to it */
SPI8Clocks(200);
SPI8Clocks(200);
return 5; //Return error
}
// DebugMessage("t>"); //Exit Token Wait
return 0;
}
/*
void MmcGetData(unsigned int amountOctets){
//DebugMessage("<G");
dataBufPtr = diskSect.raw.buf;
while (amountOctets--){
*dataBufPtr++=SPIGetChar();
}
// DebugMessage("G>");
}
*/
unsigned char RebootMMC(void){
unsigned char c;
//Try (indefinitely) to switch on the MMC card
do{
/* MMC Don't use CRC - seems to be required by some MMC cards? */
MmcCommand(0x7B,0,0,0,0);
/* MMC Init, command 0x40 should return 0x01 (idle) if all is ok. */
}while (MmcCommand(0x40,0,0,0,0)!=0x01);
// 0x01(idle) response detected.
//ConsoleWrite("Card found, starting... ");
/*Try max 255 times MMC Wake-up call: set to Not Idle (mmc returns 0x00)*/
c=255;
while ((c--)&&(MmcCommand(0x41,0,0,0,16))){
delay_ms(10);
if (c==1){
//timeout
// ConsoleWrite("Failed.\r");
return 2; /* Not able to power up mmc */
}
}
//ConsoleWrite("Ok.\r");
return 0;
}
unsigned char InitMMC(){
unsigned char c;
//Delay(10);
/* Allow MMC some time and clock cycles to reset */
for (c=0; c<200; c++){
SPIPutCharWithoutWaiting(0xff);
SPIWait();
}
delay_ms(20);
if (RebootMMC()) return 1; //not able to powerup;
//An existing MMC card should be able to respond now.
c=MmcCommand(0x50,0,0,2,0);
/* Set Block Size of 512 bytes (2 == 512 << 8) */
if (c) return c|0x80; /* blocksize error */
/* Check if MMC supports interrupted data transfer */
/* This does a simple checksum check to see if interrupted and
* non-interrupted read blocks are the same. */
/* This could be a function, so it is in braces for clarity purposes */
{
if (SeekSector(0)) return 2; //Storage powerup failure
if (ReadPhysicalSector()) return 2; //Storage powerup failure
tempo.i = diskSect.raw.buf[511];
for (c=0; c<250; c++){
tempo.i += diskSect.raw.buf[c];
}
if (SeekSector(0)) return 2;//Storage powerup failure
/* Send some extra SPI clocks */
IOSET0 |= MMC_CS;
SPIPutCharWithoutWaiting(0xff);
for (c=0; c<100; c++){
SPIPutChar(0xff);
}
SPIWait();
if (ReadPhysicalSector()){
//ConsoleWrite("Interrupted read failed.\r");
//ConsoleWrite("Using compatibility mode.\r");
return 0x0e; //ok but no support for seek-before-read
}else{
//Check if received data was same
tempo.i -= diskSect.raw.buf[511];
for (c=0; c<250; c++){
tempo.i -= diskSect.raw.buf[c];
}
}
if (tempo.i) { /* Checksum does not match */
// ConsoleWrite("This MMC has no support for interrupted read. ");
// ConsoleWrite("Using compatibility mode.\r");
return 0x0e; //ok but no support for seek-before-read
}
//ConsoleWrite("\rInitMMC ok.\r");
}
/* All OK return */
return 0; //ok and MMC supports seek-before-read
}
void PerformBlockRead(void){
/* Use shared global buffer pointer for speed*/
/* Loop unrolled 16 times for SPEED! :) */
dataBufPtr = diskSect.raw.buf;
while (dataBufPtr < diskSect.raw.buf+512){
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
/*
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
*/
/*
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
SPIPutCharWithoutWaiting(0xff);
SPIWait();
*dataBufPtr++=SPI_RESULT_BYTE;
*/
}
}
/* Unconditionally (really just do it!) seek MMC at offset sectorN*512 */
unsigned char SeekSector(unsigned long sectorN){
unsigned char c;
sectorAddress.l = sectorN * 2; //convert to bytes (combined with 8bit shift)
do{
c=MmcCommand(0x51,sectorAddress.b.b2,sectorAddress.b.b1,
sectorAddress.b.b0,0);
sectorAddress.l = sectorAddress.l >> 1; //convert back to blocks
//if MMC returs "nothing" (0xff) or 0x81(busy),
//toggle chip select and retry
if ((c==0xff)||(c==0x81)){
c=0xff;
RebootMMC();
}
if (c==0x01){ //MMC says "busy"
c=0xff; //try again
}
}while(c==0xff); //repeat until we get signal from MMC.
if ((c & 0xfe)){ //MMC returns something else than idle or busy signal
return 7; /* failed to execute mmc command */
}
return 0; //ok return
}
/* Wait for data start token and read 512 bytes to global buffer */
unsigned char ReadPhysicalSector(void){
//PORTBbits.RB7=1;
IOCLR0 |= MMC_CS;
MmcWaitForData();
PerformBlockRead();
/* generate SPI clock edges to finish up the command */
//SPI8Clocks(8); //Send 8*4=32 clocks (4 ff's) to MMC to be nice.
//MMC_XCS = MMC_NOT_SELECTED;
//SPI8Clocks(8); //Again, give the poor MMC some clocks, it likes them.
//PORTBbits.RB7=0;
return 0; //ok return
}
unsigned char WritePhysicalSector(){
unsigned char c;
//RED_LED = LED_ON;
sectorAddress.l = sectorAddress.l * 2; //convert to bytes (combined with 8bit shift)
c=MmcCommand(24 | 0x40 ,sectorAddress.b.b2,sectorAddress.b.b1,
sectorAddress.b.b0, 0);
sectorAddress.l = sectorAddress.l >> 1; //convert back to blocks
IOCLR0 |= MMC_CS;
dataBufPtr = diskSect.raw.buf;
SPIPutCharWithoutWaiting(0xFE);
SPIWait();
for (c=0;c<128;c++){
SPIPutCharWithoutWaiting(*dataBufPtr++);
SPIWait();
SPIPutCharWithoutWaiting(*dataBufPtr++);
SPIWait();
SPIPutCharWithoutWaiting(*dataBufPtr++);
SPIWait();
SPIPutCharWithoutWaiting(*dataBufPtr++);
SPIWait();
}
MmcWaitForData(); //Wait for 0xFE token
while (SPIGetChar()==0)
; // Wait until MMC not busy.
SPI8Clocks(16);
IOSET0 |= MMC_CS;
SPI8Clocks(16);
//RED_LED = LED_OFF;
return (0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -