Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

sd with fat on a pic

Status
Not open for further replies.

AtomSoft

Well-Known Member
hey guys im working on SD stuff and FAT16/32 on a PIC18F4620.. using chans code for petit fat fs..



Here is the code you need to get this working;

I called it mmc.c
Code:
/*-----------------------------------------------------------------------*/
/* PFF - Low level disk control module for ATtiny85     (C)ChaN, 2009    */
/*-----------------------------------------------------------------------*/
#include <p18cxxx.h>
#include "diskio.h"



/* SPI control functions (defined in usi.S) */
void init_spi (void);
void xmit_spi (BYTE);
BYTE rcv_spi (void);
BYTE writeSPI( BYTE data_out) ;

/* Definitions for MMC/SDC command */
#define CMD0	(0x40+0)	/* GO_IDLE_STATE */
#define CMD1	(0x40+1)	/* SEND_OP_COND (MMC) */
#define	ACMD41	(0xC0+41)	/* SEND_OP_COND (SDC) */
#define CMD8	(0x40+8)	/* SEND_IF_COND */
#define CMD9	(0x40+9)	/* SEND_CSD */
#define CMD10	(0x40+10)	/* SEND_CID */
#define CMD12	(0x40+12)	/* STOP_TRANSMISSION */
#define ACMD13	(0xC0+13)	/* SD_STATUS (SDC) */
#define CMD16	(0x40+16)	/* SET_BLOCKLEN */
#define CMD17	(0x40+17)	/* READ_SINGLE_BLOCK */
#define CMD18	(0x40+18)	/* READ_MULTIPLE_BLOCK */
#define CMD23	(0x40+23)	/* SET_BLOCK_COUNT (MMC) */
#define	ACMD23	(0xC0+23)	/* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24	(0x40+24)	/* WRITE_BLOCK */
#define CMD25	(0x40+25)	/* WRITE_MULTIPLE_BLOCK */
#define CMD55	(0x40+55)	/* APP_CMD */
#define CMD58	(0x40+58)	/* READ_OCR */


/* Port Controls  (Platform dependent) */
#define SELECT()	MMC_CS=0	/* MMC CS = L */

void DESELECT(void){
	MMC_CS=1;	/* MMC CS = H */
    writeSPI(0xFF);
}


/*--------------------------------------------------------------------------

   Module Private Functions

---------------------------------------------------------------------------*/

BYTE CardType;



/*-----------------------------------------------------------------------*/
/* Wait for card ready                                                   */
/*-----------------------------------------------------------------------*/




/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus                                 */
/*-----------------------------------------------------------------------*/

static
void release_spi (void)
{
    DESELECT();
    TRISC = 0b00010000;
    SSPSTAT = 0b01000000;
    SSPCON1 = 0b00000010;
    SSPCON1bits.SSPEN = 1;
}


/*-----------------------------------------------------------------------*/
/* Send a command packet to MMC                                          */
/*-----------------------------------------------------------------------*/

static
BYTE send_cmd (
	BYTE cmd,		/* Command byte */
	DWORD arg		/* Argument */
)
{
	BYTE res;
    BYTE i;

    DESELECT();
	/* Select the card and wait for ready */
	SELECT();

	/* Send command packet */
	xmit_spi(cmd);						/* Start + Command index */
	xmit_spi((BYTE)(arg >> 24));		/* Argument[31..24] */
	xmit_spi((BYTE)(arg >> 16));		/* Argument[23..16] */
	xmit_spi((BYTE)(arg >> 8));			/* Argument[15..8] */
	xmit_spi((BYTE)arg);				/* Argument[7..0] */
    xmit_spi(0x95);		                /* Valid CRC for CMD0(0) */

    for( i=0; i<10; i++) 
    {
        res = rcv_spi();      
        if ( res != 0xFF) 
            break;
    }

	return res;			/* Return with the response value */
}



void init_spi(void){
    SSPCON1bits.SSPEN = 0;
    TRISC = 0b00010000;

    SSPSTAT = 0x00;
    SSPSTATbits.CKE = 1;
    SSPSTATbits.SMP = 0;

    SSPCON1 = 0x00;
    SSPCON1bits.CKP = 0;
    SSPCON1bits.SSPM3 = 0;
    SSPCON1bits.SSPM2 = 0;
    SSPCON1bits.SSPM1 = 1; 
    SSPCON1bits.SSPM0 = 0;
    SSPCON1bits.SSPEN = 1;
}

