Bootloader
Overview
The purpose of DSerial bootloader is to:
- Boot DSerial firmware
- Return firmware version
- Upgrade firmware via SPI and other ports supported by the bootloader
The following sections will describe how the bootloader functions.
Interrupt Vector
Interrupt vector table on the C8051F320 is always at offset 0 in FLASH. Unfortunately, we cannot re-target it from bootloader interrupt vector table into the program interrupt vector table. Instead, we have to re-target each interrupt separately.
The following code shows how it's done in DSerial bootloader.
<cpp> void R_uartInterrupt() __interrupt (4) _naked { _asm mov a, _IrqVector ; compare IrqVector to 0 jnz 00001$ mov a, (_IrqVector+1) jz 00002$ 00001$: ; if not 0, then we need to jump to it mov dpl, _IrqVector mov dph, (_IrqVector+1) mov a, #0x23 ; this is the offset for uart irq jmp @a+dptr 00002$: ; if it's 0, then we'll handle the irq lcall _uartInterrupt ; call our own interrupt handler reti _endasm; }
// repeat for the other irqs </cpp>
IrqVector is a global variable that is set to the location of interrupt vector before enabling interrupts. The bootloader should set IrqVector to 0 while the program should set it to it's location.
<cpp> __data __at (0x7e) unsigned int IrqVector;
void main() { // ... IrqVector = 0x0800; EA = 1; // Global interrupt enable // ... } </cpp>