AVR Bootloader in C - Artikel

#1910724
Lesenswert?

Hallo Gemeinde,

ich habe einen Artikel (mein Erster!) über das Programmieren von 
Bootloader für den AVR in C geschrieben. Eigentlich sollte es nur eine 
Wissensammlung sein aber es ist jetzt mehr ein Tutorial geworden.

Es wäre schön, wenn die Gurus unter euch das mal drübergucken könnten 
und Feedback über grobe Fehler oder Anmerkungen geben könnten. Es wäre 
auch schön, wenn es jemand Ausprobieren würde. Idealerweise jemand der 
noch nicht viel mit Bootloadern gearbeitet hat.

Hier der Link zum Artikel:
AVR Bootloader in C - eine einfache Anleitung

Der Artikel ist fast fertig (es fehlen noch ein paar Bilder).

Gruß
Mario
#1911173
Lesenswert?

Turmel schrieb:
> Mario Grafe schrieb:
>> @Turmel:
>>
>> es sollte nicht so stocksteif rüberkommen. Ich fands lustig so.
>
> Dann frag halt nicht nach Kritik, wenn Du für Dich selbst schreibst.

Ich schreibe nicht (nur) für mich. Ich hoffe das auch einige andere 
etwas mit dem Artikel anfangen können. Die Kritik zum Schreibstil nehme 
ich gerne an, der nächste Artikel wird förmlicher. Aber den 
Bootloader-Artikel schreibe ich jetzt nicht nochmal komplett um 
deswegen. Das ist mir zuviel Aufwand. Wer damit nicht leben kann der 
soll ihn halt nicht lesen.

Es wäre gut wenn auch inhaltliche Kritik käme oder mal jemand den Code 
ausprobiert...
Gast #1911175
Lesenswert?

Mario Grafe schrieb:
> Turmel schrieb:
>> Mario Grafe schrieb:
>>> @Turmel:
>>>
>>> es sollte nicht so stocksteif rüberkommen. Ich fands lustig so.
>>
>> Dann frag halt nicht nach Kritik, wenn Du für Dich selbst schreibst.
>
> Ich schreibe nicht (nur) für mich. Ich hoffe das auch einige andere
> etwas mit dem Artikel anfangen können. Die Kritik zum Schreibstil nehme
> ich gerne an, der nächste Artikel wird förmlicher.

Das ist ein Irrtum. Es geht nicht um förmlich oder nicht förmlich. Ich 
habe das auch garnicht geschrieben. Wie kommst Du darauf? Ist das eine 
Verwechslung? Ich schrieb von schlechtem Deutsch. Man kann locker 
schreiben und trotzdem grammatisch korrekt.

> Es wäre gut wenn auch inhaltliche Kritik käme oder mal jemand den Code
> ausprobiert...
Ich lese das halt nicht wenn ich bei jedem dritten Wort stolpere. Tut 
mir leid.
Gast #1911178
Lesenswert?

Ich will ja nicht wirklich insistieren.
Aber das mir jemand unterstellt ich würde seinen lockeren Stil meinen, 
wenn ich von seinem Deutsch, also Grammatik und Diktion rede macht mir 
nicht gerade Mut mit ihm eine Diskussion über eines der beiden Themen 
"Stil" und "Grammatik" anzufangen.

Kleines Beispiel:
"Zu Beginn soll das notwendigste Wissen über den AVR-Bootloaderbereich 
vermittelt werden, um eine Arbeitsgrundlage zu schaffen."
Wieso das "notwendigste"? Warum die Steigerung ins Absolute? Das 
notwendige Wissen für eine Arbeitsgrundlage würde schon reichen.
Wozu diese Schwurbel-Substantiv "Bootloaderbereich"? Ist damit das Thema 
gemeint oder der Speicherbereich?

Also lassen wir das lieber.
Es gibt soviele Artikel im Web über Bootloader das ich auf den 
verzichten kann.
Gast #1911183
Lesenswert?

Turmel schrieb:
> Ich lese das halt nicht wenn ich bei jedem dritten Wort stolpere. Tut
> mir leid.

Rechts oberhalb eines jeden Abschnitts gibt es einen link "Bearbeiten". 
Den darfst du gerne für den letzten sprachlichen Feinschliff nutzen.
Auch konkrete Verbesserungsvorschläge helfen sicherlich weiter.
Also: Besser machen, oder Schnauze halten.

Ich finde den Beitrag klasse.

Oliver
Gast #1911212
Lesenswert?

Also ich habe den Artikel nur mal grob überflogen. Mein erster Eindruck:
aufwendig gestaltet (@Turmel: ich weiss, nach der ndR aufwändig) und gut 
lesbar.
Über die fachliche Solidität kann ich jetzt nichts sagen, aber ich würde 
ihn zumindest mal dankbar lesen wenn ich mich in das Thema einarbeiten 
wollte.
Von so einem Engagement lebt jedes Wiki.
Vieleicht sollte uns Turmel mal seine Artikel verlinken auf dass wir 
noch was lernen können. :-)
Gast #1911234
Lesenswert?

Hallo Mario,

du hast ohne Frage einen schönen Artikel zum Thema Bootlader 
"abgeliefert" :)

Die "Kompetenz" von Turmel kannst du in seinem letzten Satz erkennen:

Zitat: "Es gibt soviele Artikel im Web über Bootloader das ich auf den
verzichten kann."

Im Satz sind drei (!) grobe Fehler:

"Es gibt so viele Artikel im Web über Bootloader, dass ich auf den
verzichten kann."

Viele Grüße

Martin

P. S. Die Turmels dieser Welt sind in diesem Buch 
(http://www.amazon.de/Arschloch-Faktor-geschickten-Aufschneidern-Intriganten-Unternehmen/dp/3453600606/ref=sr_1_1?ie=UTF8&s=books&qid=1288014981&sr=8-1-spell) 
gut beschreiben.
#1911286
Lesenswert?

Vielen Dank für die Blumen.

Stefan B. schrieb:
> Hast du pos./neg. Erfahrungen/Empfehlungen zur Verwendung eines
> seriellen Bootloaders, wenn mit dem internen RC-Oszillator (statt
> genauerem externen Taktgeber) gearbeitet wird?

bei 9600 Baud mit ca. 0.2% Fehler geht es mit dem internen Takt von 8Mhz 
wunderbar, mit 19200 Baud auch. Die Baudratentabelle im Datenblatt hilft 
da weiter. Um ein STK500 zu simulieren, muss 115200 Baud unterstützt 
werden. Dafür ist ein externer Quarz unverzichtbar.

Mario
Persönliche Seite #1914396
Lesenswert?

Mario Grafe schrieb:
> Es wäre schön, wenn die Gurus unter euch das mal drübergucken könnten
> und Feedback über grobe Fehler oder Anmerkungen geben könnten.

Zum Layout

Hat Potential für Verbesserungen :-)

Beispiel:
1
                        }
2
                        else if(boot_state != BOOT_STATE_PARSER)                /* Programmzustand: UART Kommunikation */
3
                        {
4
                    switch((unsigned char)c)
5
                    {
6
                         ...
7
                    }
8
                        }
9
        }
10
    }
11
    while(boot_state!=BOOT_STATE_EXIT);

#1
Verwende gescheite Einrückungen für die Quelle! Hier sieht man den 
Grund, warum man keine TABs zm Einrücken nehmen sollte: Es sieht 
überall anders aus. Ergo: Einrücktiefe zB 4, und zwar mit Leerzeichen 
.

#2
Ganz offenbar stammt die Quelle von mehreren Autoren. Dennoch sollte 
ein Stil durchgehalten werden.

#3
Viele Quell-Zeilen sind zu lange. Da diese nicht umgebrochen werden, 
führt das dazu, daß die komplette HTML-Seite diese Breite bekommt und 
breitenmässig nicht mehr auf einen Bildschirm passt (Display 1024 pix). 
Zum Lesen muss beständig links-recht gescrollt werden. So macht das 
Lesen keinen Spaß!

Zum C-Code

#4
Warum wird teilweise uint8_t verwendet, teilweise unsigned char? dito 
16-Bit Typen?

#5
1
do
2
{
3
    c = uart_getc();
4

5
    if (c & UART_NO_DATA)
6
        continue;
7

8
    // 150 Zeilen Code

ist besser verständlich als
1
do
2
{
3
    c = uart_getc();
4
    if( !(c & UART_NO_DATA) )
5
    {
6
        // 150 Zeilen Code
7
    }
8
}

Zumal da bis zu 9(!) Einrückebenen folgen.

#6
Kommentare in der gleichen Zeile sind Geschmackssache (ich persönlich 
mag's nicht), aber da die Zeilen teilweise erst bei Spalte > 70 
beginnen, sollte das auf jeden Fall überdacht werden.

#7
Wozu wird an Adresse 0x0000 gesprungen? Sieht nach Hack aus...

#8
Vergleicht man die beiden Implementierungen
1
static uint16_t hex2num(unsigned char *ascii, uint8_t num)
2
{
3
  uint8_t  i;
4
  uint16_t var=0,
5
           erg=0,
6
           mult[4] = {1, 16, 256, 4096};
7
 
8
  for(i=0; i<num; i++)
9
  {
10
    if(ascii[i]<65) var = ascii[i] - 48;  /* 0..9 */
11
    if(ascii[i]>64) var = ascii[i] - 55;   /* A..F */
12
    if(ascii[i]>96) var = ascii[i] - 87;  /* a..f */
13
    erg += (uint16_t)(var * mult[num-i-1]);
14
  }
15
  return erg;  
16
}
17

18
static uint16_t hex2num_2 (const uint8_t * ascii, uint8_t num)
19
{
20
    uint8_t  i;
21
    uint16_t val = 0;
22

23
    for (i=0; i<num; i++)
24
    {
25
        uint8_t c = ascii[i];
26
        
27
        /* Hex-Ziffer auf ihren Wert abbilden */
28
        if (c >= '0' && c <= '9')            c -= '0';  
29
        else if (c >= 'A' && c <= 'F')       c -= 'A' - 10;
30
        else if (c >= 'a' && c <= 'f')       c -= 'a' - 10;
31
            
32
        val = 16 * val + c;
33
    }
34
    
35
    return val;  
36
}

So fällt auf:
# die zweite Implementierung ist leichter verständlich, zumindest für 
mich. Es gibt da keine magischen Zahlen und keine seltsame 
Multiplikation über ein Konstanten-Array.

# Die zweite Version brauch ca. 80 Bytes, die erste rund 190 Bytes an 
Code. An RAM braucht die zweite 2 Bytes für die Return-Adresse. Die 
erste Version legt bei jedem(!) Aufruf mult als Array auf dem Stack an 
und muss erst die Werte dort hinkopieren. Sie braucht 18 Bytes an Stack 
(avr-gcc 4.3.3, -Os).

Ich weiß jetzt nicht wie großzügig man in einem Bootloader mit den 
Resourcen haushalten kann...

#9
Für einige Aufgaben bieten sich Funktionen an, um den Spaghetti-Code 
etwas zu entschärfen. ZB das Parser-Zeug. gcc wird das inlinen, und wenn 
nicht, hat er gute Gründe dafür (inlining macht den Code auch bei einem 
Aufruf nicht unbedingt kleiner). Variablen wie "flag" braucht's dann 
nicht mehr, "c" lebt besser in dem Block, wo es verwendet wird...

Ok, hier mach ich mal Schluss, sonst find ich kein Ende... :-)

Und bitte nicht falsch verstehen. Ich schreib das nicht alles um 
rumzumäkeln (das wär mit die Schreibarbeit nicht wert), sondern weil ich 
Anregungen geben möchte. Text wird eben nicht nur über seine Buchstaben 
wahrgenommen, sondern zum Großteil auch über sein Layout/seine 
Typographie.
#1914676
Lesenswert?

@Johann L.:
Danke, solche Anmerkungen und Anregungen habe ich gemeint. Wenn man 
immer nur in seiner eigenen Suppe schwimmt, merkt man sowas nicht. 
Sobald ich Zeit habe, werde ich mich über deine Vorschläge hermachen und 
sie einarbeiten.
Die hex2num-Funktion von dir sieht tatsächlich viel besser aus, die 
würde ich so übernehmen.Die Quellen stammen übrigens tatsächlich alle 
von mir persönlich. Die falsche Einrückungen durch Tabs kommen durch das 
Copy&Paste in den Wiki-Editor zustande, das habe ich übersehen. Da ich 
einen ziemlich breiten Monitor habe sind mir einige "Breitenfehler" 
nicht aufgefallen.
#1916270
Lesenswert?

@ Johann L.:
ich habe jetzt schon einige Verbesserung des Layouts eingebaut (Tabs 
entfernt, Kommentare in eigene Zeile). Es sieht tatsächlich besser aus 
:)
Mein Funktion hex2num ist nicht besonders schön. Dein Vorschlag gefällt 
mir besser, ich habe ihn so übernommen. Danke nochmal. Jetzt werde ich 
mich noch mit dem "Hack" start() beschäftigen... er funktioniert zwar 
aber ein vom WDT ausgelöster Reset ist besser denke ich.
#1916292
Lesenswert?

Johann L. schrieb:
> #7
> Wozu wird an Adresse 0x0000 gesprungen? Sieht nach Hack aus...

Hallo Johann,
ich habe jetzt mal ausprobiert, den Bootloader mittels Watchdog reseten 
zu lassen, aber dabei entsteht ein Henne-Ei-Problem. Der AVR springt ja 
nach dem Reset immer wieder zuerst an Adresse 0x1800, dann wird nach 3 
sec. wieder geresetet und er landet wieder bei 0x1800. Der Bootloader 
springt also nie zur Anwendung weiter. Der "Hack" springt hart zur 
Adresse 0x0000, eigentlich doch nicht so schlecht, was meinst du? Gibt 
es noch eine andere Lösung die Anwendung loslaufen zu lassen?

Gruß
Mario
#1916332
Lesenswert?

Mario Grafe schrieb:
> Der "Hack" springt hart zur
> Adresse 0x0000, eigentlich doch nicht so schlecht, was meinst du? Gibt
> es noch eine andere Lösung die Anwendung loslaufen zu lassen?

Nein.
Der Resetvector ist ja auf den Bootloader verbogen und das läßt sich nur 
per Fusebit ändern.
Du mußt nach 0x0000 springen, das ist die saubere Lösung (kein Hack).

Du kannst auch nach oben aus dem Bootloader rauslaufen (mit NOPs bis zum 
Ende auffüllen), aber das würde ich als "dreckigen Hack" bezeichnen.


Peter
Persönliche Seite #1916358
Lesenswert?

Peter Dannegger schrieb:
> Mario Grafe schrieb:
>> Der "Hack" springt hart zur
>> Adresse 0x0000, eigentlich doch nicht so schlecht, was meinst du? Gibt
>> es noch eine andere Lösung die Anwendung loslaufen zu lassen?
>
> Nein.
> Der Resetvector ist ja auf den Bootloader verbogen und das läßt sich nur
> per Fusebit ändern.
> Du mußt nach 0x0000 springen, das ist die saubere Lösung (kein Hack).

Das Problem mit "goto 0" ist, daß das kein Reset ist, sondern eben nur 
ein "goto 0". Das initialisiert nicht die Hardware. Andererseits sind 
viele Anwendungen so geschrieben, daß sie von einer initialisierten 
Hardware ausgehen, zB Timer-Initialisierungen oder 
UART-Initialisierungen etc. die |= verwenden beim Belegen von SFRs wo 
sie eigentlich = meinen. Mit einer vor-initialisierten Hardware kann das 
zu Problemen führen.

Ich sehe da 2 Lösungsansätze

A: Der Bootloader macht seine Initialisierungen rückgängig und schreibt 
die entsprechenden Reset-Werte in die angefassten SFRs.

B: Man macht einen WDT-Reset und fragt nach dem Reset in Bootloader die 
Reset-Ursache ab. War's ein WDT-Reset, folgt ein "goto 0". Nachteil: Die 
Anwendung kann diesen Mechanismus nicht mehr verwenden, um nach einem 
eigenen WDT-Reset neu aufzusetzten (zB wenn nach einem WDT nicht neu 
initialisiert werden darf sondern an einem "Milestone" sicher aufgesetzt 
werden muss)
#1916359
Lesenswert?

