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; }
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.
I found something improper in the source code of the below URL.
And, what I used was from somewhere like "C:\Keil\ARM\Boards\Keil\MCB2100\IAP"; it worked.
I had to provide a correct get_secnum() function to this example. After some checks and tests, it worked.
(Not so sure about how to integrate this IAP example to a project.)
You're right. I was confusing myself as I actually use 4k byte sectors.
So, do you still encounter the IAP problem?
Bad of it to not generate an error about incorrect parameter.
God, this is soooo frustrating. After I fixed the sector calculation algorithm, the example IAP project appears to work. I can't say that it works with 100% confidence because you can only observe it's behaviour with the debugger, and I know the debugger makes a difference. Anyway, the next step is obviously to add my code, piece by piece, until I figure out what breaks it. The problem now is that the ULink seems to have stopped working, as it keeps reporting that it can't stop the target. I remember this happening to me before, and I had to use Flashmagic to recover the target, but that doesn't seem to do the trick now. Flashmagic claims to reprogram the target, but the ULink still doesn't work.
Have you done a full chip erase with Flash Magic?
try this: * reduce JTAG clock speed. * disable "cache code", "cache memory" in driver setup menu.