CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

FAT32 code for MultiMedia Cards
Goto page 1, 2, 3, 4, 5  Next
 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Tomi



Joined: 11 Aug 2005
Posts: 10

View user's profile Send private message

FAT32 code for MultiMedia Cards
PostPosted: Thu Aug 11, 2005 7:55 am     Reply with quote

Just removed the dust from my old FAT32 code. Maybe it will be useful for somebody... See notes in EX_ file.

So the header file (MyMMCFat32.h):
Code:
#define MAXFILES 2
typedef struct _diskinforec
{
   char   hJumpCode[3];
   char  OEMName[8];
   int16   hBytesPerSector;
   char   bSectorsPerCluster;
   int16 Reserved1;
   char   FATCopies;
   int16 hMaxRootEntries;
   int16 hSectors;
   char   Descriptor;
   int16 holdSectorsPerFat;
   int16 hSectorsPerTrack;
   int16 hNumberofHeads;
   int32   hNumberofHidden;
   int32   hNumberofSectors;

   int32 hSectorsPerFat;
   int16 hFlags;
   int16 hFAT32Version;
   int32 hRootStartCluster;
} diskinforec;

typedef struct _direntry
{
   char   sName[8];
   char   sExt[3];
   char   bAttr;
   char   bReserved[8];
      int16 hClusterH;
   int16   hTime;
   int16   hDate;
   int16   hCluster;
   int32   wSize;
} DIR;

typedef struct {
   char    IOpuffer[512];
   DIR    DirEntry;
   int32 CurrentCluster;
   int16 posinsector;
   int32   position;
   int32 dirSector;
   int16   dirIdx;
   char   mode;
   char   Free;
} FILE;

typedef struct {
   int32 MMCAddress;
   int32 FATstartidx;
   int32 gStartSector;
   int32 gFirstDataSector;
   int16 gDirEntryIdx;
   int32 gDirEntrySector;
   int16 gFirstEmptyDirEntry;
   int32 gFirstDirEntryCluster;
} FAT32Vars;

char MMCInit();
void ReadSector(int32 sector, char *hova);
void WriteSector(int32 sector, char *honnan);

void InitFAT();
char FindDirEntry(char *fname, char f);

char fopen(char *fname, char mode);
void fclose(char f);
void fflush(char f);
char cwd(char *fname, char f);
void fputch(char be, char f);
char fgetch(char *ki, char f);
void fputstring(char *be, char f); // fputs is reserved in CCS C
int16 fread(char *buffer, int16 leng, char f);
void fwrite(char *buffer, int16 leng, char f);
char remove(char *fname);
char getfsize(char *fname, int32 *fsiz);


The implementation (MyMMCFat32.c):
Code:
int32 FATTable[128];
int32 gFirstEmptyCluster;

FAT32Vars gFAT32Vars;
diskinforec DiskInfo;
FILE gFiles[MAXFILES];

#byte MMCAddressL = gFAT32Vars
#byte MMCAddressH = gFAT32Vars+1
#byte MMCAddressHL = gFAT32Vars+2
#byte MMCAddressHH = gFAT32Vars+3
#byte gStartSectorL = gFAT32Vars+8
#byte gStartSectorH = gFAT32Vars+9
#byte gStartSectorHL = gFAT32Vars+10

#locate FATTable = 0x0800
#locate gFiles = 0x0A00
#locate gFAT32Vars = 0x0E70
#locate DiskInfo = 0x0E90

#use FAST_IO(C)
#define ChipSel pin_c2
#define ChipClk pin_c3
#define ChipDin pin_c5

//#define CardInserted PIN_A4 // these pins are already defined in my main C file
//#define REDLED PIN_E7       
//#define YELLOWLED PIN_E6 // remove comments or comment out lines containing YELLOWLED refs in this file
//#define GREENLED PIN_E5


char IsSelfDir(char *be)
{
if (be[0] == '.' && be[1] == '.') return 0xFF;
else return 0;
}

void MMCOut(char indata)
{
char i;
SSPBUF=indata;
while (!BF);
i = SSPBUF;
}

void MMC8Clock()
{
char i;
SSPBUF=0xFF;
while (!BF);
i = SSPBUF;
}

char MMCIn()
{
char i;
SSPBUF=0xFF;
while (!BF);
i = SSPBUF;
return i;
}

char MMCInit()
{
   char response,iii,errcnt;

   restart_wdt();
   output_high(ChipSel);
   output_high(ChipClk);
   output_high(ChipDin);
   bit_clear(SSPCON1,5);
   SSPCON1 = 0x30; // modify this number to change SPI clock rate
   SSPSTAT = 0;
   iii = 10;
   errcnt = 100;
   do {
      MMCOut(0xFF);
   } while (--iii);
   delay_us(1000);
   output_low(ChipClk);
   output_low(ChipSel);
   MMCOut(0x40);
   MMCOut(0x00);
   MMCOut(0x00);
   MMCOut(0x00);
   MMCOut(0x00);
   MMCOut(0x95);
   MMC8Clock();
   response = MMCIn();
   output_high(ChipSel);
   output_high(ChipClk);
   do {
      delay_us(1000);
      output_low(ChipClk);
      output_low(ChipSel);
      MMCOut(0x41);
      MMCOut(0x00);
      MMCOut(0x00);
      MMCOut(0x00);
      MMCOut(0x00);
      MMCOut(0x01);
      MMC8Clock();
      response = MMCIn();
      output_high(ChipSel);
      output_high(ChipClk);
      MMC8Clock();
      errcnt--;
   } while (response && errcnt);
   return errcnt;
}