BYTE rcv_spi(void){ 
BYTE temp_data;
    temp_data = writeSPI(0xFF);
    return temp_data;
}

void xmit_spi (BYTE data){
    writeSPI(data);
}
/*--------------------------------------------------------------------------

   Public Functions

---------------------------------------------------------------------------*/
BYTE writeSPI( BYTE data_out )
{
    BYTE tmp;

   if(PIR1bits.SSPIF) PIR1bits.SSPIF = 0;

    tmp = SSPBUF ;   
    SSPBUF = data_out;   
    if ( SSPCON1 & 0x80 ){              // test if write collision occurred
        SSPCON1bits.WCOL = 0;
        return ( 254 );                 // if WCOL bit is set return FE
    }

    while(!PIR1bits.SSPIF);            // wait transfer complete
    PIR1bits.SSPIF = 0;
    return SSPBUF;                      // read the received value
}
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive                                                 */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (void)
{

	WORD tmr;
    BYTE r,i;
    tmr = 10000;
    r = 0;

    init_spi();

    // 1. with the card NOT selected
    DESELECT();

    // 2. send 80 clock cycles start up
    for ( i=0; i<10; i++)
        writeSPI(0xFF);

    // 3. now select the card
    SELECT();

    // 4. send a single RESET command
    r = send_cmd(CMD0, 0); 
    DESELECT();
    if ( r != 1)                // must return Idle
        return 1;   // comand rejected

    // 5. send repeatedly INIT until Idle terminates
    for (i=0; i<tmr; i++) 
    {
        r = send_cmd(CMD1, 0); DESELECT();
        if ( !r) 
            break; 
    } 
    if ( i == tmr)   
        return 2;  // init timed out 

	return r;
}


/*-----------------------------------------------------------------------*/
/* Read partial sector                                                   */
/*-----------------------------------------------------------------------*/

DRESULT disk_readp (
	BYTE *dest,		/* Pointer to the destination object to put data */
	DWORD lba,		/* Start sector number (LBA) */
	WORD ofs,		/* Byte offset in the sector (0..511) */
	WORD cnt		/* Byte count (1..512), b15:destination flag */
)
{

	DRESULT res;
	BYTE *p, dev, rc;
	WORD cf, tmr;
	BYTE (*f)(BYTE);


	dev = (cnt & 0x8000) ? 1 : 0;	// Destination type 
	cnt &= 0x7FFF;
	if (!cnt || ofs + cnt > 512) return RES_PARERR;

	if (!(CardType & CT_BLOCK)) lba *= 512;		// Convert to byte address if needed 

	res = RES_ERROR;
	if (send_cmd(CMD17, lba) == 0) {		// READ_SINGLE_BLOCK 

		tmr = 1000;
		do {							// Wait for data packet in timeout of 200ms 
			rc = rcv_spi();
		} while (rc == 0xFF && --tmr);

		if (rc == 0xFE) {

			cf = 512 + 2 - ofs - cnt;

			while (ofs--) rcv_spi();	// Skip top of sector 

			//if (dev) {					// Receive middle of the sector 
			//	f = *dest;
			//	do
			//		res = f(rcv_spi());
			//	while (--cnt && res);
			//	cf += cnt;
			//} else {
				p = dest;
				do
					*p++ = rcv_spi();
				while (--cnt);
			//}

			do							// Skip bottom of sector and CRC 
				rcv_spi();
			while (--cf);

			res = cnt ? RES_STRERR : RES_OK;
		}
	}

	release_spi();

	return cnt ? RES_ERROR : RES_OK;

}

On his site is code to list directories and files:


my Altered version to show icon and file name;
Code:
FRESULT scan_files (char* path)
{
    FRESULT res;
    FILINFO fno;
    DIR dir;
    int i,x;
    int cnt;
    unsigned char myext[4];

    temp[0] = '/';
    for(x=1;x<17;x++)
        temp[x] = 0;

    cnt = 5;
    res = pf_opendir(&dir, path);
    if (res == FR_OK) {
        i = strlen(path);
        while(1) {
            res = pf_readdir(&dir, &fno);
            if (res != FR_OK || fno.fname[0] == 0) break;
            if (fno.fattrib & AM_DIR) {
                //strcat(temp,fno.fname);
                LCDWriteBMP(fold,cnt-1,2);
                LCDPutStr(fno.fname,cnt,13,0,BLACK,WHITE);
                cnt+=10;
            } else {
                LCDWriteBMP(file,cnt-1,2);
                //get_ext(fno.fname,myext);
                LCDPutStr(myext,cnt,13,0,BLACK,WHITE);
                LCDPutStr(fno.fname,cnt,13,0,BLACK,WHITE);
                cnt+=10;
                //printf("%s/%s\n", path, fno.fname);
            }
        }
    }

    return res;
}

