Hello,
I'm writing this huge Forum request because the Keil support didn't answer my email support request in a proper way, yet. I'm a bit disappointed, so I hope somebody else might help me...Maybe I'm not the only one, who has problems with the flashfilesystem.
I want to use the flashfilesystem delivered with the RealTime Libary on the on the MCB2300 board (with LPC2378 from NXP). Using ARM-MDK (3.04) and RL-ARM (3.04).
First I'm describing my configuration of the FFS and after that I explain my problems.
The flashfilesystem should be placed in the upper 5 sectors of the internal flash of the microcontroller.
So this is my device configuration file FS_FlashDev.h:
... //Definition of the FlashSectors used by the Flash File System // DFB( size , baseadr ), /* Comment */ \ <-- macro continuation sign (Don't forget) #define FLASH_DEVICE \ DFB(0x001000, 0x000000), /* Sector Size 4kB */ \ DFB(0x001000, 0x001000), /* Sector Size 4kB */ \ DFB(0x001000, 0x002000), /* Sector Size 4kB */ \ DFB(0x001000, 0x003000), /* Sector Size 4kB */ \ DFB(0x001000, 0x004000), /* Sector Size 4kB */ \ // Number of previously defined sectors #define FL_NSECT 5
I setup the File_Config.c like this:
Flash Drive Option checked Target device Base address 0x0007 8000 Device Size in bytes 0x0001 0000 CPU Clock Frequency[Hz] 48000000 Initial Content of Erased Memory 0xFF Device Description File FS_FlashDev.h Default Drive: Flash
Comment: I'm not sure if I configured the Target device Base address correctly. According to the documentation it specifies the device base address in the memory space of ARM processor I guess in my case it's the absolute starting address of the first Sector defined in the FS_FlashDev.h.
I took the flashprogramming routines from the directory C:\Keil\ARM\Flash\LPC_IAP2_512 and modified them accordingto the documentation. This is the resulting FS_FlashPrg.c:
#include <File_Config.h> #define STACK_SIZE 64 // Stack Size #define SET_VALID_CODE 1 // Set Valid User Code Signature #define PAGE_SZ 256 // Page Size U32 Page[PAGE_SZ/4]; // Page Buffer unsigned long CCLK; // CCLK in kHz struct sIAP { // IAP Structure unsigned long cmd; // Command unsigned long par[4]; // Parameters unsigned long stat; // Status } IAP; /* * IAP Execute * Parameter: pIAP: Pointer to IAP * Return Value: None (stat in IAP) */ void IAP_Execute (struct sIAP *pIAP); /* * Get Sector Number * Parameter: adr: Sector Address * Return Value: Sector Number */ unsigned long GetSecNum (unsigned long adr) { unsigned long n; n = (adr >> 12) & 0x7F; // Pseudo Sector Number if (n >= 0x78) { // High Small 4kB Sectors n -= 0x62; } else if (n >= 0x08) { // Large 32kB Sectors n = 0x07 + (n >> 3); } return (n); // Sector Number } /* * Initialize Flash Programming Functions * Parameter: adr: Device Base Address * clk: Clock Frequency (Hz) * fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify) * Return Value: 0 - OK, 1 - Failed */ int fs_Init (U32 adr, U32 clk) { CCLK = clk / 1000; //convert Hz to kHz return (0); } /* * Erase Sector in Flash Memory * Parameter: adr: Sector Address * Return Value: 0 - OK, 1 - Failed */ int fs_EraseSector (U32 adr) { unsigned long n; n = GetSecNum(adr); // Get Sector Number IAP.cmd = 50; // Prepare Sector for Erase IAP.par[0] = n; // Start Sector IAP.par[1] = n; // End Sector IAP_Execute (&IAP); // Execute IAP Command if (IAP.stat) return (1); // Command Failed IAP.cmd = 52; // Erase Sector IAP.par[0] = n; // Start Sector IAP.par[1] = n; // End Sector IAP.par[2] = CCLK; // CCLK in kHz IAP_Execute (&IAP); // Execute IAP Command if (IAP.stat) return (1); // Command Failed return (0); // Finished without Errors } /* * Program Page in Flash Memory * Parameter: adr: Page Start Address * sz: Page Size * buf: Page Data * Return Value: 0 - OK, 1 - Failed */ int fs_ProgramPage (U32 adr, U32 sz, U8 *buf) { U32 padr, ofs, cnt, n; IAP.cmd = 50; // Prepare Sector for Write IAP.par[0] = GetSecNum(adr); // Start Sector IAP.par[1] = GetSecNum(adr + sz - 1); // End Sector IAP_Execute (&IAP); // Execute IAP Command if (IAP.stat) return (1); // Command Failed while (sz) { // Go through all Data padr = adr & ~(PAGE_SZ - 1); // Page Address ofs = adr - padr; // Data Offset cnt = PAGE_SZ - ofs; // Data Count if (cnt > sz) cnt = sz; // Adjust Data Count if (cnt != PAGE_SZ) { // Incomplete Page being written for (n = 0; n < PAGE_SZ/4; n++) { // Go through complete Page Page[n] = *((U32 *)padr + n); // Read Page Data from Flash } } for (n = 0; n < cnt; n++) { // Go through Page Data *((U8 *)Page + ofs++) = *buf++; // Copy & Align to Page Buffer } IAP.cmd = 51; // Copy RAM to Flash IAP.par[0] = padr; // Destination Flash Address IAP.par[1] = (U32)Page; // Source RAM Address IAP.par[2] = PAGE_SZ; // Page Size IAP.par[3] = CCLK; // CCLK in kHz IAP_Execute (&IAP); // Execute IAP Command if (IAP.stat) return (1); // Command Failed adr += cnt; // Next Address sz -= cnt; // Next Size } return (0); }
I finally added the IAP.s file for calling the IAP routine of the microcontroller and the RTLFS.lib. Everything was compiled, linked and loaded to the MCB2300 board.
I created a simple testing programm:
... int main (void) { FILE *filehandle; int ch,i; ... printf ("Initialize Flash File System..."); i = finit(); if( i != 0 ) { printf ("(finit = %d)Failed\n",i); } else { printf ("(finit() = %d)OK\n",i); } printf("Formatting Flash File System..."); if ( fformat ("F:") != 0 ){ printf ("Failed\n"); }else{ printf ("OK\n"); } printf("Writing a small Testfile..."); filehandle = fopen ("F:Test.txt","w"); if (filehandle == NULL) { printf ("File not found!\n"); }else { printf("File opened..."); printf("%d Bytes written to File...", fprintf( filehandle, "0123456789" )); fclose ( filehandle ); printf("File closed\n"); } printf("Read back the written File..."); filehandle = fopen ("F:Test.txt","r"); if (filehandle == NULL) { printf ("File not found!\n"); }else { printf("File opened..."); // Read all characters from the file while ( !feof (filehandle) ) { ch = fgetc ( filehandle ); printf("%c", ch ); if ( ferror (filehandle)) { printf ("File read error..."); break; } } fclose ( filehandle ); printf("File closed\n"); } printf ("Checking Flash File System..."); if (fcheck ("F:") != 0) { printf ("Failed\n"); printf ("Flash File System inconsistent, formatting..."); } else { printf ("OK\n"); } while(1); }
So I have the following result: 1. finit returns with "(finit() = 1)Failed"
2. fformat returns with "OK"
3. Writing to file is working. When I set a breakpoint in debugging mode after closing the written file, the correct filename is displayed in the Peripheral->RTX-Kernel->Flashfilesystem tab. When I check the memory position of the first sector, I can see the data written to the flash.
4. Reading the file doesn't work correctly. It doesn't read anything useful, because it seems to read from the wrong position and so it could not detect the file end and is reading without stopping...
So I would be happy, if anybody can give me some hints, what I have done wrong.
Thank you to all the people taking the time to read this text to help me....
Rainer
Just to inform others who may have the same problems:
I got some proper information from keil support , that the issue is due to the ECC of the LPC2378 flash memory.
So I made some tests writing data with inbuild IAP routine of the LPC2378 and read it again. So my current result is that the first writing to a position works, but the second write doesn't work. So it seems the IAP routine doesn't work properly and so it's not possible for the filesystem to write the data correctly to the internal flash of the LPC2378.
Rainer, followed is some advices, can be useful: -make sure you read errata sheet for your chip. Some manufacturers does not provides programming internal flash on max speed. -try use fwrite and fread functions instead fprintf and fgetc. -make sure you include "retarget.c" file in project. -try start using file system in RAM memory first, then move to flash.
Mikhail Sokolov,
thanks for hints!
I contacted the support of NXP, now. To get some more information about the problem with the IAP routine. But this will take some time.
LPC2148 uses ECC flash data protection algorithm. This means it has a hidden byte where a control code for the flash page is stored. Based upon this data, an automatic error correction of a few bits in a page is possible. This makes the flash data reliability much better, but on the other hand has a side effects. You can not write tha flash page twice, this means you must write the whole page only once and then erase the whole sector. I think that one page is 16 (or maybe 32) bytes. IAP routines are able to write only 512/1024 byte blocks.
Flash File System does not work with ECC pages so this is the reason it is unusable for internal flash on devices using ECC.
hello Rainer, did you got some information from keil suport? because i also got some problems with the flashfile system and the internal flash! So if you got new information could you post it please. thanks ROmain
Hello MOURA Romain,
as I already posted on 13-Feb-2007 04:04 in my case the problem is the ECC Code of the internal flash memory of the LPC23xx. It's like Franc Urbanc wrote above. To write some bytes to the flash, the whole sector must be erased before you can write one time. To write again somewhere to this sector the sector must be erased again. So it's impossible to use the internal flash memory of the LPC23xx as fast working flash filesystem.
So you need some kind of external flash memory without ECC when you use an LPC23xx.