We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
The IAP is driving me crazy. When I single step my code using ulink it works, but when I just let it run the micro reboots itself and the IAP hasn't worked. I've read the manual, AN10256, searched the forums and looked at the sample code.
Here's my code:
ErrorCode_t writeBufToOneFlashSector(uint8_t secNum) { BOOL good = TRUE; ErrorCode_t retCode = ERR_NO_ERROR; unsigned int enables; BOOL pllStat; // Disable interrupts during erase and write operations // Keep a copy of what was enabled enables = VICIntEnable; command[0] = IAP_PrepareSectors; command[1] = (uint32_t)secNum; command[2] = (uint32_t)secNum; waitTXComplete(); pauseTX(TRUE); pllStat = usePLL(FALSE); iap_entry(command, result); good = (BOOL)(IAP_CMD_SUCCESS == result[0]); if(!good) { usePLL(pllStat); retCode = ERR_IAP_ERASE_PREPARE | ERR_NUM_USED; errVal = (ParamType)result[0]; } else { command[0] = IAP_EraseSectors; command[1] = (uint32_t)secNum; command[2] = (uint32_t)secNum; command[3] = XTAL_OSC_KHZ; // Disable interrupts during erase VICIntEnable = 0; iap_entry(command, result); VICIntEnable = enables; good = (BOOL)(IAP_CMD_SUCCESS == result[0]); if(!good) { usePLL(pllStat); retCode = ERR_IAP_ERASE | ERR_NUM_USED; errVal = (ParamType)result[0]; } } // See about doing the write if(good) { command[0] = IAP_PrepareSectors; command[1] = (uint32_t)secNum; command[2] = (uint32_t)secNum; iap_entry(command, result); good = (BOOL)(IAP_CMD_SUCCESS == result[0]); if(!good) { usePLL(pllStat); retCode = ERR_IAP_WRITE_PREPARE | ERR_NUM_USED; errVal = (ParamType)result[0]; } } // Ready to write at last if(good) { command[0] = IAP_CopyRAMtoFlash; command[1] = SectorStartAddr[secNum]; command[2] = (unsigned int)nvBuf; command[3] = FLASH_NV_PAGE_SIZE8; command[4] = XTAL_OSC_KHZ; // Disable interrupts during erase VICIntEnable = 0; iap_entry(command, result); usePLL(pllStat); VICIntEnable = enables; good = (BOOL)(IAP_CMD_SUCCESS == result[0]); if(!good) { retCode = ERR_IAP_WRITE | ERR_NUM_USED; errVal = (ParamType)result[0]; } } pauseTX(FALSE); return retCode; }
1) Are you sure that it is ok to have interrupts enabled during the IAP_PrepareSectors call?
2) Are you using a watchdog that may need kicking in the middle?
There's no watchdog.
I'll check on the interrupts during the prepare, but my understanding is that the FLASH is still useable at that point.
Thanks
I've disabled interrupts around the whole function and it doesn't make any difference. I'm starting to think I'm wasting my time as i haven't found anyone, anywhere who claims to have got it working.
It works very well with the LPC23xx series, and I would expect it to work well with the 21xx series too. I haven't seen any information that the support in the 21xx series should be broken.
You haven't mentioned at what place in the sequence that you get the reboot.
I haven't figured out where it reboots because when I single step using ULink it works. My serial comms is queued and interrupt driven, so scattering putchars through the code doesn't work. Wiggling port pins may be an option I suppose.
I don't know your chip, but can you do that thing with the PLL ("usePLL(pllStat);") just like that? what happens if you remove it at the end...?
The documentation is quite specific that you must use the raw oscillator and not the PLL oscillator. What I do is store whether the PLL was in use, turn the PLL off, and then restore the PLL state when I'm done.
but are you sure you follow the data sheet by the letter on how to do that?
That bit was lifted out of the published code snippet. It looks like this:
BOOL usePLL (BOOL useIt) { BOOL pllConStat; // PLL must be enabled AND connected pllConStat = (BOOL)((PLL_STAT & PLLSTAT_PLLE_MASK) == PLLSTAT_PLLE_MASK); // Start the PLL if it's stopped if(useIt && !pllConStat) { start_pll(); } pllConStat = pllConStat && (BOOL)((PLL_STAT & PLLSTAT_PLLC_MASK) == PLLSTAT_PLLC_MASK); // Connect or disconnect as required if(useIt) { connect_pll(); } else { disconnect_pll(); } return pllConStat; } void connect_pll (void) { __asm { LDR R0, =PLL_BASE MOV R1, #0xAA MOV R2, #0x55 // Switch to PLL Clock MOV R2, #0x55 MOV R3, #(PLLCON_PLLE_ENA + PLLCON_PLLC_ENA) STR R3, [R0, #PLLCON_OFS] STR R1, [R0, #PLLFEED_OFS] STR R2, [R0, #PLLFEED_OFS] } } void start_pll (void) { __asm { LDR R0, =PLL_BASE MOV R1, #0xAA MOV R2, #0x55 // Enable PLL MOV R3, #(PLLCON_PLLE_ENA + PLLCON_PLLC_DIS) STR R3, [R0, #PLLCON_OFS] STR R1, [R0, #PLLFEED_OFS] STR R2, [R0, #PLLFEED_OFS] // Wait until PLL Locked LDR R2, =PLLSTAT_PLOCK PLL_Loop: LDR R3, [R0, #PLLSTAT_OFS] CMP R3, R2 BEQ PLL_Loop } } /* * Switch CPU to standard XTAL but leave PLL enabled */ void disconnect_pll(void) __arm { __asm { LDR R0, =PLL_BASE MOV R1, #0xAA MOV R2, #0x55 // Disconnect PLL but leave it enabled MOV R3, #(PLLCON_PLLE_ENA + PLLCON_PLLC_DIS) STR R3, [R0, #PLLCON_OFS] STR R1, [R0, #PLLFEED_OFS] STR R2, [R0, #PLLFEED_OFS] } } /* * Switch CPU to standard XTAL and disable PLL */ void stop_pll(void) __arm { __asm { LDR R0, =PLL_BASE MOV R1, #0xAA MOV R2, #0x55 // Disable PLL MOV R3, #(PLLCON_PLLE_DIS + PLLCON_PLLC_DIS) STR R3, [R0, #PLLCON_OFS] STR R1, [R0, #PLLFEED_OFS] STR R2, [R0, #PLLFEED_OFS] } }
Generate pulses on a single processor pin and use a digital scope to count the number of pulses before the reboot. That should allow you to pin-point where the reset is.
Repeat a number of times to figure out if the reset point is fixed or is jittering. Jittering would often be caused by some interrupt source not being deactivated.
Then add delays at different steps of the code and check how that affects the reset point. People who gets hit by the watchdog would quickly notice a big difference during this test.
Are you sure that you don't have any DMA transfers ongoing?
If I remember correctly, the IAP routine needs a number of bytes of RAM to operate - any collision with your memory use, for example with a stack?
Have you tried to contact a NXP support engineer?
I added some code to bash a PIO pin up and down, so now I know the IAP call to erase the flash is where it gets lost. The start of main() then happens somewhere between 401msec and 401.2msec later.
The LPC2138 doesn't seem to have a DMA capability, and I don't use it.
I don't enable the watchdog.
Hi,
I don't know much about this. But I am trying to do some IAP on my LPC2378.
Have you downloaded the below source code?
http://www.keil.com/download/docs/298.asp
It should work on the MCB2130.
And, how do you convert 'addr' to sector number?
/* * Convert 'addr' to sector number */ unsigned int get_secnum (void *addr) { unsigned int n; n = ((unsigned int) addr >> 13) & 0x1F; // pseudo sector number if (n >= (0x30000 >> 13)) { n -= 14; // high small 8kB Sectors ( } else if (n >= (0x10000 >> 13)) { n = 7 + (n >> 3); // large 64kB Sectors } return (n); // sector number }
Sorry, that source code is for CARM.
But you should have a similar example installed on your KEIL PC.
I just did some checks; and found something strange.
I've read the manual, AN10256, searched the forums and looked at the sample code.
Where do you get that sample code? What is the size of your flash memory? How do you convert 'addr' to sector number?
I don't turn an address into a sector number, I turn a sector number into an address. I do that by lookup table. I'm using two of the 8kB sectors (one primary, one duplicate backup) as that's easily enough for my application.
I can't specifically remember that I got the code snippets from anywhere other than the app notes.
Hi Oliver,
Please refer to:
UM10120 LPC2131/2/4/6/8 User manual Rev. 02 - 25 July 2006 User manual LPC213x
www.standardics.nxp.com/.../user.manual.lpc2131.lpc2132.lpc2134.lpc2136.lpc2138.pdf
Page 242, Table 223. Flash sectors in LPC2131, LPC2132, LPC2134, LPC2136 and LPC2138
0 4 0X0000 0000 - 0X0000 0FFF + + + + + [del] 7 4 0X0000 7000 - 0X0000 7FFF + + + + + 8 32 0x0000 8000 - 0X0000 FFFF + + + + [del] 21 32 0x0007 0000 - 0X0007 7FFF + 22 4 0x0007 8000 - 0X0007 8FFF + [del] 26 4 0x0007 C000 - 0X0007 CFFF +
It seems that, you don't have any 8K sectors.