Peter Dannegger schrieb:
> Einen ATtiny25 an SPI + Reset anklemmen, und so programmieren, daß er
> per ISP die Fuses ändert.
>
> In der Regel sollte aber die Schaltung bekannt sein, in der der
> Bootloader arbeitet, also sollte man die Fuses gleich richtig setzen
> können.

Gibt es keine Möglichkeit, die Fuses des eigenen AVR vom 
Bootloaderbereich aus zu ändern? Hintergrund: Ich habe den Bootloader 
daahingehend erweitert, das er sich wie ein STK500 verhält. Flashen usw. 
klappt auch ganz wunderbar, nur die Fuses kann ich nicht ändern.
Dieser Bastler hier: 
http://hubbard.engr.scu.edu/embedded/avr/bootloader/index.html
macht im Prinzip das gleiche, er muß es auch irgendwie gelöst haben, 
leider gibt er die Quellen nicht raus. Ich dächte ich hätte so etwas 
auch schon irgendwo mal gelesen, ich find es nur nicht mehr. Man muß 
natürlich aufpassen, das man sich nicht aus dem Bootloader aussperrt, 
aber das kann man ja abfangen. Nach dem Start hat man 3 Sekunden Zeit 
sich über das AVRStudio mit dem AVR zu verbinden, dann springt er weiter 
zum Programm, eigentlich ein schicke Sache. Wenn es fertig ist, werde 
ich es mal posten.

Ich bin froh das du mal über meinen Code schaust, du hast ja selbst 
schon einige Bootloader geschrieben und bist sehr aktiv und kompetent im 
Forum unterwegs. Wie findest du den Artikel?
#1916379
Lesenswert?

Mario Grafe schrieb:

> Dieser Bastler hier:
> http://hubbard.engr.scu.edu/embedded/avr/bootloader/index.html
> macht im Prinzip das gleiche, er muß es auch irgendwie gelöst haben,
> leider gibt er die Quellen nicht raus.

Ich denke das hast du misverstanden.
Der Bootloader selbst ändert keine Fuse Bits. Die muss man mit einem 
richtigen Programmer umstellen, wenn man den Bootloader in den µC 
brennt.
#1916568
Lesenswert?

Karl heinz Buchegger schrieb:
> Mario Grafe schrieb:
>
>> Dieser Bastler hier:
>> http://hubbard.engr.scu.edu/embedded/avr/bootloade...
>> macht im Prinzip das gleiche, er muß es auch irgendwie gelöst haben,
>> leider gibt er die Quellen nicht raus.
>
> Ich denke das hast du misverstanden.
> Der Bootloader selbst ändert keine Fuse Bits. Die muss man mit einem
> richtigen Programmer umstellen, wenn man den Bootloader in den µC
> brennt.

Aha, schade eigentlich. Sonst könnte man wenigstens noch die Taktquelle 
ändern oder so. Kannst du bitte auch mal über den Artikel schauen ob 
grobe Schnitzer drin sind, würde mich freuen. Schön wäre es auch wenn es 
mal jemand ausprobiert :)
Gast #1920090
Lesenswert?

Janein,
im Vergleich zu der jetzigen Implementierung kaum.

Besser wäre es die Flusssteuerung im der UART Module selbst zu machen.
Also wenn der Ringpuffer fast voll ist wird Xoff gesendet und erst wenn 
wider ein Level unterschritten wird wird Xon. Aber dafür ist die 
Implementierung von Peter Flury nicht ausgelegt.
#1920159
Lesenswert?

Hallo Mario und vielen Dank erstmal für den guten Artikel!
Auf mich wirkte er tatsächlich sehr demystifizierend und hat mir erst 
einmal ein grundsätzliches Verständnis für die Problematik gegeben.
Die Kommentare zur Rechtschreibung können wir mal getrost überlesen, die 
zu Übersichtlichkeit des Quelltextes nicht ganz. Aber dazu wurden schon 
genug Worte verloren.
Ich habe viel mehr eine konkrete Frage. Und zwar erschließt sich mir 
bisher der Sinn der Verwendung des Intel-HEX-Formates nicht, wenn dieses 
nur bewirkt, dass ich erst wieder einen Parser auf dem µC oder PC 
brauche um es zu interpretieren. Warum lasse ich mir vom Makefile nicht 
gleich mittels avr-objcopy eine Bin-Datei ausspucken und sende diese 
dann via UART an den µC?
Daran schließt sich mir auch gleich noch eine zweite Frage an. Und zwar 
bzgl. der Interpretation des Binärformates: Kann ich das so verstehen, 
dass ich einfach stets 64 Bytes (1 Page) aus der Bin-Datei auslese und 
diese nacheinander in die Speicherbereiche ab 0x0000 hochzählend 
reinschreiben kann? Oder wie muss ich mir den Aufbau des Binärformates 
vorstellen? Hab dazu nix richtig aussagekräftiges gefunden (zumindest 
nichts was mir Klarheit verschafft hat ;-) ).

Danke schon mal für die Antwort(en).
Gast #1920197
Lesenswert?

Also ich finde die Lösung mit dem Hexfile auch ganz nett :)
Wenn man sich platz sparen möchte und keine Prüfung machen will kann man 
ja auch den Parser abspecken.

z.B nach dem ":" einfach die ersten 8byte wegschmeißen und dann die 
nächsten 32 Byte lesen, usw. Das das Hexfile mit 0 Anfängt usw nimmt man 
einfach an. (naja den recodtype sollte man vielleicht noch auswerten um 
das ende zu bestimmen)
#1920604
Lesenswert?

Christoph P. schrieb:
> Ich habe viel mehr eine konkrete Frage. Und zwar erschließt sich mir
> bisher der Sinn der Verwendung des Intel-HEX-Formates nicht, wenn dieses
> nur bewirkt, dass ich erst wieder einen Parser auf dem µC oder PC
> brauche um es zu interpretieren. Warum lasse ich mir vom Makefile nicht
> gleich mittels avr-objcopy eine Bin-Datei ausspucken und sende diese
> dann via UART an den µC?
> Daran schließt sich mir auch gleich noch eine zweite Frage an. Und zwar
> bzgl. der Interpretation des Binärformates: Kann ich das so verstehen,
> dass ich einfach stets 64 Bytes (1 Page) aus der Bin-Datei auslese und
> diese nacheinander in die Speicherbereiche ab 0x0000 hochzählend
> reinschreiben kann? Oder wie muss ich mir den Aufbau des Binärformates
> vorstellen? Hab dazu nix richtig aussagekräftiges gefunden (zumindest
> nichts was mir Klarheit verschafft hat ;-) )

wie schon Johann L. schrieb: Beim Binärformat werden die empfangenen 
Daten als "echte" Binärzahlen interpretiert, d.h. wenn man eine binäre 5 
(0x05) sendet, wird sie auch als 5 gewertet. Leider ist dann die 
Flußsteuerung mit XON/XOFF nicht mehr möglich, da der gesamte Symbolraum 
ausgenutzt wird. Natürlich könnte man auch auf "echte" Flußsteuerung á 
la RTS/CTS umsteigen, aber das werden wohl die wenigsten implementiert 
haben. Zum Aufbau der Binärdatei kann ich nicht viel sagen, daher habe 
ich mich für den HEX-File-Parser entschieden, zumal keine avr-objcopy 
o.ä. nötig ist. Der Artikel sollte so einfach und verständlich wie 
möglich werden, so dass möglichst viele etwas damit anfangen können. Es 
ist auch als Anregung zu verstehen die Sache weiterzuentwicklen oder 
damit zu "spielen". Das schöne ist ja auch das durch die 
Hardwareunabhängikeit durch C der Bootloader für jeden AVR (mit 
Bootloadersupport) ohne Änderungen kompiliert werden kann.
Ich persönlich habe auch erst vor kurzem Angefangen mich speziell mit 
Bootloadern zu beschäftigen. Ich habe letztens noch einen Bootloader 
geschrieben, der sich wie ein STK500 verhält, dann wir das programmieren 
noch einfacher. Er passt auch wunderbar in die 2k, werde ich bei 
Gelegenheit mal posten.
#1921222
Lesenswert?

delay schrieb:
> z.B nach dem ":" einfach die ersten 8byte wegschmeißen und dann die
> nächsten 32 Byte lesen, usw. Das das Hexfile mit 0 Anfängt usw nimmt man
> einfach an. (naja den recodtype sollte man vielleicht noch auswerten um
> das ende zu bestimmen)

Naja abspecken wird schwierig. Man kann den Header nicht 
vernachlässigen. Die Daten stehen nicht so in der Hex-Datei wie sie 
Binär im Speicher liegen. Da sind Sprünge drin, die müssen ausgewertet 
werden. Es muß immer die Adresse ausgewertet. Eigentlich müßte der 
Parser noch erweitert werden für RecordTyp 3 bis 5, um Adressoffsets 
zuzulassen, bis jetzt sind nur 64kB addressierbar (RecordTyp 1 geht bis 
0xFFFF).
Vielleicht hat ja jemand Lust das mal zu implementieren.
Gast #1921363
Lesenswert?

Mario Grafe schrieb:
> Naja abspecken wird schwierig. Man kann den Header nicht
> vernachlässigen. Die Daten stehen nicht so in der Hex-Datei wie sie
> Binär im Speicher liegen. Da sind Sprünge drin, die müssen ausgewertet
> werden. Es muß immer die Adresse ausgewertet. Eigentlich müßte der
> Parser noch erweitert werden für RecordTyp 3 bis 5, um Adressoffsets
> zuzulassen, bis jetzt sind nur 64kB addressierbar (RecordTyp 1 geht bis
> 0xFFFF).
> Vielleicht hat ja jemand Lust das mal zu implementieren.

stimmt, das würde nur mit kleinen Programmen gehen. Und man muss 
annehmen das von 0-64k linear adressiert wird (was ja auch in der 
jetzigen Implementierung zum Teil der Fall ist).
#1923741
Lesenswert?

So, ich hab mich nun mal näher mit dem HEX-Format beschäftigt und muss 
mich aufgrund der Verwendung eines ATmega1281 sowieso mit den 
Datensatztypen 02 bis 05 beschäftigen. Dazu folgende Fragen:

1. Warum gibt es zwei verschiedene Modi/Record Types für die 
Adressierung von Speicherplätzen über 64k? Zum einen den Extended 
Segment Address Record (02) bei dem den folgenden Adressen ein Offset 
aufaddiert wird und zum andern der Extended Linear Address Record (04) 
bei dem den folgenden Adressen 4 höherwertige Bits vorrangestellt werden 
und der Adressraum somit noch größer ist? Ist dies Compiler- oder 
Architekturabhängig?

2. Der Record Type 03 (Start Segment Address Record) beinhaltet meines 
Verständnis nach den Startpunkt (Zeiger) der Anwendung falls sie nicht 
bei 0x0000 liegt (falls nicht, bitte korrigieren). Wozu dient dann noch 
der Record Type 05 (Start Linear Address Record)?

Wenns Erfolge bei mir gibt bzgl. höherem Adressraum, kann ich den 
entsprechenden Quelltext gern hier beisteuern. Und für Hinweise bzgl. 
meiner Frage zum schreiben/flashen des BIN-Formats gibt, bin ich 
weiterhin offen dafür ;)
#1929225
Lesenswert?

Olli schrieb:
> ich finde den Artikel zum Bootloader echt klasse. Kommt dann demnächst
> noch die Erweiterung auf den STK500-kompatiblen Bootloader?
Danke für die Blumen. Sobald ich Zeit habe, poste ich den 
STK500-kompatiblen Bootloader, er ist zu 90% fertig.

Jörg schrieb:
> Ist es ein Versehen, dass statt dem üblichen CR+LF-Newline ("\r\n") ein
> "\n\r" verwendet wird? Für mich ist es etwas irritierend.
Ja das ist ein Versehen, aber das Ergebnis ist das Gleiche. Könnte man 
der Schönheit wegen noch ändern.

Jörg schrieb:
> Noch eine Kleinigkeit: Die Screenshots vom Terminal stimmen zum Teil
> nicht mit den Ausgaben des Quellcodes überein. Stichwort: Gemischtes
> Englisch - Deutsch.
Richtig, das hat sich noch ein Screenshot einer Vorgängerversion 
eingeschlichen (beim "Hallo Welt"-Bootloader). Muß ich noch berichtigen.
#1933024
Lesenswert?

So, nachdem ich im AVRFreaks-Forum gelesen habe, dass der Record Type 03 
(start segment address record) bei AVRs keine Bedeutung hat 
(http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=650574 
Beitrag 6) muss im Grunde für AVRs mit >64 KB nur noch der Record Type 
02 (extended segment address record) ausgewertet werden. Alles kein 
Problem, funktioniert bei mir schon ganz gut. Nur stellt sich mir dann 
folgendes Problem: Wie kann ich - außer durch Eingabe eines festen 
Wertes à la
1
void (*start_application)(void) = 0x10000;
 eine Adresse an den Funktionszeiger übergeben?
Ich stelle mir das ungefähr so vor:
1
void (*start_application)(void);
2
uint32_t applicationAddress = 0x00010000;
3

4
start_application = (void *) (uint16_t) applicationAddress;
5
start_application = (void *) &start_application + (uint16_t) (applicationAddress >> 16);
oder alternativ ganz einfach:
1
start_application = (void *) (uint32_t) applicationAddress;

Funktioniert (natürlich) beides nicht. In der Doku der avr-libc steht 
unter 11.14 dazu folgendes:
> pointers are 16 bits (function pointers are word addresses, to allow
> addressing up to 128K program memory space)
Wie kann ich dem Funktionszeiger nun eine Variable mit dem gewünschten 
Adressinhalt übergeben?
#1933142
Lesenswert?

Christoph P. schrieb:
> Wie kann ich dem Funktionszeiger nun eine Variable mit dem gewünschten
> Adressinhalt übergeben?

Die Applikation sollte doch an Adresse 0x0000 (0x00000000) starten. 
Damit sollte es doch kein Problem geben, oder?

Ansonsten muß man inline Assembler nehmen, siehe "jmp", also etwa so:
1
asm volatile("jmp 0x8000");
Die Adresse muß meines wissens als Word-Adresse angegeben werden, daher 
0x10000/2=0x8000.

Kannst du deine Änderungen für den Segment Type 02 mal posten?
#1933321
Lesenswert?

Mario Grafe schrieb:
> Christoph P. schrieb:
>> Wie kann ich dem Funktionszeiger nun eine Variable mit dem gewünschten
>> Adressinhalt übergeben?
>
> Die Applikation sollte doch an Adresse 0x0000 (0x00000000) starten.
> Damit sollte es doch kein Problem geben, oder?
>
> Ansonsten muß man inline Assembler nehmen, siehe "jmp", also etwa so:asm 
volatile("jmp 0x8000");
> Die Adresse muß meines wissens als Word-Adresse angegeben werden, daher
> 0x10000/2=0x8000.

So lange die neue Anwendung bei der Adresse 0x0000 beginnt ist das kein 
Problem, richtig. Möchte ich aber zwei Anwendungen auf dem µC haben und 
zwischen diesen Anwendungen mittels des Bootloaders wählen können, dann 
muss ich bei (dementsprechend großen) Firmwares irgendwann auch mal in 
den Speicherbereich >64 KB hineinspringen können. Dies würde ich gern so 
"dynamisch" wie möglich machen, in dem die Startadressen der Anwendungen 
aus den HEX-Dateien gelesen, gespeichert und bei Bedarf aufgerufen 
werden.
In der avr-libc bin ich nun noch auf den uint_farptr_t gestoßen: 
http://www.nongnu.org/avr-libc/user-manual/group__avr__inttypes.html#ga72b6692e3f3123903c1a0d9a960c59b1
1
typedef int32_t int_farptr_t
> signed integer type that can hold a pointer > 64 KB
Also an irgendeiner Stelle hab ich gerade einfach noch ein 
Verständnisproblem - Byteaddresse, Wortadresse, Farpointer. Vielleicht 
kann mir da noch jemand auf die Sprünge helfen, denn 0x10000/2 = 0x8000 
=> jmp 0x8000 funktioniert auch nicht.

