Difference between revisions of "Bootloader"

From NaWiki
Jump to: navigation, search
(Overview)
(Unlocking)
Line 18: Line 18:
  
  
DSerial needs to be unlocked before use. This is required because a program might try reading an SPI EEPROM:
+
DSerial needs to be unlocked before use. This is required because a program might try reading an SPI EEPROM.
  
 
# DS sends the bytes 0x44 0x53 0x65 0x72
 
# DS sends the bytes 0x44 0x53 0x65 0x72

Revision as of 23:37, 17 December 2006

Overview

DSerial Flash Memory Map

The purpose of DSerial bootloader is to:

The following sections will describe how the bootloader functions.

Unlocking

First check whether DSerial is inserted using a SPI EEPROM compatible command:

  1. DS sends the byte 0x9F (RDID)
  2. DSerial responds with 0xC0 0xFF 0xEE


DSerial needs to be unlocked before use. This is required because a program might try reading an SPI EEPROM.

  1. DS sends the bytes 0x44 0x53 0x65 0x72
  2. DSerial is now unlocked and in firmware mode

Interrupt Vector Table

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 with a magic register, since no such register exists in the architecture. Instead, we have to re-target each interrupt separately.

The following code shows how it's done in DSerial bootloader.

<cpp> // Code in bootloader

// Redirects UART IRQ either into our (bootloader's) handler or into firmware handler. 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 ; call the interrupt handler in firmware 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> // Code in firmware

__data __at (0x7e) unsigned int IrqVector;

void main() { // ... IrqVector = 0x0800; // we're relocated to 0x0800 EA = 1; // global interrupt enable // ... } </cpp>

Note: It would also be possible to use the User Bit in PSW register instead of IrqVector. It would be less flexible, but would result in a smaller overhead in redirection. Should be considered for future bootloader and firmware.