Hello everyone, I'm having a little issue with flashing (and booting) program from another program itself running on the flash (IAP). Let me start by expliciting the context :
- IDE : µvision4 - JTAG controller : ULINK2 - Application board : MCB1700 (with LPC1768 - 512kB on chip flash)
I'm writting an small application for some project, and that works fine. I wan't to be able to update the software directly from the application. Since I will only have an ethernet connexion with the board in the end, I cannot use the on-chip bootloader via the RS-232.
I'm using (or at least trying to) use the following scheme to update the software. I divide the flash in 3 parts: the bootloader , the software 1 and space for the update (software 2). So the Flash memory map looks something like this :
+----------------+ 0x0007 FFFF | | | Software2 | | | +----------------+ START2 | | | Software1 | | | +----------------+ START1 | Bootloader | +----------------+ 0x0000 0000
The bootloader just decides which software should be booted (by reading relevant information in an EEPROM). The actual flash writing is done from the application, uploading the file is done by using the web serveur in the application.
Now the file transmission via http works fine, my code for writing the flash using IAP routines is sloppy but functional, and the bootloader (which is really a boot chooser) is rolling too.
The problem is that for a software to run it must know at compilation where it will be runned in the memory (I do this by tampering with the scatter file). But this is no good because in the future I don't want to bother about which part of the flash I'm currently using before making an update. So what can I do (beside writing a real ehternet bootloader) to solve this ?
I hope I have expressed the problem clearly enough. Good day to you all :)
The two alternatives you have (besides always building and distributing two different copies of all binaries - one for area 1 and one for area 2 but potentially stored in the same file for simplicity) is to: - build the code fully relocateable so that all accesses are relative. - always run from area 1 and download to area 2, and teach the boot loader to verify that area 2 have a valid application and then erase area 1 and copy area 2 to area 1.
Wow, thanks for answering so fast and so accurately. I still have a question : I don't know how to make a fully relocateable code. Because I think that there is no function in my code that I care where they are written (except for IAP of course but they are in the ROM so no problem there). I should think that it's the linker that decides what goes where so presumably it's some option to put in but I really don't know what. Can you help me on this, or re-route me to some documentation?
Of course, I could also implement you're second suggestion, and I might do that in the end but it's always good to learn so...
Alas, it seems that the project options only allows the data sections (RW and RO) to be position-independant. That makes it really hard to go this route - especially since you don't have access to the source code for all library functions.
If going the route where the boot loader reprograms region 1 from region 2, then it is important that the boot loader only starts this job if requested to. And that it always after power-on checks if there is a half-done job that needs to be completed. This means that the program that downloads a new binary must verify that the download is ok. Then it can write to an EEPROM or a spare flash sector that it's ok for the boot loader to switch application.
The boot loader should do the same - check checksum or md5 of region 2 before it starts to erase region 1 and then copies the application. It's really important that the only way the boot loader may fail to get a valid application into region 1 is if a bad release was sent out (but with correct checksum information) or if the flash in region 1 gets bad enough that it can't be reprogrammed one more time.
Indeed, it's also what worries me. If for some reason I cannot boot on the new software then I'm kind of stuck. The idea behind this whole partition of the flash is precisely to have the possibility of "going back" if the new software is broken.
After browsing through the RealView linker documentation, I have found that it is possible to indicate the linker that a given load region is relocable (infocenter.arm.com/.../index.jsp). Unfortunatly it is not possible to set an absolute value for my RW data (which I want to put into RAM as you might have guessed). I get an linker error when I try to use my scatter file like this :
LR_SOFT 0x00010000 RELOC 0x00038000 ; load region { ER_SOFT +0 0x00038000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x10000000 ABSOLUTE 0x00008000 ; RW data in RAM { .ANY (+DATA +ZI) } }
It is forbidden as specified here : infocenter.arm.com/.../index.jsp
--------------------------------------------------
Good news : I have tried to flash the software without caring about all this and it seems to work nonetheless (which is pretty weird). Maybe it's because the generated assembly code only uses relative jumps (jump relative to PC) instead of absolute jump? In any case I'm not very satisfied because while working for now, it might blow me in the face in the future. I must keep the project going on so i'll keep it that way for now but i'll post here if I have updates on the matter.
Thanks a lot for the insights !
Lots of compilers produces relative jump instructions (if the processor does support them) just because they get away with fewer relocation entries in the object files - so less work for the linker.
But function calls are normally always absolute, since calls often spans different source files while jumps normally are within a function. And a function pointer can't be relative without somewhere getting a base address. This means that a relative function pointer needs to be based, i.e. have a predefined base such as relative to a specific processor register.
All the more peculiar for the stuff to run than. Unless... I think I have an explanation. For my test, I have flashed the same software on the two parts. Which means that even if I boot on the second part, it will call functions in the first part, and since they are the same, there is no issues. But if I had made a real update, it would have failed (miserably I might add).
So back to square one I guess...