> Kannst du deine Änderungen für den Segment Type 02 mal posten?
Gern, nur der Record Type 03 ist (wie gesagt) völlig sinnfrei von mir 
implementiert wurden. Hab den Parser nur mal in eine eigene Funktion 
ausgelagert.
1
// boolean-defintion for software-flags
2
typedef enum
3
{
4
  FALSE,
5
  TRUE
6
} bool_t;
7

8
/**
9
 * Parser for the received HEX-file content
10
 */
11
void parse_hex_input(uint16_t receivedHexChar)
12
{
13
  static uint8_t parserState = PARSER_STATE_START,
14
      hexSize = 0,        // length of the Intel-HEX data
15
      hexRecType = 0,        // Intel-HEX record-type
16
      hexChecksumEOL = 0,      // received HEX-file checksum
17
      hexCounter = 0,        // writing position of the HEX-buffer
18
      hexDataCounter = 0;      // counter of received HEX-data of one row
19

20
  static uint16_t hexChecksum = 0,  // Intel-HEX checksum to proof received data
21
      codeSgmntAddr = 0,      // code segment address for record-type == 03
22
      instructionPtr = 0;      // instruction pointer for record-type == 03
23

24
  static bool_t  extSgmntAddrFlag = FALSE,  // flag indicating record-type == 02
25
      csRegisterFlag = FALSE,    // flag indicating code segment address of record-type == 03
26
      ipRegisterFlag = FALSE,    // flag indicating instruction pointer of record-type == 03
27
      flashPageFlag = TRUE,    // flag indicating new flash-page
28
      firstDataLineFlag = TRUE;  // flag indicating that first line of HEX-file is read
29

30
#if (SPM_PAGESIZE > 255)  // AVRs with 128k or more flash-memory
31
  static uint16_t flashCounter = 0;  // writing position of the flash-data buffer
32
  static uint32_t hexAddrOffset = 0,  // address offset of the extended segment address record-type
33
        hexAddress = 0,      // Intel-HEX target address
34
        flashPage = 0;      // to be written flash-page
35
#else            // AVRs with less than 128k flash-memory
36
  static uint8_t flashCounter = 0;  // writing position of the flash-data buffer
37
  static uint16_t hexAddrOffset = 0,  // address offset of the extended segment address record-type
38
        hexAddress = 0,      // Intel-HEX target address
39
        flashPage = 0;      // to be written flash-page
40
#endif
41

42
  hif_putc(XOFF);
43

44
  switch (parserState)
45
  {
46
  // wait for START_OF_LINE sign (':')
47
  case PARSER_STATE_START:
48
    if (receivedHexChar == START_OF_LINE)
49
    {
50
      parserState = PARSER_STATE_SIZE;
51
      hexCounter = 0;
52
      hexChecksum = 0;
53
    }
54
    break;
55

56
  // parse data-size
57
  case PARSER_STATE_SIZE:
58
    hexDataBuffer[hexCounter++] = (uint8_t) receivedHexChar;
59
    if (hexCounter == 2)
60
    {
61
      parserState = PARSER_STATE_ADDRESS;
62
      hexCounter = 0;
63
      hexSize = (uint8_t) hex2num(hexDataBuffer, 2);
64
      hexChecksum += hexSize;
65
    }
66
    break;
67

68
  // parse target address
69
  case PARSER_STATE_ADDRESS:
70
    hexDataBuffer[hexCounter++] = (uint8_t) receivedHexChar;
71
    if (hexCounter == 4)
72
    {
73
      parserState = PARSER_STATE_RECORD_TYPE;
74
      hexCounter = 0;
75
      hexAddress = (uint32_t) hex2num(hexDataBuffer, 4);
76
//      hexChecksum += (uint8_t)((hexAddress & 0xFF00) >> 8);
77
//      hexChecksum += (uint8_t)(hexAddress & 0x00FF);
78
            hexChecksum += (uint8_t) hexAddress;
79
            hexChecksum += (uint8_t) (hexAddress >> 8);
80
      if (hexAddrOffset != 0)
81
        hexAddress += hexAddrOffset;
82

83
      if(flashPageFlag == TRUE)
84
      {
85
        //flashPage = (uint16_t)((hexAddress / SPM_PAGESIZE) * SPM_PAGESIZE);
86
        flashPage = hexAddress - hexAddress % SPM_PAGESIZE;
87
        flashPageFlag = FALSE;
88
      }
89
    }
90
    break;
91

92
  // parse row-type
93
  case PARSER_STATE_RECORD_TYPE:
94
    hexDataBuffer[hexCounter++] = (uint8_t) receivedHexChar;
95
    if(hexCounter == 2)
96
    {
97
      hexCounter = 0;
98
      hexDataCounter = 0;
99
      hexRecType = (uint8_t) hex2num(hexDataBuffer, 2);
100
      hexChecksum += hexRecType;
101
      switch ((uint8_t) hexRecType)
102
      {
103
        case 0:  // data record
104
          parserState = PARSER_STATE_DATA;
105
          if (firstDataLineFlag == TRUE)
106
          {
107
            appStartAddr = hexAddress;
108
            firstDataLineFlag = FALSE;
109
          }
110
          break;
111
        case 1:  // end of file record
112
          parserState = PARSER_STATE_CHECKSUM;
113
          break;
114
        case 2:  // extended segment address record
115
          extSgmntAddrFlag = TRUE;
116
          parserState = PARSER_STATE_DATA;
117
          break;
118
        case 3:  // start segment address record
119
          csRegisterFlag = TRUE;
120
          parserState = PARSER_STATE_DATA;
121
          break;
122
/*        case 4:  // extended linear address record
123
          parserState = PARSER_STATE_DATA;
124
          break;
125
        case 5: // start linear address record
126
          parserState = PARSER_STATE_DATA;
127
          break;
128
        default:
129
          parserState = PARSER_STATE_DATA;
130
          break;*/
131
      }
132
    }
133
    break;
134

135
  // parse flash-data
136
  case PARSER_STATE_DATA:
137
    hexDataBuffer[hexCounter++] = (uint16_t) receivedHexChar;
138
    if(extSgmntAddrFlag == FALSE && csRegisterFlag == FALSE && ipRegisterFlag == FALSE && hexCounter == 2)
139
    {
140
      hif_putc('.');
141
      hexCounter = 0;
142
      flashDataBuffer[flashCounter] = (uint8_t) hex2num(hexDataBuffer, 2);
143
      hexChecksum += flashDataBuffer[flashCounter];
144
      flashCounter++;
145
      hexDataCounter++;
146
      if(hexDataCounter == hexSize)
147
      {
148
        parserState = PARSER_STATE_CHECKSUM;
149
        hexDataCounter = 0;
150
        hexCounter = 0;
151
      }
152
      // buffer full => write page
153
      if(flashCounter == SPM_PAGESIZE)
154
      {
155
        hif_puts("P\n\r");
156
        //program_page((uint16_t) flashPage, flashDataBuffer);
157
        program_page(flashPage, flashDataBuffer);
158
        memset(flashDataBuffer, 0xFF, sizeof(flashDataBuffer));
159
        flashCounter = 0;
160
        flashPageFlag = TRUE;
161
      }
162
    }
163
    else if (extSgmntAddrFlag == TRUE && hexCounter == 4)
164
    {
165
      extSgmntAddrFlag = FALSE;
166
      hexCounter = 0;
167
      hexAddrOffset = (uint32_t) hex2num(hexDataBuffer, 4);
168
//      hexChecksum += (uint8_t)((hexAddrOffset & 0xFF00) >> 8);
169
//      hexChecksum += (uint8_t)(hexAddrOffset & 0x00FF);
170
            hexChecksum += (uint8_t) hexAddrOffset;
171
            hexChecksum += (uint8_t) (hexAddrOffset >> 8);
172
            hexAddrOffset *= 16;
173
      parserState = PARSER_STATE_CHECKSUM;
174
    }
175
    else if (csRegisterFlag == TRUE && hexCounter == 4)
176
    {
177
      hexCounter = 0;
178
      csRegisterFlag = FALSE;
179
      ipRegisterFlag = TRUE;
180
      codeSgmntAddr = (uint16_t) hex2num(hexDataBuffer, 4);
181
            hexChecksum += (uint8_t) codeSgmntAddr;
182
            hexChecksum += (uint8_t) (codeSgmntAddr >> 8);
183
      parserState = PARSER_STATE_DATA;
184
    }
185
    else if (ipRegisterFlag == TRUE && hexCounter == 4)
186
    {
187
      hexCounter = 0;
188
      ipRegisterFlag = FALSE;
189
      instructionPtr = (uint16_t) hex2num(hexDataBuffer, 4);
190
            hexChecksum += (uint8_t) instructionPtr;
191
            hexChecksum += (uint8_t) (instructionPtr >> 8);
192
            parserState = PARSER_STATE_CHECKSUM;
193
    }
194
    break;
195

196
  // parse checksum
197
  case PARSER_STATE_CHECKSUM:
198
    hexDataBuffer[hexCounter++] = (uint16_t) receivedHexChar;
199
    if(hexCounter == 2)
200
    {
201
      hexChecksumEOL = (uint8_t) hex2num(hexDataBuffer, 2);
202
      hexChecksum += hexChecksumEOL;
203
      hexChecksum &= 0x00FF;
204
      // end of file => write remaining data
205
      if (hexRecType == 1)
206
      {
207
        hif_puts("P\n\r");
208
        //program_page((uint16_t) flashPage, flashDataBuffer);
209
        program_page(flashPage, flashDataBuffer);
210
        extSgmntAddrFlag = FALSE;
211
        bootState = BOOT_STATE_EXIT;
212
      }
213
      if (hexChecksum == 0)
214
        parserState = PARSER_STATE_START;
215
      else
216
        parserState = PARSER_STATE_ERROR;
217
    }
218
    break;
219

220
  case PARSER_STATE_ERROR:
221
    hif_puts("Error!\n");
222
    bootState = BOOT_STATE_ECHO;
223
    break;
224

225
  default:
226
    break;
227
  }
228

229
  hif_putc(XON);
230
}
#1934653
Lesenswert?

Christoph P. schrieb:
> Ok, ich rudere zurück. Wortadressierung mittelsappStartAddress /= 2; und 
anschließender Übergabestart_application = (void *) (uint16_t) appStartAddr; 
funktioniert scheinbar doch 8-)

Das würde mich aber wundern, dann dürfte ja
1
void (*bootloader)( void ) = 0x1800;
nicht funktionieren...

Ein verzwickeltes Problem...

Nochmal nachgefragt:
Bist du sicher das du mehrere Anwendungen im Flash ablegen willst? Wie 
hantierst du dann mit Interrupts (Stichwort: Sprungtabelle)? Was ist mit 
dem Stack?
#1934725
Lesenswert?

Mario Grafe schrieb:
> Christoph P. schrieb:
>> Ok, ich rudere zurück. Wortadressierung mittels appStartAddr /= 2; und
>> anschließender Übergabe start_application = (void *) (uint16_t) appStartAddr;
>> funktioniert scheinbar doch 8-)
>
> Das würde mich aber wundern, dann dürfte ja void (*bootloader)( void ) = 0x1800;
> nicht funktionieren...
>
> Ein verzwickeltes Problem...

Ja, das habe ich auch erst gedacht. Aber kann es sein, dass der Compiler 
bei der zweiten Version automatisch die Halbierung der Flashadresse 
vornimmt, da Funktionszeiger ja stets Wortadressen sind? Nur eine vage 
Vermutung.

Das mit den mehreren Anwendungen hat sicher noch so seine Tücken. 
Speicherkonsistenz, Interrupt-Initialisierung/-Deinitialisierung usw. 
Aber prinzipiell müsste es doch gehen, oder sehe ich das verkehrt? Was 
du mit Stack meinst verstehe ich gerade nicht ganz. Aber beim PC 
funktioniert's doch auch 8-)
#1934766
Lesenswert?

Christoph P. schrieb:
> Das mit den mehreren Anwendungen hat sicher noch so seine Tücken.
> Speicherkonsistenz, Interrupt-Initialisierung/-Deinitialisierung usw.
> Aber prinzipiell müsste es doch gehen, oder sehe ich das verkehrt? Was
> du mit Stack meinst verstehe ich gerade nicht ganz. Aber beim PC
> funktioniert's doch auch 8-)

Nein Christoph, einen PC kann man wirklich nicht mit einem AVR 
vergleichen, da er keinen linearen Adressraum hat. Schau mal nach 
"von-Neumann" und "Harvard"-Architektur bei wikipedia.

Eine Idee wäre allerdings möglich: Ein ausgefeilter Bootloader der eine 
SD-Karte lesen kann (FAT) und ein Display und Steuertasten. Dann könnte 
man via Bootloader eine Anwendung (hex oder bin-file) von der Karte 
lesen und starten (=in den Flash kopieren). NAch dem Reset startet 
wieder der Bootloader. Das fände ich durchaus praktikabel. Allerdings 
würde das den Bootloader etwas aufblähen, bei großen Controllern aber 
kein Problem.
#1934842
Lesenswert?

Christoph P. schrieb:
> Problem, richtig. Möchte ich aber zwei Anwendungen auf dem µC haben und
> zwischen diesen Anwendungen mittels des Bootloaders wählen können, dann
> muss ich bei (dementsprechend großen) Firmwares irgendwann auch mal in
> den Speicherbereich >64 KB hineinspringen können. Dies würde ich gern so
> "dynamisch" wie möglich machen, in dem die Startadressen der Anwendungen
> aus den HEX-Dateien gelesen, gespeichert und bei Bedarf aufgerufen
> werden.

Wenn du mal genauer darüber nachdenkst, dann macht es keinen Sinn, auf 
einem AVR mehr als 1 Anwendung zu haben und per Bootloader umzuschalten.

1 AVR == 1 Anwendung

zb stimmen alle Interrupt Vektoren nicht. zb landet Applikation 2 in 
Applikation 1, wenn es selber einen Sprung nach 0000 macht. Zb muss die 
2.te Applikation für einen ganz anderen Speicherbereich gelinkt sein 
etc. etc.

Die ganze Thematik kannst du getrost vergessen.
Wenn jemand wirklich 2 vorhandene Applikationen in eine verschmelzen 
will, dann muss er das auf Code Ebene machen und sich selbst um die 
ganze kleinen Feinheiten kümmern. Zum SChluss steht er dann wieder mit 
nur 1 Applikation da, die vom Bootloader ins Flash gebrannt wird und bei 
0x0000 startet.
#1934884
Lesenswert?

> Wenn du mal genauer darüber nachdenkst, dann macht es keinen Sinn, auf
> einem AVR mehr als 1 Anwendung zu haben und per Bootloader umzuschalten.
>
> 1 AVR == 1 Anwendung

Um genau zu sein, geht es mir auch mehr um die Möglichkeit eine Art 
Firmware-Update durchführen zu können und weniger darum, zwei wirklich 
verschiedene Anwendungsbereiche abzudecken. Also eher 1 AVR != 1 
Firmware-Version

> zb stimmen alle Interrupt Vektoren nicht. zb landet Applikation 2 in
> Applikation 1, wenn es selber einen Sprung nach 0000 macht. Zb muss die
> 2.te Applikation für einen ganz anderen Speicherbereich gelinkt sein
> etc. etc.