int16 GetCurrentDOSDate()
{
int16 retval;

retval = myrec.tm_year - 1980;
retval <<= 9;
retval |= ((int16)myrec.tm_mon << 5);
retval |= (int16)myrec.tm_mday;
return retval;
}

int16 GetCurrentDOSTime()
{
int16 retval;

retval = myrec.tm_hour;
retval <<= 11;
retval |= ((int16)myrec.tm_min << 5);
retval |= (int16)myrec.tm_sec >> 1;
return retval;
}

void ReadSector(int32 sector, char *hova)
{
   char errs,response;
   char cnt2,cnt3;

   #byte sectorL = sector
   #byte sectorH = sector+1
   #byte sectorHL = sector+2

   if (input(CardInserted)) return;
   Disable_interrupts(GLOBAL);
   Restart_wdt();
   MMCAddressL = 0;
   MMCAddressH = sectorL;
   MMCAddressHL = sectorH;
   MMCAddressHH = sectorHL;
   gFAT32Vars.MMCAddress <<= 1;

   output_low(ChipClk);
   output_low(ChipSel);
   MMCOut(0x51);
   MMCOut(MMCAddressHH);
   MMCOut(MMCAddressHL);
   MMCOut(MMCAddressH & 0xFE);
   MMCOut(0);
   MMCOut(0x01);
   errs = 8;
   do {
      response = MMCIn();
   } while (--errs && response==0xFF);
   errs = 50;
   do {
      response = MMCIn();
      if (response == 0xFE) break;
      delay_ms(1);
   } while (--errs);
   *0xFE9 = (int16)hova;
   cnt3 = 2;
   cnt2 = 0;
   do {
   do {
      SSPBUF=0xFF;
      while (!BF);
      *0xFEE = SSPBUF;
   } while (--cnt2);
   } while (--cnt3);
   response = MMCIn();
   response = MMCIn();
   output_high(ChipSel);
   output_high(ChipClk);
   Enable_interrupts(GLOBAL);
}

void WriteSector(int32 sector, char *honnan)
{
   char errs,response;
   char cnt2,cnt3;
   #byte sectorL = sector
   #byte sectorH = sector+1
   #byte sectorHL = sector+2

   if (input(CardInserted)) return;
   Disable_interrupts(GLOBAL);
   Restart_wdt();
   MMCAddressL = 0;
   MMCAddressH = sectorL;
   MMCAddressHL = sectorH;
   MMCAddressHH = sectorHL;
   gFAT32Vars.MMCAddress <<= 1;
   response = 0;
   output_low(ChipClk);
   output_low(ChipSel);
   MMCOut(0x58);
   MMCOut(MMCAddressHH);
   MMCOut(MMCAddressHL);
   MMCOut(MMCAddressH & 0xFE);
   MMCOut(0);
   MMCOut(0x01);
   MMC8Clock();
   errs = 8;
   do {
      response = MMCIn();
   } while (--errs && response==0xFF);
   if (response) {
        output_high(ChipSel);
        output_high(ChipClk);
      MMC8Clock();
      Enable_interrupts(GLOBAL);
        return;
   }
   MMC8Clock();
   MMCOut(0xFE);
   *0xFE9 = (int16)honnan;
   cnt3 = 2;
   cnt2 = 0;
   do {
   do {
      SSPBUF=*0xFEE;
      while (!BF);
   } while (--cnt2);
   } while (--cnt3);
   MMCOut(0x00);
   MMCOut(0x01);
   response = MMCIn();
   response ^= 0xE5;
   if (response) {
      goto endwr3;
   }
   do {
      response = MMCIn();
   } while (response == 0);
   response = 0;
   endwr3:
   output_high(ChipSel);
   output_high(ChipClk);
   MMC8Clock();
   Enable_interrupts(GLOBAL);
}

void InitFAT()
{
int32 actsector;
char i;

   gFirstEmptyCluster = 0;
   gFAT32Vars.gStartSector = 0;
   ReadSector(gFAT32Vars.gStartSector,gFiles[MAXFILES-1].IOpuffer);
   if (gFiles[MAXFILES-1].IOpuffer[0] != 0xEB) {
      gStartSectorL = gFiles[MAXFILES-1].IOpuffer[0x1C6];
      gStartSectorH = gFiles[MAXFILES-1].IOpuffer[0x1C7];
      gStartSectorHL = gFiles[MAXFILES-1].IOpuffer[0x1C8];
      ReadSector(gFAT32Vars.gStartSector,gFiles[MAXFILES-1].IOpuffer);
   }
   memcpy(&DiskInfo,gFiles[MAXFILES-1].IOpuffer,sizeof(DiskInfo));
   actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1;
   ReadSector(actsector,FATTable);
   gFAT32Vars.FATstartidx = 0;
   gFAT32Vars.gFirstDataSector = gFAT32Vars.gStartSector + DiskInfo.FATCopies*DiskInfo.hSectorsPerFat+DiskInfo.Reserved1 - 2;
   for (i=0;i<MAXFILES;i++)
      gFiles[i].Free = TRUE;
}

