Hey everyone, was hoping someone could help me with something.
I'm developing an RTX application for a LPC2387 (currently using the MCB2300) and need to write a char array to flash memory. Learned a lot about using IAP commands but I think I'm missing something still.
I'm using function inspired by the supplied algorithms for the LPC2387 (found under C:\Keil\ARM\Flash). I can write to flash and read it back fine but once I try to erase, I get a data abort exception. My code is below:
This works:
flash_write(0x00058000, protocol_buf1); flash_read(0x00058000, 5, protocol_buf2); // Code that prints out protocol_buf2 }
This doesn't work:
flash_erase(0x00058000); flash_write(0x00058000, protocol_buf1); flash_read(0x00058000, 5, protocol_buf2); // Code that prints out protocol_buf2 }
Where the flash functions are defined:
#define CCLK 4000 #define PAGE_SIZE 1024 struct sIAP { // IAP Structure U32 cmd; // Command U32 par[4]; // Parameters U32 stat; // Status U32 res; // Result } IAP; void IAP_Execute (struct sIAP *pIAP); U32 get_sect_num(U32 address) { U32 sector; // Calculate sector number sector = (address >> 12) & 0x7F; if (sector >= 0x78) sector -= 0x62; else if (sector >= 0x08) sector = 0x07 + (sector >> 3); return sector; } U8 flash_write(U32 address, U8 *buffer) { U32 sector; // Get the sector number sector = get_sect_num(address); // Prepare sector for write IAP.cmd = 50; // Command code IAP.par[0] = sector; // Start sector IAP.par[1] = sector; // End Sector IAP_Execute(&IAP); // Execute IAP Command if (IAP.stat) return 1; // Command Failed // Copy RAM to FLASH IAP.cmd = 51; // Command Code IAP.par[0] = address; // Destination Flash Address IAP.par[1] = (U32)buffer; // Source RAM Address IAP.par[2] = PAGE_SIZE; // Fixed Page Size IAP.par[3] = CCLK; // CCLK in kHz IAP_Execute(&IAP); // Execute IAP Command if (IAP.stat) return 1; // Command Failed return 0; } U8 flash_read(U32 address, U32 size, U8 *buffer) { U32 i; for (i=0; i<size; i++) buffer[i] = *((U8*)address+i); return 0; } U8 flash_erase(U32 address) { unsigned long n; n = (unsigned long)get_sect_num(address); // 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 }
assembly IAP execution
AREA IAPEXE, CODE, READONLY ;void IAP_Execute (struct sIAP *pIAP); EXPORT IAP_Execute IAP_Execute STMFD SP!,{LR} ; Save Return Address ADD R1,R0,#0x14 ; R0 = &IAP.cmd, R1 = &IAP.stat ADR LR,IAP_Exit ; Return Address LDR R2,=0x7FFFFFF1 ; IAP Entry (Thumb Mode) BX R2 ; Execute IAP Command IAP_Exit LDMFD SP!,{LR} ; Restore Return Address BX LR ; Return END
So I figured out what I was doing wrong.
I tried disabling interrupts, but I wasn't calling any in my test code, so that wasn't the problem (I added that to my main code though since it's a must have).
I eventually found this yahoo group that has a lot of example code: tech.groups.yahoo.com/.../
They have an example that uses the flash as an EEPROM which ended up being quite useful. In the end I realized I made a dumb mistake and didn't give the correct clock rate to the IAP erase and write functions. I didn't remember to take into account the PLL multiplier. Added that in and now it works splendidly.
Good of you to post the resolution to the problem, since no one here have access to enough information to catch that one.