Vielleicht gehe ich an die Sache etwas zu blauäugig ran. Aber vielleicht 
kannst du ja noch mal genauer auf die Punkte eingehen. Das Linken in den 
gewünschten Speicherbereich ist ja kein Problem. Aber warum sollte 
Anwendung 2 an die Stelle 0x0000 springen (außer Watchdog löst aus 
o.ä.)? Das Auswählen zwischen den Anwendungen wird ja durch den 
Bootloader übernommen. Am wenigsten Ahnung habe ich derzeit von den 
angesprochenen Problemen mit den Interrupt-Vektoren.
Am Beispiel der Testanwendung aus dem Tutorial gesagt: Ich habe die 
gleiche Anwendung in die Speicherbereiche ab 0x00000, ab 0x00100 und ab 
0x10000 gelinkt und per Bootloader geflasht. Das heißt: Ich kann vom 
Bootloader in alle drei Anwendungen springen und von denen wieder in den 
Bootloader. Warum sollte das mit größeren Anwendungen nicht 
funktionieren? Danke schon mal!

> Eine Idee wäre allerdings möglich: Ein ausgefeilter Bootloader der eine
> SD-Karte lesen kann (FAT) und ein Display und Steuertasten. Dann könnte
> man via Bootloader eine Anwendung (hex oder bin-file) von der Karte
> lesen und starten (=in den Flash kopieren). NAch dem Reset startet
> wieder der Bootloader. Das fände ich durchaus praktikabel. Allerdings
> würde das den Bootloader etwas aufblähen, bei großen Controllern aber
> kein Problem.

Die ganze Geschichte am Ende über einen externen Speicher (egal ob 
SD-Karte oder was auch immer) zu lösen ist auch angedacht, aber für eine 
schnelle Testlösung erstmal etwas zu viel.
#1934895
Lesenswert?

Christoph P. schrieb:

> Vielleicht gehe ich an die Sache etwas zu blauäugig ran. Aber vielleicht
> kannst du ja noch mal genauer auf die Punkte eingehen. Das Linken in den
> gewünschten Speicherbereich ist ja kein Problem. Aber warum sollte
> Anwendung 2 an die Stelle 0x0000 springen

Weil du als Bootloader Programmierer keine Kontrolle darüber hast, 
welche Schweinereien dein Anwendungsprogrammierer macht, die du nicht 
verhindern kannst.

wer will mich daran hindern zu schreiben
1
int main()
2
{
3
  void (*func)();
4
  func = 0;
5

6
  func();
7
}
Dein Bootloader ganz sicher nicht :-)


> Bootloader übernommen. Am wenigsten Ahnung habe ich derzeit von den
> angesprochenen Problemen mit den Interrupt-Vektoren.

Das kannst du auch so einfach nicht lösen. Denn die Position der 
Interrupt Vektoren ist dir von der Hardware vorgegeben.

> Am Beispiel der Testanwendung aus dem Tutorial gesagt: Ich habe die
> gleiche Anwendung in die Speicherbereiche ab 0x00000, ab 0x00100 und ab
> 0x10000 gelinkt und per Bootloader geflasht.

Na dann mach mal in deine Anwendung eine ISR rein und sieh nach welche 
angesprungen wird, wenn App3 läuft und der Interrupt auftritt
#1937691
Lesenswert?

So, ich hab mir die ganze Sache mit den Interrupt-Vektoren nochmal durch 
den Kopf gehen lassen. Zunächst mal habt ihr natürlich recht, dass die 
ISR-Vektoren immer am Anfang des Speicherbereichs stehen. Wenn der 
auszuführende Inhalt der ISRs bei allen geflashten Anwendungen gleich 
ist, dürfte die Ausführung ja kein Ding sein, oder?
Allerdings ist mir nicht ganz klar, warum der Rücksprung in die 
eigentliche Anwendung aus einer ISR ein Problem darstellt. Ist die 
Rücksprungadresse denn nicht im Programmzähler gespeichert bzw. von 
diesem abhängig? Woher weiß denn die ISR (bzw. der µC) nach der 
Codeabhandlung an welche Stelle im Flash gesprungen wird?
Also konkret: Was genau hindert mich daran, bei gleichen ISR-Inhalten, 
mehrere Anwendungen auf einem µC laufen zu lassen (mal abgesehen von 
Funktionszeigern auf bestimmte Speicheradressen und sonstigen 
programmiererspezifischen Unwegbarkeiten)?
Wie gesagt, externer Zwischenspeicher ist defintiv angedacht, aber es 
soll ja fix gehen ;)
#1942972
Lesenswert?

Schade, dass mir noch keiner eine Antwort auf obige Frage geben konnte. 
Derweil hier mal noch fix eine Funktion die eine BIN-Datei in den 
Flashspeicher schreibt. Dabei wird vorher noch (wenn auch sinnfrei der 
Diskussion zu folge) die Startadresse abgefragt und anschließend die 
Größe der BIN-Datei eingegeben. Danach einfach nur noch die Daten 
zwischenspeichern und ab in den Speicher. Vielleicht interessierts ja 
jemanden.
1
/**
2
 * Parser for the received BIN-file content
3
 */
4
void parse_bin_input(uint16_t receivedHexChar)
5
{
6
#ifdef BIN_MODE
7
  static uint8_t hexCounter = 0;    // writing position of the HEX-buffer
8

9
  static bool_t binStartAddrFlag = FALSE,  // flag indicating whether application start address is known or not
10
        binSizeFlag = FALSE;    // flag indicating whether application size is known or not
11

12
#if (SPM_PAGESIZE > 255)  // AVRs with 128k or more flash-memory
13
  static uint16_t flashCounter = 0;  // writing position of the flash-data buffer
14
  static uint32_t binStartAddr = 0,  // start flash-address of the application
15
        binSize,        // size of the application in byte
16
        flashPage = 0;      // to be written flash-page
17
#else            // AVRs with less than 128k flash-memory
18
  static uint8_t flashCounter = 0;  // writing position of the flash-data buffer
19
  static uint16_t binStartAddr = 0,  // start flash-address of the application
20
        binSize,        // size of the application in byte
21
        flashPage = 0;      // to be written flash-page
22
#endif
23

24
  hif_putc(XOFF);
25

26
  if (binStartAddrFlag == FALSE && binSizeFlag == FALSE)
27
  {
28
    hexDataBuffer[hexCounter++] = (uint8_t) receivedHexChar;
29
    if (hexCounter == 5)
30
    {
31
      binStartAddrFlag = TRUE;
32
      hexCounter = 0;
33
      binStartAddr = hex2num(hexDataBuffer, 5);
34
      flashPage = binStartAddr - binStartAddr % SPM_PAGESIZE;
35
      hif_puts("Size of BIN-file in 20 Bit Hex-format (e.g. 01F40):");
36
    }
37
  }
38

39
  else if (binStartAddrFlag == TRUE && binSizeFlag == FALSE)
40
  {
41
    hexDataBuffer[hexCounter++] = (uint8_t) receivedHexChar;
42
    if (hexCounter == 5)
43
    {
44
      binSizeFlag = TRUE;
45
      hexCounter = 0;
46
      binSize = hex2num(hexDataBuffer, 5);
47
      hif_puts("BIN-file content:");
48
    }
49
  }
50

51
  else if (binStartAddrFlag == TRUE && binSizeFlag == TRUE)
52
  {
53
    hif_putc('.');
54
    flashDataBuffer[flashCounter] = (uint8_t) receivedHexChar;
55
    flashCounter++;
56

57
    // buffer full => write page
58
    if (flashCounter == SPM_PAGESIZE)
59
    {
60
      hif_puts("P\n\r");
61
      //program_page((uint16_t) flashPage, flashDataBuffer);
62
      program_page(flashPage, flashDataBuffer);
63
      memset(flashDataBuffer, 0xFF, sizeof(flashDataBuffer));
64
      flashCounter = 0;
65
      flashPage += SPM_PAGESIZE;
66
    }
67

68
    // end of file => write remaining data
69
    else if (flashPage + flashCounter == binSize)
70
    {
71
      hif_puts("P\n\r");
72
      //program_page((uint16_t) flashPage, flashDataBuffer);
73
      program_page(flashPage, flashDataBuffer);
74
      memset(flashDataBuffer, 0xFF, sizeof(flashDataBuffer));
75
      flashCounter = 0;
76
      flashPage = 0;
77
      binStartAddrFlag = FALSE;
78
      binSizeFlag = FALSE;
79
      bootState = BOOT_STATE_EXIT;
80
    }
81
  }
82

83
  hif_putc(XON);
84
#endif  // BIN_MODE
85
}
Gast #1942995
Lesenswert?

Interressant wäre vielleicht auch ein XModem-Übertragungsprotokoll.

http://de.wikipedia.org/wiki/XModem

Bietet zumindest ein klein wenig Übertragunssicherheit, und so ziemlich 
jedes Terminal-Programm bietet einen XModem Up-/Download an.

mit "sx" gäbs unter Linux ein einfaches Kommandline-tool zum Upload.

Die XModem-Blockgröße von 128Byte passt auch gut zur SPM_PAGESIZE vieler 
AVRs, nur bei den kleinen tinys könnte es vom Ram knapp werden.
#1952071
Lesenswert?

Hallo zusammen,
Die Sache mit den Interruptvektoren und mehreren Firmwares auf einem 
Chip hat mich nun doch noch nicht in Ruhe gelassen.
Angenommen ich reserviere pro forma ab Adresse 0x0000 einen 
Speicherbereich in der Größe aller theoretisch möglichen 
Interruptvektoren. Ein vollständiges Image (inkl. Interruptvektoren) 
beider Firmwares befindet sich im Flash (im Speicherbereich entsprechend 
platziert mit den Linker-Flags im Makefile). In den reservierten 
Speicherbereich kopiere ich dann die Interrupttabelle der Anwendung, die 
ich gerade nutzen möchte. Da die Sprungziele m.M.n. absolute Adressen 
sind, müsste das doch funktionieren, oder? So kann man mittels 
Bootloader verschiedene Firmwares im Speicher platzieren und auch 
auswählen.
Ein unerwarteter Sprung zu 0x0000 würde somit auch wieder in der vorher 
verwendeten Anwendung enden.
Hoffe meine Gedankengänge sind nicht allzu wirr ;)
Persönliche Seite #1955372
Lesenswert?

Frage an die Bootloader Gemeinde:

Ich möchte für ein Projekt einen Bootloader verwenden, um
Softwareupdates zu ermöglichen.
Jedoch sind die bisher verwendeten Möglichkeiten um den Bootloader in
den Updatemodus zu versetzen bei mir nicht möglich. Ich kann also nicht
den Taster oder die typischen 2 Warte sekunden bei mir einbauen.

momentan habe ich folgendes umgesetzt:

Nach dem Start checkt der Bootloader wie er gestartet wurde, in dem er
das Reset Register ausliest.
Wurde der Controller normal gestartet, so wird das bisherige Programm
aus dem EEProm geladen.
Wurde der Controller durch einen Hardwarereset neu gestartet, so
bedeutet es, dass eine neue Firmware als update kommt. Der Hardwarereset
wird durch die aktuelle Firmware ausgelöst, meist über einen Befehl von
der RS232 Schnittstelle.
Funktioniert so auch richtig gut.

Jedoch kann ich so keinen Watchdog benutzen (da der Bootloader sonst
jedesmal eine neue Firmware erwarten würde) was mir auch nicht recht
ist, da ich den Controller in einer relativ kritischen Anwendung nutze.

Ist folgendes möglich?

Kann ich zum speichern der Updateinformation auch ein Byte im EEprom des
Controllers nutzen? Es muss dabei garantiert sein, dass der Bootloader
und die Firmware auf die selbe SPeicherzelle zugreifen.
ist dsa möglich?

schon mal Vielen Dank
#1973424
Lesenswert?

Hallo,

ich bin dem Tutorial gefolgt und habe versucht den Bootloader zum laufen 
zu bekommen.
Das Problem ist, dass die Hex-Datei nicht 1796 Byte sondern 2520 Byte 
groß ist. Hier einem mal die Ausgabe von Win-AVR beim kompletten 
Rebuild:
1
Build started 12.12.2010 at 21:52:31
2
avr-gcc  -mmcu=atmega128 -Wall -gdwarf-2 -std=gnu99          -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT Bootloader.o -MF dep/Bootloader.o.d  -c  ../Bootloader.c
3
avr-gcc  -mmcu=atmega128 -Wall -gdwarf-2 -std=gnu99          -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT uart.o -MF dep/uart.o.d  -c  ../uart.c
4
avr-gcc -mmcu=atmega128 -Wl,-Map=Bootloader.map Bootloader.o uart.o     -o Bootloader.elf
5
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature  Bootloader.elf Bootloader.hex
6
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex Bootloader.elf Bootloader.eep || exit 0
7
avr-objdump -h -S Bootloader.elf > Bootloader.lss
8

9
AVR Memory Usage
10
----------------
11
Device: atmega128
12

13
Program:    2502 bytes (1.9% Full)
14
(.text + .data + .bootloader)
15

16
Data:        352 bytes (8.6% Full)
17
(.data + .bss + .noinit)
18

19

20
Build succeeded with 0 Warnings...

Hat jemand ne Idee wo die ca. 700 Byte geblieben sind?

Danke

Felix
#1974197
Lesenswert?

Mir ist doch noch was eingefallen:
Evtl. bindet die UART library (uart.c und uart.h) etwas mehr Code ein. 
Im der Library von Peter Fleury wird der Prozessortyp ermittelt und 
entsprechend angepasste Funktionen eingebunden. Da der Atmega128 ja 
meherer UARTs hat, wird wohl mehr Code bzw. zusätzliche eingebunden 
werden.

Ich denke das ist des Rätsels Lösung.

Stell doch im Kompiler mal Spaßenshalber den Atmega88 ein und kompiliere 
es, mal sehen wir groß der Code da wird....
#2016848
Lesenswert?

Hallo!
Ich habe versucht, den Bootloader auf einem DVK90CAN1 umzusetzen. Da der 
uC AT90CAN128 von Peter Fleurys UART nicht unterstützt wird, habe ich 
die UART mit FIFO von Peter Dannegger genommen. Das Projekt wird mit dem 
AVR Studio erstellt und erfolgreich kompiliert. Die Verbindung zu einem 
Terminalprogramm klappt ebenfalls vorzüglich (Danke, Peter!).
Nun aber zu meinem Problem: Wenn ich das Programm nach Anweisung in den 
Bootloaderbereich verschiebe durch Setzen der Linker-Option
(hier -Ttext=0x1E000) und "Verbiegen" der Interrupts, passiert nichts. 
Mit dem Autor des Artikels habe ich schon konferiert, aber er ist 
ratlos.
Welcher Schalter muß noch umgelegt werden?
Helene
#2019957
Lesenswert?

Also:
Ein Programm, das compiliert, geflasht und ausgeführt wird, läuft 
erwartungsgemäß (keine Interrupts, nur "pollen").
Das Verschieben auf eine andere Anfangsadresse im Bootloaderbereich oder 
auch nur um ein paar words (na klar, compiliert, etc...) läuft nicht.
Kann mir wirklich keiner einen Tip geben?????
Helene
#2323038
Lesenswert?

Hallo Helene,

wahrscheinlich hast Du das gleiche Problem wie ich:
Der Compiler erzeugt eine falsche Interrupt-Sprungtabelle:
0001f000 <__vectors>:
   1f000:  0c 94 72 f8   jmp  0x1f0e4  ; 0x1f0e4 <__ctors_end>
   1f004:  0c 94 91 f8   jmp  0x1f122  ; 0x1f122 <__bad_interrupt>
   1f008:  0c 94 91 f8   jmp  0x1f122  ; 0x1f122 <__bad_interrupt>
   1f00c:  0c 94 91 f8   jmp  0x1f122  ; 0x1f122 <__bad_interrupt>
   1f010:  0c 94 91 f8   jmp  0x1f122  ; 0x1f122 <__bad_interrupt>
...
Die jmp's sind alle 4, und nicht nicht, wie notwendig, 2 Byte.

Ich habe bis jetzt noch keine Möglichkeit gefunden, dass die 
Vektortabelle korrekt erzeugt wird (WinAVR 20100110: Optimize for size 
(-Os), -fno-jump-tables oder auch -mshort-calls --> keine Auswirkung).

Vielleicht weiß jemand eine Möglichkeit....

Gruß,
Gunter
#2323143
Lesenswert?

Hallo Stefan,

danke für die Anregung...
Du hast recht!

