If you don't care where anything goes as long as it works, then you won't see any of that. But you probably *will* need to use the external programmer interface for any updates. (depending on what you're doing, that requirement might be a feature) Even a pre-fab bootloader needs to not be overwritten, which requires at least a little bit of linker code to not try to put stuff there, even if that bit of flash is protected otherwise. (hardware fuses, and the bootloader itself checking addresses)
This is where many LPC series microncontrollers from NXP really shine; most of them have well designed serial port bootloaders so you don't need any fancy programming hardware to do field updates.
I think you misunderstood me, but you still make a good point. There are some good pre-fab bootloaders for PIC and AVR too. But the problem with any bootloader is that it requires some non-zero amount of code space, and the compiler/linker for the main project can't be allowed to put anything there.
Maybe other toolchains have an easy way to tell them that you're using a specific bootloader, and that's all it takes to reserve that space? (and maybe even include it in the initial binary that gets programmed the first time?) I haven't seen *that* from Microchip.
---
At any rate, that wouldn't have worked for the project that I mentioned above. Most projects can get away with a completely independent bootloader that:
1. Has its own PC support app
2. Takes complete control of the entire chip, and then
3. Releases all of that control to the application code
But this project had a rather small amount of code space for what it was trying to do, and a large part of that was for our USB stack. So I ended up sharing the same USB stack between the bootloader and the application code. Not a complete separation as is usually done. (for good reason!)
Or depending on how you think of it, this "bootloader" never released control, and the "app code" was more of an "add your code here" function that was called just before the "bootloader's" main loop, another one that was called each time around the main loop, another one for USB communications that the "bootloader" didn't intercept, and a goto for the ISR since the "bootloader" and its USB stack were entirely polled. There were also some callback functions from the "app code" to the "bootloader" for USB communication back to the PC.
So because I had multiple function calls in both directions (and a goto), all of them of variable size, I had to have both the "app code" and the "bootloader" in the same project (if you can even make that distinction anymore), and download both at effectively the same time to keep the linker happy. AND minimize the chance of bricking it in the field because the user unplugged it prematurely or whatever.
I ended up with a 2-part download that always overwrote the "app code" section, a small amount of non-erasable assembly to copy that to the "bootloader" section at the top of flash if needed (this was the only chance to brick it), and a "bootloader" that checked to see if the fixed ISR target (immediately after that protected assembly) had a valid ISR in it based on its first instruction. If not, then don't call any of the "app code" functions! (Since that location could also be the start of a freshly downloaded "bootloader", I conveniently put some USB strings there. No chance of an ISR starting with a RETLW!) There were checksums too, so both the first instruction and the checksum of the entire section had to be good before it would be called "valid". The boundary between "app" and "bootloader" was flexible and could be communicated to the relocation assembly code, so we wouldn't be stuck with an unworkable boundary at some point in the future.
From the PC's perspective, the sequence was:
1. Download the new "bootloader" section (actually overwriting the old "application" section)
2. Let it reboot, drop off of USB, and eventually reappear (during this time, it's being copied to the "bootloader" section)
3. Download the new "application" section
4. Let it reboot again, drop off of USB, and eventually reappear
The custom PC app was automated to do that, starting at any point in that process as needed. The state machine was driven by the reported version number from the "bootloader" and whether it reported having valid "app code" or not:
if (reported_version != current_version)
{
download_current_bootloader();
}
else if (!has_valid_application)
{
download_current_application();
}
else
{
use_with_current_firmware();
}
Maybe now you can see where the complexity came from.