|
|
View previous topic :: View next topic |
Author |
Message |
Tomi
Joined: 11 Aug 2005 Posts: 10
|
FAT32 code for MultiMedia Cards |
Posted: Thu Aug 11, 2005 7:55 am |
|
|
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
|
|
Posted: Fri Sep 29, 2006 2:42 pm |
|
|
Is there someone who has this working for an 18F4550 ?
Thanks. |
|
|
PicFan
Joined: 01 Jan 2004 Posts: 11 Location: Indianapolis (Go Colts!)
|
RE: FAT32 code for MultiMedia Cards |
Posted: Fri Oct 06, 2006 3:04 pm |
|
|
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
|
|
Posted: Tue Dec 12, 2006 11:10 am |
|
|
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
Thanks in advance, at least you have read this ;) |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
|
|
sovalye
Joined: 08 Feb 2007 Posts: 1
|
Thanks |
Posted: Thu Feb 08, 2007 2:48 pm |
|
|
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
|
Use Pen Drive to store data |
Posted: Thu Feb 15, 2007 6:33 am |
|
|
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: 1635 Location: Perth, Australia
|
Re: Use Pen Drive to store data |
Posted: Thu Feb 15, 2007 7:11 am |
|
|
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
|
Use Pen Drive to store data |
Posted: Thu Feb 15, 2007 9:11 am |
|
|
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: 1635 Location: Perth, Australia
|
|
|
Mattr0
Joined: 27 Mar 2005 Posts: 30
|
can't get this to work |
Posted: Sat Mar 10, 2007 2:29 pm |
|
|
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
|
Sorry about definitions |
Posted: Thu Mar 22, 2007 10:54 am |
|
|
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
|
Other functions |
Posted: Mon Mar 26, 2007 2:43 am |
|
|
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
|
|
Posted: Thu Mar 29, 2007 9:59 am |
|
|
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
|
Just an error check |
Posted: Fri Mar 30, 2007 6:55 am |
|
|
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). |
|
|
|
|
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
|