Ich bin auf die unterschiedliche Adressdarstellung hereingefallen 
(Datenblatt -> Wort-Adressen; GCC-Listing -> Byte-Adressen).

(Geistesblitz....)
Das heißt, für einen ATMEGA2560 muß ich dem Linker als Adresse 0x3E000 
angeben (Byteadresse!) und nicht 1F000 (Wortadresse!)...

Arrghhh...

Dann klappt's vielleicht jetzt auch mit den Interrupts...

Nochmals danke, werde ich jetzt gleich ausprobieren....

Gunter
Gast #2376698
Lesenswert?

Kann ich das Tutorial auch für den ATmega8515 umschreiben?
Momentan hab ich das Problem, dass ich im MCUCR register vom 8515 die 
IVCE und IVSEL bits nicht finde. Haben die beim 8515 ne andere 
Bezeichnung oder gibts die gar net?
Gast #2476893
Lesenswert?

Freut mich das es die gefällt. Ich habs ans Ende des Artikels angefügt.
Ich wollte eigentlich mal wieder ein bischen dran weiterarbeiten wenn 
ich Zeit habe, vor allem die Ergänzung für die XMEGAs...mal gucken wann 
das wird.
Guten Rutsch
Mario
Gast #2508332
Lesenswert?

Hallo auch,

habe mich mal an diesem Bootloader versucht und bin auch weit gekommen 
:-D
Jetzt habe ich aber ein kleines Problem und hoffe mir kann da jemand 
helfen.

Ich Drücke also die Taste "p" um den Bottloader in den Zustand zu 
bringen, dass er die Daten des HEX-File empfängt. Der Bootloader lauscht 
auch brav danach.

Wenn ich nun das HEX-File in Putty kopiere, fängt der mit der 
Übertragung an aber leider nur eine Zeile lang, danach kommen merhere 
Zeilen - Rautesymbole - und dann bleibt alles stehen:

.....................................................p
###############################################################
###############################################################
###############################################################
####################

Ich habe schon versucht die Bautrate zu reduzieren aber hilft alles 
nichts.
Woran könnte das liegen?

Gruß und vielen Dank
Snatch
Gast #2509817
Lesenswert?

In den Error-State (Raute-Symbole) springt der Bootloader nur, wenn die 
Checksumme der Zeile nicht stimmt. Es sieht also ganz so aus als ob er 
die (erste)  Zeile nicht richtig empfängt. Das kann an der Baudrate oder 
auch an der Genauigkeit der Baudrate liegen (Baudratenfehler).

Gib mal ein paar mehr Daten:
Welcher AVR?
Taktfrequenz?
Baudrate?
Hast du etwas am Bootloader verändert?
Gast #2580377
Lesenswert?

Hallo,

ein sehr schöner Artikel. Ich war grad dabei das nachzuvollziehen, habe 
aber das aktuelle AVR Studio 5. Wo finde ich denn dort die 
Projekteinstellungen? Klar Rechtsklick auf das Projekt und Properties 
macht ja einen schönen Dialog auf (Visual Studio läßt grüßen), aber wo 
kann man denn schonmal die Frequenz einstellen? Ich such mir seit ca. 
zwei Stunden schon nen Wolf. Kann mich mal bitte jemand erleuchten.

Ich hab bisher mit programmers notepad gearbeitet und dort kann man den 
Parameter ganz einfach im makefile eingeben. Aber das AVR Studio hat 
wohl auch so einige Vorteile. Deswegen möchte ich mich gern mal 
einarbeiten.

Vielen Dank,
der ChekR
#2629373
Lesenswert?

Hallo Mario,
ich hab bestimmt was noch nicht verstanden: was ich im Code nicht sehe 
ist folgendes: wenn eine geparste Adresse aus der momentan aktuellen 
Flash-Page herausführt (also ein Adresssprung im hex-File, was ja 
möglich ist), müsste dann nicht erst die (gegebenenfalls nur teilweise 
ausgefüllte) "alte" flash page geschrieben werden und dann eine neue 
flash-page Adresse erzeugt werden? Oder einfach gefragt: funktioniert 
der Code auch wirklich bei einem nicht linear durchgehend beschriebenen 
Flash-Speicher? Im code sehe ich nur, dass der Flash bei vollem Puffer 
oder bei hexRecType = 1 (Ende des Files) geschrieben wird.
Konkret sehe ich das Problem, wenn ich ans Ende des Flashspeichers 
direkt vor dem Bootcode z.B. noch eine Versionsnummer eintragen will, 
wie das in den SD-card- Bootloadern, die mit Binärdateien arbeiten, oft 
üblich ist.  Das kann ich ja mit -section-start = xxxxxxx als 
linker-flag erreichen.
Ich will das für einen Xmega128 machen und muss dazu natürlich auch in 
den extended segment address-Bereich (währen mein restlicher code in den 
64K-Bereich passt). Die letzen vier Zeilen des hex-files sehen dann so 
aus:
:10092C0067000000000200000000650300000000EA  //letzte Zeile aus 
64K-space
:020000021000EC                              //extended address
:08FFF8007856341255AA0000EE                  //code ab addr. 0x1FFF8
:00000001FF                                  //file ende, hexRecType 1
Bei der Arbeit mit Binärfile alles kein Problem, da wird ja brav der 
gesamte flash durchgehend bis zur obersten verwendeten Adresse 
abgespeichert.
Über eine Aufklärung würde ich mich freuen.
Grüße,
Karl
@CheKr: Properties, Toolchain, AVR/GNU C Compiler, Symbols. Unter -D 
defined symbols mit dem grünen "+" Symbol F_CPU= xxxxxxUL eintragen
#2629853
Lesenswert?

und wenn man dann nur so einen kleinen "Brocken" in den Flash schreibt, 
sollte man vielleicht vorher lieber die originale flash page erst mal in 
den Puffer laden, damit man nichts verändert, was man gar nicht 
verändern will, wenn man die page wieder zurückschreibt. So macht's der 
kavr zum Beispiel.
Karl
#2664261
Lesenswert?

wen es interessiert: im Paralleluniversum
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=953604#953604
habe ich den dort ursprünglich veröffentlichten code für einen Xmega 
Bootloader, der einen hex-file von einer SD-Karte einliest, so 
umgearbeitet, dass er tatsächlich auch für flash code im Bereich >64k 
arbeitet und eine Versionskontrolle erlaubt. Getestet mit XMega128A1 und 
FAT16.
Karl
#2664776
Lesenswert?

Die downloads sind nur sichtbar, wenn man bei avrfreaks angemeldet ist, 
was aber ja keine Hürde sein sollte. Ich fand es dem Autor bei 
avrfreaks, dessen Programm ich erweitert habe, unfair gegenüber, den 
code auch hier anzuhängen. Ich lasse mich vom Moderator aber gerne eines 
besseren belehren bzw. meinen Post hier löschen.
Karl
Gast #2668123
Lesenswert?

Gunter Heuckeroth schrieb:

> (Geistesblitz....)
> Das heißt, für einen ATMEGA2560 muß ich dem Linker als Adresse 0x3E000
> angeben (Byteadresse!) und nicht 1F000 (Wortadresse!)...


Danke an Stefan und an Gunter, genau das war auch mein Problem. Hatte 
beim ATmega324pa anstatt der Byte-adresse 0x7800 die Wort-adresse 0x3c00 
dem Linker mitgegeben. Mit 0x7800 klappts auf Anhieb.
Gast #3029038
Lesenswert?

Hallo Leute,

ich hoffe der Thread ist nicht zu alt und ich bekomme ich hier noch eine 
Antowrt, das wäre super.
Erstmal danke an den Autor, eine Super Arbeit!!

Ich bin dabei, den Bootloader für meinen AT90CAN auszulegen. Allerdings 
habe ich ein Problem mit der hex_checksum. Nach der ersten Zeile Code 
bekomme ich nur noch Fehler, die zb so aussehen:
.............#######################################
also beginnt der Bootloader nichtmal eine Page zu beschreiben. Hat 
Jemand eine Idee wodran es liegen könnte und ob es eine einfache Lösung 
des Problems gibt auf die ich nicht komme?
Als kommunikation benutze ich eine eigene UART lib mit flowcontrol, die 
aber einwandfrei funktioniert.

grüße

Ollo
#3319652
Lesenswert?

Mario schrieb:
> Ich wollte eigentlich mal wieder ein bischen dran weiterarbeiten wenn
> ich Zeit habe, vor allem die Ergänzung für die XMEGAs...mal gucken wann
> das wird.

Guten Morgen Mario,

hast Du bereits etwas für die xmegas optimiert?
Habe gestern Deine Anleitung gelesen und heute wollte ich sie testen, 
allerdings spuckt AtmelStudio 6 erstmal einen Berg Fehlermeldungen und 
Warnings aus. (Selbst beim Hallo-Welt-'Bootloader')

Angefangen bei der boot.h "#  error AVR processor does not provide 
bootloader support!" gibts eigentlich nur Probleme.

Habe nun von Atmel den xmega-Bootloader drin, aber der ist eben nicht so 
einfach gehalten und so gut anpassbar.

Gruß Tobi
#3336586
Lesenswert?

Hallo Tobi,

Tobias Gläser schrieb:
> hast Du bereits etwas für die xmegas optimiert?

Nein ich hatte noch keine Zeit dazu.

Tobias Gläser schrieb:
> Habe gestern Deine Anleitung gelesen und heute wollte ich sie testen,
> allerdings spuckt AtmelStudio 6 erstmal einen Berg Fehlermeldungen und
> Warnings aus. (Selbst beim Hallo-Welt-'Bootloader')

Das wundert mich, es sollte auch mit dem AtmelStudio und Xmegas 
prinzipiell funktionieren, vorrausgesetzt man passt die Einstellungen 
für den Atxmega an. Welchen hast du denn?

Tobias Gläser schrieb:
> Angefangen bei der boot.h "#  error AVR processor does not provide
> bootloader support!" gibts eigentlich nur Probleme.

Das klingt eher nach falschen Controller-Settings.

Gruß
Mario
Gast #3621187
Lesenswert?

Hallo Mario,

Vielen Dank für den Beitrag.
eins ist mir noch nicht klar:

"...an Word-Adresse 0xC00, also Byteadresse 0xC00 * 2 = 0x1800"

um die Adresse eines Words zu bekommen, muss man die Adresse von dem 
Byte mit 2 multiplizieren??

warum?
Gast #3622824
Lesenswert?

Umgekehrt. Man möchte die Byteadresse aus der Wordadresse ermitteln.
Beim Word ist das Datenwort 16 Bit, beim Byte nur 8 Bit. Demzufolge 
entspricht die Byteadresse = 2 * Wordadresse.

Man kann es auch Bitweise ausrechnen: 8 * 0xC000 = 16 * 0x1800
#3867779
Lesenswert?

Hallo Mario,

mithilfe deines Artikels ist es auch mir als "nicht Profi" gelungen, den 
Bootloader auf dem Atmega 644 zum laufen zu bringen. Ein Update des uC 
aus meiner Labiew Applikation ist so problemlos möglich.

Nun muss ich aber auf den 1284 umsteigen. Ich dachte schon der 
Bootloader läuft auch hier, aber da hatte ich den Hinweis auf die 
fehlende Unterstützung >64K Flash leider überlesen.

Da ich wie gesagt eher der Anwendungsprogrammierer bin, tue ich mich mit 
der Integration der erweiterten Adressräume (HEX-Zeilentyp 2 bis 5) 
etwas schwer, bzw. weiss nicht so richtig wo ich da ansetzen muss.

Hat evtl. schon jemand diese Erweiterung gemacht oder kannst Du mir 
einen Tipp geben wie ich das am besten angehe?

Gruß
Jan
#3880500
Lesenswert?

Nein tut mir leid. Ich hab zur Zeit zu viel zu tun.
Letztenendes muss in diesem Abschnitt:
1
...
2
   case PARSER_STATE_TYPE:  
3
       hex_buffer[hex_cnt++] = (uint8_t)c;
4
       if(hex_cnt == 2)
5
       {
6
           uart_putc(XOFF);
7
           hex_cnt = 0;
8
           hex_data_cnt = 0;
9
           hex_type = (uint8_t)hex2num(hex_buffer, 2);
10
           hex_check += hex_type;
11
           switch(hex_type)
12
           {
13
               case 0: parser_state = PARSER_STATE_DATA; break;
14
               case 1: parser_state = PARSER_STATE_CHECKSUM; break;
15
               default: parser_state = PARSER_STATE_DATA; break;
16
          }
17
          uart_putc(XON);
18
        }
19
        break;
noch der "case" 2 eingebaut werden (Extended Segment Address Record) und 
dann der Adresszeiger entsprechend manipuliert werden. Das einfachste 
ist man fügt eine Offsetvariable hinzu welche bei der Berechnung der 
"flash_page" hinzuaddiert wird. Achtung: vor dem Berechnen der neuen 
Adresse sollten die alte Page auf jeden Fall noch geschrieben werden ( 
auch wenn sie noch nicht voll ist).

Ich schau mal ob ich das eingebaut bekomme. Ich werde es aber leider 
nicht so fix testen können...
#3880835
Lesenswert?

So ich habe mal im Tutorial ein neues Kapitel für Programme >64k 
angefangen und die Auswertung des Record-Typ 2 in den Bootloader 
eingebaut, hauptsächlich wurde die Variable "hex_addr" auf 32 Bit 
erweitert und ein Offset (auch 32 Bit) eingeführt. Wenn der Record-Typ 2 
kommt wird im Zustand "PARSER_STATE_DATA" entsprechend die 
Segmentoffset-Adresse (hex_addr_offset) geparst und gesetzt. Alle 
folgenden Schreiboperationen beziehen den Offset dann ein. Vor dem 
Ändern des Offsets wird noch die Angefangene Page geschrieben.

@Jan Müller: bitte testen..
#3881902
Lesenswert?

Hallo Mario,

beim compilieren bekomme ich folgende Warnung:

/* Berechnen der Offsetadresse */
hex_addr_offset = (uint32_t)(hex2num(hex_buffer, 4) << 16);


../bootloader.c:313: warning: left shift count >= width of type

Habe das Programm dann mal geladen:


Eine 60K Hex Datei wird geladen und das Programm läuft dann auch.

Eine 104K Hex Datei wird geladen und aber das Programm läuft dann nicht.

Gruß
Jan
#3882840
Lesenswert?

Hab grad festegestellt, das ich meinen eigenen Code nicht mehr verstehe. 
Kann mir jemand (Karl Heinz?) die Berechnung der Flash-Adresse 
erläutern:
1
flash_page = hex_addr - hex_addr % SPM_PAGESIZE;

Irgendwie steh ich grad auf dem Schlauch...so ist das wenn man sich 
lange nicht mehr damit beschäftigt hat.... :)
#3887567
Lesenswert?

Hallo Jan,

ich habe den Quellcode für den Bootloader nochmal komplett überarbeitet.
Es waren noch einige Bugys drin. Ich habe mal das alte Atmega88-Vehikel 
zum Testen reaktiviert. Mit diesem habe ich auch getestet, das 
funktioniert erstmal soweit...

Ich musste noch einiges straffen damit es in die 2048 Byte reinpasst.

Bitte teste jetzt mal mit Hex-Daten > 64k...

Im Anhang mal das Quellfile der "main.c", dann sparst du dir das 
Copy&Paste :)

Gruß
Mario
Angehängte Dateien:
Gast #3887611
Lesenswert?

im Quellcode bitte sehr:

- alle Einrückungen ohne Tabs
- alle Einrückungen gleichmässig (4 blanks ist ein gute Zahl)
- ä, ö, ü  etc  vermeiden

Muss man das begründen?

Ist mir so auf die Schnelle aufgefallen, vielleicht gibt es
noch mehr ....
#3888070
Lesenswert?

isidor schrieb:
> im Quellcode bitte sehr:
>
> - alle Einrückungen ohne Tabs
> - alle Einrückungen gleichmässig (4 blanks ist ein gute Zahl)
> - ä, ö, ü  etc  vermeiden
>
> Muss man das begründen?
>
> Ist mir so auf die Schnelle aufgefallen, vielleicht gibt es
> noch mehr ....

