Forum: Compiler & IDEs AVR Bootloader in C - Artikel


von Mario G. (mario)


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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Super Artikel! Danke!

von Mario G. (mario)


Lesenswert?

So ich habe jetzt den letzten Schliff am Artikel gemacht, jetzt ist er 
erstmal fertig. Ich hoffe noch auf ein bischen Feedback...

von Turmel (Gast)


Lesenswert?

Scheussliches Deutsch.
Krankenschwestern-Wir.

von Martin J. (bluematrix) Benutzerseite


Lesenswert?

abo

von Mario G. (mario)


Lesenswert?

@Turmel:

es sollte nicht so stocksteif rüberkommen. Ich fands lustig so.

von Martin (Gast)


Lesenswert?

Guter Artikel Mario :)

von Mario G. (mario)


Lesenswert?

Danke :)
Ich hoffe ich habe etwas Licht ins Dunkel der Bootloaderei gebracht...

von Turmel (Gast)


Lesenswert?

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.

von Mario G. (mario)


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...

von Turmel (Gast)


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.

von Turmel (Gast)


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.

von Oliver (Gast)


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

von U.R. Schmitt (Gast)


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. :-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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

von Martin (Gast)


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.

von Mario G. (mario)


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

von Mario G. (mario)


Lesenswert?

Wäre schön wenn mal jemand den Bootloader ausprobiert :)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Turmel schrieb:
> Aber das mir jemand unterstellt ich würde seinen lockeren Stil meinen,
       ^^^                       ^
       dass                      ,

> 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.

4 Fehler in einem Satz. Glashaus, Steine.

von Johann L. (gjlayde) Benutzerseite


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.

von Mario G. (mario)


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.

von Olli (Gast)


Lesenswert?

Hallo,

flash_cnt sollte vom Typ unsigned int sein, da SPM_PAGESIZE z.B. auf 
einem Atmega644 256 ist und von flash_cnt somit nie erreicht werden 
kann.

Grüße,
Olli

von Mario G. (mario)


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.

von Mario G. (mario)


Lesenswert?

@ Olli:
habe ich geändert, danke für den Hinweis.

von Mario G. (mario)


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

von Mario G. (mario)


Lesenswert?

@ Johann L.:
Kennst du eine elegante Möglichkeit wie man die Fuses vom Bootloader aus 
setzten kann?

von Peter D. (peda)


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

von Peter D. (peda)


Lesenswert?

Mario Grafe schrieb:
> Kennst du eine elegante Möglichkeit wie man die Fuses vom Bootloader aus
> setzten kann?

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.


Peter

von Johann L. (gjlayde) Benutzerseite


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)

von Mario G. (mario)


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?

von Karl H. (kbuchegg)


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.

von Mario G. (mario)


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 :)

von delay (Gast)


Lesenswert?

Hallo,
kleiner Tipp von mir, statt in jedem case Zweig Xoff und wieder Xon zu 
schicken kannst du das auch vor und nach dem Switch machen. Danke für 
den Artikel.

von Mario G. (mario)


Lesenswert?

delay schrieb:
> Hallo,
> kleiner Tipp von mir, statt in jedem case Zweig Xoff und wieder Xon zu
> schicken kannst du das auch vor und nach dem Switch machen. Danke für
> den Artikel.

Da habe ich auch schon dran gedacht. Müßte man mal probieren. Könnte 
sein das die Kommunikation dann langsamer wird da der AVR ständig den 
Empfang stoppt.

von delay (Gast)


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.

von Christoph P. (sirbundy)


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).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Christoph P. schrieb:
> 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?

Dimit ginge zumindest kein XON/XOFF mehr, weil dann alle Hex-Werte 
00..ff belegt wären. Zudem hat man so ne kleine Konsistenzpfüfung via 
Prüfsumme.

von delay (Gast)


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)

von Mario G. (mario)


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.

von Mario G. (mario)


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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Mario Grafe schrieb:

> Vielleicht hat ja jemand Lust das mal zu implementieren.

Am besten gleich mit flex/bison :o)

von delay (Gast)


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).

von Christoph P. (sirbundy)


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 ;)

von Olli (Gast)


Lesenswert?

Hi,

