转自:http://blog.csdn.net/ming1006/article/details/7283689
上一篇文章已经介绍了Micro SD卡SPI模式的实现方法,这里给出自己写的基于nios ii的Micro SD卡读写程序(IO口模拟spi)。
硬件设计就不多说了,主要是添加4的1为PIO口来模拟SPI的CS、SCLK、MISO和MOSI。
以下是代码:
头文件SD_spi_solution.h
- #ifndef SD_SPI_SOLUTION_H_
- #define SD_SPI_SOLUTION_H_
- #include<system.h>
- #include<alt_types.h>
- #include<altera_avalon_pio_regs.h>
- #define CMD0 0 /* GO_IDLE_STATE */
- #define CMD55 55 /* APP_CMD */
- #define ACMD41 41 /* SEND_OP_COND (ACMD) */
- #define CMD1 1 /* SEND_OP_COND */
- #define CMD17 17 /* READ_SINGLE_BLOCK */
- #define CMD8 8 /* SEND_IF_COND */
- #define CMD18 18 /* READ_MULTIPLE_BLOCK */
- #define CMD12 12 /* STOP_TRANSMISSION */
- #define CMD24 24 /* WRITE_BLOCK */
- #define CMD25 25 /* WRITE_MULTIPLE_BLOCK */
- #define CMD13 13 /* SEND_STATUS */
- #define CMD9 9 /* SEND_CSD */
- #define CMD10 10 /* SEND_CID */
- #define CSD 9
- #define CID 10
- //delay 1us(actually not,it maybe is several us,I don't test it)
- void usleep(alt_u8 i);
- //set CS low
- void CS_Enable();
- //set CS high and send 8 clocks
- void CS_Disable();
- //write a byte
- void SDWriteByte(alt_u8 data);
- //read a byte
- alt_u8 SDReadByte();
- //send a command and send back the response
- alt_u8 SDSendCmd(alt_u8 cmd,alt_u32 arg,alt_u8 crc);
- //reset SD card
- alt_u8 SDReset();
- //initial SD card
- alt_u8 SDInit();
- //read a single sector
- alt_u8 SDReadSector(alt_u32 addr,alt_u8 * buffer);
- //read multiple sectors
- alt_u8 SDReadMultiSector(alt_u32 addr,alt_u8 sector_num,alt_u8 * buffer);
- //write a single sector
- alt_u8 SDWriteSector(alt_u32 addr,alt_u8 * buffer);
- //write multiple sectors
- alt_u8 SDWriteMultiSector(alt_u32 addr,alt_u8 sector_num,alt_u8 * buffer);
- //get CID or CSD
- alt_u8 SDGetCIDCSD(alt_u8 cid_csd,alt_u8 * buffer);
- //spi speed(0-255),0 is fastest
- alt_u8 spi_speed;
- #endif /* SD_SPI_SOLUTION_H_ */
- #include"SD_spi_Solution.h"
- alt_u8 spi_speed = 10;//the spi speed(0-255),0 is fastest
- //delay 1us(actually not,it maybe is several us,I don't test it)
- void usleep(alt_u8 i)
- {
- while(i --);
- }
- //set CS low
- void CS_Enable()
- {
- //set CS low
- IOWR_ALTERA_AVALON_PIO_DATA(CS_BASE, 0x00);
- }
- //set CS high and send 8 clocks
- void CS_Disable()
- {
- //set CS high
- IOWR_ALTERA_AVALON_PIO_DATA(CS_BASE, 0x01);
- //send 8 clocks
- SDWriteByte(0xff);
- }
- //write a byte
- void SDWriteByte(alt_u8 data)
- {
- alt_u8 i;
- //write 8 bits(MSB)
- for(i = 0;i < 8;i ++)
- {
- IOWR_ALTERA_AVALON_PIO_DATA(SCLK_BASE, 0x00);
- usleep(spi_speed);
- if(data & 0x80) IOWR_ALTERA_AVALON_PIO_DATA(DI_BASE, 0x01);
- else IOWR_ALTERA_AVALON_PIO_DATA(DI_BASE, 0x00);
- data <<= 1;
- IOWR_ALTERA_AVALON_PIO_DATA(SCLK_BASE, 0x01);
- usleep(spi_speed);
- }
- //when DI is free,it should be set high
- IOWR_ALTERA_AVALON_PIO_DATA(DI_BASE, 0x01);
- }
- //read a byte
- alt_u8 SDReadByte()
- {
- alt_u8 data = 0x00,i;
- //read 8 bit(MSB)
- for(i = 0;i < 8;i ++)
- {
- IOWR_ALTERA_AVALON_PIO_DATA(SCLK_BASE, 0x00);
- usleep(spi_speed);
- IOWR_ALTERA_AVALON_PIO_DATA(SCLK_BASE, 0x01);
- data <<= 1;
- if(IORD_ALTERA_AVALON_PIO_DATA(DO_BASE)) data |= 0x01;
- usleep(spi_speed);
- }
- return data;
- }
- //send a command and send back the response
- alt_u8 SDSendCmd(alt_u8 cmd,alt_u32 arg,alt_u8 crc)
- {
- alt_u8 r1,time = 0;
- //send the command,arguments and CRC
- SDWriteByte((cmd & 0x3f) | 0x40);
- SDWriteByte(arg >> 24);
- SDWriteByte(arg >> 16);
- SDWriteByte(arg >> 8);
- SDWriteByte(arg);
- SDWriteByte(crc);
- //read the respond until responds is not '0xff' or timeout
- do{
- r1 = SDReadByte();
- time ++;
- //if time out,return
- if(time > 254) break;
- }while(r1 == 0xff);
- return r1;
- }
- //reset SD card
- alt_u8 SDReset()
- {
- alt_u8 i,r1,time = 0;
- //set CS high
- CS_Disable();
- //send 128 clocks
- for(i = 0;i < 16;i ++)
- {
- SDWriteByte(0xff);
- }
- //set CS low
- CS_Enable();
- //send CMD0 till the response is 0x01
- do{
- r1 = SDSendCmd(CMD0,0,0x95);
- time ++;
- //if time out,set CS high and return r1
- if(time > 254)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0x01);
- //set CS high and send 8 clocks
- CS_Disable();
- return 0;
- }
- //initial SD card(send CMD55+ACMD41 or CMD1)
- alt_u8 SDInit()
- {
- alt_u8 r1,time = 0;
- //set CS low
- CS_Enable();
- //check interface operating condition
- r1 = SDSendCmd(CMD8,0x000001aa,0x87);
- //if support Ver1.x,but do not support Ver2.0,set CS high and return r1
- if(r1 == 0x05)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- //read the other 4 bytes of response(the response of CMD8 is 5 bytes)
- r1=SDReadByte();
- r1=SDReadByte();
- r1=SDReadByte();
- r1=SDReadByte();
- do{
- //send CMD55+ACMD41 to initial SD card
- do{
- r1 = SDSendCmd(CMD55,0,0xff);
- time ++;
- //if time out,set CS high and return r1
- if(time > 254)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0x01);
- r1 = SDSendCmd(ACMD41,0x40000000,0xff);
- //send CMD1 to initial SD card
- //r1 = SDSendCmd(CMD1,0x00ffc000,0xff);
- time ++;
- //if time out,set CS high and return r1
- if(time > 254)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0x00);
- //set CS high and send 8 clocks
- CS_Disable();
- return 0;
- }
- //read a single sector
- alt_u8 SDReadSector(alt_u32 addr,alt_u8 * buffer)
- {
- alt_u8 r1;
- alt_u16 i,time = 0;
- //set CS low
- CS_Enable();
- //send CMD17 for single block read
- r1 = SDSendCmd(CMD17,addr << 9,0x55);
- //if CMD17 fail,return
- if(r1 != 0x00)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- //continually read till get the start byte 0xfe
- do{
- r1 = SDReadByte();
- time ++;
- //if time out,set CS high and return r1
- if(time > 30000)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0xfe);
- //read 512 Bits of data
- for(i = 0;i < 512;i ++)
- {
- buffer[i] = SDReadByte();
- }
- //read two bits of CRC
- SDReadByte();
- SDReadByte();
- //set CS high and send 8 clocks
- CS_Disable();
- return 0;
- }
- //read multiple sectors
- alt_u8 SDReadMultiSector(alt_u32 addr,alt_u8 sector_num,alt_u8 * buffer)
- {
- alt_u16 i,time = 0;
- alt_u8 r1;
- //set CS low
- CS_Enable();
- //send CMD18 for multiple blocks read
- r1 = SDSendCmd(CMD18,addr << 9,0xff);
- //if CMD18 fail,return
- if(r1 != 0x00)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- //read sector_num sector
- do{
- //continually read till get start byte
- do{
- r1 = SDReadByte();
- time ++;
- //if time out,set CS high and return r1
- if(time > 30000 || ((r1 & 0xf0) == 0x00 && (r1 & 0x0f)))
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0xfe);
- time = 0;
- //read 512 Bits of data
- for(i = 0;i < 512;i ++)
- {
- *buffer ++ = SDReadByte();
- }
- //read two bits of CRC
- SDReadByte();
- SDReadByte();
- }while( -- sector_num);
- time = 0;
- //stop multiple reading
- r1 = SDSendCmd(CMD12,0,0xff);
- //set CS high and send 8 clocks
- CS_Disable();
- return 0;
- }
- //write a single sector
- alt_u8 SDWriteSector(alt_u32 addr,alt_u8 * buffer)
- {
- alt_u16 i,time = 0;
- alt_u8 r1;
- //set CS low
- CS_Enable();
- do{
- do{
- //send CMD24 for single block write
- r1 = SDSendCmd(CMD24,addr << 9,0xff);
- time ++;
- //if time out,set CS high and return r1
- if(time > 254)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0x00);
- time = 0;
- //send some dummy clocks
- for(i = 0;i < 5;i ++)
- {
- SDWriteByte(0xff);
- }
- //write start byte
- SDWriteByte(0xfe);
- //write 512 bytes of data
- for(i = 0;i < 512;i ++)
- {
- SDWriteByte(buffer[i]);
- }
- //write 2 bytes of CRC
- SDWriteByte(0xff);
- SDWriteByte(0xff);
- //read response
- r1 = SDReadByte();
- time ++;
- //if time out,set CS high and return r1
- if(time > 254)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while((r1 & 0x1f)!= 0x05);
- time = 0;
- //check busy
- do{
- r1 = SDReadByte();
- time ++;
- //if time out,set CS high and return r1
- if(time > 60000)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0xff);
- //set CS high and send 8 clocks
- CS_Disable();
- return 0;
- }
- //write several blocks
- alt_u8 SDWriteMultiSector(alt_u32 addr,alt_u8 sector_num,alt_u8 * buffer)
- {
- alt_u16 i,time = 0;
- alt_u8 r1;
- //set CS low
- CS_Enable();
- //send CMD25 for multiple block read
- r1 = SDSendCmd(CMD25,addr << 9,0xff);
- //if CMD25 fail,return
- if(r1 != 0x00)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- do{
- do{
- //send several dummy clocks
- for(i = 0;i < 5;i ++)
- {
- SDWriteByte(0xff);
- }
- //write start byte
- SDWriteByte(0xfc);
- //write 512 byte of data
- for(i = 0;i < 512;i ++)
- {
- SDWriteByte(*buffer ++);
- }
- //write 2 byte of CRC
- SDWriteByte(0xff);
- SDWriteByte(0xff);
- //read response
- r1 = SDReadByte();
- time ++;
- //if time out,set CS high and return r1
- if(time > 254)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while((r1 & 0x1f)!= 0x05);
- time = 0;
- //check busy
- do{
- r1 = SDReadByte();printf("n%d",r1);
- time ++;
- //if time out,set CS high and return r1
- if(time > 30000)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0xff);
- time = 0;
- }while(-- sector_num);
- //send stop byte
- SDWriteByte(0xfd);
- //check busy
- do{
- r1 = SDReadByte();
- time ++;
- //if time out,set CS high and return r1
- if(time > 30000)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0xff);
- //set CS high and send 8 clocks
- CS_Disable();
- return 0;
- }
- //get CID or CSD
- alt_u8 SDGetCIDCSD(alt_u8 cid_csd,alt_u8 * buffer)
- {
- alt_u8 r1;
- alt_u16 i,time = 0;
- //set CS low
- CS_Enable();
- //send CMD10 for CID read or CMD9 for CSD
- do{
- if(cid_csd == CID)
- r1 = SDSendCmd(CMD10,0,0xff);
- else
- r1 = SDSendCmd(CMD9,0,0xff);
- time ++;
- //if time out,set CS high and return r1
- if(time > 254)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0x00);
- time = 0;
- //continually read till get 0xfe
- do{
- r1 = SDReadByte();
- time ++;
- //if time out,set CS high and return r1
- if(time > 30000)
- {
- //set CS high and send 8 clocks
- CS_Disable();
- return r1;
- }
- }while(r1 != 0xfe);
- //read 512 Bits of data
- for(i = 0;i < 16;i ++)
- {
- *buffer ++ = SDReadByte();
- }
- //read two bits of CRC
- SDReadByte();
- SDReadByte();
- //set CS high and send 8 clocks
- CS_Disable();
- return 0;
- }