PIC bootloader head scratching - Page 1
Forum section: electronics / general

author: TomS_
author_rank: Frequent Contributor
timestamp: January 01, 2018, 04:30:38 am
content: Hi all.Theres a lot of information and ideas out there, and a lot of implementations of bootloaders that its a bit hard to make heads or tails of what exactly is the best, simplest way to do something for your own situation.Im trying to get my head around some theory, so I'll think out loud and if anyone has some input I'd greatly appreciate it.Im working on a project, I have an existing means of "communicating with my PIC", and have already implemented a method to send new firmware to that PIC - it gets stored in an attached EEPROM where it can be later retrieved (thanks to mikeselectricstuff for that idea).The part Im having difficulties with is the "bootloader" bit. What I thought would be super simple for my situation would be, within the first few lines of code of the application, use the "call" instruction to enter the bootloader, which can do some quick checks to determine whether anything needs to be done (e.g. software needs to be copied out of EEPROM), and if not it can simply "return" and the main application carries on. If firmware does need to be updated, the bootloader can go about doing that, and when it is done it can perform a reset and the PIC starts up as usual.Ive seen a lot of examples of bootloaders being placed towards the beginning of program memory, but I believe this complicates things a bit with remapped interrupt vectors, so I think placing the bootloader higher in memory is more ideal - I can just reprogram the IVT as part of the firmware update. I figure I can get away without using interrupts in the bootloader as it should only need to be incredibly simple, some loops to read EEPROM and write program flash - really, nothing fancy.The other thing I have noticed is that, compiling a bootloader separately seems to include a lot of "initialisation code" if you will, that executes before the main program loop of the bootloader. I believe that sets up the stack and other bits of the processor. Naturally, if the entry point to the bootloader is through the main application, that will already have been done, so the bootloader doesnt really need to be much beyond the code for the bootloader itself. So how to compile the bootloader without all of that additional initialisation code?I dont really mind doing it the other way around if need be - reset vector to the bootloader which jumps to the address of the main application code. Either works for me.So, I guess the question is, does anyone have any thoughts about this? I realise its "yet another way to do it", and may be reinventing parts of the wheel with "yet another implementation", but Im looking for something incredibly light weight that I can get my head around. Everything else seems geared towards direct communication with UARTs etc, whereas I already have that bit sorted, and just need to work out how to execute my bootloader to do the copy and return to the application itself while cutting out a little bit of fat.Cheers and happy new year!Tom

author: Ian.M
author_rank: Super Contributor
timestamp: January 01, 2018, 05:00:29 am
content: Its absolutely critical to know which PIC family you are considering a bootloader for. e.g. the three 8 bit PIC families that can support a bootloader require different strategies due to their differing instruction set limitations.The idea of writing the bootloader as a subroutine in a high level language can be dangerous - unless extreme care is taken, its probable that the bootloader's RAM allocation will conflict with the main application, making it impossible to return control to the main application without resetting the PIC, and any failed firmware update will brick the device with no possibility of recovery short of ICSP.

author: TomS_
author_rank: Frequent Contributor
timestamp: January 01, 2018, 05:30:36 am
content: In my case its a PIC24E.Since my intention is to only jump in to the bootloader when the PIC starts up -notduring run time - I shouldnt imagine that overlapping RAM would be an issue. I want to do it as early as possible before any RAM is allocated to anything of particular interest, get in, get out, and when the main application starts it can simply overwrite any memory that was used by the bootloader.edit: so my intended workflow for firmware updates would be:1. while application is running, upload new firmware to EEPROM2. initiate reboot3. at beginning of boot, bootloader is called somehow, and checks for new firmware3a. if no new firmware, "return" and application continues to run as normal3b. if new firmware, copy to flash, then go to step 2

author: TomS_
author_rank: Frequent Contributor
timestamp: January 01, 2018, 05:34:11 am
content: I suppose the way I am thinking about it, it might also be possible to have the main application update the bootloader as a separate run-time process.

author: Howardlong
author_rank: Super Contributor
timestamp: January 01, 2018, 10:08:07 am
content: In the PIC bootloaders I’ve done (PIC24 and PIC32, both over USB HiD), the key is to make sure that the bootloader is bulletproof, and that you have ways into the bootloader in the event of the application being suspect.I take a multi-tiered approach. The devices aways hit the booloader first on boot, and any reset reason. I do a firmware CRC check on the application flash area on every boot, and implement a 2s watchdog, exception traps, and I also check the reset reason: if it is a watchdog timeout or non-POR reset (e.g., reset trap, software reset, hardware reset (there are a couple of PCB pads available to short on MCLR) for example, stay in the bootloader. There is also a way in from the application itself using the software reset. I’ve never had to resort to the PCB pad shorting in the field, it’s the last resort.I had to hack linker files, and write protect flash areas to prevent accidental overwrites, although in the bootloader software I also check it’s not trying to overwrite itself (belt and braces!).I also have an area of flash I use for persisting device settings during re-flashing. This can only be protected in software.Looking at my PIC24FJxxGB002 version, jumping from bootloader to application is managed with an asm goto. I also have some minimal example stub app code loaded at the app’s absolute location in the bootloader source for debugging the bootloader’s behaviour itself.To jump from the application to the bootloader, I do an asm reset, not a goto, to force a software reset that can be detected by the bootloader as a reason to remain in the bootloader. Check out the RCON register.One further thing, remember to reset all the peripherals and any other state when switching between app and bootloader. If the device is USB for bootloader and application, you will also need to delay after resetting the USB peripheral for a short while or else it won’t re-enumerate.

author: TomS_
author_rank: Frequent Contributor
timestamp: January 01, 2018, 11:10:11 am
content: Thanks for your in-depth post. There are some good ideas in there, like checking the reset reason to determine whether the bootloader should be called up. Im still getting to grips with traps etc, so not sure if I will be using those at this stage. Baby steps I suppose.I guess your bootloader is the method that you use to receive the new firmware itself, and do the programming?Over the past few hours Ive been fiddling with project settings and linker files and I think Ive figured out how I can achieve my intended setup.Ive got two projects, one is the bootloader and the other will be the application. Each project is configured to preserve the memory space of the other, so programming one doesnt obliterate the other. And Ive worked out how to modify the linker scripts appropriately so that I can have the application compile with a reset vector pointing directly in to the bootloader or in to itself depending on how I decide to go with this, and also placing the two in their respective memory regions.Ive also worked out how to trim the fat from the bootloader that I mentioned in my first post, so this is all looking good so far.And Ive reserved one page of flash to use as a sort of internal EEPROM for settings etc - thats a great idea, since this one doesnt have any internal EEPROM.I guess the only thing left to do is to start writing a bootloader that starts copying contents out of the external EEPROM, and test jumping from one to the next and vice versa. Some more time fiddling and trying things out should help clear the fog.Error handling is going to be an interesting challenge for sure....