int32 GetNextCluster(int32 curcluster)
{
   int32 actsector;
   int32 clpage;
   char clpos;

   clpage = curcluster >> 7;
   clpos = curcluster & 0x7F;
   if (clpage != gFAT32Vars.FATstartidx) { // read in the requested page
      actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
      ReadSector(actsector,FATTable);
      gFAT32Vars.FATstartidx = clpage;
   }
   return (FATTable[clpos]);
}

void SetClusterEntry(int32 curcluster,int32 value)
{
   int32 actsector;
   int32 clpage;
   char clpos;

   clpage = curcluster >> 7;
   clpos = curcluster & 0x7F;
   actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
   if (clpage != gFAT32Vars.FATstartidx) {
      ReadSector(actsector,FATTable);
      gFAT32Vars.FATstartidx = clpage;
   }
   FATTable[clpos] = value;
   WriteSector(actsector,FATTable);
   actsector += DiskInfo.hSectorsPerFat;
   WriteSector(actsector,FATTable);
}

void ClearClusterEntry(int32 curcluster)
{
   int32 actsector;
   int32 clpage;
   char clpos;

   clpage = curcluster >> 7;
   clpos = curcluster & 0x7F;
   if (clpage != gFAT32Vars.FATstartidx) {
      actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + gFAT32Vars.FATstartidx;
      WriteSector(actsector,FATTable);
      actsector += DiskInfo.hSectorsPerFat;
      WriteSector(actsector,FATTable);
      actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
      ReadSector(actsector,FATTable);
      gFAT32Vars.FATstartidx = clpage;
   }
   FATTable[clpos] = 0;
}

int32 FindFirstFreeCluster()
{
int32 i,st,actsector,retval;
char j;

   st = gFirstEmptyCluster;
   for (i=st;i<DiskInfo.hSectorsPerFat;i++) {
      if (i != gFAT32Vars.FATstartidx) {
         actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + i;
         ReadSector(actsector,FATTable);
         gFAT32Vars.FATstartidx = gFirstEmptyCluster = i;
      }
      for (j=0;j<128;j++)
         if (FATTable[j] == 0) {
            retval = i;
            retval <<= 7;
            retval |= j;
            return retval;
         }
   }
   return 0x0FFFFFFF;
}

void ConvertFilename(DIR *beDir,char *name)
{
char i,j,c;

   j = 0;
   name[0] = 0;
   for (i=0;i<8;i++) {
      c = beDir->sName[i];
      if (c == ' ') break;
      name[j++] = c;
   }
   for (i=0;i<3;i++) {
      c = beDir->sExt[i];
      if (c == ' ' || c == 0) break;
      if (!i) name[j++] = '.';
      name[j++] = c;
   }
   name[j++] = 0;
}

void GetDOSName(DIR *pDir, char *fname)
{
char i,j,leng,c,toext;

   toext = FALSE;
   j = 0;
   leng = strlen(fname);
   for (i=0;i<8;i++)
      pDir->sName[i] = ' ';
   for (i=0;i<3;i++)
      pDir->sExt[i] = ' ';
   for (i=0;i<leng;i++) {
      c = fname[i];
      c = toupper(c);
      if (c == '.') {
         toext = TRUE;
         continue;
      }
      if (toext) pDir->sExt[j++] = c;
      else pDir->sName[i] = c;
   }
}

void ReadRootDirectory(char fil)
{
int32 actsector;

   if (fil > (MAXFILES-1)) return;
   actsector = gFAT32Vars.gStartSector + DiskInfo.FATCopies*DiskInfo.hSectorsPerFat+DiskInfo.Reserved1;
   ReadSector(actsector,gFiles[fil].IOpuffer);
   gFAT32Vars.gDirEntrySector = actsector;
   gFiles[fil].dirSector = actsector;
   gFiles[fil].dirIdx = 0;
   memcpy(&(gFiles[fil].DirEntry),gFiles[fil].IOpuffer,32);
   gFiles[fil].CurrentCluster = DiskInfo.hRootStartCluster;
}

char FindDirEntry(char *fname,char f)
{
   DIR *pDir;
   int16 i;
   char filename[16];
   int32 nextcluster,actsector;

   if (f > (MAXFILES-1)) return FALSE;
   gFAT32Vars.gFirstEmptyDirEntry = 0xFFFF;
   gFAT32Vars.gFirstDirEntryCluster = 0x0FFFFFFF;
   do {
      pDir = (DIR*)(gFiles[f].IOpuffer);
      for (i=0;i<16;i++) {
         if ((pDir->sName[0] == 0xE5 || pDir->sName[0] == 0) && gFAT32Vars.gFirstEmptyDirEntry == 0xFFFF) { // store first free
            gFAT32Vars.gFirstEmptyDirEntry = i;
            gFAT32Vars.gFirstDirEntryCluster = gFiles[f].CurrentCluster;
         }
         if (pDir->sName[0] == 0) return FALSE;
         ConvertFilename(pDir,filename);
         if (!strcmp(filename,fname)) {
            memcpy(&(gFiles[f].DirEntry),pDir,32);
            gFiles[f].dirIdx = i;
            gFAT32Vars.gDirEntryIdx = i;
            return TRUE;
         }
         pDir++;
      }
      nextcluster = GetNextCluster(gFiles[f].CurrentCluster);
      if (nextcluster != 0x0FFFFFFF && nextcluster != 0) {
         actsector = nextcluster + gFAT32Vars.gFirstDataSector;
         ReadSector(actsector,gFiles[f].IOpuffer);
         gFAT32Vars.gDirEntrySector = actsector;
         gFiles[f].dirSector = actsector;
         gFiles[f].CurrentCluster = nextcluster;
      }
   } while (nextcluster != 0x0FFFFFFF && nextcluster != 0);
   return FALSE;
}