ich finde den Artikel zum Bootloader echt klasse. Kommt dann demnächst 
noch die Erweiterung auf den STK500-kompatiblen Bootloader?

Grüße,
Olli

von Jörg (Gast)


Lesenswert?

Danke für den informative Artikel!

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.

von Jörg (Gast)


Lesenswert?

Noch eine Kleinigkeit: Die Screenshots vom Terminal stimmen zum Teil 
nicht mit den Ausgaben des Quellcodes überein. Stichwort: Gemischtes 
Englisch - Deutsch.

von Mario G. (mario)


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.

von manni (Gast)


Lesenswert?

Hallo, geht das auch ohne AVR-Studio , nur mit Winavr und dann rüber?

Gruss

von Mario G. (mario)


Lesenswert?

manni schrieb:
> Hallo, geht das auch ohne AVR-Studio , nur mit Winavr und dann rüber?

Selbstverständlich! Letztenendes steckt ja auch nur WinAVR dahinter. Du 
brauchst allerdings ein makefile, in dem du die Verschiebung der Sektion 
.text als Option -Ttext=0xXXXX mitgeben kannst.

von Lutz (Gast)


Lesenswert?

Hallo Mario,

super gemacht, vielen Dank!

von Mario G. (mario)


Lesenswert?

So, die alten Screenshots von Putty für den "Hallo Welt"-Bootloader habe 
ich aktualisiert. Die waren nicht mehr konsistent.

von Christoph P. (sirbundy)


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?

von Mario G. (mario)


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?

von Christoph P. (sirbundy)


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
}

von Christoph P. (sirbundy)


Lesenswert?

Ok, ich rudere zurück. Wortadressierung mittels
1
appStartAddress /= 2;
 und anschließender Übergabe
1
start_application = (void *) (uint16_t) appStartAddr;
 funktioniert scheinbar doch 8-)

von Mario G. (mario)


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?

von Christoph P. (sirbundy)


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-)

von Mario G. (mario)


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.

von Karl H. (kbuchegg)


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.

von Christoph P. (sirbundy)


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.

von Karl H. (kbuchegg)


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

von Christoph P. (sirbundy)


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 ;)

von Christoph P. (sirbundy)


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
}

von Web-Applikator (Gast)


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.

von Christoph P. (sirbundy)


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 ;)

von Martin J. (bluematrix) Benutzerseite


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

von Christoph P. (sirbundy)


Lesenswert?

Martin J. schrieb:
> 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?

Natürlich, wieso auch nicht?
Wie, steht bspw. hier: 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#EEPROM

von Felix N. (felix188)


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

von Mario G. (mario)


Lesenswert?

Hallo Felix,

nein das ist mir schleierhaft. Die Beispiele wurden mit einem Atmega88 
getestet. Da der Atmega128 aber einen genügend großen Bootloaderbereich 
hat, sollte es trotzdem gehen (nach richtiger Fuse-Konfiguration).

Hast du es mal ausprobiert?

von Mario G. (mario)


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....

von Ingeborg W. (helene2011)


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

von Ingeborg W. (helene2011)


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

von Gunter H. (heuckeg)


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

von Stefan E. (sternst)


Lesenswert?

Gunter Heuckeroth schrieb:
> Die jmp's sind alle 4, und nicht nicht, wie notwendig, 2 Byte.

Dann hast du wohl beim Linken den falschen Controller angegeben.

von Gunter H. (heuckeg)


Lesenswert?

Hallo Stefan,

also, dann benutzt AvrStudio + Eclipse, wenn beim Linken 
"-Ttext=0x1F000" angegeben ist, einen anderen Controller als wenn diese 
Option nicht angegeben ist....

Hast Du es selbst mal probiert?

Gunter

von Stefan E. (sternst)


Lesenswert?

Gunter Heuckeroth schrieb:
> "-Ttext=0x1F000"

Du benutzt also einen Controller mit 128k Flash. Wie kommst du darauf, 
dass die Vektoren 2 Bytes lang sein müssen? Die sind bei deinem 
Controller mit 100%iger Sicherheit 4 Bytes (2 Words) groß.

von Gunter H. (heuckeg)


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

von Unwissender III. (Gast)


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?