Also i just created a function which when you place a filename in it, it will return the extension ... great for looping through a directory and loading only txt files or images....

Code:
void get_ext (char* path,char* ext)
{
    int i,x,end;

    i = strlen(path);

    for (x=0;x<i;x++){
        if(*path++ == '.') break;
    }
    end = i - x;

    for(x=0;x<end;x++)
        *ext++ = *path++;
}
 
Last edited:

AtomSoft

Well-Known Member
I altered the scan file a bit. This way i can scan files or directories separate. I tried to incorporate like based on type but its hard heh. I can get the type of each but comparing is giving me a headache... The code below will list either directories or files and place them on my LCD at top/left with a image first.

You can do simple addition to find out positions but since i know what files i had and wanted to see how it look i ran this
Code:
    lsdir('/','d',5,5);
    lsdir('/','f',25,5);

This listed directories then files.
Code:
FRESULT lsdir (BYTE* path, BYTE type, BYTE top, BYTE left)
{
    FRESULT res;
    FILINFO fno;
    DIR dir;
    int i,x;

    res = pf_opendir(&dir, path);

    if (res == FR_OK) {
        i = strlen(path);
        while(1) {
            res = pf_readdir(&dir, &fno);
            if (res != FR_OK || fno.fname[0] == 0) break;
            if (fno.fattrib & AM_DIR) {
                if(type == 'd'){
                    //strcat(temp,fno.fname);
                    LCDWriteBMP(fold,top-1,2);
                    LCDPutStr(fno.fname,top,13,0,BLACK,WHITE);
                    top+=10;
                }
            } else {
                if(type == 'f'){
                   LCDWriteBMP(file,top-1,2);
                   LCDPutStr(fno.fname,top,13,0,BLACK,WHITE);
                   top+=10;
               }
            }
        }
    }
    return res;
}

Here are some pictures:
 

Attachments

  • lsdir.jpg
    lsdir.jpg
    340.4 KB · Views: 375
  • lsdir2.jpg
    lsdir2.jpg
    314.8 KB · Views: 339
Last edited:

Mr RB

Well-Known Member
SD and MMC is standard feature and library item that comes with the MikroC compiler and their dev boards.

But it's still pretty impressive what you've done. :)
 

AtomSoft

Well-Known Member
heh forgot to post a nice small example. This code should work on a bunch of pics.. I tested on a 18f4620 but should work on many many pics.

This will open a file in the root directory of SD or SDHC card and read the first 30 bytes.

The file i chose is called "readme.txt" and contains the words: "Test text."

It will open the file read the contents to a buffer and then copy to another buffer with string length info... pretty simple...

EDIT: Cleaner v2

SD_Only2.zip
 

Attachments

  • SD_Only2.zip
    22 KB · Views: 329
Last edited:

kjennejohn

New Member
Hi, Atomsoft. For some reason Winzip on my computer won't unzip the file. It claims it is not a legit archive. What did you compress this with?
My interest in SD is to get it to work with the Atom series from Basic Micro. Their PIC16F887 bootloading chip has a compiler that does SPI, which should allow me to save large blocks of data into a 25Cxxx EEPROM first, then into a SD card. First I have to noodle out what you are doing and then convert that to the BMicro MBasic.
Thanks for the effort.
Happy Holidays!
kenjj
 

AtomSoft

Well-Known Member
im using winRar but ill download winzip then since a lot of people have complained heh give me a minute to download and reupload ok


EDIT:
Done
 

Attachments

  • SD_Only.zip
    22.4 KB · Views: 171
Last edited:

AtomSoft

Well-Known Member
Im actually working on opening a BMP straight off the SD card without first converting it. Seems like a tricky thing....

Gota read header pixel data... heh its gonna be a nice feat to accomplish tho.
 

AtomSoft

Well-Known Member
your welcome and happy holidays also:


Here is what i got so far header wise. The data can be obtained easy....
 

Attachments

  • bmpheader.jpg
    bmpheader.jpg
    65.7 KB · Views: 265
Last edited:
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top