// file I/O routines
char* TryFile(char *fname, char *f)
{
   char i,leng;
   char *filename;

   *f = 0xFF;
   for (i=0;i<MAXFILES;i++) {
      if (gFiles[i].Free) {
         *f = i;
         break;
      }
   }
   if (*f == 0xFF) return 0;
   ReadRootDirectory(*f);
   filename = fname;
   leng = strlen(fname);
   for (i=0;i<leng;i++) {
      if (fname[i] == '/') {
         fname[i] = 0;
         if (!cwd(filename,*f)) {
            gFiles[*f].Free = TRUE;
            return 0;
         }
         filename = fname+i+1;
      }
   }
   return filename;
}

char fcreate(char f,char *fname)
{
   DIR *pDir;
   int32 actsector,actcl;
   int16 i;

   if (f > (MAXFILES-1)) return FALSE;
   if (gFAT32Vars.gFirstDirEntryCluster == 0x0FFFFFFF) {
      // extend the directory file !!!
      gFAT32Vars.gFirstDirEntryCluster = FindFirstFreeCluster();
      gFAT32Vars.gFirstEmptyDirEntry = 0;
      SetClusterEntry(gFiles[f].CurrentCluster,gFAT32Vars.gFirstDirEntryCluster);
      SetClusterEntry(gFAT32Vars.gFirstDirEntryCluster,0x0FFFFFFF);
      actsector = gFAT32Vars.gFirstDirEntryCluster + gFAT32Vars.gFirstDataSector;
      for (i=0;i<512;i++)
         gFiles[f].IOpuffer[i] = 0;
      WriteSector(actsector,gFiles[f].IOpuffer);
   }
   actsector = gFAT32Vars.gFirstDirEntryCluster + gFAT32Vars.gFirstDataSector;
   ReadSector(actsector,gFiles[f].IOpuffer);
   pDir = (DIR*)(&(gFiles[f].IOpuffer[32*gFAT32Vars.gFirstEmptyDirEntry]));
   gFiles[f].dirSector = actsector;
   gFiles[f].dirIdx = gFAT32Vars.gFirstEmptyDirEntry;
   GetDOSName(pDir,fname);
   pDir->bAttr = 0;
   actcl = FindFirstFreeCluster();
   pDir->hCluster = actcl & 0xFFFF;
   pDir->hClusterH = actcl >> 16;
   SetClusterEntry(actcl,0x0FFFFFFF);
   pDir->wSize = 0;
   gFiles[f].position = 0;
   pDir->hDate = GetCurrentDOSDate();
   pDir->hTime = GetCurrentDOSTime();
   WriteSector(actsector,gFiles[f].IOpuffer);
   memcpy(&(gFiles[f].DirEntry),pDir,32);
   return TRUE;
}

int32 ComposeCluster(char f)
{
int32 retval;

retval = gFiles[f].DirEntry.hClusterH;
retval <<= 16;
retval |= gFiles[f].DirEntry.hCluster;
return retval;
}

char fopen(char *fname, char mode)
{
   char found;
   char f;
   int32 actsector,actcluster,nextcluster;
   char *filename;

   if (input(CardInserted)) return 0xFF;
   output_high(YELLOWLED);
   filename = TryFile(fname,&f);
   if (filename == 0) return 0xFF;
   found = FALSE;
   found = FindDirEntry(filename,f);
   if (!found) {
      if (mode == 'r') {
         gFiles[f].Free = TRUE;
         return 0xFF;
      } else {
         if (!fcreate(f,filename)) return 0xFF;
         found = TRUE;
      }
   }
   if (found) {
      gFiles[f].Free = FALSE;
      gFiles[f].mode = mode;
      if  (mode == 'a') {
         gFiles[f].position = gFiles[f].DirEntry.wSize;
         actcluster = ComposeCluster(f);
            while (actcluster != 0x0FFFFFFF && nextcluster != 0) {
               nextcluster = GetNextCluster(actcluster);
               if (nextcluster == 0x0FFFFFFF || nextcluster == 0) break;
               actcluster = nextcluster;
            }
         actsector = actcluster + gFAT32Vars.gFirstDataSector;
         ReadSector(actsector,gFiles[f].IOpuffer);
         gFiles[f].CurrentCluster = actcluster;
         gFiles[f].posinsector = gFiles[f].position & 0x01FF;
         if (gFiles[f].posinsector == 0 && gFiles[f].position != 0) gFiles[f].posinsector = 512;
      } else {
         gFiles[f].position = 0;
         actsector = ComposeCluster(f);
               actsector += gFAT32Vars.gFirstDataSector;
         ReadSector(actsector,gFiles[f].IOpuffer);
         gFiles[f].CurrentCluster = ComposeCluster(f);
         gFiles[f].posinsector = 0;
      }
   }
   return f;
}

void fclose(char f)
{
   output_low(YELLOWLED);
   if (f > (MAXFILES-1)) return;
   if ((gFiles[f].mode == 'a') || (gFiles[f].mode == 'w')) fflush(f);
   gFiles[f].Free = TRUE;
}

