这个程序是基于avr单片机的,使用了硬件spi接口,
导出了三个关键函数:
MMCReadSector(unsigned long sector, unsigned char *buf);
MMCWriteSector(unsigned long sector, unsigned char *buf);
MMCIdentify(void);
使用之前必须先调用函数MMCIdentify进行初始化.然后使用MMCReadSector,MMCWriteSector来进行访问.
mmc_spi.c
--------------------------------------------------------------------------------
//###########################################################
// File: mmc_spi.c
//
// Read-/Writeroutines for MMC MultiMedia cards and
// SD SecureDigital cards in SPI mode.
//
// This will work only for MMC cards with 512 bytes block length !
// This will work only for MMC cards with a partition table !
//
//
//#########################################################################
// Last change: 21.05.2004
//#########################################################################
// holger.klabunde@t-online.de
// http://home.t-online.de/home/holger.klabunde/homepage.htm
//#########################################################################
// Compiler: AVR-GCC 3.2
//#########################################################################
#include <io.h>
#include "dos.h"
#ifdef MMC_CARD_SPI
//######################################################
unsigned char MMCCommand(unsigned char command, unsigned long adress)
//######################################################
{
SPI_WRITE(0xFF); //Dummy write
SPI_WRITE(command);
SPI_WRITE((unsigned char)(adress>>24)); //MSB of adress
SPI_WRITE((unsigned char)(adress>>16));
SPI_WRITE((unsigned char)(adress>>8));
SPI_WRITE((unsigned char)adress); //LSB of adress
SPI_WRITE(0xFF); //dummy checksum
SPI_WRITE(0xFF); //16 bit response
SPI_WRITE(0xFF);
return SPDR; // only last 8 bits used
}
//######################################################
unsigned char MMCReadSector(unsigned long sector, unsigned char *buf)
//######################################################
{
unsigned int i;
unsigned char *p;
unsigned long startadr;
if(sector>=maxsect) return 1; //sectornumber too big
p=buf; //using a pointer is much faster than indexing buf[i]
MMC_CS_OFF();
//calculate startadress of the sector
startadr=sector * (unsigned long)BYTE_PER_SEC;
MMCCommand(MMC_READ_BLOCK,startadr);
do
{
SPI_WRITE(0xFF);
}while(SPDR!=0xFE); // wait for card response
for(i=0; i<BYTE_PER_SEC; i++)
{
SPI_WRITE(0xFF); // shift out a byte into SPDR
*p++=SPDR; // store byte in buffer
}
SPI_WRITE(0xFF); // 16 bit crc follows data
SPI_WRITE(0xFF);
MMC_CS_ON();
return 0;
}
#ifdef DOS_WRITE
//######################################################
unsigned char MMCWriteSector(unsigned long sector, unsigned char *buf)
//######################################################
{
unsigned int i;
unsigned char *p, by;
unsigned long startadr;
if(sector>=maxsect) return 1; //sectornumber too big
p=buf; //using a pointer is much faster than indexing buf[i]
MMC_CS_OFF();
//calculate startadress
startadr=sector * (unsigned long)BYTE_PER_SEC;
MMCCommand(MMC_WRITE_BLOCK,startadr);
SPI_WRITE(0xFF); // do we need this TWO dummy writes ?
SPI_WRITE(0xFF);
SPI_WRITE(0xFE); // start block token
for(i=0; i<BYTE_PER_SEC; i++)
{
SPI_WRITE(*p++);
}
SPI_WRITE(0xFF); // 16 bit crc follows data
SPI_WRITE(0xFF);
SPI_WRITE(0xFF); // read response
by=SPDR & 0x1F;
if(by != 0x05) // data block accepted ?
{
MMC_CS_ON();
return 1;
}
do
{
SPI_WRITE(0xFF);
}while(SPDR !=0xFF); // wait til busy is gone
MMC_CS_ON();
return 0;
}
#endif //DOS_WRITE
//######################################################
unsigned char MMCIdentify(void)
//######################################################
{
unsigned char by;
unsigned int i;
unsigned int c_size, c_size_mult, read_bl_len;
unsigned long drive_size;
//Init SPI with a very slow transfer rate first !
//SPCR SPI Controlregister
// SPIE=0; //No SPI Interrupt
// SPE=1; //SPI Enable
// DORD=0; //Send MSB first
// MSTR=1; //I am the master !
// CPOL=0; //SCK low if IDLE
// CPHA=0; //SPI Mode 0
// SPR1=1; //SPI Clock = f/128 = 125kHz @16MHz Clock
// SPR0=1; //or f/64 if SPI2X = 1 in SPSR register
SPCR=0x53;
//SPSR SPI Statusregister
// SPI2X=1; //Double speed for SPI = 250kHz @16MHz Clock
// SPSR=0x01;
SPSR=0x00;
for(i=0; i<10; i++) SPI_WRITE(0xFF); // give min 74 clock pulses before
// sending commands
MMC_CS_OFF();
//send CMD0 for RESET
SPI_WRITE(MMC_RESET); //command code CMD0
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x95); // CMD0 needs a checksum !
SPI_WRITE(0xFF); // get 16 bit response high
SPI_WRITE(0xFF); // get 16 bit response low
by=SPDR; // only last 8 bits neccessary
//repeat CMD1 til result=0
do
{
by=MMCCommand(MMC_INIT,0);
}while(by!=0);
//read CID
// MMCCommand(MMC_READ_CID,0); // nothing really interesting here
//read CSD Card Specific Data
MMCCommand(MMC_READ_CSD,0);
SPI_WRITE(0xFF); // ignore response 0xFE
for(i=0; i<16; i++) //CSD has 128 bits -> 16 bytes
{
SPI_WRITE(0xFF);
by=SPDR;
// ShowHex(by);
iob[i]=by;
}
SPI_WRITE(0xFF); // 16 bit crc follows data
SPI_WRITE(0xFF);
c_size=iob[6] & 0x03; //bits 1..0
c_size<<=10;
c_size+=(unsigned int)iob[7]<<2;
c_size+=iob[8]>>6;
by= iob[5] & 0x0F;
read_bl_len=1;
read_bl_len<<=by;
by=iob[9] & 0x03;
by<<=1;
by+=iob[10] >> 7;
c_size_mult=1;
c_size_mult<<=(2+by);
drive_size=(unsigned long)(c_size+1) * (unsigned long)c_size_mult * (unsigned long)read_bl_len;
maxsect= drive_size / BYTE_PER_SEC;
MMC_CS_ON();
//switch to high speed SPI
// SPR1=0; //SPI Clock = f/4 = 4MHz @16MHz Clock
// SPR0=0; //or f/2 if SPI2X = 1 in SPSR register
SPCR=0x50;
//SPSR SPI Statusregister
// SPI2X=1; //Double speed for SPI = 8MHz @16MHz Clock
SPSR=0x01;
return 0;
}
#endif //MMC_CARD_SPI
--------------------------------------------------------------------------------
mmc_spi.h
--------------------------------------------------------------------------------
//#########################################################################
// File: mmc_spi.h
//
// MMC MultiMediaCard and SD SecureDigital definitions for SPI protocol
//
//#########################################################################
// Last change: 21.05.2004
//#########################################################################
// holger.klabunde@t-online.de
// http://home.t-online.de/home/holger.klabunde/homepage.htm
//#########################################################################
// Compiler: AVR-GCC 3.2
//#########################################################################
#ifndef __MMC_CARD_SPI_H
#define __MMC_CARD_SPI_H
#define SPI_WRITE(a) { SPDR=(a); while(!(SPSR&0x80)); }
// you don't really need the /CS pin. it works also if /CS is
// connected to ground.
#define MMC_CS 4 //Pin number for MMC_CS
#define MMC_CS_PORT PORTB //Port where MMC_CS is located
#define MMC_CS_ON() sbi(MMC_CS_PORT,MMC_CS);
#define MMC_CS_OFF() cbi(MMC_CS_PORT,MMC_CS);
// MMC/SD commands
#define MMC_RESET 0x40 + 0
#define MMC_INIT 0x40 + 1
#define MMC_READ_CSD 0x40 + 9
#define MMC_READ_CID 0x40 + 10
#define MMC_STOP_TRANSMISSION 0x40 + 12
#define MMC_SEND_STATUS 0x40 + 13
#define MMC_SET_BLOCKLEN 0x40 + 16
#define MMC_READ_BLOCK 0x40 + 17
#define MMC_READ_MULTI_BLOCK 0x40 + 18
#define MMC_WRITE_BLOCK 0x40 + 24
#define MMC_WRITE_MULTI_