⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmc.c

📁 KaOS is a real-time operating system that has been implemented with the basic real-time constraints
💻 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 + -