lpcware

IAP ROM Bug!!!

Discussion created by lpcware Employee on Jun 15, 2016
Latest reply on Dec 9, 2016 by Harrie Noorlander
Content originally posted in LPCWare by kralux on Fri Oct 26 09:52:41 MST 2012
The In-App Flash Programming on the LPC11xx has bugs in it!
The following piece of code erases the memory and then programs it twice with different values.
Bits that are reset to 0 during the first or second programming should remain to zero and bits programmed to 1 both times should remain to one.
So writing this pattern 0xAAFFFF55 followed by 0xFFAA55FF should lead to a Flash page programmed with 0xAAAA5555 and it does for most of the bytes except every 16 bytes, one bit is flipped down whereas it should not be.
The result in memory is:
0xAAAA5555 0xAAAA5[COLOR=Red]1[/COLOR]55 0xAAAA5555 0xAAAA5555 instead of
0xAAAA5555 0xAAAA5555 0xAAAA5555 0xAAAA5555
Note that the result you get is also pattern depending which also points to a bug (meaning if you write 1000 times 0xFFFFFFFF, no bit flip will occur). For instance if the second pattern is 0xFF55AAFF, then the result in memory will be:
0xAA55AA55 0xAA55A[COLOR=Red]E[/COLOR]55 0xAA55AA55 0xAA55AA55 instead of
0xAA55AA55 0xAA55AA55  0xAA55AA55 0xAA55AA55

Here is the code for you to test and confirm this is a real ROM routine bug:


// IAP Calls
typedef void (*IAP) (uint32_t [],uint32_t []);
#define IAP_LOCATION0x1fff1ff1
// IAP Commands
#define PREPARE_SECTORS50
#define COPY_RAM_TO_FLASH51
#define ERASE_SECTORS52
#define BLANK_CHECK_SECTORS53
#define COMPARE56
#define READ_UID58
#define ERASE_PAGE59


uint32_t retVal0, retVal1, retVal2, retVal3, retVal4, retVal5;
int32_t i;
// TEST
__disable_irq();  // since Flash is unavailable during operations, disable ALL IRQs to avoid crashing
retVal0 = prepareSectors(8, 8);
retVal1 = erasePages(128, 128); // addr 0x8000
__enable_irq();

for (i = 0; i < 256 / 4; i++) {
buf0.chunk = 0xaaFFFF55;
}
for (i = 256 / 4; i < 512 / 4; i++) {
buf0.chunk = 0xFFaaFFFF;
}

for (i = 0; i < 1; i++) {
__disable_irq();  // since Flash is unavailable during operations, disable ALL IRQs to avoid crashing
retVal2 = prepareSectors(8, 8);
retVal3 = writePages(0x8000, (uint32_t) &buf0.chunk, 256);
retVal4 = prepareSectors(8, 8);
retVal5 = writePages(0x8000, (uint32_t) &buf0.chunk[256/4], 256);
__enable_irq();
}


// Prepares sectors for write/erase.
// Will prepare both start and end sectors. They should both be the same to prepare a single sector
uint32_t prepareSectors(int32_t startSector, int32_t endSector) {
command[0] = PREPARE_SECTORS;
command[1] = startSector;
command[2] = endSector;
iapEntry(command, result);
return result[0];
}

// Erases a page or multiple pages in the flash memory.
// Use the same start and end page to erase only one page.
uint32_t erasePages(int32_t startPage, int32_t endPage) {
command[0] = ERASE_PAGE;
command[1] = startPage;
command[2] = endPage;
command[3] = PLL_FREQ * 1000; // clock in kHz
iapEntry(command, result);
return result[0];
}

// Programs the flash memory. Sectors must be prepares first, then erased (set to 0xFF) before being able to be programmed.
// The boot sector can not be written by this command.
// flashDestinationAddr: Destination flash address where data bytes are to be written. This address should be a 256 byte boundary.
// ramSourceAddr: Source RAM address from which data bytes are to be read. This address should be a word boundary.
// size: Number of bytes to be written. Should be 256 | 512 | 1024 | 4096.
uint32_t writePages(uint32_t flashDestinationAddr, uint32_t ramSourceAddr, uint32_t size) {
command[0] = COPY_RAM_TO_FLASH;
command[1] = flashDestinationAddr;
command[2] = ramSourceAddr;
command[3] = size;
command[4] = PLL_FREQ * 1000; // clock in kHz
iapEntry(command, result);
return result[0];
}


So am I doing something wrong or is it really a bug or limitation that you cannot program more than once after erasing (understood that it will act as an AND between successive programming of course)?

This was tested on an LPC1115 so you may need to change the address of the Flash to which you are writing to if you don't have 64 KB of Flash memory like the LPC1115 (just change the sector, page and address 0x8000 accordingly). You will also need to set PLL_FREQ to whichever value you need to.

Outcomes