Difference between revisions of "Bootloader"

From NaWiki
Jump to: navigation, search
(Interrupt Vector Table)
(Overview)
Line 9: Line 9:
  
 
The following sections will describe how the bootloader functions.
 
The following sections will describe how the bootloader functions.
 +
 +
== Unlocking ==
 +
 +
First check whether DSerial is inserted using a [http://www.st.com/stonline/books/pdf/docs/10823.pdf SPI EEPROM] compatible command:
 +
 +
# DS sends the byte 0x9F (RDID)
 +
# 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:
 +
 +
# DS sends the bytes 0x44 0x53 0x65 0x72
 +
# DSerial is now unlocked and in [[firmware]] mode
  
 
== Interrupt Vector Table ==
 
== Interrupt Vector Table ==

Revision as of 00:37, 18 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.