Forum: Compiler & IDEs AVR-GCC, Flash teilweise ersetzen (Bootloader?), die Zweite


von Jürgen S. (jsachs)


Lesenswert?

Hallo,

Etwas Länger, sorry.

Erst kurz die Beschreibung worum es geht:
Ich will mich in ein existierendes Bussystem einklinken, das klappt auch 
schon Prima. Es gibt fertige Software für Programmierung und Firmware 
Update. Die möchte ich auch nutzen um komplett Transparent zu bleiben.
Bis auf das Firmwareupdate habe ich alles im Griff. Das Chart im Anhang 
zeigt wie ich mir das denke.

Nun zu meinee Aufgabenstellung:
Die eigentliche Busanbindung ist für jedes "Geräte" gleich, ob Taster, 
Bediengerät, oder Aktor. Das Programm ist im Moment in 2 Teile 
Unterteilt, die im Moment aber in einem Stück entwickelt und geflash 
werden.
Teil 1 ist der Protokoll Bereich (PA im Anhang) und User Bereich (UA in 
Anhang, aber nicht im Chart vorhanden).
Nun würde ich gerne UA und PA getrennt entwickeln und auch flashen 
können. Also PA und UA getrennt flashbar. Damit das geht muß ich für den 
UA Bereich eine Sprungtabelle anlegen und diese beim Start vom PA 
Bereich laden. Da nicht genug Speicher vorhanden ist um das im Ram 
komplett Zwischenzuspeichern, dachte ich an folgendes vorgehen:
- Wird der UA Bereich neu geflashed, sorge ich nur dafür, das die 
Sprünge aus der PA nicht ins leere gehen (Pseudo Function Table 
erzeugen), Lösche den UA Bereich und schreibe die in Häpchen von 128 
Byte empfangene Daten in den UA Bereich. Danach einen Reset (Details 
siehe Anhang).

- wird der PA Bereich neu geflashed, brauche ich einen Zwischenspeicher, 
da der PA Bereich ja die Daten noch empfangen muß. Daher gleiches 
vorgehen wie beim UA, PA wird also in UA gespeichert, und nach dem Reset 
vom Bootloader in den PA kopiert. Anschliesend muß wieder der UA 
geflashed werden, das ist aktzeptabel ! Hierdurch habe ich IMMER eine 
Funktionierende PA, geht der Empfang schief muß ich Ihn ja nicht 
kopieren !

- Einen Ersatz des Bootloaders strebe ich nicht an.

So, nun meine Fragen: :-) (Einfach nur die Nummern übernehmen bei der 
Antwort)
1) Der Bootloader ist so klein, das er vermutlich bequem in 512 Byte 
passt, daher kann ich den ja als "normales Programm" entwickeln und 
einfach den kompletten ".txt" in den Bootloader verschieben. Oder ist es 
besser das trotzdem als "BOOTLOADER section im Programm zu definieren ?

2) Vermutlich ist es das beste immer im Bootloader zu starten, 
Gültigkeit der PA zu prüfen und dann mit eine "jmp 0000" in Programm zu 
springen und dadurch den PA zu starten. Müsste ich das was beachten ? 
Der Bootloader hat ja schon Stack usw Initialisert. Oder wird das dann 
eben nochmal vom PA erledigt und überschrieben.

3) PA wird ja wieder als "Normales" Programm entwickelt und der 
Einfachheit halber per ISP geflashed. Überschreibe ich mir dann nicht 
gleich wieder meinen Bootloader beim Programmieren über ISP ?

4) den UA Bereich will/muss ich ja dann ohne jegliche Initilisierung und 
main Funktion schreiben, ist also nur eine Funktionssammlung. Wie gebe 
ich das beim gcc an ?

5) ein teilweises Löschen des Flash und neu schreiben sollte ja kein 
Problem sein laut Datenblatt. Ich definier dann eben das die PA immer 
bei 0x0000 steht, die PA bei 0x0400 und der Bootloader steht ja immer am 
Ende. Muss ich hierbei was beachten ?

