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

📄 mmc_spi.c

📁 avr的fat文件系统测试程序
💻 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 !
//
// 29.09.2004 split SPI_WRITE() into SPI_WRITE() and SPI_WAIT()
//            speeds up program because CPU can do something else
//            while SPI hardware module is shifting in/out data 
//            see MMCReadSector() and MMCWriteSector()
//
//#########################################################################
// Last change: 29.09.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_WAIT();
 SPI_WRITE(command);
 SPI_WAIT();
 SPI_WRITE((unsigned char)(adress>>24)); //MSB of adress
 SPI_WAIT();
 SPI_WRITE((unsigned char)(adress>>16));
 SPI_WAIT();
 SPI_WRITE((unsigned char)(adress>>8));
 SPI_WAIT();
 SPI_WRITE((unsigned char)adress);       //LSB of adress
 SPI_WAIT();
 SPI_WRITE(0xFF); 			 //dummy checksum
 SPI_WAIT();
 SPI_WRITE(0xFF); 			 //16 bit response
 SPI_WAIT();
 SPI_WRITE(0xFF);
 SPI_WAIT();

 return SPDR;      			 // only last 8 bits used
}

//######################################################
unsigned char MMCReadSector(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 of the sector
 startadr=sector * (unsigned long)BYTE_PER_SEC;

 MMCCommand(MMC_READ_BLOCK,startadr);

 do
  {
   SPI_WRITE(0xFF);
   SPI_WAIT();
  }while(SPDR!=0xFE); // wait for card response
  
//the following code looks very strange !
//the idea is not to stop the cpu while SPI module transfers data.
//you have 16 cpu cycles until transmission has finished !
//you can use this time to do something like storing your last data
//or get your next data out of memory, doing some loop overhead.....
//don't wait for end of transmission until you have done something better ;)

 SPI_WRITE(0xFF); // shift in first byte
 SPI_WAIT();      // we have to wait for the first byte, but ONLY for the first byte
 by=SPDR;         // get first byte, but store later !
 
 SPI_WRITE(0xFF); // start shift in next byte
                  
 for(i=0; i< (BYTE_PER_SEC-1); i++) //execute the loop while transmission is running in background
  {
   // do the for() loop overhead at this point while SPI module shifts in new data
   *p++=by;         // store last byte in buffer while SPI module shifts in new data
   SPI_WAIT();      // wait for next byte
   by=SPDR;         // get next byte, but store later !
   SPI_WRITE(0xFF); // start shift in next byte
  } 

 // last SPI_WRITE(0xFF); is shifting in crc part1 at this point
 *p++=by;         // store last byte in buffer while SPI module shifts in crc part1
 SPI_WAIT();
 SPI_WRITE(0xFF); // shift in crc part2
 SPI_WAIT();

 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_WAIT();
 SPI_WRITE(0xFF);
 SPI_WAIT();

 SPI_WRITE(0xFE); // start block token for next sector
                  
 for(i=0; i<BYTE_PER_SEC; i++) // execute the loop while transmission is running in background
  {
   // do the for() loop overhead at this point while SPI module shifts out new data
   by=*p++;       // get next data from memory while SPI module shifts out new data
   SPI_WAIT();    // wait for end of transmission
   SPI_WRITE(by); // start shift out next byte
  }

 SPI_WAIT();      // wait til last byte is written to MMC
 SPI_WRITE(0xFF); // 16 bit crc follows data
 SPI_WAIT();
 SPI_WRITE(0xFF);
 SPI_WAIT();

 SPI_WRITE(0xFF); // read response
 SPI_WAIT();
 by=SPDR & 0x1F;
 if(by != 0x05)   // data block accepted ?
  {
   MMC_CS_ON();
   return 1;
  }

 do
  {
   SPI_WRITE(0xFF);
   SPI_WAIT();
  }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 SPI clock pulses before
                                      // sending commands
   SPI_WAIT();
  }                                      
 
 MMC_CS_OFF();

//send CMD0 for RESET
 SPI_WRITE(MMC_RESET); //command code CMD0
 SPI_WAIT();
 SPI_WRITE(0x00);
 SPI_WAIT();
 SPI_WRITE(0x00);
 SPI_WAIT();
 SPI_WRITE(0x00);
 SPI_WAIT();
 SPI_WRITE(0x00);
 SPI_WAIT();
 SPI_WRITE(0x95); // CMD0 needs a checksum !
 SPI_WAIT();
 SPI_WRITE(0xFF); // get 16 bit response high
 SPI_WAIT();
 SPI_WRITE(0xFF); // get 16 bit response low
 SPI_WAIT();

//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
 SPI_WAIT();

 for(i=0; i<16; i++) //CSD has 128 bits -> 16 bytes
  {
   SPI_WRITE(0xFF);
   SPI_WAIT();
   by=SPDR;
//   ShowHex(by);
   iob[i]=by;
  }

 SPI_WRITE(0xFF); // 16 bit crc follows data
 SPI_WAIT();
 SPI_WRITE(0xFF);
 SPI_WAIT();

//here comes the hard stuff !
//calculate disk size and number of last sector
//that can be used on your mmc/sd card

 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -