I have a project for a PIC16F1454 that needs some custom linking. Basically, I've separated my code into two parts that can be downloaded separately in the field and thus update (almost) all of the flash memory, including the bootloader. As part of the plan to avoid bricking itself, I have this structure:

  • Lower, protected by hardware, not field-updateable:
    • Startup and image-copy code, written in assembly
  • Middle:
    • Application space
    • Also used to download new images
  • Upper:
    • Bootloader space

And there's some code in various places that enforces that structure.

The bootloader includes a USB stack, a main loop, and some helper functions that add up to slightly more than one page of flash, which causes some problems for the linker. For example, the help file says that this option is supposed to concatenate the entire list and put it against the specified upper limit (note the negative address):

  • -L-pUSBCode=-1FFEh,USBConst,BootloaderCode,BootloaderConst

But when I do that, all four psects overlap, with the usual, unintended consequences. I did this:

  • -L-aBootloader=1400h-17FFh,1800h-1FFDh -L-dBootloader=2 -L-pUSBCode=Bootloader -L-pUSBConst=Bootloader -L-pBootloaderCode=Bootloader -L-pBootloaderConst=Bootloader

which defines a class with 2-byte elements that crosses a page boundary at 1800h and puts all four psects in that class. While they didn't overlap, I got a big hole next to the page boundary, big enough for several of the helper functions to fit in.

I could assign functions more granularly to more than four psects, and that would probably make things fit better, but I'd rather not make it any more complicated than I have to. Someone else (could be me after a few months) is probably going to modify it later, and I don't expect him to be intimately familiar with the details.

How can I pack the entire bootloader section as tightly as possible into upper memory, accounting for the springboard to main() at 1FFEh-1FFFh, without requiring a future developer to change anything outside of the C source files?


First off, have you looked into the Optimization on the XC8? It may require a paid license, but it could also get you down below a page, keeping you from having to have those extra bits dangling onto the next page. Another thing to note is that sometimes the X series compilers will do very, very strange things under optimization settings. Thoroughly test your product if you use optimization settings. You may very well find bugs. Remember that Microchip is in the Processor Business, not the Compiler Business. It shows.

Secondly, have you considered trying the C18 compiler to see if that will give you a smaller binary? I'm not positive it will work with your chip, but it produces slightly different binaries, which could end up being smaller than the one XC8 gives you.

Finally, you may have to just rewrite the code until the compiler spits out something smaller. I've had to do this a few times to get around page lengths myself, and while it's never pretty, it's almost always better than having to manually add data to the end of a page when installing another Binary.

| improve this answer | |
  • I'm currently using the 60-day free trial of the pro version, which is the "best" of three options, and both optimization settings - speed and space - are still bigger than 1 page. I wish it was that easy. Changing toolchains at this point is still possible, but I'd rather not throw away the investment so far. – AaronD Aug 29 '14 at 17:10
  • Yup. The XC8 compiler will do very strange things when optimizing. In one case, it decided that my interrupt service routine was not needed...... – CurtisHx Aug 29 '14 at 18:28
  • @AaronD have you considered upgrading to a chip with more memory? Or maybe using external flash via I2C or some other interface? – Ampt Sep 2 '14 at 14:18
  • Memory space is not a problem, once it all gets in there. Are you suggesting that I download the new image to an external chip and then copy from there to my internal flash? – AaronD Sep 2 '14 at 15:38
  • You could put the code to access the external flash into the startup page, then just store the entire bootloader into external flash, completely separating it from the image space. – Ampt Sep 2 '14 at 15:41

I solved the problem, but not in the way I was thinking originally. I realized that it was okay to have some application code in the bootloader section, just not the other way around. So if the boot section is bigger than it needs to be and the linker fills in some of the gaps with app code, that's fine. The app code just won't run until the app section is verified.

So now I have:

  • -L-pUSBConst=1200h -L-aBootloader=1200h-17FFh,1800h-1FFDh -L-dBootloader=2 -L-pBootloaderText=Bootloader -L-pUSBText=Bootloader -L-pISRText=0220h

and it seems to work. 0x1200 is the halfway point of the space left by the startup code, rounded up to the nearest 0x0100 so it doesn't complain about the constants being there. This, then, is the biggest bootloader / USB driver I can have without causing other problems anyway.

As a side-note, the optimizer only works on sections named *text* (wildcards, not case-sensitive). It took a while to figure out why my carefully-timed ISR was optimized even worse than the free version.

Thanks for your help!

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.