6) gibt es eine einfach Möglichkeit, statt eine HEX Datei zum flashen 
eine Binäre Datei zu erstellen, die danach 1:1 den zu Programmierenden 
Daten entspricht ? Das geht vermutlich mit "obj-copy" ?

7) Ist das so überhaupt machbar ?

8) Wie lege ich die Sprungtabbelle der Funktionen vom PA an den Anfang 
der zu flashenden Datei. Das ist ja mein einziger Fixpunkt.

9) Meine Funktionszeiger in der Sprungtabelle für den PA müssen ja 
relativ zum Anfang des PA sein, wo der PA später im Flash steht weis der 
gcc ja nicht ! Muß ich da was beachten, oder wäre das automatisch so ?



Theoretische Speichermap:

----------------------
| PA Bereich         | 0x0000
|                    |
|                    |
|                    |
----------------------
| UA Sprungtabelle   | 0x0400
----------------------
| UA Bereich         |
|                    |
|                    |
|                    |
|                    |
----------------------
| Bootloader         | 0x????
----------------------


Ich hoffe Ihr könnt mir da ein paar Tips geben.
Als Proz kommt im Moment ein atMega8515 zum Einsatz.

Danke
Juergen

von Martin Thomas (Gast)


Lesenswert?

zu 1) Einfacher ist es, vor Allem wenn man Interrupts im Bootloader 
benötigt, die Startaddresse von .text zu verschieben und keinen extra 
"Bootloader"-Section einzuführen.

2) Normalerweise ist nicht viel zu beachten, die Stack-Intitialisierung 
wird ja im "PA"-Startupcode nochmals gemacht. Man sollte jedoch 
sicherstellen, das man SFRs, die im Bootloader vom Reset-default 
abweichend eingestellt werden vor "JMP 0" wieder auf Reset-Werte 
zurücksetzt. Das spart Sucherei in der Anwendung, falls jemand anderes 
diese programmiert und davon ausgehen, das beim Start alle Register auf 
Reset-Default stehen.

3) Üblicherweise wird bei ISP vorher ein Chip-Erase ausgelöst, um den 
Flash-Speicher auf "alles 0xff" zu initialisieren. Der Bootloader wird 
somit auch gelöscht. Abhilfe vielleicht mit einem ISP-Programm, das nur 
die benötigten Speicherbereiche initialisiert - ist mir aber keines 
bekannt.

4) kann ich nicht wirklich viel zu schreiben, bei AVR nie gemacht. 
Testweise den Objectcode mit -nostartupfiles linken und sich map-files 
und disassmbly der elf-Datei anschauen.

5) ist abhängig davon, wie man den Bootloader und die Ansteuersoftware 
des Bootloaders implementiert. Beachtenswert ist vielleicht (aber 
offensichtlich), dass man die beiden Bereich bei Page-Bounderys 
(Seitenaddresse) trennt.

6) im Makefile kann man das Format schon einstellen und so direkt 
"passend" von elf nach ihex oder binary konvertieren. Im nachhinein 
objcopy -I ihex -O binary rein.hex raus.bin.

7) Erscheint mit machbar. Sind wahrscheinlich auch nur ein paar Zeilen 
im Quellcode, Makefile und evtl. eigenem Linkerscript, aber düfte 
einiges an Zeit kosten alles "richtig" einzustellen.

8) Festlegen von Speicheraddressen für Daten funktioniert meines Wissens 
"sauber" in dem man die Sprungtabelle einer memory-section zuweist, für 
die man dem Linker die Addresse angibt. Evtl. mit eigenem Linker-Script 
auf Grundlage der standard Linker-Scripte.

9) Der Programmteil, der die Funktionen bereitstellt die in der 
Sprungtabelle eingetragen sind, kennt auch die Addressen und kann diese 
entspechend eintragen. Sollt also funktionieren.

Bin nicht sicher, ob ich die Aufgabenstellung 100% verstanden habe, aber 
hoffe, die Antworten helfen zumindest ein wenig weiter.

Martin Thomas

von Jürgen S. (jsachs)


Lesenswert?

Hallo, erst mal danke für die Antworten.