void fflush(char f)
{
int32 actsector;
DIR *pDir;

   if (f > (MAXFILES-1)) return;
   actsector = gFiles[f].CurrentCluster + gFAT32Vars.gFirstDataSector;
   WriteSector(actsector,gFiles[f].IOpuffer);
   ReadSector(gFiles[f].dirSector,gFiles[f].IOpuffer);
   pDir = (DIR*)(&(gFiles[f].IOpuffer[32*gFiles[f].dirIdx]));
   if (gFiles[f].DirEntry.bAttr & 0x10) pDir->wSize = 0; // if it is a directory
      else pDir->wSize = gFiles[f].position;
   pDir->hDate = GetCurrentDOSDate();
   pDir->hTime = GetCurrentDOSTime();
   WriteSector(gFiles[f].dirSector,gFiles[f].IOpuffer);
   ReadSector(actsector,gFiles[f].IOpuffer);
}

char cwd(char *fname, char f)
{
int32 actsector;

   if (f > (MAXFILES-1)) return FALSE; // just in case of overaddressing
   if (IsSelfDir(fname)) return TRUE; // already in Root dir
   if (!FindDirEntry(fname,f)) return FALSE; // not found
   actsector = ComposeCluster(f);
   actsector += gFAT32Vars.gFirstDataSector; // read current dir
   ReadSector(actsector,gFiles[f].IOpuffer);
   gFAT32Vars.gDirEntrySector = actsector;
   gFiles[f].dirSector = actsector;
   gFiles[f].CurrentCluster = ComposeCluster(f);
   return TRUE;
}

void fputch(char be, char f)
{
   int32 nextcluster,actsector;

   if (f > (MAXFILES-1)) return;
   if (gFiles[f].posinsector == 512) {
      actsector = gFiles[f].CurrentCluster + gFAT32Vars.gFirstDataSector;
      WriteSector(actsector,gFiles[f].IOpuffer);
      nextcluster = FindFirstFreeCluster();
      if (nextcluster != 0x0FFFFFFF && nextcluster != 0) {
         SetClusterEntry(gFiles[f].CurrentCluster,nextcluster);
         SetClusterEntry(nextcluster,0x0FFFFFFF);
         actsector = nextcluster + gFAT32Vars.gFirstDataSector;
         ReadSector(actsector,gFiles[f].IOpuffer);
         gFiles[f].CurrentCluster = nextcluster;
         gFiles[f].posinsector = 0;
      }
   }
   gFiles[f].IOpuffer[gFiles[f].posinsector] = be;
   gFiles[f].posinsector++;
   gFiles[f].position++;

}

void fputstring(char *be, char f)
{
int16 leng,i;

   if (f > (MAXFILES-1)) return;
   leng = strlen(be);
   for (i=0;i<leng;i++)
      fputch(be[i],f);
}

int16 fread(char *buffer, int16 leng, char f)
{
int16 i,retv;
char c,v;

   if (f > (MAXFILES-1)) return 0;
   retv = 0;
   for (i=0;i<leng;i++) {
      v = fgetch(&c,f);
      if (v) {
         buffer[i] = c;
         retv++;
      }
      else break;
   }
   return retv;
}

void fwrite(char *buffer, int16 leng, char f)
{
int16 i;

   if (f > (MAXFILES-1)) return;
   for (i=0;i<leng;i++)
      fputch(buffer[i],f);

}

char fgetch(char *ki,char f)
{
   int32 nextcluster,actsector;

   if (f > (MAXFILES-1)) return FALSE;
   if (gFiles[f].position >= gFiles[f].DirEntry.wSize) return FALSE;
   *ki = gFiles[f].IOpuffer[gFiles[f].posinsector];
   gFiles[f].posinsector++;
   gFiles[f].position++;
   if (gFiles[f].posinsector == 512) {
      nextcluster = GetNextCluster(gFiles[f].CurrentCluster);
      if (nextcluster != 0x0FFFFFFF && nextcluster != 0) {
         actsector = nextcluster + gFAT32Vars.gFirstDataSector;
         ReadSector(actsector,gFiles[f].IOpuffer);
         gFiles[f].CurrentCluster = nextcluster;
         gFiles[f].posinsector = 0;
      }
   }
   return TRUE;
}

char remove(char *fname)
{
   char i,found;
   char f;
   DIR *pDir;
   int32 nextcluster,currentcluster;
   char *filename;

   filename = TryFile(fname,&f);
   if (filename == 0) return FALSE;
   found = FindDirEntry(filename,f);
   if (!found) {
      gFiles[f].Free = TRUE;
      return FALSE;
   }
   output_high(YELLOWLED);
   pDir = (DIR*)(&(gFiles[f].IOpuffer[32*gFAT32Vars.gDirEntryIdx]));
   pDir->sName[0] = 0xE5;
   for (i=1;i<8;i++)
      pDir->sName[i] = ' ';
   for (i=0;i<3;i++)
      pDir->sExt[i] = ' ';
   WriteSector(gFAT32Vars.gDirEntrySector,gFiles[f].IOpuffer);
   currentcluster = ComposeCluster(f);
   while (currentcluster != 0x0FFFFFFF && nextcluster != 0) {
      nextcluster = GetNextCluster(currentcluster);
      ClearClusterEntry(currentcluster);
      currentcluster = nextcluster;
   }
   ClearClusterEntry(currentcluster);
   SetClusterEntry(currentcluster,0);
   currentcluster = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + gFAT32Vars.FATstartidx;
   WriteSector(currentcluster,FATTable);
   currentcluster += DiskInfo.hSectorsPerFat;
   WriteSector(currentcluster,FATTable);
   gFiles[f].Free = TRUE;
   output_low(YELLOWLED);
   return TRUE;
}

