11.12.5 Example of Simple Bootloader Application

A simple bootloader might look like this:

#include <xc.h>
#include "bootloader.h"

volatile int safe_to_continue = 0;

void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void) { 
  safe_to_continue = 1;
  IFS0bits.T1IF = 0;
}

/*
* will be filled in by target application
*/
void (*volatile startup_location)(void)  __attribute__((section("startup"),shared));
main() {
  IPC0bits.T1IP = 6;
  IEC0bits.T1IE=1;
  PR1 = 1000;
  T1CONbits.TON = 1;
  while (safe_to_continue == 0);
  T1CONbits.TON = 0;

  // presumably we have no communications request, and can proceed
  if (startup_location) startup_location();
}

The variable startup_location is shared and defined in the bootloader. The end application may redefine the contents of the variable, but not the address. The target application will provide an over-ridden definition of this value to be the address of its startup location. For a C application, this will be the function _reset.

#include <xc.h>
#include <stdio.h>
#include "bootloader.h"

extern void _reset(void);

void (*volatile startup_location)(void)  __attribute__((section("startup"),shared)) = &_reset;

main() { 
  fprintf(stderr,"Hello world\n");
}

The rest of the bootloader application could be filled-in to accept some communication and re-program the target. When the whole system starts, the NULL initialization of startup_location may be over-written by the target application.