von Gunter H. (heuckeg)


Lesenswert?

Hallo Unwissender ;-)

Nach einem kurzen Überfliegen des Datenblattes des 8515:
Es gibt kein "Boot"-Flash-Bereich, in dem ein Bootloader stehen könnte.
Das Teil kann nur per "parallelem" Programming oder "seriell" geflasht 
werden.

Gruß,
Gunter

von EW (Gast)


Lesenswert?

Hallo Mario,

wirklich guter Artikel.
Ich würde vorschlagen, den Bootloader vom Arduino Board auch unter 
Referenzen / Links mit aufzulisten. Der geht noch einen Schritt weiter.
Link: 
https://github.com/arduino/Arduino/blob/master/hardware/arduino/bootloaders/atmega/ATmegaBOOT_168.c

Gruß
EW

von Mario (Gast)


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

von Snatch (Gast)


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

von Mario (Gast)


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?

von CheckR (Gast)


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

von Karl J. (kjacobs)


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

von Karl H. (kbuchegg)


Lesenswert?

Karl Jacobs schrieb:
> Hallo Mario,
> ich hab bestimmt was noch nicht verstanden:

Ich würde sagen: Das hast du im Code richtig gesehen.

von Karl J. (kjacobs)


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

von Karl J. (kjacobs)


Angehängte Dateien:

Lesenswert?

und hier wäre dann mein Vorschlag, die oben beschriebenen Probleme zu 
beheben, als Erweiterung von Marios Code, mit Kommentaren. Der Code ist 
aber ungetestet, ich weiß gar nicht, ob so was hier erlaubt ist... Er 
sollte jetzt auch hex-Files schlucken, in dem die Adressen kreuz und 
quer gehen.
Grüße,
Karl

von Karl J. (kjacobs)


Angehängte Dateien:

Lesenswert?

eine Zeile war verrutscht.
Karl

von Mario G. (mario)


Lesenswert?

Hallo Karl,
du hast richtig gelesen. Adresssprünge und Code >64K wurden bisher nicht 
berücksichtigt. Dies ist auch am Ende des Tutorials vermerkt.
Mario

von Karl J. (kjacobs)


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

von Troll gesichtet (Gast)


Lesenswert?

haha

von no member of AVRFreaks.net (Gast)


Lesenswert?

haha³ - wo isser denn, der Code?

von Karl J. (kjacobs)


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

von no member of AVRFreaks.net (Gast)


Lesenswert?

Karl Jacobs schrieb:
> Die downloads sind nur sichtbar, wenn man bei avrfreaks angemeldet ist,
> was aber ja keine Hürde sein sollte.
Sign Up? -> Fehlanzeige...

von Karl J. (kjacobs)


Lesenswert?

no member of AVRFreaks.net schrieb:
> Sign Up? -> Fehlanzeige...

Lieber Gast, ich verstehe diese Meldung zwar nicht, aber wenn Du hier 
angemeldet wärest, könntest Du mir eine Nachricht schicken und bekämst 
den code direkt von mir. Ich möchte allerdings nicht das Forum hier 
vollmüllen, das ist daher mein letzter post zu diesem Thema.

von Morxi (Gast)


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.

von Ollo (Gast)


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

von Tobias G. (t-g-laeser)


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

von Mario G. (mario)


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

von otman (Gast)


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?

von Mario (Gast)


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

von peter (Gast)


Lesenswert?

Hallo,
toller Artikel! Trotzdem habe ich noch eine Anmerkung:
Bei einigen Typen - zumindest beim ATmega32 - sind die IVSEL und IVCE 
bits nicht im MCUCR, sondern im GICR.
Gruß,
Peter

von Mario G. (mario)


Lesenswert?


von Jan M. (jan91)


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

von Mario G. (mario)


Lesenswert?

Hallo Jan, der richtige weg ist die state-machine zu erweitern. Ich 
wollte das sowieso mal noch machen. Ich bin die Woche leider unterwegs. 
Ich melde mich Ende der Woche nochmal.

von Jan M. (jan91)


Lesenswert?

Hallo Mario,

hast Du evtl. schon Zeit gehabt, die state-machine zu erweitern?

Ich bin da bisher leider kläglich gescheitert.