char getfsize(char *fname, int32 *fsiz)
{
   char found;
   char f;
   DIR *pDir;
   char *filename;

   filename = TryFile(fname,&f);
   if (filename == 0) return FALSE;
   found = FindDirEntry(filename,f);
   if (!found) {
      gFiles[f].Free = TRUE;
      return FALSE;
   }
   pDir = (DIR*)(&(gFiles[f].IOpuffer[32*gFAT32Vars.gDirEntryIdx]));
   gFiles[f].Free = TRUE;
   *fsiz = pDir->wSize;
   return TRUE;
}



And a small example (EX_MyFat32.c):
Code:
/* This is a small demo file for FAT32 library usage
Written by Tamas Bodorics (Tomi)

Some notes:
-----------
 - I use it with a PIC18F6720 (3.5kByte RAM) HW SPI @11.0592 MHz crystal; tested with 64-256MB MMCs
 - The RAM area is moved to upper region by #locate directives
 - The MMC has 2 GND pins; one of them is pulled up by a resistor (10k) to +5V and connected to PIN_A4
   so the MMC is "hot swappable".
 - The MMC has to format FAT32, 512bytes/cluster
 - The number of opened files at a time is limited to 2 because of RAM limitations (some dsPICs have 8K RAM... ;-) )
 - No long names; use DOS-like 8+3 name format
 - No MKDIR and RMDIR functions (not yet...) so create the subdirs right after the format (and use 8+3 capital characters...)
   I use the following DOS batch in XP:

      format I: /A:512 /V:TOMI /FS:FAT32
      mkdir I:\BERS
      mkdir I:\WINDS

 - Use '/' as directory separator, e.g. "MYDIR/ELEMENT.WND" "MYDIR/SUBDIR/OTHER.TXT" etc.
 - The possible modes for file open (char and NOT string as in std. C): 'r'(read) 'w'(write; the previous content will overwritten) 'a'(append)
 - fputs is reserved keyword by CCS C so use fputstring() instead
 - In the example the EVENT.LOG file uses the Hungarian date format (YYYY.MM.DD. HH.mm.SS) sorry...
 - There are some functions normally not to use:
       -  fflush(f) Use it only if you want to flush data into MMC while you keep the file opened
       -  TryFile() tries to open the file incl. resolving the path
       -  cwd(fname,f) is used by TryFile to resolve the path name
       -  fcreate() If you open a file with 'a' or 'w' the file is automatically created if not exist
*/

#include <18F6720.h>
..........
#include <string.h>

typedef struct  {
unsigned long    tm_year;
char            tm_mon;
char            tm_day;
char            tm_mday;    
char            tm_hour;    
char            tm_min;     
char            tm_sec;     
} TimeRecord;

....................

TimeRecord myrec; // this variable is updated in regular intervals in DoIdle()

....................
....................
....................

#include "MyMMCFat32.h"
#include "MyMMCFat32.c"

....................
....................

void main()
{
char f,v,msg[64],gfilename[32];
char gPrevCard,gActCard; // previous and actual card states (inserted, removed)

.................... // other declarations
....................

.................... // INIT code parts
....................

   InitClockInt(); // init the clock chip
   ReadClock();    // read the current time

   if (!input(CardInserted)) { // if MMC card is in place
      do {
         output_high(REDLED);
         v = MMCInit(); // init the card
         delay_ms(50);
         output_low(REDLED);
         delay_ms(50);
      } while (!v);
      output_high(YELLOWLED);
      InitFAT(); // init the file system
      output_low(YELLOWLED);
      output_low(REDLED);
   }
..................

   strcpy(gfilename,"EVENTS.LOG");
   f = fopen(gfilename,'a'); // open EVENTS.LOG for append
   if (f < MAXFILES) {
      sprintf(msg,"%04lu.%02u.%02u. %02u:%02u:%02u ",myrec.tm_year,myrec.tm_mon,myrec.tm_mday,myrec.tm_hour,myrec.tm_min,myrec.tm_sec);
      fputstring(msg,f);
      strcpy(msg,"System started\r\n");
      fputstring(msg,f);
      fclose(f);
   }

   while (1) {
   restart_wdt();
   ResetPorts();
      DoIdle(); // Idle function incl. clock update

....................
....................

      gActCard = input(CardInserted);
      if (gActCard) output_high(REDLED);
         else output_low(REDLED);
      if (gActCard == 0 && gPrevCard != 0) { // card was pulled out then pushed back now
         delay_ms(50);
         do {
            output_high(REDLED);
         v = MMCInit();
            delay_ms(50);
            output_low(REDLED);
            delay_ms(50);
         } while (!v);
         output_high(YELLOWLED);
         InitFAT();
         output_low(YELLOWLED);
         output_low(REDLED);
         delay_ms(50);
         strcpy(gfilename,"EVENTS.LOG");
         f = fopen(gfilename,'a');
         if (f < MAXFILES) {
            sprintf(msg,"%04lu.%02u.%02u. %02u:%02u:%02u ",myrec.tm_year,myrec.tm_mon,myrec.tm_mday,myrec.tm_hour,myrec.tm_min,myrec.tm_sec);
            fputstring(msg,f);
            strcpy(msg,"Memory card replacement\r\n");
            fputstring(msg,f);
            fclose(f);
         }
      }
      gPrevCard = gActCard;
   }
}

