Ok, seems the attachment was stripped. It's here:
http://www.htsoft.com/resources/sd.c
Clyde
On Thu, Apr 13, 2006 at 05:51:01AM +1000, Clyde Stubbs wrote:
> Attached is some code for driving an SD card via an SPI port. This
> was written specifically for a SiLabs C8051F320 but should adapt
> with little trouble to any other SPI interface.
>
> The code has been widely tested on a variety of different brand SD
> cards - some have little quirks.
>
> Clyde
>
>
> On Wed, Apr 12, 2006 at 07:16:32PM -0000, darcy_will wrote:
> > Thanks to everyone that has offered their help with this topic! I
> > honestly didn't expect such a fantastic response in such a short
> > period of time.
> >
> > Cheers all
> > D.
> >
> >
> >
> >
> >
> >
> > Yahoo! Groups Links
> >
> >
> >
> >
> >
>
> --
> Clyde Stubbs | HI-TECH Software
> Email: clyde@... | Phone Fax
> WWW: http://www.htsoft.com/ | USA: (408) 490 2885 (408) 490 2885
> PGP: finger clyde@... | AUS: +61 7 3722 7777 +61 7 3722 7778
> ---------------------------------------------------------------------------
> HI-TECH C: compiling the real world.
>
> ----------
>
> /* SD card interface. Copyright (C) 2005 HI-TECH Software Pty. Ltd. */
>
> #include <8051.h>
>
> #define FALSE 0
> #define TRUE 1
>
> // Error codes for the SD
>
> enum {
> RESET_FAIL=1, READ_FAIL, CSD_FAIL, WRITE_FAIL, STATUS_FAIL, ACMD_FAIL, ERASE_FAIL
> };
>
>
> // card present states
>
> enum {
> CARD_MISSING = 0,
> CARD_PRESENT,
> CARD_READY,
> CARD_FAIL,
> CARD_EJECTED
> } card_state;
>
> static unsigned char * xptr; // data pointer
> static unsigned char error_code; // code d'error
> static unsigned long card_size; // card size in blocks
> static unsigned long part_offset;// offset to start of first partition
> static unsigned char file_format; // partition layout
>
> #define V33 (1<< 6) // bit identifying 3.3V
> #define SD_BLKLEN 512 // block size
> #define CSD_SIZE 16 // CSD size in bytes
> #define CID_SIZE 16 // CID size in bytes
>
>
> unsigned char blkbuf[SD_BLKLEN];
>
>
>
> #define ACMD 55 // command following is application specific
> #define CARD_SELECT (P1_BITS.B3) // this bit should drive the card select
> #define SPIBUSY 0x80 // spi busy bit
> #define CRC 0x95 // all purpose CRC
>
> static bit fat32; // set if we have a fat32 card
> static bit fat_check; // we need to check the fat again
> static unsigned char timeout; // timeout value in ticks
>
> // this must be implemented in an timer interrupt. If timeout is non-zero, the
> // interrupt routine should decrement it once per timer tick.
> // adjust the calculation in SET_TIMEOUT so that the argument represents milliseconds.
>
> #define SET_TIMEOUT(x) (timeout = (((x)*128UL))/1000+1)
> #define TIMEDOUT() (timeout == 0)
>
> // fetch a long value from the buffer
>
> static unsigned long
> get_long(unsigned char * ptr)
> {
> unsigned long value;
>
> value = *ptr++;
> value += *ptr++ << 8;
> value += (unsigned long)*ptr++ << 16;
> value += (unsigned long)*ptr++ << 24;
> return value;
> }
>
> static void
> SPI_init(void)
> {
> // setup the SPI for the SD card.
> // Data latched on rising edge, input valid in middle of clock,
> // idle state is high.
> // initial clock for the SD card must be very slow - 200kHz
> // due to the open-drain connection
>
> SPI0CKR = 0x30; // start SPI real slow
> SPI0CFG = 0B01000000;
> SPI0CN = 1;
> }
>
> // Send one byte to the SPI
>
> static void
> SPI_send(unsigned char databyte)
> {
> while(TXBMT == 0)
> continue;
> SPI0DAT = databyte;
> }
>
> // read one byte from the SPI
>
> static unsigned char
> SPI_read(void)
> {
> SPIF = 0;
> SPI0DAT = 0xFF; // clock out 1s while clocking in data
> while(!SPIF)
> continue;
> return SPI0DAT;
> }
>
> // Send idle (0xFF) a specified number of bytes
>
> static void
> SD_idle(unsigned char cnt)
> {
> while(cnt--)
> SPI_send(0xFF);
> }
>
> // Send a command and wait for a response
>
> static unsigned char
> SD_send(unsigned char cmd, unsigned long arg)
> {
> unsigned char tok;
>
> CARD_SELECT = 0; // select the card
> SD_idle(3); // lead-in
> SPI_send(cmd|0x40); // send the command
> SPI_send(arg >> 24);
> SPI_send(arg >> 16);
> SPI_send(arg >> 8);
> SPI_send(arg);
> SPI_send(CRC);
> cmd = 16;
> do
> tok = SPI_read(); // wait for response - up to 16 times
> while(tok & 0x80 && --cmd != 0);
> return tok;
> }
>
> static bit
> SD_reset(void)
> {
> SPI_init();
> SD_idle(100);
> CARD_SELECT = 0; // select the card
> SD_idle(100); // send numerous clocks to initialize
> CARD_SELECT = 1;
> SD_idle(100);
> SD_send(0, 0); // send initialization command
> SET_TIMEOUT(1000); // initialization should take no more than 1 second
> do {
> if(TIMEDOUT()) {
> error_code = RESET_FAIL;
> return FALSE;
> }
> SD_send(55, 0); // app-specific command follows
> } while(SD_send(41, 0) & 1);
> SPI0CKR = 0; // set SPI to maximum speed - 12 MHz
> return TRUE;
> }
>
>
> static unsigned char
> SD_cmd(unsigned char cmd, unsigned long arg)
> {
> if(SD_send(cmd, arg) == 0)
> return 0;
> // card did not respond in a reasonable time - might be a PNY!
> // hard reset the card and retry the command, but only once.
> _delay(24000000/4); // wait 240 ms to ensure buffers flushed
> SD_reset();
> return SD_send(cmd, arg);
> }
>
> // read the status register
>
> static unsigned
> SD_readstatus(void)
> {
> unsigned char i;
>
> i = SD_cmd(13, 0);
> if(i & 0x80) {
> error_code = STATUS_FAIL;
> return FALSE;
> }
> return (i << 8) + SPI_read();
> }
>
> // read the CSD - 16 bytes
>
> static bit
> SD_readcsd(void)
> {
> unsigned char token;
> unsigned char i;
> unsigned int len;
>
> if(SD_cmd(9, 0)) {
> error_code = CSD_FAIL;
> return FALSE;
> }
> SET_TIMEOUT(200);
> do
> token = SPI_read();
> while(token != 0xFE && !TIMEDOUT());
> if(token & 1) {
> error_code = CSD_FAIL;
> return FALSE;
> }
> i = 0;
> do
> blkbuf[i] = SPI_read();
> while(++i != CSD_SIZE);
> SPI_read();
> SPI_read();
> i = (blkbuf[15-6] & 3) << 1; // bits 48-49
> i += blkbuf[15-5] >> 7; // bit 47
> i += 2;
> len = blkbuf[15-8] << 2;
> len += blkbuf[15-7] >> 6;
> len += (blkbuf[15-9] & 3) << 10;
> len++;
> card_size = (1L << i) * len - 1; // set to number of last block
> file_format = (blkbuf[15-1] >> 2) & 3;
> return TRUE;
> }
>
> static void
> SD_stopwrite(void)
> {
> SPI_send(0xFD);
> SET_TIMEOUT(500);
> SPI_send(0xFF);
> while(!TIMEDOUT())
> if(SPI_read() == 0xFF)
> break;
> }
>
> // commence a read operation
>
> static bit
> SD_startread(unsigned long blockno)
> {
> if(SD_cmd(17, blockno << 9)) {
> error_code = READ_FAIL;
> return FALSE;
> }
> return TRUE;
> }
>
> static bit
> SD_waitread(void)
> {
> unsigned char token;
> unsigned int i;
>
> SET_TIMEOUT(200);
> do
> token = SPI_read();
> while(token != 0xFE && !TIMEDOUT());
> if(token & 1) {
> error_code = READ_FAIL;
> return FALSE;
> }
> return TRUE;
> }
>
> // commence a write operation
>
> static bit
> SD_startwrite(unsigned long blockno)
> {
> unsigned char token;
> unsigned int i;
>
> if(SD_cmd(24, blockno << 9)) {
> error_code = WRITE_FAIL;
> return FALSE;
> }
> SPI_send(0xFF);
> SPI_send(0xFE); // start of write
> return TRUE;
> }
>
> static bit
> SD_writeblock(unsigned long blockno, unsigned char * buf)
> {
> unsigned int i;
> unsigned char tok;
>
> if(!SD_startwrite(blockno))
> return FALSE;
> i = SD_BLKLEN;
> do
> SPI_send(*buf++);
> while(--i != 0);
> do
> tok = SPI_read();
> while(tok == 0xFF);
> tok &= 0x1F;
> if(tok != 5) {
> error_code = WRITE_FAIL;
> return FALSE;
> }
> // wait for completion
> while(SPI_read() != 0xFF)
> continue;
> return TRUE;
> }
>
> // read one BLKLEN block from the card.
>
> static bit
> SD_readblock(unsigned long blockno, unsigned char * buf)
> {
> unsigned int i;
>
> if(!SD_startread(blockno))
> return FALSE;
> if(!SD_waitread())
> return FALSE;
> i = 0;
> do
> *buf++ = SPI_read();
> while(++i != SD_BLKLEN);
> SPI_read();
> SPI_read(); // flush unwanted CRC
> return TRUE;
> }
>
>
> // init the SD card
> static bit
> SD_init(void)
> {
> unsigned char i;
> unsigned long sectors;
>
> part_offset = 0;
> card_size = 0;
>
> if(!SD_reset() || !SD_readcsd())
> return FALSE;
> if(file_format == 0) {
> if(!SD_readblock(0, blkbuf))
> return FALSE;
> if(blkbuf[SD_BLKLEN-1] == 0xAA && blkbuf[SD_BLKLEN-2] == 0x55) {
> xptr = blkbuf+0x1BE; // point to start of partition table
> i = 4;
> do {
> if(xptr[0] == 0 &&
> (xptr[4] == 1 || xptr[4] == 4 || xptr[4] == 6 || xptr[4] == 14)) {
> part_offset = get_long(xptr+8);
> card_size -= part_offset;
> break;
> }
> } while(--i != 0);
> }
> }
> return TRUE;
> }
>
> // check the filesystem type - set a flag if it is FAT32
> static void
> SD_fatchick(void)
> {
> unsigned char i;
> unsigned long sectors;
>
> fat32 = 0;
> fat_check = 0;
> if(!SD_readblock(part_offset, blkbuf))
> return;
> if(blkbuf[0x13] != 0 || blkbuf[0x14] != 0)
> return; // must be <= 32MB, quite safe
> sectors = get_long(blkbuf+0x20); // get number of sectors
> i = blkbuf[0x0D]; // sectors per cluster
> while((i >>= 1) != 0)
> sectors >>= 1;
> if(sectors >= 65525)
> fat32 = 1;
> }
>
>
>
>
> [Non-text portions of this message have been removed]
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
--
Clyde Stubbs | HI-TECH Software
Email: clyde@... | Phone Fax
WWW: http://www.htsoft.com/ | USA: (408) 490 2885 (408) 490 2885
PGP: finger clyde@... | AUS: +61 7 3722 7777 +61 7 3722 7778
---------------------------------------------------------------------------
HI-TECH C: compiling the real world.Message
Re: [lpc2000] SD/SPI driver code
2006-04-12 by Clyde Stubbs
Attachments
- No local attachments were found for this message.