Derjenige, dem es weniger auf die
Details ankommt, sondern der den Bootloader einfach nur anwenden
möchte, der schaue
bitte auf diese Seite.
Bootloader
-
Allgemeines
Ein
fertiger Bootloader
Grundlagen
Limits
USB-Bootloader
von Microchip
Anpassen
des USB-Bootloaders an eigene Bedürfnisse
ProjektpfadeLinker Script für die Anwendersoftware
Anpassen der Konfiguration
Der Bootloader-Schalter
LEDs
Bus Powered
Taktquelle
Konfiguration-Taktquelle
C18-Einstellungen
Schrumpfkur
Diese Software nennt man den Bootloader. Sie muss vorab auf konventionellem Wege in den PIC gebrannt werden, also in einem Brenner.
Der Bootloader wird aber nur ein Mal in den PIC gebrannt, danach steht er für viele USB-Brennvorgänge zur Verfügung. Das bringt deutliche Vorteile, wenn die Software in einem PIC häufig modifiziert werden muss, insbesondere dann, wenn der Nutzer des PIC-gesteuerten Gerätes gar keinen eigenen Brenner besitzt. Man könnte damit also Firmwareupdates mit Hilfe eines einfachen PCs durchführen.
Das ist ein USB-Bootloader, der
auf dem
Bootloader von Miocrochip basiert. Er ist in C geschrieben, und kann
mit
der Student-Edition des C18-Compilers compiliert werden, nachdem die
Projekt-Pfade
an den eigenen PC angepasst wurden. Er passt in den Bootblock des
PIC18F2550.
Der PIC arbeitet mit einem 8
MHz-Quarz
oder einem 8 MHz Keramikresonator. Mit Hilfe des Windowsprogramms USBoot kann dann eine beliebige Software via USB in den PIC gebrannt werden, deren Startadresse 0x800 sein muss (siehe unten). Da ich meine eigene VID_PID verwende, kann das PICDEM FS USB Demo Tool nicht anstelle von USBooot verwendet werden. |
Vor der Benutzung des
Bootloaders muss
der USB-Treiber (von Microchip) installiert werden. Er liegt im
Zip-File
von USBoot. Dieser Treiber enthält eine Anpassung an meine
VID_PID, er sollte also auch installiert werden, falls der
Microchip-USB-Treiber bereits einmal (z.B. für ein PICDEM
FS USB DEMONSTRATION BOARD) installiert wurde. Nach dem Anstecken des USB-Gerätes mit dem Bootloader und gestecktem Jumper JP1, fordert Windows zur Installation auf. (Der Jumper muss während des Ansteckens gesteckt sein. Ein nachträgliches Jumpersetzen funktioniert nicht!) Die Testplatine findet man jetzt im Gerätemanager als sprut-device (eventuell auch als Brenner8, falls der Treiber schon installiert war.) Im Gerätemanager muss man unter Eigenschafen unbedingt Windows verbieten, das Gerät zum Energiesparen abzuschalten. Andernfalls wird das Brennen mit dem Bootloader extrem langsam. Danach kann USBoot aufgerufen werden. Findet es den Bootloader am USB-Bus, dann kann mit dem Button 1 (Upload new Firmware) ein HEX-File ausgewählt und in den PIC geladen werden. Der Jumper ist zu entfernen, und der Button 2 (Reset) zu drücken. Die in den PIC geladene Software startet. USBoot beschreibt nur den Flash-Speicher ab der Adresse 0x800. Der Boot-Block (mit dem Bootloader), der EEPROM und die Config werden nicht verändert. |
Damit man auch etwas hat, das man mit dem Bootloader laden kann, hier eine abgewandelte Version des einfachen LED-Blinkprogramms. Es schaltet abwechselnd die Pins RB0 und RB7 ein und aus. Zwei dort angeschlossenen LEDs blinken abwechselnd mit ca. 0,6 Hz.
Nicht jeder wird den Jumper an RE3 (MCLR/Vpp) und die LED an RB7 anschließen wollen. Vielleicht will man auch einen anderen Quarz/Resonator einsetzen. Wie man den Bootloader an die eigenen Bedürfnisse anpasst, das kann man im Folgenden erfahren.
Der Bootloader muss sich mit dem
in
den PIC zu brennenden Anwendungsprogramm gut vertragen. Darum sollte
der
Bootloader in einem Flash-Speicherbereich stehen, der vom
Anwendungsprogramm
nicht verwendet wird.
Beim PIC18F2550 ist dafür der
Boot-Block
vorgesehen. Er ist 1024 Worte groß, und liegt am Anfang des
Flash-Speichers
(0x0000 ... 0x07FF). Ist der Bootloader in diesen Bereich gebrannt,
dann
lässt sich dieser Bootblock mit einem Schreibschutz versehen.
Dadurch ist er davor geschützt, durch versehentliche falsche
Schreibzugriffe
beschädigt zu werden. Da der Bootloader immer wieder eingesetzt
werden
soll, darf er sich nicht versehentlich selbst überschreiben.
Im Bootblock liegt aber auch der Resetvektor (bei dem der PIC mit der Abarbeitung des Programms beginnt) und die beiden Interruptvektoren. Der Bootloader muss deshalb diese Vektoren "umbiegen".
Das Anwendungsprogramm, das vom
Bootloader
geladen wird, darf natürlich den Speicherbereich des
Flash-Bootloaders
nicht verwenden. Ein solches Programm beginnt also
nicht
an der Adresse 0x0000 sondern an 0x0800 (direkt hinter dem
Bootblock).
Die Interruptroutinen müssen über die "umgebogenen" Vektoren
verwaltet werden. Folglich muss ein Programm, das vom Bootloader
geladen
werden soll, speziell angepasst werden.
Beim Reset des PIC muss zunächst der Bootloader gestartet werden. (Dafür steht an der Adresse0x0000 des Flash ein Sprung zum Bootloader.) Er überprüft, ob eine neue Software in den PIC gebrannt werden soll. Dazu ist z.B. ein an einem Pin angeschlossener Schalter bzw. Jumper abzufragen.
Wenn es nichts zu brennen gibt, muss der Bootloader das Anwendungsprogramm starten, das sich z.Z. neben dem Bootloader im Flash befindet. Dieses Programm muss den PIC so vorfinden, als wäre der Bootloader nach dem Reset nie gelaufen. Der Bootloader muss also alle relevanten Veränderungen, die er in den PIC-Registern vorgenommen hat wieder rückgängig machen, bevor er das Nutzprogramm startet.
Er kann auch die Konfiguration
verändern.
Hierbei ist aber Vorsicht geboten. Einige Konfigurationseinstellungen
sind
für die Funktion des USB-Interfaces von Bedeutung. Werden diese
vom
Bootloader verändert, dann kann der Bootloader von da an nicht
mehr
funktionieren. Das betrifft z.B. die Taktgeneratoreinstellung des PIC
Er ist aber auf das PICDEM FS USB
DEMONSTRATION
BOARD von Microchip zugeschnitten. Diese Experimentierplatine ist
mit
einem PIC18F4550 bestückt.
Der Bootloader startet beim Anlegen der
Betriebsspannung (oder Reset) und Testet einen Schalter ab, der am Pin
RB4 entweder 0V oder 5V anlegt. Bei 5V wird das Nutzprogramm gestartet,
bei 0V startet der Bootloader. Während der Arbeit zeigt der
Bootloader
seinen Status mit vier LEDs an, die an die Pins RD0..RD3 angeschlossen
sind.
Für Anwendungen außerhalb des PICDEM FS USB DEMONSTRATION BOARD muss der Bootloader aus folgenden Gründen modifiziert werden:
Die freie Student-Edition des C18-Compilers
hat aber leider nicht alle diese Optimierung. Folglich erzeugt sie
einen Code, der
für den Boot Block etwas zu groß ist.
Entfernt man aus dem
Bootloader-Code aber alles Überflüssige (insbesondere die
Spielerei mit dem LEDs), dann erzeugt auch die Student-Edition des C18
einen Code, der in den Boot-Block passt.
Im Verzeichnis C:\MCHPFSUSB\fw\Boot\ befindet sich das
Projektfile MCHPUSB.mcp, das
man mit MPLAB öffnen kann. Es enthält Pfadeinstellungen, die
sich auf die Standardinstallationspfade von MPLAB und C18 (c:\mcc18\)
beziehen. Hat man C18 in einem anderen als dem Standardverzeichnis
installiert, dann ist in MPLAB unter "Project
-
Build
options
- Project" das Build-Options-Fenster
zu
öffnen,
und
dort unter Directories
der Library search path
anzupassen.
Ein Klick auf Make ergibt nun
noch Fehlermeldungen, da die Konfiguration nicht richtig eingestellt
ist.
Außerdem weist MPLAB eventuell noch daraufhin, dass Compiler
und Linker nicht dort liegen, wo sie beim letzten Compilieren (also auf
dem Computer auf dem bei Microchip das Projekt erstellt wurde) lagen.
Mann wählt in den dabei erscheinenden Dialogboxen den aktuellen
Pfad zu Compiler und Linker aus. MPLAB merkt sich das dann.
Frühere Versionen des USB-Framework enthielten gar keine
Konfiguration. Nun ist sie im Projekt enthalten. Allerdings passt sie
nicht perfekt auf alle USB-PICs. Um den PIC18F4550 oder PIC18F2550
nutzen zu können sind ein paar Konfigurationsoptionen in der Datei
main.c durch Vorstellen eines
"//" auszukommentieren (FCMEN, BORV) bzw. zu ändern (PWRT,
BOR,
MCLRE, WRTB)
C:\MCHPFSUSB\fw\Boot\main.c
... //#pragma config FCMEN = OFF ... #pragma config PWRT = ON #pragma config BOR = OFF //#pragma config BORV = 3 ... #pragma config MCLRE = OFF //MCLR Disabled RE3 enabled ... #pragma config WRTB = OFF // Boot Block Write Protection ... |
Ein Klick auf Make sollte
nun zu einer fehlerfreien Kompilierung führen. Das
entstehende HEX-File entspricht aber noch nicht unseren Ansprüchen
(ist auf das Demo-Board zugeschnitten). Außerdem ist es so
groß, das es gar nicht in den Bootsektor eines PIC passt (mit der
Student-Edition des C18 compiliert).
Ein Klick auf View -
Program-Memory zeigt, dass der Bootloader momentan
noch bis zur Adresse 0x878 geht, dabei ist 0x7FE das Limit für den
Bootsektor.
Ein Schalter entscheidet beim Start des PIC, ob der Bootloader ausgeführt wird, oder ob zum Hauptprogramm gegangen wird. Die Abfrage des Schalters am Pin RB4 erfolgt in der Datei main.c in der procedur main, und sieht wie folgt aus:
C:\MCHPFSUSB\fw\Boot\main.c (original)
... temp = ADCON1; ADCON1 |= 0x0F; //TRISBbits.TRISB4 = 1; // Reset value is already '1' //Check Bootload Mode Entry Condition if(PORTBbits.RB4 == 1) // If not pressed, User Mode { ADCON1 = temp; // Restore reset value _asm goto RM_RESET_VECTOR _endasm }//end if //Bootload Mode ... |
Ich verwende aber einen Schalter am Pin RE3/MCLR. Deshalb muss diese
Abfrage im Programm angepasst werden.
In der Zeile "if (PORTBbits.RB4 ==
1)"
kann PORTBbits.RB4 durch die Beschreibung jedes anderen Pins
ersetzt
werden. Ist der Schalter an Pin RE3 angeschlossen, so lautet die Zeile
"if (PORTEbits.RE3 == 1)" .
Weiter oben wurde in der Konfiguration bereits das MCLR-Pin zum RE3-Pin
gemacht (#pragma config MCLRE = OFF).
C:\MCHPFSUSB\fw\Boot\main.c (angepasst)
... temp = ADCON1; ADCON1 |= 0x0F; //TRISBbits.TRISB4 = 1; // Reset value is already '1' //Check Bootload Mode Entry Condition // if(PORTBbits.RB4 == 1) // If not pressed, User Mode if(PORTEbits.RE3 == 1) // If not pressed, User Mode { ADCON1 = temp; // Restore reset value _asm goto RM_RESET_VECTOR _endasm }//end if //Bootload Mode ... |
Die Pins, an denen die LEDs
angeschlossen
sind, sind in der Datei io_cfg.h festgelegt.
Im Beispiel habe ich die Datei so
geändert,
dass anstelle der 4 LEDs an PortD nur 2 LEDs an den Pins RB0 und RC1
angeschlossen
sind.
C:\MCHPFSUSB\fw\Boot\io_cfg.h
... /** L E D ***********************************************************/ // LEDs hängen an RB0 (LED1 grün) und RC1 (LED2 gelb) #define mInitAllLEDs() LATB &= 0xFE; TRISB &= 0xFE; LATC &= 0xFD; TRISC &= 0xFD; #define
mLED_1
LATBbits.LATB0
#define
mLED_1_On()
mLED_1 = 1; #define
mLED_1_Off() mLED_1
= 0; #define mLED_1_Toggle() mLED_1 =
!mLED_1; |
C:\MCHPFSUSB\fw\Boot\boot.c
... case UPDATE_LED: if(dataPacket.led_num == 3) { // mLED_3 = dataPacket.led_status; mLED_1 = dataPacket.led_status; counter = 0x01; }//end if if(dataPacket.led_num == 4) { // mLED_4 = dataPacket.led_status; mLED_2 = dataPacket.led_status; counter = 0x01; }//end if break; ... |
Will man sein USB-Gerät nur aus
dem
USB-Bus mit Spannung versorgen lassen, müssen zwei Definitionen in
der Datei usbcfg.h entfernt werden. Der modifizierte Abschnitt
mit
den auskommentierten Definitionen USE_SELF_POWER_SENSE_IO
und
USE_USB_BUS_SENSE_IO ist nachfolgend zu sehen. In der
Version 1.3 des Framework ist das schon per Default so.
C:\MCHPFSUSB\fw\Boot\autofiles\usbcfg.h
... /* * Both I/O sense pins below are not used in this application. * This helps to decrease the size of the firmware code. */ //#define USE_SELF_POWER_SENSE_IO //#define USE_USB_BUS_SENSE_IO /** D E V I C E C L A S S U S A G E
*******************************/ |
Der PIC mit dem Bootloader kann sowohl mit einem Keramikresonator wie auch mit einem Quarz betrieben werden. Wird ein Quarz verwendet, dann sind auch die beiden Lastkondensatoren für den Quarz (C2 & C3) einzusetzen. Wird dagegen ein Keramikresonator eingesetzt, dann entfallen die beiden Kondensatoren.
Als Frequenz für den Resonator/Quarz ist im Beispiel-Bootloader 8 MHz vorgesehen. Der Einsatz anderer Typen ist möglich, wenn folgendes beachtet wird:
Standardmäßig wird die Quarzfrequenz im PIC zunächst mit einem 2:1 Frequenzteiler auf 4 MHz heruntergeteilt. Aus diesen 4 MHz werden anschließend mit einer PLL 96 MHz erzeugt. Diese wiederum dient als Basis für den USB-Takt (2:1 Teilung) und den PIC-Takt (ebenfalls 2:1 Teilung). Die Grafik veranschaulicht das. Dort, wo ich blaue Pfeile verwendet habe, muss die jeweils angegebene Frequenz eingehalten werden.
Die 4 MHz für die PLL lassen sich natürlich nicht nur aus 8 MHz erzeugen. Da der PLL-Vorteiler neben dem Teilverhältnis 2:1 auch die Teilverhältnisse 12:1, 10:1, 6:1, 5:1, 4:1, 3:1 und 1:1 beherrscht, kommen auch Resonatoren/Quarze mit 48 MHz, 40 MHz, 24 MHz, 20 MHz, 16 MHz, 12 MHz und 4 MHz in Frage. Man muss nur die Vorteilereinstellung ändern. Das erfolgt in der Konfigurationseinstellung. mit dem Parameter PLLDIV.
Auch der CPU-Takt ist variabel. Der
durch
CPUDIV
kontrollierte Teiler beherrscht die Teilerverhältnisse 2:1, 3:1,
4:1
und 6:1. Der CPU-Takt kann also durch Änderung von CPUDIV einfach
auf bis zu 16 MHz herabgesenkt werden. Auch lassen sich für die
CPU
andere Taktquellen verwenden (der Quarz ohne PLL oder der interne
Takt).
Die Details stehen im Handbuch des PIC18F2550.
Die Konfigurationseinstellungen stehen in der Datei main.c
ein. Damit werden sie
Bestandteil
des HEX-Files. Die originalen Einstellungen in main.c sind für den
Betrieb an einem 20 MHz-Quarz ausgelegt.(PLLDIV = 5)
Um den PIC mit einem 8 MHz-Quarz/Resonator zu betreiben muss PLLDIV
auf den Wert 2 geändert werden.
Die Beschreibung der möglichen Config-Einstellungen steht im Dokument PIC18-Config-Settings-Addendum_51537d.pdf, das zur Dokumentation von C18 gehört.
C:\MCHPFSUSB\fw\Boot\system\usb\class\boot\main.c
... //#pragma config PLLDIV = 5 // (20 MHz input) #pragma config PLLDIV = 2 // (8 MHz input) ... |
Damit der Bootloader in den Bootblock des PIC passt (0x0000 .. 0x0800), muss der C18-Compiler einen möglichst effektiven Code erzeugen. Die Optimierungsfunktion und der erweiterte Befehlssatz stehen in der Student-Edition des C18 leider nicht zu Verfügung. Es bleibt aber noch eines zu tun:
Man öffnet in MPLAB das Fenster
für
die Build Optionen des Projektes: Project - Build Options - Project
Dort wählt man die Karteikarte: MPLAB
C18
Den Parameter Default storage class
ändert man von Auto auf Static.
Das spart ein paar Byte Code ein, und
die können entscheidend sein.
In neueren Versionen des Framework ist diese Einstellung bereits
Standard.
Um auch mit der Student-Edition des C18 einen Bootloader zu erzeugen, der in den Boot-Block passt, muss der Code verkleinert werden. Alles Überflüssige muss über Bord. Am leichtesten verzichtet man auf die LED-Blinkerei. Deshalb wird in der Datei boot.c ausgemistet.
Zuerst wird am Ende der Datei die ganze BlinkUSBStatus-Funktion entfernt. Dazu muss dann auch der Eintrag von BlinkUSBStatus in PRIVATE PROTOTYPES entfernt werden, wie auch der Aufruf von BlinkUSBStatus in BootService.
C:\MCHPFSUSB\fw\Boot\system\usb\class\boot\boot.c
... /** P R I V A T E P R O T O T Y P E S ***************************************/ // DIE FOLGENDE ZEILE MUSS WEG //void BlinkUSBStatus(void); ... ... ... void BootService(void) { // DIE FOLGENDE ZEILE MUSS WEG // BlinkUSBStatus(); if((usb_device_state < CONFIGURED_STATE)||(UCONbits.SUSPND==1)) return; ... |
So, das sollte fast schon reichen. Der
Bootloader benimmt sich noch genau wie der originale Booloader, und mit
Hilfe des PICDEM FS USB Demo Tool von Microchip kann man nun
hex-Files
via Bootloader in den PIC18F2550 laden.
C:\MCHPFSUSB\fw\Boot\system\usb\class\boot\boot.c
... switch(dataPacket.CMD) { ... ... ... break; /* case UPDATE_LED: if(dataPacket.led_num == 3) { mLED_1 = dataPacket.led_status; counter = 0x01; }//end if if(dataPacket.led_num == 4) { mLED_2 = dataPacket.led_status; counter = 0x01; }//end if break; */ default: ... |
was aber zu einer Incompatibilität mit zukünftigen Versionen des PICDEM FS USB Demo Tool führen könnte. Sicherer ist eine Verkürzung des UPDATE_LED-Teils:
C:\MCHPFSUSB\fw\Boot\system\usb\class\boot\boot.c
... switch(dataPacket.CMD) { ... ... ... break;
case
UPDATE_LED:
default:
|
Linker Script für die Anwendersoftware
Programme, die mit dem Bootloader in
den
PIC gebrannt werden sollen, müssen dafürt etwas angepasst
werden.
Ein angepasstes Linker Script für
den C18-Compiler (eigentlich für den Linker) sorgt dafür, das
der Code eines Anwenderprogrammes erst ab 0x0800 beginnt.
Wer Interrupts benutzen will, der
muss
beachten, dass die Interruptvektoren verbogen sind, der immer
notwendige
Reset-Vektor ist auch verbogen
...
/** V E C T O R R E M A P P I N G *******************************************/ extern void _startup
(void);
// See c018i.c in your C18 compiler dir #pragma code _HIGH_INTERRUPT_VECTOR = 0x000808 #pragma code _LOW_INTERRUPT_VECTOR = 0x000818 ... |
Der Bootloader ist nun
funktionstüchtig. Beim Anschluss an einen PC meldet sich ein
mit dem Bootloader ausgestattetes Device mit derVendor-ID
VID=0x04D8 (Hersteller: Microchip) und der Product-ID
PID0x000B (Microchip-Bootloader im PICDEM FS USB-Board) am USB-Bus an.
Dadurch weiss Windows, welchen treiber es laden muss, und PICDEM FS
USB Demo Tool das akzeptiert es als Bootloader.
...
/* Device Descriptor */rom USB_DEV_DSC device_dsc= { sizeof(USB_DEV_DSC), // Size of this descriptor in bytes DSC_DEV, // DEVICE descriptor type 0x0200, // USB Spec Release Number in BCD format 0x00, // Class Code 0x00, // Subclass code 0x00, // Protocol code EP0_BUFF_SIZE, // Max packet size for EP0, see usbcfg.h 0x04D8, // Vendor ID // 0x000b, // Product ID: PICDEM FS USB (Boot Mode) 0xFF0B, // Product ID: Sprut 0x0000, // Device release number in BCD format 0x00, // Manufacturer string index 0x00, // Product string index 0x00, // Device serial number string index 0x01 // Number of possible configurations }; ... |