/* other short examples:
1: to send out a file content to serial line

               strcpy(gfilename,"SMSDATA.TXT");
               f = fopen(gfilename,'r');
               if (f < MAXFILES) {
                  while (fgetch(&c,f)) fputc(c,HOST2);
                  fclose(f);
               }

2: to save daily measures:
      sprintf(gfilename,"BERS/%04lu%02u%02u.BER",myrec.tm_year,myrec.tm_mon,myrec.tm_mday); // the file name is YYYYMMDD.BER
      f = fopen(gfilename,'a');
      for (actidx=0;actidx<22;actidx++) { // to save the last 22 updated measures
         if (!bit_test(saveflags,actidx)) continue; // skip if this record is not updated
         gBER = gLastBERs[actidx];
         if (f < MAXFILES) fwrite(&gBER,sizeof(gBER),f);
      }
      fclose(f);

*/
Bart



Joined: 12 Jul 2005
Posts: 49

View user's profile Send private message

PostPosted: Fri Sep 29, 2006 2:42 pm     Reply with quote

Is there someone who has this working for an 18F4550 ?

Thanks.
PicFan



Joined: 01 Jan 2004
Posts: 11
Location: Indianapolis (Go Colts!)

View user's profile Send private message

RE: FAT32 code for MultiMedia Cards
PostPosted: Fri Oct 06, 2006 3:04 pm     Reply with quote

Tomi,

Thanks for posting the code, I'm having a little difficulty when compiling.

Can't seem to find two functions that are being called:
ResetPorts()
DoIdle()

Do these functions provide any critical support for the overall MMC or FAT usage?


Best Regards,
PicFan
raus



Joined: 12 Dec 2006
Posts: 1

View user's profile Send private message

PostPosted: Tue Dec 12, 2006 11:10 am     Reply with quote

Hi!!

Has anyone tested this code in PIC18F6720? I'm very interested in it. If anybody knows more about it, or a similar code for FAT32 and SD/MMC cards, please help me Laughing

Thanks in advance, at least you have read this ;)
asmallri



Joined: 12 Aug 2004
Posts: 1630
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Tue Dec 19, 2006 9:59 am     Reply with quote

I have a SD/MMC file system that will support this and other 18F series PICs. http://www.brushelectronics.com/index.php?page=software#SDFS

In addition you will find multiple working reference schematics on the projects page.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
sovalye



Joined: 08 Feb 2007
Posts: 1

View user's profile Send private message

Thanks
PostPosted: Thu Feb 08, 2007 2:48 pm     Reply with quote

Hey Tomi
You are a big man.
Thank you very much to send this code.

With this code we will have a filesystem inside PIC.

I will try it. I also want to make it USB Mass storage device. Can we use this code for it, is it similar?
pokemontro



Joined: 15 Feb 2007
Posts: 2

View user's profile Send private message

Use Pen Drive to store data
PostPosted: Thu Feb 15, 2007 6:33 am     Reply with quote

Hey! It's amazing!
I need to use a Pen Drive (Mass Storage Device) and mount a archive with all data processed using a PIC device. Have you a example code about this? It's possible?

Thanks!
asmallri



Joined: 12 Aug 2004
Posts: 1630
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

Re: Use Pen Drive to store data
PostPosted: Thu Feb 15, 2007 7:11 am     Reply with quote

pokemontro wrote:
Hey! It's amazing!
I need to use a Pen Drive (Mass Storage Device) and mount a archive with all data processed using a PIC device. Have you a example code about this? It's possible?

Thanks!


It is possible, but not practical, to use a Pen Drive - these are USB devices which would require the PIC to implement a USB host controller. You could use a third party USB host controller - Maxim makes one that attached via the SPI bus but if you were going down this path it would be far easier to implement an SD/MMC card interface and communicate to the PIC via the SPI bus. You can find hardware reference designs on my site for interfacing SD/MMC cards to various PICs.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
pokemontro



Joined: 15 Feb 2007
Posts: 2

View user's profile Send private message

Use Pen Drive to store data
PostPosted: Thu Feb 15, 2007 9:11 am     Reply with quote

Well,

But use a Pen Drive is more pratic to me. I know that to use a SD/MMC card is more easy.
If the implementation of Pen Drive is possible, I can use this. You know how I use that? You have any example or a place to download it?

Thanks.
asmallri



Joined: 12 Aug 2004
Posts: 1630
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Feb 15, 2007 9:39 am     Reply with quote

Here is the link to the USB host controller:

http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3639

You will need to develop your own low level driver to interface with the FAT file system.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
Mattr0



Joined: 27 Mar 2005
Posts: 30

View user's profile Send private message Visit poster's website

can't get this to work
PostPosted: Sat Mar 10, 2007 2:29 pm     Reply with quote

I am having a problem getting this to work. The problem is it will not compile due to the SSPBUF on the MMC routines. I tried to switch this to SPI_WRITE read etc. but I am having no luck. The FAT16 driver on forum works without a problem but I don't know how to write a file to that one. This one look to be better if I could get it to work. I am using a 18F4620 with compiler ver 4.025



Thanks

void MMCOut(char indata)
{
char i;
SSPBUF=indata; //not defined
while (!BF);
i = SSPBUF;
}
Tomi



Joined: 11 Aug 2005
Posts: 10

View user's profile Send private message

Sorry about definitions
PostPosted: Thu Mar 22, 2007 10:54 am     Reply with quote