Danke für den Hinweis, natürlich weiß ich das. Ich habe es mir aber für 
morgen aufgehoben den Quelltext "aufzuhübschen". Jan sollte erstmal 
weiterkommen und meine Zeit am Code zu arbeiten ist derzeit sehr 
begrenzt...
#3888403
Lesenswert?

Hallo Mario,

beim Compilieren habe ich Probleme mit der Funktion
"memcpy_PF"

Warnung:
../bootloader.c:257: warning: implicit declaration of function 
'memcpy_PF'

Error:
R:\BP700\SW\01_Controller\12_bootloader1284P\work_2\default/../bootloade 
r.c:257:  undefined reference to `memcpy_PF'


Ich verwende "WinAVR-20100110", in der pgmspace.h gibt es nur eine 
Funktion 'memcpy_P'.

Habe dann im Internet eine neuere pgmspace.h mit der Funktion 
"memcpy_PF" gefunden und die Datei "pgmspace.h" ausgetauscht.
Dann war die Warnung weg, aber der Error steht weiterhin an.

Gruß
jan
#3888514
Lesenswert?

Hallo Jan,

die "memcpy_PF"-Funktion ist in der Tat teil der avr-libc:
http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

das "..F" bedeutet "far" für Kopieraktionen in Speicherbereichen >64k.
Du kannst die auch eine Routine mit "pgm_read_byte(...)" schreiben.

Dein WinAVR ist in ziemlich alt. Ich habe für das kompilieren das 
AVRStudio 6.2 mit der gcc.Verision: gcc version 4.8.1 
(AVR_8_bit_GNU_Toolchain_3.4.4_1162) benutzt. Evtl. wäre es eine gute 
Idee zumindest den gcc mit der gnu toolchain zu updaten...

mein avr-libc ist vermutlich 1.8 (muss ich noch checken)...

Schlimmstenfalls kannst du erstmal die "memcpy-PF" auskommentieren und 
probieren. Das ist eigentlich nur wichtig wenn es Adress-Sprünge 
innerhalb des Hex-Files gibt...
#3888572
Lesenswert?

so, habe die "memcpy-PF" mal auskommentiert, das Ergebnis ist leider wie 
bisher auch:

Eine 60K Hex Datei wird geladen und das Programm läuft dann auch.

Eine 104K Hex Datei wird geladen und aber das Programm läuft dann nicht,
der Controller macht permanent Reset.
(ohne Bootloader, direkt in den Controller geladen, funktioniert die 
104K Hex Datei einwandfrei).

Werde dann mal das AVR Studio updaten.

Irgendwie finde ich keinen neueren WinAVR Installer als meinen
WinAVR-20100110-install.exe

Gruß
jan
#3888635
Lesenswert?

Jan Müller schrieb:
>
> Ich verwende "WinAVR-20100110", in der pgmspace.h gibt es nur eine
> Funktion 'memcpy_P'.
>
> Habe dann im Internet eine neuere pgmspace.h mit der Funktion
> "memcpy_PF" gefunden und die Datei "pgmspace.h" ausgetauscht.
> Dann war die Warnung weg, aber der Error steht weiterhin an.
>
> Gruß
> jan

Da fehlt tatsächlich etwas in der lib. Aber es reicht nicht das
Header File zu ersetzen.

Es gibt eine neuere Version, die hier: avr-libc-1.8.1

hier herunter zu laden:

http://download.savannah.gnu.org/releases/avr-libc/

Dort ist memcpy_PF enthalten. Hoffentlich der zugehörige Code
ebenfalls. Ich habe mich aber nicht getraut meine existierene
WinAVR-20100110 Installation zu patchen.
#3889137
Lesenswert?

Ich glaube ich habe den Fehler (zumindest einen Fehler) gefunden:

Die Berechnung der Offset-Adresse für Record Typ 2 ist definitiv falsch,
sie muss etwa so aussehen:
1
...
2
   case 2: hex_addr_offset = ((uint32_t)(hex2num(hex_buffer, 4)) << 4; break;
3
...

da beim Record Typ 2 stellt die Offset-Adresse den oberen Teil (Bit 
4-19) einer 20 Bit-Adresse dar, daher die Verschiebung um 4 Bit nach 
links. Ich habe es im Wiki geändert. Im Anhang die aktuelle "main.c"

@Jan: Bitte testen...
Angehängte Dateien:
#3890469
Lesenswert?

Sorry, aber das funktioniert leider immer noch nicht.

Eine 60K Hex Datei wird geladen und das Programm läuft dann auch.

Eine 67K Hex Datei wird geladen und aber das Programm läuft dann nicht,
der Controller macht allerdings nun nur noch einen Reset (nach dem Ende 
des Ladens), aber das Programm läuft dann nicht.

Gruß
jan
#3890489
Lesenswert?

Mario Grafe schrieb:
> Hab grad festegestellt, das ich meinen eigenen Code nicht mehr verstehe.
> Kann mir jemand (Karl Heinz?) die Berechnung der Flash-Adresse
> erläutern:
>
>
1
> flash_page = hex_addr - hex_addr % SPM_PAGESIZE;
2
>
>
> Irgendwie steh ich grad auf dem Schlauch...so ist das wenn man sich
> lange nicht mehr damit beschäftigt hat.... :)

Wenn du die Zahl 834 hast und SPM_PAGESIZE 100 ist, was ergibt dann der 
Ausdruck
1
   834 - 834 % 100
das ergibt eine glatte 800.

D.h. die Berechnung beantwortet wohl die Fragestellung: Wenn ich eine 
beliebige Adresse x habe und eine beliebige Page-Size, welches ist dann 
die erste Adresse in der Page, in der die Adresse x liegt.

Am Beispiel: Bei einer Pagesize von 100 liegt die Adresse 834 in 
derjenigen Page, die bei der Adresse 800 startet.
#3891431
Lesenswert?

Karl Heinz schrieb:
> Wenn du die Zahl 834 hast und SPM_PAGESIZE 100 ist, was ergibt dann der
> Ausdruck   834 - 834 % 100
> das ergibt eine glatte 800.
>
> D.h. die Berechnung beantwortet wohl die Fragestellung: Wenn ich eine
> beliebige Adresse x habe und eine beliebige Page-Size, welches ist dann
> die erste Adresse in der Page, in der die Adresse x liegt.
>
> Am Beispiel: Bei einer Pagesize von 100 liegt die Adresse 834 in
> derjenigen Page, die bei der Adresse 800 startet.

Danke, zwischenzeitlich ist es mir auch wieder wie Schuppen aus den 
Haaren gefallen :)
Ich hatte vergessen, das die Page-Write-Funktion nicht die Nummer der 
Page sondern die Startadresse der Page übernimmt..
#3891434
Lesenswert?

Jan Müller schrieb:
> Sorry, aber das funktioniert leider immer noch nicht.
>
> Eine 60K Hex Datei wird geladen und das Programm läuft dann auch.
>
> Eine 67K Hex Datei wird geladen und aber das Programm läuft dann nicht,
> der Controller macht allerdings nun nur noch einen Reset (nach dem Ende
> des Ladens), aber das Programm läuft dann nicht.

Ohne debuggen wird das nix. Die Adressberechnung sollte eigentlich jetzt 
stimmen. Ich habe noch ein ATmega2560-Geschoß rumliegen, ich werde mal 
versuchen das zu reaktivieren...
#3892201
Lesenswert?

Ich bekomme den Bootloader auf dem ATmega2560 im Augenblick nicht zu 
laufen. Es scheint ein Problem mit UART und dem AVR zu geben. Ich 
verwende die USART-Lib von Peter Fleury. Das UART-Senden funktioniert. 
Einzelne Zeichen empfangen geht auch. Sobald ich das HEX-File rüber 
schiebe resetet sich der ATmega2560...

Der Code ist der gleich wie beim ATmega88...sehr seltsam...
Gast #3904195
Lesenswert?

Hallo,

vorweg ein großes Dankeschön für das tolle Tutorial. Leider bekomme ich 
den Bootloader auf dem Atmega32 nicht zum laufen.
Die Ausgabe sieht so aus: ...............############### usw.

Ich habe das MCUCR zu GICR angepasst und als Adresse 0x7800 (Bootsz 
1024) gewählt, die Baudrate liegt bei 9k6 aber auch bei niedrigeren 
Baudraten kommt es zum Checksum Fehler. Als Oszillator nutze ich einen 
externen 8 MHz Quarz.

Hat jemand den Bootloader schon auf einem Mega32 zum laufen gebracht und 
kann mir sagen was alles angepasst werden muss?
Gast #3905137
Lesenswert?

Xon/Xoff waren eingeschaltet, hat aber scheinbar nicht funktioniert.
Ich habe die Softwareflusssteuerung jetzt auskommentiert, die 
_delay_ms(100) beim schreiben einer Page gestrichen und in C# ein 
Terminalprogramm geschrieben, welches nach jeder übertragener Line kurz 
wartet. Jetzt funktioniert alles. Das Problem lag wohl daran, dass 
Xon/off nicht immer funktioniert hat und somit der RX-Buffer 
übergelaufen ist.
Ich werde heute mal versuchen den Parser im Terminalprogramm zu 
implementieren.
#3905462
Lesenswert?

Nochmal zu der Flusssteuerung:
Ich habe ja die UART-Library von Peter Fleury benutzt. Diese hat einen 
Empfangs- und Sendpuffer, d.h. die "uart_putc" schreibt nur in den 
Puffer, wann das Byte gesendet wird steht auf einem anderen Blatt. Wenn 
der Empfangsinterrupt permanent aktiv ist bleibt vermutlich zu wenig 
Rechenzeit zum Senden übrig. Mit einer "echten" Flusssteuerung (RTS/CTS) 
würde es natürlich klappen.
Eine andere Möglichkeit ist natürlich nach einer bestimmten Anzahl von 
Bytes zu warten. Das müsste aber dann das Terminal machen.

Falls jemand eine gute Idee hat wie man es besser machen könnte nur raus 
damit :)

Evtl. hilft auch eine höhere Taktfrequenz damit mehr Rechenzeit (neben 
dem Abarbeiten des Empfangsinterrupts) übrig bleibt. Eine 
IR-Priorisierung wäre auch nicht schlecht, geht aber beim ATmega nicht.
Gast #3905691
Lesenswert?

Ich habe den Parser jetzt aus dem Bootloader genommen und lasse das 
Terminalprogramm das Hex-File "übersetzen". Jetzt geht das flashen 
doppelt so schnell, da nur noch halb so viele Bytes übertragen werden 
müssen.
Nach jeder Line wartet das Terminal eine kurze Zeit (20-50ms), damit hat 
der Controller mehr als genug Zeit um die Page zu schreiben.

Danke für die super Anleitung und deine Hilfe!
#3906194
Lesenswert?

Sorry noch nicht. Ich habe versucht rauszufinden warum mein ATmega2560 
nicht funktioniert. Dafür habe ich alles möglich auskommentiert. Er 
startet jedoch nach dem Empfang von ein paar Zeichen ohne Grund immer 
neu. Ich habe fast das Gefühl es liegt am ATmega2560...

Das ISR-umschalten funktioniert. Der Bootloader läuft auch los. 
Irgendwie scheint die Lib von Peter Fleury nicht zu funktionieren...

Wenn Zeit ist muß ich nochnmal weiter suchen...
Gast #3937940
Lesenswert?

Hallo freunde,
Erstmal herzlichen dank Mario für dein bootloader.
Mit Atmega88 funktioniert es, aber mit Atmega8 leider nicht.
Laut Datenblatt BootStart adresse ist 0xC00 (WORD) also 0x1800 (Byte)
Ich hab die Fuse so eingestellt BOOTRST = 0 (programmed) und Bootloader 
size = 00 (1024)(word) und 8 Mhz eingestellt.

Kann mir bitte jemand tips geben was ich eventuell falsch gemacht habe.

Danke euch

MFG
Eddy
#3938833
Lesenswert?

Hallo Mario,
Vielen Dank für dein super Tutorial, mir hat es sehr sehr geholfen.

... und was Turmel geschrieben hat ist voll nicht verständlich, für mich 
hat der Typ kein Ahnung. Wenn ich was durch arbeite, achte nicht auf 
Rechtschreibung, achte auf den Inhalt was ich auch mit erfolg durch 
gearbeitet habe.

Mach dir nichts draus es gibt immer Idiotien die schnell mit negativen 
Feedback sich beteiligen.
MFG
Eddy
#3939102
Lesenswert?

Eddy C. schrieb:
> Hallo Mario,
> Vielen Dank für dein super Tutorial, mir hat es sehr sehr geholfen.
>
> ... und was Turmel geschrieben hat ist voll nicht verständlich, für mich
> hat der Typ kein Ahnung. Wenn ich was durch arbeite, achte nicht auf
> Rechtschreibung, achte auf den Inhalt was ich auch mit erfolg durch
> gearbeitet habe.
>
> Mach dir nichts draus es gibt immer Idiotien die schnell mit negativen
> Feedback sich beteiligen.

Danke für die Blumen :)

Ich habe das Tutorial geschrieben weil ich mich selbst tief in das Thema 
einarbeiten mußte und nur wenig brauchbare Hilfe gefunden habe. Das 
erarbeitete Know-How wollte ich nun weitergeben. Ich finde es gut wenn 
es auch anderen nützt.

Guten Rutsch
Mario
Gast #3939953
Lesenswert?

hallo Andy,

ich versuche das Bootloader-Programm auf Atmega8 zu übertragen, leider 
ohne Erfolg.

Meine Einstellungen für den Fuse sind: LOW:0x44 HIGH:0x41. Sind sie 
richtig?

Hast das Programm geändert(ausser die Zeilen:
temp = GICR;
GICR = temp | (1<<IVCE);
GICR = temp | (1<<IVSEL);
)

Danke im Voraus
#3948924
Lesenswert?

hallo zusammen,

ich habe folgendes gemacht:

1. Die Bootrst wurde unprogrammiert. Das Bootloader programm geflasht 
und dann die Anwendung eingefügt (wie es in die Anleitung beschrieben).
Nach einem Reset, wird die Anwendung ausgeführt. Nach der Eingabe eine 
'b', wird das Programm zum Bootloader-Bereich gesprungen und bleibt 
hängen.

Hallo hier ist der echte Bootloader
Programmiere den Flash!
Kopiere die Hex-Datei und f▒ge sie hier ein (rechte Maustaste)
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
............................................................P
Reset AVR!

Hier ist das Anwendungsprogramm...
Du hast folgendes Zeichen gesendet:
Du hast folgendes Zeichen gesendet:
Du hast folgendes Zeichen gesendet:
Du hast folgendes Zeichen gesendet:
Du hast folgendes Zeichen gesendet:
Du hast folgendes Zeichen gesendet: d
Du hast folgendes Zeichen gesendet: d
Du hast folgendes Zeichen gesendet: d
Du hast folgendes Zeichen gesendet: d
Springe zum Bootloader...
Hallo hier ist der echte Bootloader
Reset AVR!


2. Wenn ich das Bootrst-bit programmiere, bleibt das Programm hängen.


Hallo hier ist der echte Bootloader
Programmiere den Flash!
Kopiere die Hex-Datei und f▒ge sie hier ein (rechte Maustaste)
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
................................................................P
............................................................P
Reset AVR!





Ich benutze
- AVR Studio 4.18
- WinAVR-20100110
- Extrem Burner
-Putty (Einstellung 9600,8,Kein,XON/XOFF)
- Atmega8 mit ext. Quarz 16MHz. Fuse: LOW: FF HIGH : D1

Kann jemand mir weiter helfen??
Angehängte Dateien:
#3960194
Lesenswert?

halloMario,

Schön,das Du da bist.

ich habe den ersten Test auf Atmega32, hat wunderbar geklappt. Nun jetzt 
teste ich den Atmega16 und macht Ärger.

Ich habe die gleichen Programme wie für Atmega32 genommen und auf 
Atmega16 übertragen. Die Adresse des Bootloaders auf (word: ox1C00, 
Byte:0x3800) geändert. Nach dem Flashen des Bootloaders habe ich 
versucht, die kleine Anwendung (auch schon angepasst auf Atmega16) 
kopiert (ich meine hex-File) und angefügt, leider klappt nicht die 
Übertragung, es wird immer unterbrochen.


Hast du eine Idee?

Danke im Voraus

Die Fuse: Low FF, High:D0 (Extern Quarz 16MHz)
#3960815
Lesenswert?

Leandro Leandro schrieb:
> Ich habe die gleichen Programme wie für Atmega32 genommen und auf
> Atmega16 übertragen. Die Adresse des Bootloaders auf (word: ox1C00,
> Byte:0x3800) geändert. Nach dem Flashen des Bootloaders habe ich
> versucht, die kleine Anwendung (auch schon angepasst auf Atmega16)
> kopiert (ich meine hex-File) und angefügt, leider klappt nicht die
> Übertragung, es wird immer unterbrochen.

Kannst du mal einen Screenshot der Ausgabe im Terminal machen?
Welche Baudrate verwendest du?

Das Hauptproblem bei der Übertragung ist die Flußkontrolle. Meistens 
hängen die Problem damit zusammen. Die Software-Flußkontrolle (XON/XOFF) 
funktioniert nur so leidlich. Wenn der Controller mit Daten zugeballert 
wird kann er u.U. das XOFF nicht mehr senden, besser wäre die 
Implementation einer Hardware-Flußkontrolle (DTS/RTS).
#3960858
Lesenswert?

ich habe die folgenden Baudrate: 9600, 19200 und 115200 versucht, leider 
wurde das Problem nicht behoben.

anbei ein Screenshot:

Hallo hier ist der echte Bootloader
Reset AVR!
Hallo hier ist der echte Bootloader
Reset AVR!
Hallo hier ist der echte Bootloader
Reset AVR!
Hallo hier ist der echte Bootloader
Reset AVR!
Hallo hier ist der echte Bootloader
Programmiere den Flash!
Kopiere die Hex-Datei und f▒ge sie hier ein (rechte Maustaste)
........................................................................ 
........................................................P
........................................................................ 
........................................................P





und dann bleibt hängen.
#3960887
Lesenswert?

Sieht komisch aus, al ob die Flashgröße (SPM_PAGESIZE) nicht stimmt oder 
der Parser nicht funktioniert. Scheinbar schreibt er ja 2 Pages, danach 
bleibt er in einem State hängen.

Du mußt die mal ein paar mehr Debugausgaben machen, z.B. in welchem 
State sich das Programm grade befindet. Ich empfehle einzelne Zeichen 
(z.B. "S" für State State), da sonst die Übertragung zu sehr gestört 
wird.

Welches Terminalprogramm nimmst du?
Die Programm was du runterlädst ist definitiv für den Atmega16?
#3960903
Lesenswert?

habe ich gerade gemacht und es wurde wieder unterbrochen. nachdem ich 
nochmal geflasht habe, könnte ich keine eingabe machen bzw. hat er nicht 
auf meine Eingaben reagiert:
Reset AVR!
Hallo hier ist der echte Bootloader
Reset AVR!
Hallo hier ist der echte Bootloader
Reset AVR!
Hallo hier ist der echte Bootloader
Reset AVR!
Hallo hier ist der echte Bootloader
Gast #3981026
Lesenswert?

Hallo,

bei mir funktionierts leider nicht mit einem Mega32. Kann man bei putty 
irgendwie ein delay einstellen? Bzw. mit welchem Terminlprogramm (linux) 
kann man eine Verzögerung hinbekommen? Mit GtkTerm scheints nicht zu 
gehen. Trotzdem guter Artikel. Schade dass es nicht läuft.

Viele Grüße
Gast #3981089
Lesenswert?

Hallo,

bei mir funktionierts jetzt auch. Hab die Flusssteuerung raus genommen, 
die Puffer erhöht und die Baudrate (auf 300) runter gesetzt. So ist das 
jetzt zwar erst mal eine Zumutung bei der Nutzung aber es läuft 
grundsätzlich. Jetzt muss das halt noch etwas optimiert werden.
Danke für den Artikel und viele Grüße!
#4047527
Lesenswert?

Hallo Zusammen,

ich habe mehrere Schaltungen mit ATMega 328 und 644 mit diesem 
Bootloader im Einsatz.

Nach einem Jahr ist jetzt bei einem 644 folgendes passiert:

Eine Schaltung lief mehrmals wöchentlich bei jedem Neustart immer sauber 
an, doch nun nach ca. 12 Monaten passiert nichts mehr.

Also die Schaltung ausgebaut (war natürlich nicht so einfach) und in die 
Werkstatt gebracht.
Nach dem Netz Ein meldet sich der Bootloader wie gewohnt einmal, aber 
das Anwenderprogramm wird nicht gestartet. Seit einem Jahr war an der 
seriellen Schnittstelle aber nichts mehr angeschlossen.

Da ich die LockBits so eingestellt habe, das man den Controller nicht 
mehr auslesen kann (Further programming and verification disabled) kann 
ich auch nicht nachsehen, was da nun falsch ist.

Was kann wohl die Ursache dafür sein?
# Controller defekt?
# Spannungsschwankungen? ich schalte die 5V Versorgung bei <4.2V ab
# Fehler im Anwenderprogramm?
# ???

Hat sonst jemand ähnliche Erfahrungen gemacht?

Gruß
Jan
Gast #4061930
Lesenswert?

Ich finde den Artikel sehr gelungen. Die Grammatik ist nicht so schlimm, 
du hast was auf die Beine gestellt, allein das zählt.

Nun zu meiner Frage:

Da ich kein AvrStudio habe(ich benutze Linux) möchte ich wissen wie man 
den Bootloader mit avr-gcc kompiliert.

Hoffe Du kannst mir da n bissl helfen.

Gruss TechChristoph
#4063279
Lesenswert?

AVRMember schrieb:
> Super Artikel :-) thumbsup
> Wirklich schön geschrieben, und sehr informativ.

Danke für die Blumen :)

TechChristoph schrieb:
> Da ich kein AvrStudio habe(ich benutze Linux) möchte ich wissen wie man
> den Bootloader mit avr-gcc kompiliert.
>
> Hoffe Du kannst mir da n bissl helfen.

Unter dem AVRStudio werkt ja auch bloß das avr-gcc mit der Toolchain. 
Insovern müsste nur das Makefile angepasst werden. Ein Linkerparameter 
für die Verschiebung das Linken des Kompilats in den Bootloaderbereich 
muß hinzugefügt werden: -Ttext=0x????
???? ist die Startadresse des Bootloeaderbereichs (s. Artikel)

Unter Linux wirst du sicher schon mit Makefiles arbeiten, da kannst du 
den Parameter mit eintragen...
Gast #4156350
Lesenswert?

Hallo,

danke an Mario G. für den tollen Bootloader Artikel.

Ich bin auf ein kleines Problem gestoßen, sobald ein Programm mit Timer 
über den Bootloader geladen wird hängt sich der Bootloader auf.
Vermutlich weil der Timer vom Programm noch aktiv ist.

Programme ohne Timer funktionieren problemlos.

Johann L. schrieb:
> Das Problem mit "goto 0" ist, daß das kein Reset ist, sondern eben nur
> ein "goto 0". Das initialisiert nicht die Hardware. Andererseits sind
> viele Anwendungen so geschrieben, daß sie von einer initialisierten
> Hardware ausgehen, zB Timer-Initialisierungen oder
> UART-Initialisierungen etc. die |= verwenden beim Belegen von SFRs wo
> sie eigentlich = meinen. Mit einer vor-initialisierten Hardware kann das
> zu Problemen führen.

Gibt es dafür eine einfache Lösung?
#4160912
Lesenswert?

Sebastian schrieb:
> Roman schrieb:
>> > Das Problem mit "goto 0" ist, daß das kein Reset ist
>> Gibt es dafür eine einfache Lösung?
>
> Reset per Watchdog?
> (cli(), Watchdog auf eine kurze Zeit einstellen, Endlosschleife)

Dann hast du das 'Problem', dass du nach einem Reset wieder im 
Bootloader landest. Und das soll ja auch so sein. Selbst wenn in der 
eigentlichen App nichts mehr geht, soll man mittels eines Reset immer 
wieder zumindest in den Bootloader kommen können um eine neue 
Programmversion einspielen zu können.

Zum genannten Problem fällt mir eigentlich nur ein:
Dann muss eben der Bootloader alle von ihm benutzten 
Konfigurationsregister vor dem Sprung in die Applikation wieder auf ihre 
Ausgangswerte zurücksetzen.
So viel benutzt ein Bootloader ja üblicherweise nicht, so dass das 
durchaus handhabbar sein sollte.
#4165094
Lesenswert?

Roman schrieb:
> Ich bin auf ein kleines Problem gestoßen, sobald ein Programm mit Timer
> über den Bootloader geladen wird hängt sich der Bootloader auf.
> Vermutlich weil der Timer vom Programm noch aktiv ist.
>
> Programme ohne Timer funktionieren problemlos.


Vor dem Sprung in den Bootloader sollten man dafür sorgen dass keine 
Timer mehr aktiv sind.
Am Anfang des Bootloaders werden ja auch die Adressen der 
Interrupt-Vektoren in den Bootloader Bereich verschoben:
1
...
2
   /* Interrupt Vektoren verbiegen */
3
    temp = MCUCR;
4
    MCUCR = temp | (1<<IVCE);
5
    MCUCR = temp | (1<<IVSEL);
6
...

und kurz vor dem Sprung zurück ins Programm wieder an die richtige 
Adresse zurück gestellt:
1
...
2
    /* Interrupt Vektoren wieder gerade biegen */
3
    temp = MCUCR;
4
    MCUCR = temp | (1<<IVCE);
5
    MCUCR = temp & ~(1<<IVSEL);
6
...

In welchem Zustand die interruptfähigen Hardware-Elemente des 
Controllers sind, muß der Nutzer selbst festlegen.
Ich könnte mir vorstellen, das ein Verschieben der Interrupt-Vektoren 
mit aktivem Timer Probleme macht..

Ist es dieses Problem was du meinst?
Gast #4178207
Lesenswert?

Hallo Zusammen,

erstmal Vielen Dank, dass du dir die Mühe mit dem Tutorial gemacht hast! 
Ich finde es echt sehr gut gelungen. :)

Bei mir scheint es allerdings leider nicht vollständig zu funktionieren. 
Ich nutze den Bootloader auf einem ATmega2560 und habe ihn dafür etwas 
angepasst, den Hex-Parser habe ich allerdings 1 zu 1 übernommen.
Mir ist nun aufgefallen, dass per Bootloader geflashte Programme nicht 
richtig zu funktionieren scheinen. Es tritt immer wieder unerklärliches 
Verhalten, wie zum Beispiel komische Zeichen im UART auf. Flashe ich 
dasselbe Programm dann direkt, funktioniert alles wie gewollt.

Zum Testen habe ich deshalb ein Programm einmal per Bootloader und 
einmal direkt per JTAG geflasht und beide Male anschließend den Inhalt 
des Flashspeichers ausgelesen. Mir ist dabei aufgefallen, dass drei 
Zeilen der ausgelesenen Hex-Dateien nicht übereinstimmen (den 
Bootloaderteil am Ende des Flash ausgenommen). Es scheint also, dass der 
Bootloader die Hex-Datei nicht richtig flasht bzw. einige Teile nicht 
richtig übernimmt. Aus diesem Grund funktioniert logischerweise das 
geflashte Programm nicht richtig.

Ich weiß nicht, ob es notwendig ist den Code hier zu posten, da 
zumindest der Parser-Teil 1 zu 1 aus dem Tutorial übernommen ist. Falls 
doch kann ich das gerne nachholen.

Ich bin noch ein Anfänger und würde mich über jedwede Tipps oder 
Ratschläge freuen!
Schonmal Danke im Vorraus.
#4178247
Lesenswert?

Dominik schrieb:

> des Flashspeichers ausgelesen. Mir ist dabei aufgefallen, dass drei
> Zeilen der ausgelesenen Hex-Dateien nicht übereinstimmen (den
> Bootloaderteil am Ende des Flash ausgenommen).

Dann stell fest welche das sind bzw. worin sie sich unterscheiden und 
such nach Mustern in den Fehlern. Das können zb auch spezielle Adressen 
sein an denen das zu Flashende steht (zb Page-Grenzen oder dergleichen).


> Ich bin noch ein Anfänger und würde mich über jedwede Tipps oder
> Ratschläge freuen!

Ist kein Argument.
Wer einen Bootloader schreibt muss auch damit rechnen selbst debuggen zu 
müssen. Irgendwann muss man schliesslich ja auch mal die Technik des 
Fehlersuchens lernen. Ein Bootloader ist da jetzt nicht unbedingt ein 
ideales Objekt dafür, aber ... den hast du dir ausgesucht.
Gast #4199036
Lesenswert?

Hallo allerseits,

ich bin gerade dabei, den Bootloader für den 16er ATMEGA umzusetzen. Zum 
Thema "Interrupt Vektoren" verbiegen ist es vielleicht auch wichtig zu 
erwähnen, dass man mit dem Debuglevel aufpassen muss. Sonst wird das 
nichts mit den 4 Taktzyklen.

Ich hoffe, ich habe die Information nicht im Tutorial oder hier im 
Thread übersehen. Falls doch, bitte ich um Nachsicht.

lg Torsten
#4289536
Lesenswert?

hallo,

ich sitze gerade am bootloader-tutorial und komme leider beim letzten 
schritt nicht weiter (die anwendung per bootloader laden).

aber weil ich mir unsicher bin, ob ich bis hierhin alles richtig gemacht 
habe, hier mein bisheriger weg:

ich benutze den im tutorial verwendeten atmega88 mit dem stk500 als 
programmer und als "test-hardware" mit der zweiten seriellen 
schnittstelle, mache das alles unter linux mit avrdude und putty.

nun zu den drei einzelnen etappen:
1. "hallo welt": hier hatte ich zunächst vier probleme/fragen:
a) warum lässt sich die extended fuse nicht auf 0xf8 setzen?
ich habe leider lange dafür gebraucht, aber jetzt bin ich mir recht 
sicher: weil es das beim atmega88 nicht gibt und die fuse auf 0x00 genau 
richtig ist. falls ich da richtig liege, kann man das ja im tutorial 
verbessern, das verwirrt anfänger wie mich etwas).

b) wo trage ich das "-Ttext=0x1800" ins makefile ein?
ich verwende dieses makefile: 
https://www.mikrocontroller.net/wikifiles/b/b6/Makefile

und da gibt es folgenden absatz:

# Linker flags.
#  -Wl,...:     tell GCC to pass this to linker.
#    -Map:      create map file
#    --cref:    add cross reference to  map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)

und den habe ich so erweitert:

# Linker flags.
#  -Wl,...:     tell GCC to pass this to linker.
#    -Map:      create map file
#    --cref:    add cross reference to  map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
LDFLAGS += -Ttext=0x1800

c) uart-library einbinden:
ich habe die library runtergeladen, im gleiche verzeichnis, wie die 
main.c entpackt, es funktionierte aber erst, nachdem ich noch folgendes 
ins main.c geschrieben habe:

#include "uart.c"

d) freq.
der uart hat "was" gemacht, aber immer nur "sonderzeichen". dann habe 
ich folgendes in die main.c geschrieben und dann ging es:

#define F_CPU 8000000

waren diese bisherigen schritte so ok von mir?

2. die test-anwendung:
ich habe auch hier wieder die schritte 1.a)+c)+d) gemacht und dann ging 
es.

3. der echte bootloader:
hier habe ich wieder die schritte 1.a)-d) komplett durchgeführt und der 
bootloader verhält sich, wie beschrieben - bis ich das hex-file eingebe. 
bei linux mache ich das nicht mit der rechten, sondern der mittleren 
maustaste, aber sonst, wie im tutorial mit der dort angegebenen datei. 
der bootloader erkennt, dass es eine hex-datei ist die ersten "punkte" 
erscheinen. nach etwa 10-20 "punkten" stoppt der bootloader und es 
kommen etwa ebenso viele sonderzeichen.

dann wurde mir klar, dass das hex für die anwendung ja nicht meinen 
änderungen an der main.c bneinhaltet (siehe oben 1. c)+d). also bin ich 
in den ordner, den ich erfolgreich für die test-anwendung verwendet habe 
und habe und habe die dort liegende main.hex geöffnet und es mit diesem 
hex-text versucht.
die anzahl der punkte und sonderzeichen waren abweichend aber in der 
selben grössenordnung und sonst war alles gleich.

ich habe dann ewig rumgesucht und nur den hinweis gefunden, es mal mit 
niedrigeren baudraten zu versuchen. das habe ich gemacht und die 
übertragung ist auch merkbar langsamer, aber das ergebnis bleibt das 
gleiche.

ich habe jetzt keine ahnung mehr, wo ich weiter nach einem ansatz suchen 
soll und freue mich über jeden hinweis (auch bestätigung meiner 
bisherigen schritte wären hilfreich, dann weiss ich schnomal, wo ich 
nicht weiter suchen muss).

vielen dank und beste grüsse
a.
#4289733
Lesenswert?

Hallo,

es war von mir sicherlich nicht richtig, dass ich die Gross- und 
Kleinschreibung missachtet habe, ich finde die Antwort stilistisch dann 
aber ehrlich gesagt auch etwas dürftig (Netiquette sagt meines Erachtens 
u.A.: „Vergiss niemals, dass auf der anderen Seite ein Mensch sitzt!“).

Aber egal - hier also nochmal:

Ich sitze gerade am Bootloader-Tutorial und komme leider beim letzten
Schritt nicht weiter (die Anwendung per Bootloader laden).

Aber weil ich mir unsicher bin, ob ich bis hierhin Alles richtig gemacht
habe, hier mein bisheriger Weg:

Ich benutze den im Tutorial verwendeten Atmega88 mit dem Stk500 als
Programmer und als "Test-Hardware" mit der zweiten seriellen
Schnittstelle, mache das alles unter Linux mit avrdude und putty.

Nun zu den drei einzelnen Etappen:
1. "Hallo Welt": Hier hatte ich zunächst vier Probleme/Fragen:
a) Warum lässt sich die Extended Fuse nicht auf 0xf8 setzen?
Ich habe leider lange dafür gebraucht, aber jetzt bin ich mir recht
sicher: Weil es das beim Atmega88 nicht gibt und die Fuse auf 0x00 genau
richtig ist. Falls ich da richtig liege, kann man das ja im Tutorial
verbessern, das verwirrt Anfänger wie mich etwas).

b) Wo trage ich das "-Ttext=0x1800" ins Makefile ein?
Ich verwende dieses makefile:
https://www.mikrocontroller.net/wikifiles/b/b6/Makefile

Und da gibt es folgenden Absatz:

# Linker flags.
#  -Wl,...:     tell GCC to pass this to linker.
#    -Map:      create map file
#    --cref:    add cross reference to  map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)

Und den habe ich so erweitert:

# Linker flags.
#  -Wl,...:     tell GCC to pass this to linker.
#    -Map:      create map file
#    --cref:    add cross reference to  map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
LDFLAGS += -Ttext=0x1800

c) Uart-Library einbinden:
Ich habe die Library runtergeladen, im gleichen Verzeichnis, wie die
main.c entpackt, es funktionierte aber erst, nachdem ich noch folgendes
ins main.c geschrieben habe:

#include "uart.c"

d) Freq.
Der Uart hat "was" gemacht, aber immer nur "sonderzeichen". Dann habe
ich folgendes in die main.c geschrieben und dann ging es:

#define F_CPU 8000000

Waren diese bisherigen Schritte so ok von mir?

2. Die Test-Anwendung:
Ich habe auch hier wieder die Schritte 1.a)+c)+d) gemacht und dann ging
es.

3. Der echte Bootloader:
Hier habe ich wieder die Schritte 1.a)-d) komplett durchgeführt und der
Bootloader verhält sich, wie beschrieben - bis ich das Hex-File eingebe.
Bei Linux mache ich das nicht mit der rechten, sondern der mittleren
Maustaste, aber sonst, wie im Tutorial mit der dort angegebenen Datei.
Der Bootloader erkennt, dass es eine Hex-Datei ist, die ersten "Punkte"
erscheinen. Nach etwa 10-20 "Punkten" stoppt der Bootloader und es
kommen etwa ebenso viele Sonderzeichen.

Dann wurde mir klar, dass das Hex-file für die Anwendung ja nicht meine
Änderungen an der main.c beinhaltet (siehe oben 1. c)+d). Also bin ich
in den Ordner, den ich erfolgreich für die Test-Anwendung verwendet habe 
und habe die dort liegende main.hex geöffnet und es mit diesem
Hex-Text versucht.
Die Anzahl der Punkte und Sonderzeichen waren abweichend aber in der
selben Grössenordnung und sonst war alles gleich.

Ich habe dann ewig rumgesucht und nur den Hinweis gefunden, es mal mit
niedrigeren Baudraten zu versuchen. Das habe ich gemacht und die
Übertragung ist auch merkbar langsamer, aber das Ergebnis bleibt das
gleiche.

Ich habe jetzt keine Ahnung mehr, wo ich weiter nach einem Ansatz suchen
soll und freue mich über jeden Hinweis (auch Bestätigung meiner
bisherigen Schritte wären hilfreich, dann weiss ich schonmal, wo ich
nicht weiter suchen muss).

Vielen Dank und beste Grüsse
A.
#4289777
Lesenswert?

a) Es gibt sehr wohl eine "Extended Fuse" im Atmega88 --> siehe 
Datenblatt http://www.atmel.com/Images/doc2545.pdf --> Seite 286, diese 
Fuse legt die Größe der "bootloader section" fest

b) Dieser Angabe der Position der Section ".text" gehört natürlich zu 
den Linkerflags, ist also bei LDFLAGS gut aufgehoben

c) Du musst das Makefile entsprechend anpassen und ein Target für uart.c 
hinzufügen, siehe z.B. hier 
http://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/

d) das define von F_CPU habe ich nicht explizit erwähnt, aber 
vorausgesetzt. Die uart-Bibliothek benötigt für die Berechnung der 
Baudraten-Timerwerte die Prozessorfrequenz

Generell:
Testanwendung und Bootloader sind zwei verschiendene Programme. Für die 
Testanwendung brauchst du ein eigenes Makefile, welches die Verschiebung 
von ".text" nicht enthält.
#4290284
Lesenswert?

Hallo,

super - vielen Dank für die Antwort.

zu a):
Da habe ich mich dann missverständlich ausgedrückt. Natürlich gibt es 
eine Extended Fuse. Allerdings kann die nicht den Wert 0xF8 annehmen, da 
sie nicht so viele Bits nutzt. Wenn ich mich richtig erinnere, waren es 
nur die unteren drei und da sind 0xF8 und 0x00 gleich. Somit funtioniert 
es auch, wenn ich die Fuses auf 0xF8 setze, weil die Fuses, die gesetzt 
werden können ja richtig sind. Avrdude gibt mir aber eine Fehlermeldung 
aus, weil er versucht alle Bits auszulesen und das geforderte 0xF8 
findet er nicht vor. Also im Ergebnis alles kein Problem, aber es gibt 
eine unnötige Fehlermeldung, wenn man avrdude verwendet.
Ich hoffe, ich habe das jetzt alles richtig und verständlich 
wiedergegeben.

zu c):
Vielen Dank für den Link, das werde ich mir in Ruhe anschauen. Aber 
jetzt schon eine Frage: Mein Weg (Eintragen in die main.c) hat ja 
funktioniert - ist das falsch oder unsauber oder ist das auch OK?

Zum Generellen:
Das mit den zwei unabhängigen Anwendungen habe ich verstanden und sowohl 
der Hallo-welt-Bootlaoder, als auch die Einfach-Anwendung laufen ja 
jetzt problemlos und auch der Echte-Bootloader scheint ja erstmal zu 
machen, was er soll.

Ich stehe jetzt leider an dem Punkt, dass entweder der Bootloader einen 
Fehler macht, wenn er das Hex-File verarbeiten soll oder das Hex-File 
einen Fehler hat und deshalb nicht verarbeitet werden kann. Aber wer der 
beiden jetzt der "Schuldige" ist und wie ich den Fehler dann finden 
kann, da bin ich momentan etwas ratlos und hoffe weiterhin auf Hilfe.

Beste Grüsse
A.
#4345167
Lesenswert?

Hallo Zusammen,

ich habe mehrere Schaltungen mit ATMega 328 und 644 mit diesem
Bootloader im Einsatz.

Hat bisher problemlos funktioniert.

Nun habe ich das Anwendungsprogramm für den ATMeaga 328 etwas erweitert.
Wenn ich das Programm direkt in den Controller schreibe funktioniert es 
wie gewollt.
Lade ich es jedoch via Bootloader, dann macht der Controller permanet 
einen Reset.

Benutze ich für das geänderte Programm eine andere Optimierungs 
Einstellung des Compilers, funtioniert das Programm auch wieder mit dem 
Bootloader.


Ursprungsprogramm:   14282 Byte mit Compiler Optimierung -Os  läuft
geändertes Programm: 14732 Byte mit Compiler Optimierung -Os  läuft 
nicht
geändertes Programm: 16188 Byte mit Compiler Optimierung -O1  läuft


Ich bin da ziemlich ratlos,
kann mir vieleicht jemand weiterhelfen?

Gruß
jan
#4345252
Lesenswert?

Hallo Mario,

ja, ohne Bootloader läuft das Programm.

Ich habe in der Zwischenzeit herausgefunden, das der Fehler auftritt, 
wenn ich 922 Telegramme zum Boatloader schicke.

Wenn mein Programm etwas verkleinere oder vergrößere, dann ist alles 
gut.

Bei 921 und 923 funktioniert alles, bei 922 Telegrammen tritt der Fehler 
auf.

Wie kann ich ein Überlauf - oder Stackproblem erkennen ?

Gruß
Jan
#4345411
Lesenswert?

Überlauf und Stackprobleme sind üblicherweise schwer zu erkennen, da sie 
in undeterministischen Verhalten münden, d.h. es passieren jedes Mal 
andere Fehler. Da der Bootloader eigentlich relativ einfach gestrickt 
ist könnte ich mir vorstellen das auch ein deterministisches Verhalten 
auftreten könnte. Es passiert ja immer das gleiche. Hast du dir mal das 
922 Telegramm angeschaut? Du meinst mit "Telegramm" doch sicher eine 
Hex-Zeile, oder?
Häng doch mal dein Hex-File dran...
#4345553
Lesenswert?

Im Hex-File  922_telegramme.hex sehen die Zeilen 901/902 irgendwie 
merkwürdig aus (mit Notepad++):

...
900 :103830006291AE17BF07C8F30895DC01CB01FC010C
901 :10384000F999FECF06C0F2BDE1BDF89A319600B4F9
902 :0E3850000D9241505040B8F70895F894FFCF04
903 :10385E00FF9B03FF0106040101019A02D00700003D
904 :10386E0001FFFFFFFF20B573004300562030312EBD
905 :10387E003236202020000000000000000000000171
...



Jan
Gast #4429265
Lesenswert?

Hi Mario,

das Tutorial gefällt mir sehr gut - danke für die Arbeit!
Eine Anmerkung und eine Frage:

- Vielleicht nimmst du diesen Thread in die Links mit auf
- Im "Hallo Welt Bootloader"-Teil steht folgende Anmerkung, die etwas 
verwirrend ist:

"Achtung! Bug im Quellcode! Serielle Schnittstelle funktioniert nicht 
mehr wenn es als Bootloder (mit Addr 0x0180 geflasht wird), bei 0x0000 
funktioniert die UART aber es ist natürlich keine Bootloader Funktion 
gegeben (Atmega8)"

Wie ist das jetzt gemeint? Müsste da 0x1800 stehen wahrscheinlich? Ich 
habe obigen Hallo-Welt BL ausprobiert und an 0x1800 (bzw. beim 328p dann 
0x7800) funktioniert UART so halb: Der Bootloader macht kein TX, also 
gibts keine Info auf dem Terminal. Zeichen empfangen kann er aber 
anscheinend schon (habe mit Blinksequenzen an einer Debug LED gesehen: 
3x blinken bei Bootloader Start (also auch nach "q" Eingabe und Togglen 
sonst). Sollte UART insgesamt tatsächlich nicht funktionieren, wäre er 
ja an sich offensichtlich obsolet - also: wie ist das gemeint?

UART Ausgabe wäre ja schon noch schön - ist der von dir erwähnte Bug 
denn bekannt? --> Oder geh ich einfach erstmal weiter im Tutorial 
Richtung "echtem" Bootloader und da gibts dann keine Probleme?

Viele Grüße
Christian
Gast #4429586
Lesenswert?

Oh, Asche auf mein Haupt - TX des Atemgas war am falschen Pin des FTDI 
verbunden. Jetzt klappt alles. Bleibt nach wie vor (und jetzt erst 
recht) die Frage, wie die Anmerkung mit dem Bug zu verstehen ist.
Gast #4527371
Lesenswert?

Hallo Dominik,

das Problem das du beschreibst habe ich aktuell auch, es tritt bei mir 
immer nach dem Schreiben einer Page auf. Es werden die Daten in der 
nächsten Zeile nach dem Schreiben der Page nicht geschrieben, bzw. 
teilweise wird quasi die übernächste Zeile geschrieben.
Beim ATMega2560 sollte eine Page auch 256 Byte lang sein, dort scheint 
der Fehler aufzutreten.

Die Daten werden korrekt empfangen aber aktuell suche ich noch den 
Fehler, wenn ich ihn finde poste ich ihn.


Gruß,
Martin
#4645241
Lesenswert?

UART-Bug im Hallo Welt BL schrieb:
> - Im "Hallo Welt Bootloader"-Teil steht folgende Anmerkung, die etwas
> verwirrend ist:
>
> "Achtung! Bug im Quellcode! Serielle Schnittstelle funktioniert nicht
> mehr wenn es als Bootloder (mit Addr 0x0180 geflasht wird), bei 0x0000
> funktioniert die UART aber es ist natürlich keine Bootloader Funktion
> gegeben (Atmega8)"

Ich weiß nicht wer das ins Wiki eingetragen hat, ich nicht. Ich habe es 
mit dem Hinweis auf das Umschalten der Interruptvektoren wieder 
entfernt. Man muß unbedingt darauf achten dass das richtige SFR für das 
Umschalten verwendet wird, dann klappt es auch mit UART & Co...
#7923296
Lesenswert?

Hallo zusammen. Ich weiß, der letzte Beitrag ist schon steinalt. Vielleicht hilft es aber trotzdem jemand. Ich habe mich nun mehrere Tage mit dem Fehlverhalten dieses Bootloaders auf einem ATMEGA328p herumgeschlagen. Endlich ist mir die Erleuchtung gekommen. Mein Problem war, dass am Ende meiner .hex-Dateien immer wieder einmal Daten in einer Zeile standen, die über die Grenze einer "page" gingen. Zum Schluss wurde dann noch unter "... schreibe Restdaten..." die erste Page wieder überschrieben. Anbei haftet nun meine korrigierte Version. Die funktioniert zumindest mit den .hex-Dateien, die der originale Bootloader nicht ordentlich schreiben wollte.

Viele Grüße Mario K.

Angehängte Dateien:
#7923328
Lesenswert?

So, jetzt muss ich noch eine Änderung hochladen. Nach meinem unsachgemäßen Eingriff hat der Bootloader die Adresse am Zeilenanfang überhaupt nicht mehr beachtet, wenn die zuvor gesendete Zeile genau eine Page aufgefüllt hat. Ich denke, dass ich das jetzt behoben habe. Außerdem sollten die Einrückungen jetzt wieder passen. Vielleicht kann sich das aber noch jemand mit mehr Erfahrung anschauen.

Viele Grüße Mario K.

Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren