News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Creating a bootloader

Started by kcsl, Jun 29, 2025, 09:53 AM

Previous topic - Next topic

kcsl

I need to create a bootloader, and realised I don't know as much about this topic as I thought I did.

It seems that the PIC 18F27Q83 always boots/resets to address $0, so that's where the bootloader must reside.
So, the first chunk of program memory would contain the boot loader, then the application program would reside after that.
As an example, the application will have "DECLARE Compiler_Start_Address = 0x1000".

In the bootloader, I can configure the system clock, hardware I/O pins, timer module etc.
The bootloader then decides there's nothing to do, so starts execution of the main application from address $1000

I assume I do something like this when the Bootloader is ready to start the main application:

' Start executing the main application
ASM
   GOTO $1000
ENDASM

Now the main application is running, I just need to re-setup the interrupts for the timers, modules etc as their addresses they jump to will have all changed.
I don't need to re-configure the clock or any of the hardware as it's already been done by the bootloader and since there was no RESET, that should all still be valid.

I've probably over simplified but is this basically it, because it feels there's a giant trap I'm about to fall into?


Regards,
Joe
There's no room for optimism in software or hardware engineering.

trastikata

Here's how I typically design USB HID bootloaders for my devices:

1. Re-map Interrupt Vectors
Ensure the high and low priority interrupt vectors are redirected:

On_Interrupt      GoTo HIGH_INTERRUPT_VECTOR 
On_Low_Interrupt  GoTo LOW_INTERRUPT_VECTOR

2. Configure Fuse Settings
Fuse settings should be locked in such a way that the bootloader always runs—regardless of what is flashed afterward. Protect the bootloader's flash area when possible.

Example – Using traditional protection bits:
Config_Start
    ...
    CP0   = OFF  ; Code protection disabled for Block 0 
    CP1   = OFF  ; Code protection disabled for Block 1 
    CPB   = OFF  ; Code protection disabled for Boot block 
    CPD   = OFF  ; Code protection disabled for Data EEPROM 
    WRT0  = OFF  ; Write protection disabled for Block 0 
    WRT1  = OFF  ; Write protection disabled for Block 1 
    WRTC  = ON   ; Configuration registers write-protected 
    WRTB  = ON   ; Boot block write-protected 
    WRTD  = OFF  ; Write protection disabled for Data EEPROM 
    EBTR0 = OFF  ; Block 0 not protected from external table reads 
    EBTR1 = OFF  ; Block 1 not protected from external table reads 
    EBTRB = OFF  ; Boot block not protected from external table reads 
Config_End

Example – Using flash write-protect range:
Config_Start
    ...
    WPFP   = PAGE_3   ; Write-protect up to Page 63 
    WPEND  = PAGE_0   ; Protection applies from Page 0 to WPFP 
    WPCFG  = ON       ; Configuration Words page write/erase-protected 
    WPDIS  = ON       ; Enables write protection as defined above 
Config_End

3. Flash Status Check at Boot
Upon boot, verify whether the last firmware update completed successfully by checking a stored marker:

BootOk = ERead FlashClearedStatus  ; From EEPROM 
; or 
BootOk = CRead FlashClearedStatus  ; From FLASH

4. Decide Next Action
Based on the BootOk flag:
 - Wait a few seconds and receive a FLASH request or check an input pin to trigger flash mode
 - Immediately enter flash mode
 - Proceed to the main application

5. Firmware Flashing Procedure
If flashing a new program:
 - Mark BootOk as "Not OK" (or equivalent)
 - Set up a reliable communication and addressing mechanism
 - Handle erasure and writing, accounting for block and page sizes
 - Implement safeguards to avoid overwriting the bootloader if not protected by fuses for example if flash address is below certain number, don't erase/flash
 - Flash the new firmware
 - Set BootOk to "OK" (or equivalent)

I recommend storing the BootOk flag in a FLASH data block located within the bootloader section (rather than EEPROM) for better integrity.

6. Start the Main Application
Jump to the main application code. The start address should align with the flash erase block size:

@ Call MainCodeStart

7. Set User Interrupt Vectors
Make sure the interrupt vectors in your application code are correctly aligned:

Org MainCodeStart + $8 
HIGH_INTERRUPT_VECTOR: 

Org MainCodeStart + $18 
LOW_INTERRUPT_VECTOR:

kcsl

trastikata, that's great information, thanks.
I need to have a proper read and a think now.

Regards,
Joe
There's no room for optimism in software or hardware engineering.