Sorry for that, always include "my6720.h" what looks like this:
Code:

#byte    STATUS = 0xFD8
#bit       bCARRY = STATUS.0
#byte    port_A = 0xF80
#byte    port_B = 0xF81
#byte    port_C = 0xF82
#byte    port_D = 0xF83
#byte    port_E = 0xF84
#byte    port_F = 0xF85
#byte    port_G = 0xF86
#byte    tris_A = 0xF92
#byte    tris_B = 0xF93
#byte    tris_C = 0xF94
#byte    tris_D = 0xF95
#byte    tris_E = 0xF96
#byte    tris_F = 0xF97
#byte    tris_G = 0xF98

#byte    PCON   = 0xFD0
#byte    bRCSTA = 0xFAB
#define    bCREN 4
#define    bOERR 2

#byte SSPADD = 0xFC8
#byte SSPCON1= 0xFC6
#byte SSPCON2= 0xFC5
#byte SSPBUF = 0xFC9
#byte SSPSTAT= 0xFC7
#byte PIR1   = 0xF9E
#byte PIE1   = 0xF9D
#byte PIR2   = 0xFA1
#bit  SSPOV  = SSPCON1.6
#bit  SEN    = SSPCON2.0
#bit  RSEN   = SSPCON2.1
#bit  PEN    = SSPCON2.2
#bit  RCEN   = SSPCON2.3
#bit  ACKEN  = SSPCON2.4
#bit  ACKDT  = SSPCON2.5
#bit  ACKSTAT= SSPCON2.6
#bit  SSPIF  = PIR1.3
#bit  BCLIF  = PIR2.3
#bit  BF  = SSPSTAT.0

Thes are simple register definitions.
Tomi



Joined: 11 Aug 2005
Posts: 10

View user's profile Send private message

Other functions
PostPosted: Mon Mar 26, 2007 2:43 am     Reply with quote

Some people have problems using my FAT32 code especially with undefined functions.
You can find below some short explanations.

1. The clock functions. I use a Ricoh clock chip to get a real time clock because my target circuit is a data logger.
InitClockInt() funtion sets up the INT_A output of the chip as 32768Hz clock output so it is called only once in early main() in initialization section. It is then connected to the PIC's TIMER1 input to get an interrupt in every 2 seconds. The logger has battery-backup solar power supply so I have to use Sleep() to minimize the power consumption. The target board is waked up in every 2 seconds.

2. ReadClock() functions reads out the current date and time and stores the data in a standard "struct tm" structure. The definition:
Code:

typedef struct  {
unsigned long    tm_year;    
char            tm_mon;    
char            tm_day;    
char            tm_mday;
char            tm_hour;    
char            tm_min;     
char            tm_sec;     
} RAMRecord;

It is important to handle the creation/modification dates in a file system if it is used for data loggers. If you don't want to use correct times then simply use a fixed date/time or you can use a software clock.

3. ResetPorts() function is called as frequently as possible to set up the port TRIS registers, timer settings, etc. It is an old Microchip suggession to make a stable card in a noisy environment (the TRIS registers could be corrupted by high level noises). If you have a stable power supply and could keep external noises in an affordable low level then simply use an empty function:

Code:

void ResetPorts()
{
}


4. DoIdle() function is called when a TIMER1 interrupt occurs. So normally it is called in every 2 seconds. It is the main data logger function. A small example what it has to do:
a/ Update the clock structure by calling ReadClock()
b/ Get the current wind speed and direction. Store it on MMC if necessary.
c/ If the old minute differs from the newly read then one minute is elapsed; read the temperatures, pressure, etc. so get the "one minute averages" and store them in a file (MMC).
d/ After these, call Restart_wdt() and Sleep() to enter into sleep mode and to wait the next timer1 interrupt.
spiken



Joined: 29 Mar 2007
Posts: 1

View user's profile Send private message

PostPosted: Thu Mar 29, 2007 9:59 am     Reply with quote

Hi,

I found some strange code in fopen and remove. Why do you need
&& nextcluster != 0? The nextcluster can be zero when it's initialized.
Also, can nextcluster be zero when the actcluster is anything else than 0 or 0x0FFFFFFF?


int32 actsector,actcluster,nextcluster;
....
....
actcluster = ComposeCluster(f);
while (actcluster != 0x0FFFFFFF
&& nextcluster != 0) {
nextcluster = GetNextCluster(actcluster);
if (nextcluster == 0x0FFFFFFF || nextcluster == 0) break;
actcluster = nextcluster;
}
Tomi



Joined: 11 Aug 2005
Posts: 10

View user's profile Send private message

Just an error check
PostPosted: Fri Mar 30, 2007 6:55 am     Reply with quote

It is only an error check. The cluster number in this case never could be zero because it is a part of an existing file what you want to open or delete. In this case every cluster number could be either a legal number (the next cluster number) or 0x0FFFFFFF (last cluster; end of file).
A zero in the cluster chain of an existing file means a broken file (otherwise zero means "cluster is not in use"). It could happens when the sector content is already written to, but the FAT is not updated yet; for example because the card is pulled out by the user under the update (in the logger I write momentary wind in every 2 seconds so the probability is high; keep in mind that we don't have enough RAM space in the PIC to keep the FAT and data sector in the RAM at same time; we have to swap the RAM contents freqently).
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Goto page 1, 2, 3, 4, 5  Next
Page 1 of 5

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group