📄 mmc.c
字号:
// SPI information obtained from SanDisk's SD card manual
// http://www.sandisk.com/pdf/oem/ProdManualSDCardv1.9.pdf
/*
Portions of this code were adapted and used from
Radig Ulrich <mail@ulrichradig.de>
*/
#define TRUE (0x1)
#define FALSE (0x0)
#define R1_IN_IDLE_STATE (0x1) // The card is in idle state and running initializing process.
#define R1_ERASE_RESET (0x2) // An erase sequence was cleared before executing because of an out of erase sequence command was received.
#define R1_ILLEGAL_COMMAND (0x4) // An illegal command code was detected
#define R1_COM_CRC_ERROR (0x8) // The CRC check of the last command failed.
#define R1_ERASE_SEQ_ERROR (0x10) // An error in the sequence of erase commands occured.
#define R1_ADDRESS_ERROR (0x20) // A misaligned address, which did not match the block length was used in the command.
#define R1_PARAMETER (0x40) // The command's argument (e.g. address, block length) was out of the allowed range for this card.
#define READ_START_BLOCK (0b11111110)
#define WRITE_SINGLE_START_BLOCK (0b11111110)
#define WRITE_MULTIPLE_START_BLOCK (0b11111100)
#define WRITE_MULTIPLE_STOP_TRAN (0b11111101)
#define MMC_DR_MASK 0x1F
#define MMC_DR_ACCEPT 0x05
#define MSTR 4
#define SPR0 0
#define SPR1 1
#define SPE 6
#define SPI2X 0
#define SPIF 7
#define MMC_Write PORTB
#define MMC_Read PINB
#define MMC_Direction_REG DDRB
#define SPI_DI 6
#define SPI_DO 5
#define SPI_Clock 7
#define MMC_Chip_Select 0
#define SPI_SS 4
#define nop() #asm("nop")
//set MMC_Chip_Select to high (MMC/SD-Karte Inaktiv)
#define MMC_Disable() MMC_Write|= (1<<MMC_Chip_Select);
//set MMC_Chip_Select to low (MMC/SD-Karte Aktiv)
#define MMC_Enable() MMC_Write&=~(1<<MMC_Chip_Select);
inline void Write_Byte_MMC(UCHAR Byte)
{
SPDR = Byte;
while(!(SPSR & (1<<SPIF)));
}
inline UCHAR Read_Byte_MMC(void)
{
UCHAR Byte;
SPDR = 0xff;
while(!(SPSR & (1<<SPIF)));
Byte = SPDR;
return (Byte);
}
UCHAR Write_Command_MMC(UCHAR *CMD)
{
UCHAR a;
UCHAR tmp = 0xff;
UCHAR Timeout = 0;
// Raise chip select
MMC_Disable();
// Send an 8 bit pulse
Write_Byte_MMC(0xFF);
// Lower chip select
MMC_Enable();
// Send the 6 byte command
for (a = 0;a<0x06;a++)
{
Write_Byte_MMC(*CMD++);
}
// Wait for the response
while (tmp == 0xff)
{
tmp = Read_Byte_MMC();
if (Timeout++ > 100)
{
break;
}
}
// for some reason we need to delay here
delay_ms(1);
return(tmp);
}
UCHAR MmcInit()
{
UCHAR a,b, retry;
UCHAR CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};
// Set certain pins to inputs and others to outputs
// Only SPI_DI (data in) is an input
MMC_Direction_REG &=~(1<<SPI_DI);
MMC_Direction_REG |= (1<<SPI_Clock);
MMC_Direction_REG |= (1<<SPI_DO);
MMC_Direction_REG |= (1<<MMC_Chip_Select);
MMC_Direction_REG |= (1<<SPI_SS);
MMC_Write |= (1<<MMC_Chip_Select);
// We need to wait for the MMC_Direction_REG to be ready
for(a=0;a<200;a++)
{
nop();
};
// Enable SPI in Master Mode with IDLE low and clock at 16E6/128
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPR1);
SPSR = (0<<SPI2X);
// We need to give the card about a hundred cycles to load
for (b = 0; b < 0x0f; ++b)
{
Write_Byte_MMC(0xff);
}
// Send the initialization commands to the card
retry = 0;
// Note, many examples check for (Write_Command_MMC(CMD) == R1_IN_IDLE_STATE)
// However, with our setup the card was in IDLE state and returning another command
while((Write_Command_MMC(CMD) & R1_IN_IDLE_STATE) == 0)
{
// fail and return
if (retry++ > 50)
{
return 1;
}
}
// Send the 2nd command
retry = 0;
CMD[0] = 0x41;
CMD[5] = 0xFF;
while( Write_Command_MMC (CMD) != 0)
{
if (retry++ > 50)
{
return 2;
}
}
// Set the SPI bus to full speed
SPCR = SPCR|(0<<SPR0)|(0<<SPR1);
SPSR = SPSR|(1<<SPI2X);
// Raise Chip Select
MMC_Disable();
return 0;
}
UCHAR mmc_write_sector (unsigned long addr,UCHAR *Buffer)
{
UCHAR tmp;
UINT a;
// Command to write a block to the memory card
UCHAR CMD[] = {0x58,0x00,0x00,0x00,0x00,0xFF};
// Encode the address to a 32-bit address
// Ignore the bottom byte of the address as we give the address of the sector
CMD[1] = ((addr & 0xFF000000) >> 24);
CMD[2] = ((addr & 0x00FF0000) >> 16);
CMD[3] = ((addr & 0x0000FF00) >> 8);
// Send the write command
tmp = Write_Command_MMC (CMD);
if (tmp != 0)
{
return(tmp);
}
// Wait a little bit
for (a = 0; a < 100; ++a)
{
Read_Byte_MMC();
}
// Send the start byte
Write_Byte_MMC(0xFE);
// Send all 512 bytes in the buffer
for (a = 0; a < 512; ++a)
{
Write_Byte_MMC(*Buffer++);
}
// Write CRC byte
Write_Byte_MMC(0xFF);
Write_Byte_MMC(0xFF);
// Wait for the write to complete
while (Read_Byte_MMC() != 0xff);
// Set MMC_Chip_Select to high
MMC_Disable();
return(0);
}
void MMC_Read_Block(UCHAR *CMD,UCHAR *Buffer,UINT Bytes)
{
UINT a;
// Send the read command
if (Write_Command_MMC(CMD) != 0)
{
return;
}
// Send the start byte
while (Read_Byte_MMC() != 0xfe);
// Read off all the bytes in the block
for (a = 0; a < Bytes; ++a)
{
*Buffer++ = Read_Byte_MMC();
}
// Read CRC byte
Read_Byte_MMC();
Read_Byte_MMC();
// Set MMC_Chip_Select to high
MMC_Disable();
return;
}
UCHAR mmc_read_sector (unsigned long addr, UCHAR *Buffer)
{
// Command to read a 512-byte sector
UCHAR CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};
// Encode the address to a 32-bit address
// Ignore the bottom byte of the address as we give the address of the sector
//addr = addr << 9; //addr = addr * 512
CMD[1] = ((addr & 0xFF000000) >> 24);
CMD[2] = ((addr & 0x00FF0000) >> 16);
CMD[3] = ((addr & 0x0000FF00) >> 8);
MMC_Read_Block(CMD,Buffer,512);
return(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -