|
|
View previous topic :: View next topic |
Author |
Message |
manish12
Joined: 18 Jan 2009 Posts: 15
|
any 100% working code for mmc + pic18f series |
Posted: Thu Jan 22, 2009 1:13 pm |
|
|
i thankfull to all who support for mmc and sd card interface [from code lib ]but , i try all[almost all code] with my best level , not suc.
if any one have working code for mmc + pic18f series pl upload it or any project which is check , also helpful to me.
[pic18f4620,452,2550, etc] |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
Re: any 100% working code for mmc + pic18f series |
Posted: Fri Jan 23, 2009 12:09 am |
|
|
manish12 wrote: | i thankfull to all who support for mmc and sd card interface [from code lib ]but , i try all[almost all code] with my best level , not suc.
if any one have working code for mmc + pic18f series pl upload it or any project which is check , also helpful to me.
[pic18f4620,452,2550, etc] |
I sell working SD/SDHC/MMC low level drivers and file system for the PIC18F with the CCS compiler. They work. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Fri Feb 27, 2009 10:44 am |
|
|
Alright,
lets go to the code..
MMCFat32.c
Code: |
/**********************************************
* ANDRE L. V. SILVA
* [email protected]
*
* change the strings to your own language if you want (it is in portuguese br)
*
* Example of use:
*
*
int main (void)
{
pic initialization....
InicializaSPI ();
InicializaMMC ();
InicializaFAT32 ();
While (TRUE)
{
your code ....
}
return 0;
}
**********************************************/
#include "MMCFat32.h"
#include "string.h"
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Funções do cartão MMC
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
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
//-------------------------------------------------------------------------
// Detecção do MMC
//-------------------------------------------------------------------------
char DetectaMMC (void)
{
char Resp;
TRIS_DETECTA_MMC = ENTRADA;
printf ("\r\nDetectando MMC...");
if (MMC_DETECT)
{
printf ("Nao Conectado !");
printf ("\r\nAguardando Conexao... ");
while (MMC_DETECT);
}
TRIS_DETECTA_MMC = ENTRADA;
MMC_DETECT = SAIDA;
MMC_DETECT = FALSE;
printf ("OK");
return Resp;
}
//-------------------------------------------------------------------------
// Configuração da SPI
//-------------------------------------------------------------------------
void InicializaSPI (char Tipo)
{
TRIS_SPI_SCK = SAIDA;
TRIS_SPI_SDI = ENTRADA;
TRIS_SPI_SDO = SAIDA;
TRIS_SPI_MMC_CS = SAIDA;
MMC_CS = TRUE;
SPI_SCK = TRUE;
SPI_DI = TRUE;
SPI_DO = FALSE;
if (Tipo == MAXIMO)
{
printf ("\r\nAjustando SPI: ");
printf ("5 MHz...");
CKE = FALSE;
SMP = TRUE;
CKP = TRUE;
SSPCON1 = SSPCON1 & SPI_MASTER_SCK_DIV_4;
SSPEN = TRUE;
}
else if (Tipo == MEDIO)
{
printf ("\r\nAjustando SPI: ");
printf ("1.25 MHz...");
CKE = FALSE;
SMP = TRUE;
CKP = TRUE;
SSPCON1 = SSPCON1 & SPI_MASTER_SCK_DIV_16;
SSPEN = TRUE;
}
else
{
printf ("\r\nInicializando SPI: ");
printf ("312.5 KHz...");
CKE = FALSE;
SMP = TRUE;
CKP = TRUE;
SSPCON1 = SSPCON1 & SPI_MASTER_SCK_DIV_4;
SSPEN = TRUE;
}
printf ("OK");
delay_ms (10);
return;
}
//-------------------------------------------------------------------------
// Função de Seleção do CS do MMC
//-------------------------------------------------------------------------
void SelecionaMMC (boolean Flag)
{
if (Flag)
{
MMC_CS = FALSE;
}
else
{
MMC_CS = TRUE;
}
}
//-------------------------------------------------------------------------
// Função para enviar um dado via SPI
//-------------------------------------------------------------------------
void EnviaMMC (char a)
{
char b;
BF = FALSE;
SSPBUF = a;
while (! BF);
b = SSPBUF;
return;
}
//-------------------------------------------------------------------------
// Função para receber um dado via SPI
//-------------------------------------------------------------------------
char RecebeMMC (void)
{
char b;
BF = FALSE;
SSPBUF = 0xff;
while (! BF);
b = SSPBUF;
return b;
}
//-------------------------------------------------------------------------
// 8 pulsos de clock dummy
//-------------------------------------------------------------------------
void MMC8Clock (void)
{
EnviaMMC (0xff);
return;
}
//-------------------------------------------------------------------------
// Comando de Reset
//-------------------------------------------------------------------------
void ExecutaCMD0 (void)
{
char Resp;
long TimeOut;
char i;
// comando CMD0 - Reset
// printf ("\r\n\tResposta ao CMD0...");
do
{
Resp = 0xff;
TimeOut = 100;
// envia pelo pulsos de clock para inicialização
for (i = 0; i < 10; i++) MMC8Clock ();
// envia CMD0 -> Idle state
SelecionaMMC (TRUE);
EnviaMMC (0x40); // CMD0
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x95); // CRC - OK
MMC8Clock ();
// espera pela resposta = 0x01 - caso contrário = falha
while ((Resp != 0x01) && (TimeOut))
{
Resp = RecebeMMC ();
TimeOut--;
}
SelecionaMMC (FALSE);
// roda enquanto der timeout
} while (! TimeOut);
// printf ("OK");
return;
}
//-------------------------------------------------------------------------
// Modo SPI
//-------------------------------------------------------------------------
void ExecutaCMD1 (void)
{
char Resp;
long TimeOut;
// comando CMD1 - Modo SPI
// printf ("\r\n\tResposta ao CMD1...");
do
{
Resp = 0xff;
TimeOut = 100;
// envia CMD1 -> Modo SPI
SelecionaMMC (TRUE);
EnviaMMC (0x41); // CMD1
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x01); // CRC - OK
MMC8Clock ();
// espera pela resposta = 0x00 - caso contrário = falha
while (Resp && TimeOut)
{
Resp = RecebeMMC ();
TimeOut--;
}
SelecionaMMC (FALSE);
// roda enquanto der timeout
} while (! TimeOut);
// printf ("OK");
return;
}
//-------------------------------------------------------------------------
// Ajusta o tamanho do bloco - 512 bytes
//-------------------------------------------------------------------------
void ExecutaCMD16 (void)
{
char Resp;
long TimeOut;
// comando CMD16 - Bloco de 512 bytes
// printf ("\r\n\tResposta ao CMD16...");
do
{
Resp = 0xff;
TimeOut = 100;
// envia CMD16 -> block lenght
SelecionaMMC (TRUE);
EnviaMMC (0x50); // CMD1
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x02);
EnviaMMC (0x00);
EnviaMMC (0x01); // CRC - OK
MMC8Clock ();
// espera pela resposta = 0x00 - caso contrário = falha
while (Resp && TimeOut)
{
Resp = RecebeMMC ();
TimeOut--;
}
SelecionaMMC (FALSE);
// roda enquanto der timeout
} while (! TimeOut);
// printf ("OK");
return;
}
//-------------------------------------------------------------------------
// Lê a identificação do cartão - CID
//-------------------------------------------------------------------------
void ExecutaCMD10 (void)
{
char Resp;
long TimeOut;
char i;
char Ano;
char Mes;
char HW;
char FW;
// comando CMD10 - Lê a identificação do cartão
do
{
Resp = 0xff;
TimeOut = 100;
SelecionaMMC (TRUE);
EnviaMMC (0x4A); //CMD10 - Le CID
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x01);
MMC8Clock ();
// espera pela resposta = 0x00 - caso contrário = falha
while (Resp && TimeOut)
{
Resp = RecebeMMC ();
TimeOut--;
}
// dummy
MMC8Clock ();
// respondeu
if (TimeOut)
{
// // recebe a identificação - binário (8bits)
// printf ("\r\n\r\n\tID do Fabricante: 0x%x", RecebeMMC ()); // identificação para MMCA
//
// // recebe a id de aplicação - binário (16bits)
// printf ("\r\n\tID da Aplicação: 0x");
// for (i = 0; i < 2; i++)
// {
// printf ("%x", RecebeMMC ()); // identificação para MMCA
// }
//
// printf ("\r\n\r\n\tProduto: ");
// for (i = 0; i < 6; i++)
// {
// printf ("%c", RecebeMMC ()); // 6 próximos bytes - Nome do Produto
// }
//
// // revisão do produto - 8bits - BCD
// printf ("\r\n\r\n\tRevisão do Produto: %02d", RecebeMMC ());
//
// printf ("\r\n\tSerial: 0x");
//
// for (i = 0; i < 4; i++)
// {
// printf ("%x", RecebeMMC ()); // 4 próximos bytes - Serial do Produto
// }
//
//
//
//
// FW = Resp & 0x0f; // Firmware = 4bits menos significativos
// HW = (Resp >> 4) & 0x0f; // Hardware = 4bits mais significativos
// printf ("\r\n\tFirmware: %2d", FW);
// printf ("\r\n\tHardware: %02d", HW);
// printf ("\r\n\tFW+HW: 0x%x", Resp);
//
//
//
// Resp = RecebeMMC (); // Mes + Ano;
// Ano = Resp & 0x0f; // Ano = 4bits menos significativos
// Mes = (Resp >> 4) & 0x0f; // Ano = 4bits mais significativos
//
// printf ("\r\n\tAno: %02d", Ano);
// printf ("\r\n\tMes: %02d", Mes);
// printf ("\r\n\tAno+Mes: 0x%x\r\n", Resp);
}
SelecionaMMC (FALSE);
// roda enquanto der timeout
} while (! TimeOut);
return;
}
//-------------------------------------------------------------------------
// Lê o formato do cartão - CSD
//-------------------------------------------------------------------------
void ExecutaCMD9 (void)
{
char Resp;
long TimeOut;
// comando CMD9 - Lê o formato do cartão
// printf ("\r\n\tResposta ao CMD9...");
do
{
Resp = 0xff;
TimeOut = 100;
SelecionaMMC (TRUE);
EnviaMMC (0x49); //CMD9 - Le CSD
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x00);
EnviaMMC (0x01);
MMC8Clock ();
// espera pela resposta = 0x00 - caso contrário = falha
while (Resp && TimeOut)
{
Resp = RecebeMMC ();
TimeOut--;
}
// Respondeu
if (TimeOut)
{
}
SelecionaMMC (FALSE);
// roda enquanto der timeout
} while (! TimeOut);
// printf ("OK");
return;
}
//-------------------------------------------------------------------------
// Muda para o modo de high-speed
//-------------------------------------------------------------------------
void ExecutaCMD6 (void)
{
char Resp;
long TimeOut;
// comando CMD6 - high speed (manual mmc plus)
// printf ("\r\n\tResposta ao CMD6...");
do
{
Resp = 0xff;
TimeOut = 100;
SelecionaMMC (TRUE);
EnviaMMC (0x46); // CMD6
EnviaMMC (0x03);
EnviaMMC (0xb9);
EnviaMMC (0x01);
EnviaMMC (0x00);
EnviaMMC (0x01); // CRC - OK
MMC8Clock ();
// espera pela resposta = 0x00 - caso contrário = falha
while (Resp && TimeOut)
{
Resp = RecebeMMC ();
TimeOut--;
}
SelecionaMMC (FALSE);
// roda enquanto der timeout
} while (! TimeOut);
// printf ("OK");
return;
}
//-------------------------------------------------------------------------
// Inicialização do MMC
//-------------------------------------------------------------------------
void InicializaMMC (void)
{
printf ("\r\nInicializando MMC...");
ExecutaCMD0 ();
ExecutaCMD1 ();
ExecutaCMD16 ();
ExecutaCMD10 ();
ExecutaCMD9 ();
printf ("\r\nInicializando MMC...OK");
return;
}
//-------------------------------------------------------------------------
// Le um setor da memória - FAT32
//-------------------------------------------------------------------------
void ReadSector(int32 sector, char *buffer)
{
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;
SelecionaMMC (TRUE);
EnviaMMC (0x51);
EnviaMMC (MMCAddressHH);
EnviaMMC (MMCAddressHL);
EnviaMMC (MMCAddressH & 0xFE);
EnviaMMC (0);
EnviaMMC (0x01);
errs = 8;
do
{
response = RecebeMMC ();
} while ((--errs) && (response == 0xFF));
errs = 50;
do
{
response = RecebeMMC ();
if (response == 0xFE) break;
delay_ms(1);
} while (--errs);
*0xFE9 = (int16) buffer;
cnt3 = 2;
cnt2 = 0;
do
{
do
{
SSPBUF = 0xFF;
while (!BF);
*0xFEE = SSPBUF;
} while (--cnt2);
} while (--cnt3);
response = RecebeMMC ();
response = RecebeMMC ();
SelecionaMMC (FALSE);
// enable_interrupts(GLOBAL);
}
//-------------------------------------------------------------------------
// Escreve em um setor da memória - FAT32
//-------------------------------------------------------------------------
void WriteSector (int32 sector, char *buffer)
{
char errs;
char response;
char cnt2;
char 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;
SelecionaMMC (TRUE);
EnviaMMC (0x58);
EnviaMMC (MMCAddressHH);
EnviaMMC (MMCAddressHL);
EnviaMMC (MMCAddressH & 0xFE);
EnviaMMC (0);
EnviaMMC (0x01);
MMC8Clock ();
errs = 8;
do
{
response = RecebeMMC ();
} while (--errs && response==0xFF);
if (response)
{
SelecionaMMC (FALSE);
MMC8Clock();
// enable_interrupts(GLOBAL);
return;
}
MMC8Clock ();
EnviaMMC (0xFE);
*0xFE9 = (int16)buffer;
cnt3 = 2;
cnt2 = 0;
do
{
do
{
SSPBUF = *0xFEE;
while (!BF);
response = SSPBUF;
} while (--cnt2);
} while (--cnt3);
EnviaMMC (0x00);
EnviaMMC (0x01);
response = RecebeMMC ();
response ^= 0xE5;
if (response)
{
goto endwr3;
}
do
{
response = RecebeMMC ();
} while (response == 0);
response = 0;
endwr3:
SelecionaMMC (FALSE);
MMC8Clock();
// enable_interrupts (GLOBAL);
}
//-------------------------------------------------------------------------
// mostra um determinado setor - FAT32
//-------------------------------------------------------------------------
void MostraSetor (int32 setor, char *dados, long tamanho)
{
long i;
long j;
long k;
printf ("\r\n\r\nLendo setor: %lx\r\n\r\n", setor);
ReadSector (setor, dados);
j = 0;
for (i = 0; i < tamanho; i++)
{
printf ("%02X ", dados[i]);
if (j >= 15)
{
printf (" ");
for (k = (i - 15); k < i; k++)
{
if (! isalnum (dados[k])) printf (".");
else printf ("%c", dados[k]);
}
printf ("\r\n");
j = 0;
}
else
{
j++;
}
delay_ms (1);
}
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Funções da FAT32
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
char IsSelfDir (char *be)
{
if (be[0] == '.' && be[1] == '.') return 0xFF;
else return 0;
}
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 InicializaFAT32 ()
{
int32 actsector;
char i;
gFirstEmptyCluster = 0;
gFAT32Vars.gStartSector = 0;
// limpa o CREN (comunicação contínua)
printf ("\r\nInicializando FAT32...");
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;
printf ("OK");
return;
}
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;
int32 st;
int32 actsector;
int32 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;
char j;
char 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->spam[i];
if ((c == ' ') || (c == 0)) break;
if (!i) name[j++] = '.';
name[j++] = c;
}
name[j++] = 0;
}
void GetDOSName (DIR *pDir, char *fname)
{
char i;
char j;
char leng;
char c;
char toext;
toext = FALSE;
j = 0;
leng = strlen(fname);
for (i = 0; i < 8; i++)
pDir->sName[i] = ' ';
for (i = 0; i < 3; i++)
pDir->spam[i] = ' ';
for (i = 0; i < leng; i++)
{
c = fname[i];
c = toupper(c);
if (c == '.')
{
toext = TRUE;
continue;
}
if (toext) pDir->spam[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;
int32 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;
char 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;
char 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;
int32 actcluster;
int32 nextcluster;
char *filename;
//if (input(CardInserted)) return 0xFF;
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') // com problemas
{
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)
{
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;
int32 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); //-- nao tem a necessidade de ler o setor toda vez que for gravar um bloco
gFiles[f].CurrentCluster = nextcluster;
gFiles[f].posinsector = 0;
}
}
gFiles[f].IOpuffer[gFiles[f].posinsector] = be;
gFiles[f].posinsector++;
gFiles[f].position++;
return;
}
void fputstring (char *be, char f)
{
int16 leng;
int16 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;
int16 retv;
char c;
char 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;
int32 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;
char found;
char f;
DIR *pDir;
int32 nextcluster;
int32 currentcluster;
char *filename;
filename = TryFile (fname, &f);
if (filename == 0) return FALSE;
found = FindDirEntry (filename,f);
if (!found)
{
gFiles[f].Free = TRUE;
printf ("Arquivo não encontrado...\r\n");
return FALSE;
}
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->spam[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;
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;
}
|
MMCFAT32.h
Code: |
/*******************************************************
* ANDRE L. V. SILVA
* [email protected]
*******************************************************/
#ifndef __MMCFat32_h__
#define __MMCFat32_h__
// user config. - change it for your desired pic
#byte PORTA_A = 0xf80 // (PIC16F - 0x05) (PIC18F - 0xf80)
#byte PORTA_B = 0xf81 // (PIC16F - 0x06) (PIC18F - 0xf81)
#byte PORTA_C = 0xf82 // (PIC16F - 0x07) (PIC18F - 0xf82)
#byte TRIS_PORTA_A = 0xf92 // (PIC16F - 0x85) (PIC18F - 0xf92)
#byte TRIS_PORTA_B = 0xf93 // (PIC16F - 0x86) (PIC18F - 0xf93)
#byte TRIS_PORTA_C = 0xf94 // (PIC16F - 0x87) (PIC18F - 0xf94)
#bit TRIS_SPI_SCK = TRIS_PORTA_C.3
#bit TRIS_SPI_SDI = TRIS_PORTA_C.4
#bit TRIS_SPI_SDO = TRIS_PORTA_C.5
#bit TRIS_SPI_MMC_CS = TRIS_PORTA_B.0
#bit TRIS_DETECTA_MMC = TRIS_PORTA_B.4
#bit MMC_CS = PORTA_B.0
#bit SPI_SCK = PORTA_C.3
#bit SPI_DI = PORTA_C.4
#bit SPI_DO = PORTA_C.5
#bit MMC_DETECT = PORTA_B.4
#byte SSPBUF = 0xfc9 // (PIC16F - 0x13) (PIC18F - 0xfc9)
#byte SSPSTAT = 0xfc7 // (PIC16F - 0x94) (PIC18F - 0xfc7)
#byte SSPCON1 = 0xfc6 // (PIC16F - 0x14) (PIC18F - 0xfc6)
#byte SSPCON2 = 0xfc5 // (PIC16F - 0x91) (PIC18F - 0xfc5)
/////////////////////////////////////////////////////////////
#bit BF = SSPSTAT.0 // flag that indicates traffic on SPI bus
#bit CKE = SSPSTAT.6 // 1 = data exchange on HIGH to Idle, 0 on Idle to HIGH
#bit SMP = SSPSTAT.7 // in Master mode let this bit set (sample at end), in slave mode this bit must be cleared 0
#bit CKP = SSPCON1.4 // clock polarity (1 = low, 0 = high)
#bit SSPEN = SSPCON1.5 // 1 = spi mode, 0 = io mode
#define SPI_SLAVE_SS_DESABILITADO 0xf5
#define SPI_SLAVE_SS_HABILITADO 0xf4
#define SPI_MASTER_SCK_TMR2 0xf3
#define SPI_MASTER_SCK_DIV_64 0xf2
#define SPI_MASTER_SCK_DIV_16 0xf1
#define SPI_MASTER_SCK_DIV_4 0xf0
// timer 0 = 1 / 4000000 / 4 / 256 = 64us (with pll, timer 0 uses 4MHZ clock ???)
#ifndef MAXFILES
#define MAXFILES 1
#endif
#ifndef SAIDA
#define SAIDA 0
#endif
#ifndef ENTRADA
#define ENTRADA 1
#endif
#define MINIMO 0
#define MEDIO 1
#define MAXIMO 2
#define SINAL 0
#define SALVAR 1
#define PARAR 0
#define TAMANHO_BLOCO 512
#define START_BYTE 0xfe
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()
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 spam[3];
char bAttr;
char bReserved[8];
int16 hClusterH;
int16 hTime;
int16 hDate;
int16 hCluster;
int32 wSize;
} DIR;
typedef struct _fileentry
{
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;
void InicializaSPI (char Tipo);
void InicializaMMC (void);
void SelecionaMMC (boolean Flag);
void EnviaMMC (char a);
char RecebeMMC (void);
void MMC8Clock (void);
void ReadSector (int32 sector, char *buffer);
void WriteSector (int32 sector, char *buffer);
char DetectaMMC (void);
void ExecutaCMD0 (void);
void ExecutaCMD1 (void);
void ExecutaCMD16 (void);
void ExecutaCMD10 (void);
void ExecutaCMD9 (void);
void ExecutaCMD6 (void);
void InicializaFAT32 ();
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);
#endif
|
enjoy it.
I got it working on my 18f4620, 18f4525, 18f2620
regards. _________________ Andre |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Mar 02, 2009 6:18 pm |
|
|
Andre, thanks for posting the code.
A few comments though:
Code: | else
{
printf ("\r\nInicializando SPI: ");
printf ("312.5 KHz...");
CKE = FALSE;
SMP = TRUE;
CKP = TRUE;
SSPCON1 = SSPCON1 & SPI_MASTER_SCK_DIV_4;
SSPEN = TRUE;
}
| The setup for SSPCON1 has two problems:
1) you should have used DIV_64 instead of DIV_4
2) The '&' construction only resets bits, but a few bits need to be set as well.
For example change to: Code: | SPI_MASTER_SCK_DIV_64 0x02
SPI_MASTER_SCK_DIV_16 0x01
SPI_MASTER_SCK_DIV_4 0x00
SSPCON1 = (SSPCON1 & 0xF0) | SPI_MASTER_SCK_DIV_64; |
According to the MMC / SD card specifications you have to send a minimum of 74 clock pulses to the card after power-on. This is used by the card for internal initialisation. The chip select line should not be active during these pulses and the clock speed should be lower than 400kHz.
You have mixed this functionality with sending the CMD0 command. Not very nice as it now only works for the slowest clock speed setting.
The above mentioned problems with clock speed setting could cause some cards to fail starting up correctly. |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Mon Mar 02, 2009 10:20 pm |
|
|
ckielstra
thanks for looking the code, it was the first that I got running, there are wrong comments, but a new one is almost finished.
but just to fix it, replace that code for this new one
Code: |
if (Tipo == MAXIMO)
{
SSPEN = FALSE;
SSPCON1 = SPI_MASTER_SCK_DIV_4;
SMP = TRUE;
CKE = FALSE;
CKP = TRUE;
SSPEN = TRUE;
}
else if (Tipo == MEDIO)
{
SSPEN = FALSE;
SSPCON1 = SPI_MASTER_SCK_DIV_16;
SMP = TRUE;
CKE = FALSE;
CKP = TRUE;
SSPEN = TRUE;
}
else if (Tipo == MINIMO)
{
SSPEN = FALSE;
SSPCON1 = SPI_MASTER_SCK_DIV_64;
SMP = TRUE;
CKE = FALSE;
CKP = TRUE;
SSPEN = TRUE;
|
I think that Im not far to got my SDHC running... hope to post it working soon..
thanks again..
regards _________________ Andre |
|
|
manish12
Joined: 18 Jan 2009 Posts: 15
|
|
Posted: Wed Mar 04, 2009 6:33 am |
|
|
ckt diagram for this code pic18f4620 / else, xtal value, setting programming bits ?? |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Wed Mar 04, 2009 7:24 am |
|
|
Manish,
this is only the library functions, but I used with 10, 20 and 40Mhz, (HS and H4 fuses) this was my first "functional" code.
And if you have some problems with card initialization, tell me then I post a new one. Sorry for didn't post the later version, but everything that comes for free has no funny to work with =)
ps 1: in "initicializaMMC" function on CMD the issue regarding CS Active as ckielstra said, I believe that is correct, because I'm just sending dummy clocks for "clean" and make sure that SD Card has nothing else to respond.
ps2: Some cards cannot initializes correctly with this function, so you should try removing 2 commands from the code:
Code: |
ExecutaCMD10 ();
ExecutaCMD9 ();
|
I know.. this makes a very basic initialization sequence but will work fine with SDSC and MMC cards. How I said, I'm still working on a better lib, and a few moments before post this message I got my SDHC (4GB kingston) working =), hope to post it soon.
regards. _________________ Andre |
|
|
vascotech88
Joined: 10 Mar 2009 Posts: 33 Location: Aveiro, Portugal / Lodz, Polska
|
|
Posted: Mon Jul 05, 2010 11:06 am |
|
|
Hi andre!
Before all thanks for sharing your code with the community!
Luckily i understand your code because i am Portuguese :P
I want to ask one think that i never found concrete answer. Your code works with MMC only or with SD cards too?
What have to be changed if its different working?
I am trying to put your code working with Proteus, but its not easy :S
See ya! |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Mon Jul 05, 2010 11:57 am |
|
|
Hi Mate =), nice to now that you are from Portugal, I prefer to speak in portuguese, but as we are here to help, let keep it using the English Language.
My code works with both mmc and sd card, I believe that it will be hard to get it working on proteus, I made myself crazy just trying to work with cards over there. In my first attempt it was working fine, but then I lost control and I move to the real circuitry and there I got better results.
I have my library working with mmc, sd, minisd, sdsc, sdhc (>= 4GB). But unfortunately I still can't share for free.
regards,
Andre _________________ Andre |
|
|
vascotech88
Joined: 10 Mar 2009 Posts: 33 Location: Aveiro, Portugal / Lodz, Polska
|
|
Posted: Mon Jul 05, 2010 1:29 pm |
|
|
Yes, its true, we have to keep language!
Well actually I have half of your code working in Proteus. I haven't start making it on real because I am waiting for components.
Until now I can read and write RAW data to sectors to a zero filled card image. It works great. The next step will be try to add the FAT support.
I will spend next thousand hours in front of CCS :P
Yes! Of course I understand that you don't share it for free! Most part of this takes lots of time and to "work just to heat up" like we say in PT is not good idea! hahaha. Anyway I think is better for other people to understand the code than just copy it from somebody.
I will try to put this working! If I have some problem I will ask!
Best regards mate! =) Thanks! |
|
|
KONAMI
Joined: 29 Aug 2010 Posts: 11
|
How to Handle fopen |
Posted: Wed Mar 14, 2012 6:32 am |
|
|
Hi Andrew.
How do you handle fopen?
I am asking how do you know if filename exist or name on mms/sd
and what error did you return in in case of exist or not ? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Mar 14, 2012 12:57 pm |
|
|
Konami,
Please don't bump all the old SD Card related threads.
The questions you post here make no sense to me because we have no clue as to which SD-library you are using.
If you have a problem then start a new thread where you explain your problem and ask clear questions, if possible with a small demo program. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Wed Mar 14, 2012 3:53 pm |
|
|
Also show us a schematic of the hardware you're using !! |
|
|
prometyus2010
Joined: 12 Feb 2012 Posts: 7
|
|
Posted: Fri Mar 16, 2012 2:09 pm |
|
|
hi..
Thanks for code.
How can I use this code for example how can open a file (xxx.txt) ?
What code I must write main func. ? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Mar 18, 2012 7:21 am |
|
|
prometyus2010 wrote: | What code I must write main func. ? | Have a look at the first 10 lines of the posted code.
Then for opening a file it makes sense to add a call to fopen().
But, why use this library? Andre did a great job by posting this code, but as he writes himself it is only a first running version. A new version was promised back in 2009 but never posted.
As alternatives with more users using the same code you can choose from:
- CCS supplied library (has few known problems but workarounds are posted in the forums).
- Tomi's FAT32 code in the Code Library
- Douglas' FAT16 code, also in the Code Library
- A commercial FAT32 implementation from Brush Electronics |
|
|
|
|
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
|