Gruß
Jan

von Mario G. (mario)


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...

von Jan M. (jan91)


Lesenswert?

Da ich hier ein Testboard mit einem ATmega 1284P laufen habe, könnte ich 
das Testen übernehmen, wenn es den Sinn macht.

Gruß
Jan

von Mario G. (mario)


Lesenswert?

Das wäre eine Variante. Kannst du bitte mal ein Hex-File > 64K erzeugen 
und schauen welche Record Typen vorkommen (ausser 0 und 1)?

von Mario G. (mario)


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..

von Jan M. (jan91)


Lesenswert?

Hallo Mario,

Super, ich teste das sobald ich wieder zu Hause bin, evtl. Freitag, 
spätenstens am nächsten Montag.

Danke

Jan

von Mario G. (mario)


Lesenswert?

So ich habe jetzt noch die Auswertung des Record Typ 04 eingefügt und 
ein paar kleine Fehler beseitigt.

von Jan M. (jan91)


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

von Karl H. (kbuchegg)


Lesenswert?

Jan Müller schrieb:
> Hallo Mario,
>
> beim compilieren bekomme ich folgende Warnung:
>
> /* Berechnen der Offsetadresse */
> hex_addr_offset = (uint32_t)(hex2num(hex_buffer, 4) << 16);

Der Cast ist an der falschen Stelle. Das muss lauten
1
   hex_addr_offset = ((uint32_t)hex2num(hex_buffer, 4)) << 16;

von Mario G. (mario)


Lesenswert?

Karl Heinz schrieb:
> Der Cast ist an der falschen Stelle. Das muss lauten
>    hex_addr_offset = ((uint32_t)hex2num(hex_buffer, 4)) << 16;

...geändert. Danke.

von Mario G. (mario)


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.... :)

von Jan M. (jan91)


Angehängte Dateien:

Lesenswert?

Hallo Mario,

ich habe das heute noch mal ausprobiert:

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.

Gruß
jan

von Mario G. (mario)


Angehängte Dateien:

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

von isidor (Gast)


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 ....

von Mario G. (mario)


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...

von Jan M. (jan91)


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

von Mario G. (mario)


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...

von Jan M. (jan91)


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

von Mario G. (mario)


Lesenswert?

Hmm, ich muß mal schauen ob ich irgendwie ein Testvehikel auftreibe.
Benutzt du Putty als serielle Konsole?
Kommt irgendwann mal die Ausschrift "J"?

Vermutlich gibt es noch ein Problem in der Addressberechnung...

: Bearbeitet durch User
von Jan M. (jan91)


Lesenswert?

ja, ich nutzte Putty zum Testen und ich sehe einmal ein "J" als Antwort.

von Loocee L. (loocee)


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.

: Bearbeitet durch User
von Julius F. (julz)


Lesenswert?

Sehr Guter Artikel, Danke

von Loocee L. (loocee)


Lesenswert?

Julius Faust schrieb:
> Sehr Guter Artikel, Danke

Kannst ja mal austesten und berichten ob das Patchen funktioniert.

Bemerkungen gibt es auch hier:
Beitrag "avr-libc 1.8.1 freigegeben"

: Bearbeitet durch User
von Mario G. (mario)


Angehängte Dateien:

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...

von Jan M. (jan91)


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

von Karl H. (kbuchegg)


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.

von Mario G. (mario)


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..

von Mario G. (mario)


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...

von Mario G. (mario)


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...

von DF9FW (Gast)


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?

von mario (Gast)


Lesenswert?

Schau mal ob du die Flusssteuerung (xon/xoff) eingeschaltet hast. Sie 
muss aktiviert sein.

von DF9FW (Gast)


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.

von mario (Gast)


Lesenswert?

Richtig. Es kann trotz xonn/xoff passieren das es nicht klappt, da beim 
permanenten empfangen permanent die empfangs-isr-routine zuschlägt...

von Mario G. (mario)


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.

von DF9FW (Gast)


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!

von Jan M. (jan91)


Lesenswert?

Hallo Mario,

bist Du vielleicht zwischenzeitlich mit dem Bootloader >64K 
weitergekommen?


Gruß
jan

von Mario G. (mario)


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...

