How to boot from the 2nd half of a 24C512?
As mentioned here, an FM24C512 or BL24C512 can be very useful for storing a unique serial number or MAC address in the "hidden" 128 byte ID page. But it can also be very useful for storing a second boot image because it has twice as much memory as the P1 needs. This could be used to make field software updates fail safe. If the download process gets interrupted by a power failure or cable disconnect the boot loader in the first half of the memory stays operable and can be used to retry the update later.
If the bootloader detects a valid boot image in the second half it can load it into RAM and execute it. But how can this be done? A REBOOT command is not what I want because it would look for serial boot and the boot image in the first half of the EEPROM, again. I should start cog0 with the Spin interpreter as it's done after loading the EEPROM contents to RAM by the ROM bootloader. Is there a defined entry point where I can jump to?
Comments
This ASM snippet will boot from upper. ($8000- or change the start address with the mem_start variable)
Code that boots upper half of 512 EEprom was in OBEX.
I can't remember the exact name of the code.
For this to work, you would always store new firmware to upper half of EEprom.
And lower half of EEprom always hold the code that loads from upper half
Thanks @VonSzarvas
So the whole boot process can be summarized like this:
1. load the first 10 bytes from EEPROM address $8000 to RAM address $0000
2. take the length of the boot image from byte 8 and 9
3. load the rest of the image to RAM
4. check if code is valid (checksum or whatever)
5. take XTAL/PLL mode from byte 4
6. switch clock mode, wait 20ms for PLL
7. execute a
COGINT interpreter
command.. where
<interpreter>
points to the somehow magic address $7C010. Ah, I just looked up the P1 COGINT instruction. $7C010 = 1<<18 + $3C01<<4 + 0 means PAR=$0004 and code adr=$F004 for cog #0. This is the entry point for the spin interpreter.The code above assumes that it is launched in cog 0, right? So
coginit interpreter
restarts its own cog and does not fall into the shutdown procedure. I have to do it differently. If no valid code is found in the upper half of the EEPROM I have to go back and startup the network interface to accept firmware updates from the PC. No problem... I just have to start the ASM code in a different cog (say 1) and wait with cog 0 if it reports an error. If there's no error it will never come back but restarts cog 0 with the interpreter and the main program in RAM and shuts down cog 1.Correct.
In a product it worked like this...
The lower EEPROM held a bootloader that ran each time the P1 reset.
The bootloader pinged a server (over GPRS) for firmware updates, and if existed then downloaded and copied the update to upper EEPROM, verified the checksum and repeated if failed. The repeat delay got longer each attempt, etc..
Finally the ASM code snippet was executed with
COGINIT BootUpper, 0
Jippee! It actually seems to work. Although it's a lot more complicated than I first thought.
I'd like to protect the firmware image in the second half of the EEPROM with a checksum to be able to detect incomplete or corrupted downloads. But I can tell whether the checksum is correct or not only after I have read the complete firmware image and I don't want to do that twice. So if I detect an error I have to re-load the bootloader from the first half of the EEPROM and launch it in network mode so it can wait for downloads from the PC.
To detect if the bootloader comes fresh from a cold start or if the firmware boot already failed I patch a global variable after loading the bootloader from EEPROM to RAM. The address of the variable is passed to the bootstrap ASM code in the PAR register.
Cunning
Btw... One way I handled the checksum in the past was by downloading an update in 128 long blocks, saving to ram and verifying a checksum before writing to EE. Then repeat until the full image stored.
Trouble was it didn't help if a powerfail occured on the last write, so the bootloader being able to re-try the update is still important.
I also zero'd the first few longs of EE when starting the update, and then downloaded the image backwards. It means the checksum bytes close to $8000 are the last written, so quick to verify if a valid image exists.