C Grundlagen Bootloader

Janiiix3

Aktives Mitglied
28. Sep. 2013
1.333
10
38
Hannover
Sprachen
  1. ANSI C
  2. C#
Nabend,

möchte mich jetzt endlich mal an einen Bootloader ran wagen.
Habe mir gestern folgenden Artikel durchgelesen..
https://www.mikrocontroller.net/art...tt_1_-_Konfiguration_der_Projekteinstellungen
https://www.mikrocontroller.net/art...tt_1_-_Konfiguration_der_Projekteinstellungen
Dort wird noch alles mit dem alten AVR Studio erklärt.
Ich möchte jetzt gerne mit dem neueren AVR Studio (7.0) los legen.

Um den Bootloader in den richtigen Bereich zu schreiben, muss es in dem Projekt ja hinterlegt werden.
Wo genau muss ich das machen? Stimmen die Parameter aus dem Artikel noch überein (.Ttext=xxxx)?

Wie berechne ich jetzt die Bootloader Adresse von einem MEGA32?
 
Um den Bootloader in den richtigen Bereich zu schreiben, muss es in dem Projekt ja hinterlegt werden.
Wo genau muss ich das machen?
Der Mega32 unterstützt die Implementierung eines Bootlaoders, welcher dann am Ende des Flash lokalisiert sein muß. Wie groß der Bereich m Ende ist, kannst Du mithilfe entsprechender Fusebits festlegen (und damit auch die Adresse, ab der Du den Loader programmieren mußt.
Siehe auch Datenblatt (Q-Version) ab Seite 244...
 
Der Mega32 unterstützt die Implementierung eines Bootlaoders, welcher dann am Ende des Flash lokalisiert sein muß. Wie groß der Bereich m Ende ist, kannst Du mithilfe entsprechender Fusebits festlegen (und damit auch die Adresse, ab der Du den Loader programmieren mußt.

Ja genau.

Hier die möglichen Startadressen.
Um den Bootloader in den richtigen Bereich zu schreiben, muss es in dem Projekt ja hinterlegt werden.
Wo genau muss ich das machen? Stimmen die Parameter aus dem Artikel noch überein (.Ttext=xxxx)?

Wie berechne ich jetzt die Bootloader Adresse von einem MEGA32?
Die Quelle habe ich mir nicht durchgelesen.

Project Properties -> Toolchain -> AVR/GNU Linker -> Memory Settings -> Flash Segment.

Dort mit Add Item zum Beispiel .text=0x3800 eintragen.

Code:
ATmega32

Fusebits            size          start address
BOOTSZ[1..0] = 00   2048 words    .text=0x3800
BOOTSZ[1..0] = 01   1024 words    .text=0x3C00
BOOTSZ[1..0] = 10    512 words    .text=0x3E00
BOOTSZ[1..0] = 11    256 words    .text=0x3F00
 
So, Urlaub vorbei. Jetzt geht es wieder los ;)
Also.. Bis jetzt habe ich bei dem Bootloader nicht weiter gemacht.
Habe hier mir das Tutorial mal ein wenig unter die Lupe genommen https://www.mikrocontroller.net/articles/AVR_Bootloader_in_C_-_eine_einfache_Anleitung ..

Diesen konnte ich bereits auch auf den µC flashen (MEGA32).. Er meldet sich auch. Schiebe ich die .hex rüber, bekomme ich auch die Antwort wie beschrieben.
Nur, startet wieder der Bootloader anstatt meine Applikation die ich geschrieben habe. Diese sollte einfach nur mal eine LED ein und aus schalten.

Ich bin mir überhaupt nicht sicher ob ich alles richtig eingstellt habe..

upload_2017-9-9_9-14-33.png

Hier habe ich die Adresse eingestellt wo der Bootloader seinen Platz finden soll.
 

Anhänge

  • upload_2017-9-9_9-8-17.png
    upload_2017-9-9_9-8-17.png
    109 KB · Aufrufe: 4
Nur, startet wieder der Bootloader anstatt meine Applikation die ich geschrieben habe.
Hast du die Fusebits programmiert?

Ich müsste nun in die Bootloadersoftware reinschauen, um mehr sagen zu können, nur mir fehlt die Zeit.

Wenn ich einen Bootloader programmiere, lasse ich den Bootloader immer beim Start prüfen, ob eine Applikation vorhanden ist. Eventuell macht dein Bootloader dies ja auch so und startet die Applikation nicht, weil diese eventuell nicht programmiert wurde.

Dirk :ciao:
 
Bootloader klappt jetzt!
Kann man eigentlich von der eigentlichen Applikaton wieder zum Bootloader? Geht das irgendwie?
Habe gelesen das man das wohl irgendwie mit einer Art Funktionspointer machen kann? So zu sagen einen Sprung..



CodeBox C
void (*Bootloader)(void) =  0xxxxx

Klappt das irgendwie?
 
Kann man eigentlich von der eigentlichen Applikaton wieder zum Bootloader? Geht das irgendwie?
Habe gelesen das man das wohl irgendwie mit einer Art Funktionspointer machen kann? So zu sagen einen Sprung..
void (*Bootloader)(void) = 0xxxxx
Klappt das irgendwie?

Ja, so in etwa. Hier habe ich einige Beispiele (weiter unten in Code Boxen) ...
 


CodeBox C
// the pointer to bootloader
void (*boot_start)(void) = 0x1F800;  // word

So habe ich das auch gemacht. Nur mit einer anderen Adresse. Wenn ich das so Compiliere, meckert er das er das noch casten muss..?
 
Bei mir meckert der Compiler nicht (ich hatte es damals denke mit AtmelStudio 5 entwickelt und jetzt auch noch mal mit AS7.0 kompiliert).

Eventuell liegt es an einer anderen Stelle in deinem Programm oder an einer anderen Einstellung bei der Toolchain.
 
Hier..
upload_2017-9-12_17-0-34.png
 
Ja, du hast diese Zeile auch innerhalb einer Routine oder Funktion.

Du definierst ja auch keine Funktion innerhalb einer Funktion.

Schau dir meine Beispiele an.

Dirk :ciao:
 
Wenn ich es mit "0x0000" mache, klappt es!
Auch wenn ich es außerhalb der main() deklariere (also über der main), funktioniert das nicht..
Habe mir ja deine Beispiele angeschaut.
 
Auch wenn ich es außerhalb der main() deklariere (also über der main), funktioniert das nicht..
Habe mir ja deine Beispiele angeschaut.

Was genau funktioniert dann nicht?

Fehlermeldung/Warnung
oder
Bootloader starten geht nicht?
 
Genau das gleiche wie in Post #10.
Genau und ich kann dann nicht zum bootloader springen, erst ein reset bewirkt das der bootloader wieder angesprungen wird.
 
Genau das gleiche wie in Post #10.

Also die Warnung sollte nicht vorhanden sein.

... und wenn du es über main definierst, wie springst du den Bootloader an?

ggf. poste man dein Programm (main.c)
 


CodeBox C
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/boot.h>

#include "uart.h"
#include "hard_def.h"

#ifndef F_CPU
#define F_CPU 16e6
#endif

#include <util/delay.h>

#define BOOT_UART_BAUD_RATE     19200     /* Baudrate */
#define XON                     17       /* XON Zeichen */
#define XOFF                    19       /* XOFF Zeichen */
#define START_SIGN              ':'      /* Hex-Datei Zeilenstartzeichen */

/* Zustände des Bootloader-Programms */
#define BOOT_STATE_EXIT           0
#define BOOT_STATE_PARSER       1

/* Zustände des Hex-File-Parsers */
#define PARSER_STATE_START      0
#define PARSER_STATE_SIZE       1
#define PARSER_STATE_ADDRESS    2
#define PARSER_STATE_TYPE       3
#define PARSER_STATE_DATA       4
#define PARSER_STATE_CHECKSUM   5
#define PARSER_STATE_ERROR      6

void program_page (uint32_t page, uint8_t *buf)
{
   uint16_t i;
   uint8_t sreg;
   
   /* Disable interrupts */
   sreg = SREG;
   cli();
   
   eeprom_busy_wait ();
   
   boot_page_erase (page);
   boot_spm_busy_wait ();      /* Wait until the memory is erased. */
   
   for (i=0; i<SPM_PAGESIZE; i+=2)
   {
       /* Set up little-endian word. */
       uint16_t w = *buf++;
       w += (*buf++) << 8;
       
       boot_page_fill (page + i, w);
   }
   
   boot_page_write (page);     /* Store buffer in flash page.       */
   boot_spm_busy_wait();       /* Wait until the memory is written.*/
   
   /* Reenable RWW-section again. We need this if we want to jump back */
   /* to the application after bootloading. */
   boot_rww_enable ();
   
   /* Re-enable interrupts (if they were ever enabled). */
   SREG = sreg;
}

static uint16_t hex2num (const uint8_t * ascii, uint8_t num)
{
   uint8_t  i;
   uint16_t val = 0;
   
   for (i=0; i<num; i++)
   {
       uint8_t c = ascii[i];
       
       /* Hex-Ziffer auf ihren Wert abbilden */
       if (c >= '0' && c <= '9')            c -= '0';
       else if (c >= 'A' && c <= 'F')       c -= 'A' - 10;
       else if (c >= 'a' && c <= 'f')       c -= 'a' - 10;
       
       val = 16 * val + c;
   }
   
   return val;
}

void write_page(uint32_t page, uint8_t *buf)
{
   uart_puts("P\n\r");
   _delay_ms(100);
   program_page(page, buf);
   memset(buf, 0xFF, sizeof(SPM_PAGESIZE));
}

void (*test)(void) = 0x0100;

int main()
{   
   /* Intel-HEX Zieladresse */
   uint32_t        hex_addr = 0,
   /* Intel-HEX Zieladress-Offset */
   hex_addr_offset = 0,
   /* Zu schreibende Flash-Page */
   flash_page = 0;
   /* Empfangenes Zeichen + Statuscode */
   uint16_t        c = 0,
   /* Intel-HEX Checksumme zum Überprüfen des Daten */
   hex_check = 0,
   /* Positions zum Schreiben in der Datenpuffer */
   flash_cnt = 0;
   /* temporäre Variable */
   uint8_t         temp,
   /* Flag zum steuern des Programmiermodus */
   boot_state = BOOT_STATE_EXIT,
   /* Empfangszustandssteuerung */
   parser_state = PARSER_STATE_START,
   /* Flag zum ermitteln einer neuen Flash-Page */
   flash_page_flag = 1,
   /* Datenpuffer für die Hexdaten*/
   flash_data[SPM_PAGESIZE],
   /* Position zum Schreiben in den HEX-Puffer */
   hex_cnt = 0,
   /* Puffer für die Umwandlung der ASCII in Binärdaten */
   hex_buffer[5],
   /* Intel-HEX Datenlänge */
   hex_size = 0,
   /* Zähler für die empfangenen HEX-Daten einer Zeile */
   hex_data_cnt = 0,
   /* Intel-HEX Recordtype */
   hex_type = 0,
   /* empfangene HEX-Checksumme */
   hex_checksum=0;
   /* Funktionspointer auf 0x0000 */
   void            (*start)( void ) = 0x0000;
   
   /* Füllen der Puffer mit definierten Werten */
   memset(hex_buffer, 0x00, sizeof(hex_buffer));
   memset(flash_data, 0xFF, sizeof(flash_data));
   
   /* Interrupt Vektoren verbiegen */
   temp = GICR;
   GICR = temp | (1<<IVCE);
   GICR = temp | (1<<IVSEL);
   
   /* Einstellen der Baudrate und aktivieren der Interrupts */
   uart_init( UART_BAUD_SELECT(BOOT_UART_BAUD_RATE,F_CPU) );
   sei();
   
   uart_puts("***********************\n\r"    );
   uart_puts("* J.H Elec-Booty\n\r"        );
   uart_puts("* press \"p\" for prog.\n\r"    );

   _delay_ms(500);       
   
   do
   {
       c = uart_getc();
       if( !(c & UART_NO_DATA) )
       {
           /* Programmzustand: Parser */
           if(boot_state == BOOT_STATE_PARSER)
           {
               switch(parser_state)
               {
                   /* Warte auf Zeilen-Startzeichen */
                   case PARSER_STATE_START:
                   if((uint8_t)c == START_SIGN)
                   {
                       uart_putc(XOFF);
                       parser_state = PARSER_STATE_SIZE;
                       hex_cnt = 0;
                       hex_check = 0;
                       uart_putc(XON);
                   }
                   break;
                   /* Parse Datengröße */
                   case PARSER_STATE_SIZE:
                   hex_buffer[hex_cnt++] = (uint8_t)c;
                   if(hex_cnt == 2)
                   {
                       uart_putc(XOFF);
                       parser_state = PARSER_STATE_ADDRESS;
                       hex_cnt = 0;
                       hex_size = (uint8_t)hex2num(hex_buffer, 2);
                       hex_check += hex_size;
                       uart_putc(XON);
                   }
                   break;
                   /* Parse Zieladresse */
                   case PARSER_STATE_ADDRESS:
                   hex_buffer[hex_cnt++] = (uint8_t)c;
                   if(hex_cnt == 4)
                   {
                       uart_putc(XOFF);
                       parser_state = PARSER_STATE_TYPE;
                       hex_cnt = 0;
                       hex_addr = hex_addr_offset;
                       hex_addr += hex2num(hex_buffer, 4);
                       hex_check += (uint8_t) hex_addr;
                       hex_check += (uint8_t) (hex_addr >> 8);
                       
                       uart_putc(XON);
                   }
                   break;
                   /* Parse Zeilentyp */
                   case PARSER_STATE_TYPE:
                   hex_buffer[hex_cnt++] = (uint8_t)c;
                   if(hex_cnt == 2)
                   {
                       uart_putc(XOFF);
                       hex_cnt = 0;
                       hex_data_cnt = 0;
                       hex_type = (uint8_t)hex2num(hex_buffer, 2);
                       hex_check += hex_type;
                       switch(hex_type)
                       {
                           case 1: parser_state = PARSER_STATE_CHECKSUM; break;
                           case 0:
                           case 2:
                           case 4: parser_state = PARSER_STATE_DATA;
                           
                           /* Berechnen der neue Flash-Page (abhängig von hex_type) */
                           /* Liegen die Daten noch in der aktuellen Flash-Page? */
                           if(!flash_page_flag && (flash_page != (hex_addr - hex_addr % SPM_PAGESIZE)) )
                           {
                               /* Wenn die Daten nicht in der aktuellen Flash-Page liegen, */
                               /* wird die aktuelle Page geschrieben und ein Flag          */
                               /* zum berechnen der neuen Page-Startadresse gesetzt        */
                               write_page(flash_page, flash_data);
                               flash_cnt = 0;
                               flash_page_flag = 1;
                           }
                           
                           /* Muss die Page-Startadresse neu berechnet werden? */
                           if(flash_page_flag)
                           {
                               /* Berechnen der neuen Page-Startadresse */
                               flash_page = hex_addr - hex_addr % SPM_PAGESIZE;
                               
                               /* Füllen des Flash-Puffers mit dem "alten" Inhalt der Page */
                               memcpy_PF(flash_data, flash_page, SPM_PAGESIZE);
                               
                               /* Flag setzen um anzuzeigen das eine neue Adresse da ist */
                               flash_page_flag = 0;
                           }
                           break;
                           default: parser_state = PARSER_STATE_DATA; break;
                       }
                       uart_putc(XON);
                   }
                   break;
                   /* Parse Flash-Daten */
                   case PARSER_STATE_DATA:
                   hex_buffer[hex_cnt++] = (uint8_t)c;
                   switch(hex_type)
                   {
                       case 0:  /* Record Typ 00 - Data Record auswerten */
                       if(hex_cnt == 2)
                       {
                           uart_putc(XOFF);
                           uart_putc(c);
                           hex_cnt = 0;
                           flash_data[flash_cnt] = (uint8_t)hex2num(hex_buffer, 2);
                           hex_check += flash_data[flash_cnt];
                           flash_cnt++;
                           hex_data_cnt++;
                           if(hex_data_cnt == hex_size)
                           {
                               parser_state = PARSER_STATE_CHECKSUM;
                               hex_data_cnt=0;
                               hex_cnt = 0;
                           }
                           /* Puffer voll -> schreibe Page */
                           if(flash_cnt == SPM_PAGESIZE)
                           {
                               write_page(flash_page, flash_data);
                               flash_cnt = 0;
                               flash_page_flag = 1;
                           }
                           uart_putc(XON);
                       }
                       break;
                       case 2:   /* Record Typ 02 - Extended Segment Address auswerten */
                       case 4:   /* Record Typ 04 - Extended Linear Address auswerten */
                       if(hex_cnt == 4)
                       {
                           uart_putc(XOFF);
                           uart_putc('J');
                           hex_cnt = 0;
                           
                           /* Schreibe angfangene Flash-Page vor Segment-Sprung */
                           write_page(flash_page, flash_data);
                           flash_cnt = 0;
                           flash_page_flag = 1;
                           
                           /* Berechnen der Offsetadresse */
                           switch(hex_type)
                           {
                               case 2: hex_addr_offset = ((uint32_t)hex2num(hex_buffer, 4)) << 4; break;
                               case 4: hex_addr_offset = ((uint32_t)hex2num(hex_buffer, 4)) << 16; break;
                           }
                           
                           /* Addieren der empfangenen Werte für die Checksumme */
                           hex_check += (uint8_t) hex2num(hex_buffer, 2);
                           hex_check += (uint8_t) hex2num(hex_buffer + 2, 2);
                           
                           parser_state = PARSER_STATE_CHECKSUM;
                           hex_data_cnt=0;
                           hex_cnt = 0;
                       }
                       break;
                       default:
                       break;
                   }
                   break;
                   /* Parse Checksumme */
                   case PARSER_STATE_CHECKSUM:
                   hex_buffer[hex_cnt++] = (uint8_t)c;
                   if(hex_cnt == 2)
                   {
                       uart_putc(XOFF);
                       hex_checksum = (uint8_t)hex2num(hex_buffer, 2);
                       hex_check += hex_checksum;
                       hex_check &= 0x00FF;
                       /* Dateiende -> schreibe Restdaten */
                       if(hex_type == 1)
                       {
                           write_page(flash_page, flash_data);
                           boot_state = BOOT_STATE_EXIT;
                       }
                       /* Überprüfe Checksumme -> muss '0' sein */
                       if(hex_check == 0) parser_state = PARSER_STATE_START;
                       else parser_state = PARSER_STATE_ERROR;
                       uart_putc(XON);
                   }
                   break;
                   /* Parserfehler (falsche Checksumme) */
                   case PARSER_STATE_ERROR:
                   uart_putc('#');
                   break;
                   default:
                   break;
               }
           }
           /* Programmzustand: UART Kommunikation */
           else if(boot_state != BOOT_STATE_PARSER)
           {
               switch((uint8_t)c)
               {
                   case 'p':
                   boot_state = BOOT_STATE_PARSER;
                   uart_puts("paste .hex here\n\r");
                   break;
                   case 'q':
                   boot_state = BOOT_STATE_EXIT;
                   uart_puts("leave Booty\n\r");
                   break;
                   default:
                   uart_putc((unsigned char)c);
                   uart_puts("\n\r");
                   break;
               }
           }
       }
   }
   while(boot_state!=BOOT_STATE_EXIT);
   
   uart_puts("*  ->Reset now!\n\r"                    );
       uart_puts("***********************\n\r"        );
   _delay_ms(500);
   
   /* Interrupt Vektoren wieder gerade biegen */
   temp = GICR;
   GICR = temp | (1<<IVCE);
   GICR = temp & ~(1<<IVSEL);
   
   /* Reset */
   start();
   
   return 0;
}


Das ist jetzt nur der Bootloader. Ich habe oben am Anfang einen Funktionspointer (test) deklariert. Diesen benutze ich nirgends! Trodzdem meckert der Compiler rum. Villeicht kann ich das Projekt mal hochladen und du Kompilierst es mal bei dir?
 
Der Bootloader bringt mir im Moment nichts.

Ich habe oben am Anfang einen Funktionspointer (test) deklariert. Diesen benutze ich nirgends! Trodzdem meckert der Compiler rum.

Du hast es immernoch innerhalb main() im Bootloader! Das ist ein Problem.

Villeicht kann ich das Projekt mal hochladen und du Kompilierst es mal bei dir?
Ja, probiere mal das Applikations-Projekt anzuhängen.
 
Du hast es immernoch innerhalb main() im Bootloader! Das ist ein Problem.

Ich habe doch geschrieben, dass ich außerhalb der main() einen neuen Funktionspointer erstellt habe um zu testen ob es wirklich das Problem ist. Siehe Zeile 96.
Wenn ich dort schon Fehlermeldungen bekomme, brauche ich das Projekt ja auch nicht anhängen. Da muss was faul sein.. Bei der Bootloader.c muss es ja schon klappen sonst brauche ich das Hauptprojekt nicht anhängen. Da ist genau der gleiche Fehler.
 
Ja, da wird was faul sein.

Was möchtest du denn in Zeile 135 machen bzw erreichen?

Ich schau später noch mal rein, bin mal jetzt offline.
 
Da mache ich einen "reset" das heißt ich springe damit an Adresse "0x0000" dort wird dann mein Programm ausgeführt. Klappt auch.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)