von Eddy_C (Gast)


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

von Eddy_C (Gast)


Lesenswert?

..hat sich erledigt ich hab fehler in code gehabt.

:-)

von Eddy C. (eddy_c)


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

von Mario G. (mario)


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

von Eddy C. (eddy_c)


Lesenswert?

...mach weiter so ist vollkommen in Ordnung :-)

Guten Rutsch
Eddy

von Tetef (Gast)


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

von Leandro L. (tetef)


Angehängte Dateien:

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??

von Leandro L. (tetef)


Lesenswert?

hallo zusammen,

gelöst

Der fehler lag beim Kopieren. Es war mein Fehler.

GICR = temp & ~(1<<IVSEL);
anstatt

GICR = temp | (1<<IVSEL);

Ciao

von Mario G. (mario)


Lesenswert?

Schön das sich manche Probleme alleine lösen...

war im internetfreien Urlaub... :)

von Leandro L. (tetef)


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)

von Mario G. (mario)


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).

von Leandro L. (tetef)


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.

von Mario G. (mario)


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?

von Leandro L. (tetef)


Lesenswert?

1. ich benutzte putty.
2. Die Programme sind für Atmega16.

ich benutze jetzt Baudrate 19200 und habe die delays vom 100 auf 10 
gesetzt.

es hat nur einmal geklappt und dann niemehr

von Mario G. (mario)


Lesenswert?

Leandro Leandro schrieb:
> ich benutze jetzt Baudrate 19200 und habe die delays vom 100 auf 10
> gesetzt.
>
> es hat nur einmal geklappt und dann niemehr

Versuch mal den bootloader neu zu flashen. Geht es dann beim ersten mal?

von Leandro L. (tetef)


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

von Leandro L. (tetef)


Lesenswert?

ich habe jetzt die Baudrate auf 19200 gelassen und die delay auf 2 
gesetzt.
Es scheint, es funktioniert.

von Markus (Gast)


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

von Markus (Gast)


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!

von Jan M. (jan91)


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

von TechChristoph (Gast)


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

von AVRMember (Gast)


Lesenswert?

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

von Mario G. (mario)


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...

von Roman (Gast)


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?

von Sebastian (Gast)


Lesenswert?

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)

von Karl H. (kbuchegg)


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.

von Mario G. (mario)


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?

: Bearbeitet durch User
von Dominik (Gast)


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.

von Karl H. (kbuchegg)


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.

: Bearbeitet durch User
von Torsten O. (Gast)


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

von An F. (hallofrage)


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.

von Bernd (Gast)


Lesenswert?

Keine Netiquette - keine Hilfe.

von An F. (hallofrage)


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.

von Mario G. (mario)


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.

von An F. (hallofrage)


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.

von Jan M. (jan91)


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

von Mario G. (mario)


Lesenswert?

Funktioniert das neue Programm wenn du es direkt auf den Controller 
"flashst", also ohne Bootloader?

Die Bedeutung der Compileroptimierungen kann man hier nachlesen:
AVR-GCC-Codeoptimierung

In beiden Fällen (-Os und -O1) wird die Größe optimiert. Gibt es ein 
Überlauf- oder Stackproblem, was evtl. in einer Variante wegoptimiert 
wird?

von Jan M. (jan91)


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

von Mario G. (mario)


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...

von Jan M. (jan91)


Angehängte Dateien:

Lesenswert?

Hier mal die beiden Hex-Files.

Beide mit den gleichen Einstellungen compiliert.

Nur einen Delay Befehl hinzugefügt, um auf 923 telegramme zu kommen.
Und dann funktioniert es auch via Bootloader.

Direkt auf den Controller programmiert laufen beide.

Gruß

Jan

von Jan M. (jan91)


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

von Mario G. (mario)


Lesenswert?

Es ist etwas seltsam, das die Länge "0x0E" vorkommt...aber sonst ok.
Es wäre noch interessant, ob irgendwelche Sprünge (Type 02, 05) 
vorkommen. Das wird bislang nicht abgefangen.

von UART-Bug im Hallo Welt BL (Gast)


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

von UART-Bug im Hallo Welt BL (Gast)


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.

von Martin (Gast)


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

von Mario G. (mario)


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...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.