4 ?) Ok, sehe ich mir an. Weis jemand zufällig wie man das macht ?

8+9 ?) Kannst Du mir das etwas näher Erklären ? Das hab ich nicht ganz 
verstanden !

1) Ok, ich verschiebe die .text
2) Mit SFRs meinst Du vermutlich die Interrupt und Controll Register, jo 
Sehr gute Idee
3) Hmm, das wird problematisch. Den Bootloade rladen ist ja Ok, aber 
einmal muß ich das PA und den Bootloader haben.... Da muß ich mir was 
überlegen. 1. Bootloader, dann PA, dann ist aber wieder Bootloader 
weg... Grübel...
5) Ja Page bounderies ist klar, danke für den Hinweis
6) Super das hab ich gesucht
7) Ja leider, deswegen hab ich hier auf Hilfe gehoft

Gruss
Juergen

von Martin Thomas (Gast)


Lesenswert?

Versuch "näherer" Erklärung zu 8:
Nur ein paar Stichworte zum Linken an einer festgelegten Addresse: Die 
Sprungtablle (das Array mit Funktionszeigern) versieht man mit einem 
section-attribute (vgl. gcc-Manual). Im Linker-Skript kann man dieser 
section eine feste Addresse zuweisen (vgl. GNU Linker-Manual).

zu 9:
Wenn in UA die Funktionen der Sprungtabelle implementiert sind, sind 
deren Addressen für die Einträge in der UA-Sprungtabelle beim Linken von 
UA bekannt. Aber an der Stelle mag ich die Aufgabe falsch verstanden 
haben, da ich dabei kein Problem erkenne.

zur 3:
Man programmiert zuerst den Bootloader per ISP und legt dann den 
ISP-Progammer zur Seite. Der Bootloader wird so implementiert, dass PA 
und UA getrennt voneinander in den entsprechenden Speicherbereich 
programmiert werden können. Evtl. die Programmierfunktion für einen der 
Bereiche per Bootloader schützen, falls der Endanwender nur den anderen 
Bereich ändern darf (z.B. nur einmal aufrufbar machen, Bootloader prüft 
ob einige aufeinanderfolgende Speicherstellen !=0xffff und verweigert 
Überschreiben dieses Bereichs).

von Jürgen S. (jsachs)


Lesenswert?

Zu 8)
Da bin ich gerade dran. Meine Sprungtabelle steht (ist eigentlich ganz 
einfach) Jetzt bau ich mir ne fest im Rom auf und "zwinge diese" auf ne 
feste Adresse. Noch PA und UA als ein Block, wenn das geht rupf ich 
beide auseinander :-) Schritt für Schritt eben. Danke das Hilft sehr 
weiter !

Zu 9) Mein Problem ist hier: Wenn ich nun UA alleine ohne Startup code 
Linke, und dem Linker sage "die Sprungtabelle auf den Anfang". Welche 
Adresse geb ich Ihm dann vor, ich nehme an 0x0000, da diese ja relativ 
zum Anfang des UA Binaries sein muß..... Ich nehme an die Sprungtabelle 
des UA muß am Anfang stehen, ist ja mein einzig Sinnvoller Fixpunkt ?!

Zu 3) Das Problem ist, das der Bootloader selbst keine Daten empfangen 
kann, sondern nur Daten verschieben von UA in PA und feststellen ob die 
PA gültig ist und gestartet werden kann. Sonst müsste ich die PA in den 
Bootloader packen, was das Update erschwert.
Vermutlich werde ich den Bootloader so lösen, das ich PA und Bootloader 
in einem File Linken kann für den ersten Flash, dann kann ich beides auf 
einmal Programmieren und danach bei Bedarf den PA ersetzen.
Quasi eine Inbetriebnahme Firmware mit PA und Bootloader. Per DEFINE 
kann ich die PA dann auch ohne Bootloader erzeugen.
Das sehe ich mir nach 8 an, zum schluss kommt 9 :-)
Mann darf den Bootloader hier weniger als Loader sehen, sondern mehr als 
Bios.

Danke für die Hilfe soweit.

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.