Konzept für einen ATtiny-Bootloader in C
Die ATtiny-Mikroprozessoren unterstützen das Prinzip des Bootloaders der
ATMega-Prozessorreihe eigentlich nicht. Dafür fehlen den ATtinys
folgende Merkmale:
- Fehlende Fuses für einen definierten und geschützten
Bootloader-Bereich
- Fehlender Resetvektor exklusiv für den Bootloader
- Fehlende Interruptvektor-Tabelle für ISRs innerhalb des Bootloaders
Trotzdem sind Bootloader-Implementationen für ATtinys durchaus möglich -
wie zum Beispiel diese Threads aus der Codesammlung belegen:
- Beitrag "ATtiny45 Bootloader"
- Beitrag ""Bootloader" für ATTiny2313"
- Beitrag "UART Bootloader ATtiny13 - ATmega644"
Jedoch sind diese Bootloader allesamt in Assembler realisiert, denn nur
hier hat der Programmierer alle Freiheiten, die er braucht, um die
Speicherverwaltung im SRAM (und auch im Flash) selbst zu kontrollieren.
C (hier im speziellen avr-gcc) ermöglicht es eigentlich nicht, ohne
größere Klimmzüge einen Bootloader für ATtinys zu programmieren - aus
oben genannten Gründen.
Hinzu kommt, dass ATtinys einen eher kleinen Flash-Speicher haben. Daher
wäre es sinnvoll, wenn die Applikation Funktionen des Bootloaders selbst
nutzen könnte, ohne sie neu zu implementieren und diese damit doppelt im
Flash-Speicher abzulegen. Wenn der Bootloader zum Beispiel sowieso
eigene Software-UART-Funktionen verwendet, ist es Unsinn, diese nochmals
für die Applikation neu zu programmieren. Dabei ergibt sich aber wieder
ein neues Problem: Der Bootloader wird dann eventuell globale Variablen
benötigen, die in einem geschützten Bereich liegen müssen. Nur so ist
ein "Parallelbetrieb" von Bootloader und Applikation möglich, damit die
Applikation Funktionen des Bootloaders (wie z.B. den Software-UART)
nutzen kann.
In folgenden Threads werden u.a. die oben angedeuteten Probleme
angesprochen, ohne dafür Lösungen anzubieten:
- Beitrag "ATTiny85 Interrupt Vector verschieben"
- Beitrag "Re: Bootloader Grundkenntnisse"
- Beitrag "ATtiny861 Interruptvektoren für Bootloader manipulieren"
- Beitrag "bootloader + Software-Uart"
Der Artikel
http://www.mikrocontroller.net/articles/Konzept_f%C3%BCr_einen_ATtiny-Bootloader_in_C
soll zeigen, dass ein ATtiny-Bootloader auch in C möglich ist - ja, dass
sogar eigene Interrupt-Routinen innerhalb des Bootloaders realisiert
werden können, obwohl ein ATtiny keinen Austausch der
Interruptvektor-Tabelle über das IVSEL-Bit bietet, wie es bei den
ATMegas der Fall ist. Auch wird das Thema, wie man Funktionen zwischen
Bootloader und Applikation "sharen" kann, beschrieben.
Ich freue mich über Feedback und wünsche viel Spaß beim Lesen,
Frank
P.S.
Einige Kapitel (für die Fortgeschrittenen) sind noch nicht gefüllt,
werden aber von mir in Kürze nachgetragen.
Die entscheidende Fragestellung ist: was soll ein Bootloader machen ?
Die Prioritäten wie man die Antworten daraufhin ordnet entscheidet dann
welchen Weg man gehen muß. Die oberste Priorität bei einem Bootloader
sollte Stabilität und Produktsicherheit sein. Aus Stabilitätsgründen
sollte man also die Vermischung von Bootloader und Applikation immer
vermeiden da mit dem Zugriff der Applikation auf den Bootloader ein für
den Entwickler des Bootloaders unbestimmbares neues Element eingeführt
wird. Und alles was nicht bestimmbar ist, zu einem Zeitpunkt, macht aus
der deterministischen Strategie des Bootloader-Entwicklers ein Produkt
dessen Eigenschaften defakto ebenfalls unbestimmbar sind. Ergo: ein
solches Konzept wie deines widerspricht dem Konzept eines Bootloaders.
Es ist also nicht verwunderlich das die meistens erfahrenen Entwickler
von Bootloadern von vornherein eine solche Mixtur meiden wie die Pest.
Es zeugt von der Erfahrung dieser Leute.
Das nun die Realität grau ist und nicht schwarz weiß gemalt wird sollte
allen klar sein. Dh. Ausnahmen bestätigen die Regel.
Gruß Hagen
Hagen Re schrieb:> Die Prioritäten wie man die Antworten daraufhin ordnet entscheidet dann> welchen Weg man gehen muß. Die oberste Priorität bei einem Bootloader> sollte Stabilität und Produktsicherheit sein. Aus Stabilitätsgründen> sollte man also die Vermischung von Bootloader und Applikation immer> vermeiden da mit dem Zugriff der Applikation auf den Bootloader ein für> den Entwickler des Bootloaders unbestimmbares neues Element eingeführt> wird.
Die Vermischung (die ich im Artikel übrigens noch nicht dokumentiert
habe) besteht lediglich im Sharen von Funktionen bzw. Interrupts. Beides
ist optional. Was bisher im Artikel beschrieben ist, ist ein Bootloader,
der nichts - aber auch gar nichts mit der Applikation zu tun hat. Die
Applikation hat auch keinen(!) Zugriff auf Elemente des Bootloaders.
Somit ist die Stabilität absolut gegeben, der Bootloader behält die
Kontrolle.
Nun zum Sharen von Interrupts und Funktionen - was, wie gesagt, nur ein
optionales Schmankerl sein soll:
Du musst Dir das so vorstellen: Der Bootloader ist das "Betriebssystem",
die Applikation kann Betriebssystem-Funktionen kontrolliert benutzen -
mehr nicht. Der Bootloader behält in jedem Fall die Kontrolle. Die
Applikation kann in keinem Fall Funktionen des Bootloaders benutzen,
welche das Flash beschreiben. Diese sind natürlich alle static definiert
und können nicht von der Applikation genutzt werdne.
Der Bootloader wird für sich allein kompliliert - und auch geflasht. Der
Bootloader lädt die Applikation nach und kann - auf Abruf - bestimmte
Funktionalitäten an die Applikation exportieren - d.h. freigeben. Das
können zum Beispiel die vom Bootloader verwendeten SW-UART-Funktionen
sein. Sie können aber nur über eine kontrollierte Schnittstelle
verwendet werden. Vermischt wird hier gar nichts!
Wenn ich diesen Mechanismus beschrieben habe, können wir uns darüber
gern nochmal unterhalten ;-)
> Und alles was nicht bestimmbar ist, zu einem Zeitpunkt, macht aus> der deterministischen Strategie des Bootloader-Entwicklers ein Produkt> dessen Eigenschaften defakto ebenfalls unbestimmbar sind. Ergo: ein> solches Konzept wie deines widerspricht dem Konzept eines Bootloaders.
Was ist an meinem Konzept nicht bestimmbar?
> Es ist also nicht verwunderlich das die meistens erfahrenen Entwickler> von Bootloadern von vornherein eine solche Mixtur meiden wie die Pest.
Ich glaube, Du bist da einem Missverständnis auferlegen. Hast Du den
Artikel überhaupt gelesen? Da ist überhaupt nicht von Mixtur die Rede.
Ausserdem ist der Bootloader nicht(!) vom Good-Will der Applikation
abhängig. Die Applikation kann noch so "böse" sein, sie kriegt den
Bootloader nicht kaputt!
Anmerkung dazu:
Natürlich kann die Applikation auf einem ATtiny mutwillig das Flash
löschen, weil so ein Schutz bei ATtinys nicht möglich ist, aber damit
kriege ich auch jeden Deiner Bootloader kaputt ;-)
> Es zeugt von der Erfahrung dieser Leute.
Du kannst Dir gewiss sein, dass ich genügend Erfahrung besitze ;-)
> Das nun die Realität grau ist und nicht schwarz weiß gemalt wird sollte> allen klar sein. Dh. Ausnahmen bestätigen die Regel.
Bitte lies den Artikel nochmal und zeige mir eine Schwachstelle, die die
Stabilität gefährden könnte.
Danke für Dein Feedback,
Frank
Nur mal dieser Absatz:
Frank M. schrieb:> Die Vermischung (die ich im Artikel übrigens noch nicht dokumentiert> habe) besteht lediglich im Sharen von Funktionen bzw. Interrupts. Beides> ist optional. Was bisher im Artikel beschrieben ist, ist ein Bootloader,> der nichts - aber auch gar nichts mit der Applikation zu tun hat. Die> Applikation hat auch keinen(!) Zugriff auf Elemente des Bootloaders.> Somit ist die Stabilität absolut gegeben, der Bootloader behält die> Kontrolle.
Deine Aussage stimmt wenn du den Best Case betrachtest. Was passiert
wenn die Applikation Code im Bootloader ausführen kann und dabei mit
fehlerhaft mit falschen Einsprungspunkten arbeitet ? Dh. die Applikation
möchte die UART Routinen im Bootloader aufrufen ruft aber auf Grund
eines Fehlers die FLASH Programmierfunktionen ohne Sinn und Verstand auf
?
Der Bootloader sollte vollständig getrennt, also nochnichtmal sichtbar
für die ALU zu diesem Zeitpunkt, sein. Ein falscher Sprung in den
Bootloader Bereich sollte durch die Hardware blockiert werden, zb. durch
Exceptions wie im Protected Mode einer heutigen CPU.
Bootloader sind nicht nur Softwareseitig zu betrachten, sondern auch
Hardwareseitig.
Gruß Hagen
Hagen Re schrieb:> Deine Aussage stimmt wenn du den Best Case betrachtest. Was passiert> wenn die Applikation Code im Bootloader ausführen kann und dabei mit> fehlerhaft mit falschen Einsprungspunkten arbeitet ? Dh. die Applikation> möchte die UART Routinen im Bootloader aufrufen ruft aber auf Grund> eines Fehlers die FLASH Programmierfunktionen ohne Sinn und Verstand auf> ?
Du hast es immer noch nicht verstanden:
Der Bootloader ist ein Stand-Alone-Programm und wird OHNE Applikation
auf den Chip gebrannt. Die Applikation wird NICHT mit dem Bootloader
gelinkt!
Der Bootloader kann später, wenn die Applikation geladen ist, bestimmte
Einstiegspunkte exportieren, macht dies aber natürlich nicht für die
FLASH-Programmierfunktionen. Da kommt die Applikation gar nicht dran -
ausser, indem sie willkürlich irgendwohin durch Trial- und Error in den
Bootloader-Bereich springt. Aber das kann man mit jedem Bootloader!
> Der Bootloader sollte vollständig getrennt, also nochnichtmal sichtbar> für die ALU zu diesem Zeitpunkt, sein. Ein falscher Sprung in den> Bootloader Bereich sollte durch die Hardware blockiert werden, zb. durch> Exceptions wie im Protected Mode einer heutigen CPU.
Du weisst genau, dass dies auf einem ATtiny hardware-technisch nicht
möglich ist. Auch Du als Assembler-Bootloader-Programmierer weisst, dass
ein ATtiny dies nicht verhindern kann.
Was soll das also jetzt? Zuerst sagst Du, dass mein Konzept her nicht
sicher ist, jetzt sagst Du, dass alle ATtiny-Bootloader schon aus
hardware-technischen Gründen nicht sicher sein können.
Auf einem AVR-µC, auf dem auch ein Bootloader ist, kann eine
wildgewordene Applikation immer auch "versehentlich" auf
Bootloader-Funktionen zugreifen. Auf einem ATmega wird aber
hardware-technisch verhindert, dass die Applikation dadurch das Flash
modifizieren kann. Auf einem ATtiny kannst Du das nicht verhindern, denn
hier fehlen diese Schutzmechanismen - außer Du löschst die
SELFPRGEN-Fuse und führst damit einen Bootloader ad absurdum.
Also: Wie blockierst Du den Aufruf Deines Bootloader-Codes auf einem
ATtiny durch eine amoklaufende Applikation?
> Bootloader sind nicht nur Softwareseitig zu betrachten, sondern auch> Hardwareseitig.
Es geht um einen Bootloader für ATtinys, der komplett in C realisierbar
ist. Ich will lediglich zeigen, dass dies eben auch in C möglich ist und
dass man nicht notwendigerweise in Assembler programmieren muss.
Ich habe bisher keinen einzigen Bootloader für ATtinys gefunden, der in
C programmiert ist. Alle sind in Assembler geschrieben - eben weil sich
da noch keiner rangetraut hat. Auf den ATmegas hat man es leicht, denn
da hat der Bootloader einen eigenen Reset-Vektor (in seiner eigenen
Interrupt-Vektor-Tabelle). Und dieser fehlt auf den ATtinys - wie auch
die anderen Interrupt-Vektoren. Ich wollte zeigen, dass man dieses Manko
auch in C durch entsprechende Mechanismen ausgleichen kann.
Die Argumente, die Du hier jetzt bringst, sind vollkommen allgemeiner
Natur. Sie gelten für alle ATtiny-Bootloader. Letztendlich lese ich
nur ein Fazit aus Deinem Beitrag: ATtiny-Bootloader sind unmöglich, da
nicht sicher. Die Hardware bringts einfach nicht. Aber was hat das jetzt
im speziellen mit meinem Konzept zu tun? Hier geht es um: "Und es geht
doch in C" und nicht darum, dass er sicherer ist als alle anderen
Assembler-Bootloader für ATtinys.
Bitte weiche nicht in allgemeingültiges Geschwafel ab. Ich las in Deiner
ersten Antwort, dass gerade im speziellen mein Konzept nicht sicher bzw.
stabil ist. Du konntest aber bisher noch keinen einzigen Punkt nennen,
wo er unsicherer ist als irgendein anderer ATtiny-Bootloader. Er ist
genauso sicher und er ist genauso unsicher.
Für die Hardware (ATtiny) mit ihrer eingeschränkten Sicherheit bzgl.
Flash-Programmieren kann ich persönlich gar nichts.
Gruß,
Frank
Hi Frank,
ich finde die Idee gut. So hat man wenigstens eine Chance zu verstehen
wie das alles funktioniert.
Was mir noch nicht klar ist:
- wie bekommst du die Daten in den attiny?
- bei welchem Speicherverbrauch bist du jetzt (mit -Os, aber ohne
schwarze Magie)
Weiter so!
Anon Ymous schrieb:> ich finde die Idee gut. So hat man wenigstens eine Chance zu verstehen> wie das alles funktioniert.
Genau darum ging es mir - nämlich den Vorgang Schritt für Schritt zu
erklären, wie man einen Bootloader auf ATtinys bauen kann, obwohl den
Tinys dafür wichtige Features fehlen. Man sollte das Konzept daher nicht
auf ATmegas übertragen. Denn da ist alles ganz anders... und viel
einfacher.
> Was mir noch nicht klar ist:> - wie bekommst du die Daten in den attiny?
Genau das wollte ich eigentlich offen lassen, denn mir ging es um die
Mechanismen und nicht um eine konkrete Schnittstelle. Die Übertragung
der Daten kann über einen SW-UART erfolgen, kann aber auch über jede
andere denkbare Kommunikationsschnittstelle erfolgen. Ich hatte da zum
Beispiel schon einmal den SOUNDRX-Bootloader in einem Artikel
vorgestellt, wo man einen ATmega über die Soundkarte des PCs flasht.
Soundkarte hat jeder am PC, aber einen UART nicht unbedingt ;-)
Ich werde aber später im Artikel einen konkreten Bootloader vorstellen,
der das beschriebene Konzept über einen SW-UART nutzt. Diesen habe ich
für ein spezielles Projekt entwickelt, wo 60 ATtinys in einer einzigen
Schaltung in Reihe über einen einzigen Anschluss miteinander in einer
Kette verbunden sind. Hier werden alle 60 ATtinys "in einem Rutsch" über
den Bootloader geflasht. Wofür man 60 ATtinys in einer langen Kette (mit
insgesamt 480 MIPS Leistung) braucht, möchte ich aber erst verraten,
wenn es soweit ist. Den konkreten Bootloader-Source werde ich jedoch
schon vorab in den nächsten Tagen im Artikel vorstellen.
> - bei welchem Speicherverbrauch bist du jetzt (mit -Os, aber ohne> schwarze Magie)
Es sind momentan ca. 1800 Bytes, also unter 2 KB. Das hört sich erstmal
nach viel an gegenüber einem in Assembler-Bootloader programmierten
Bootloader. Man muss aber bedenken, dass die SW-UART-Routinen und die
Kommunikationroutinen über die "Kette" der seriell geschalteten ATtinys
da schon miteingerechnet sind... und auch von der Applikation genutzt
werden, also nur einmal im Flash vorhanden sind. Von daher relativiert
sich die Größe.
> Weiter so!
Danke, natürlich mache ich weiter, schließlich will ich mein
60-ATtiny-Projekt damit realisieren - und irgendwann hier auch
vorstellen ;-)
Gruß,
Frank
Frank, du kannst mir glauben das ich dich sehr gut verstehe und das ich
sehr genau abschätzen kann was real möglich ist und was theoretisch am
Besten wäre.
Nun, meine Kritik ist das Du mit deinem Artikel ein Problem lösen
möchtest das sich theoretisch garnicht ergeben sollte. Ich sehe den
konkreten Sinn nicht ausser in einer akademischen Anwendung, als eine
Machbarkeitsstudie.
Bei meinem AVRootloader zB. habe ich ebenfalls mit Sprungtabellen das
Gleiche gemacht. Das erfolgte auf mehrfachem Wunsch von Anwendern da ich
selbst es nicht brauchte und auch nicht als sinnvoll erachtete. Und das
Fazit: bis heute haben selbst diejenigen die mich darum baten diese
Schnittstelle nicht benutzt, ergo nicht real benötigt.
Die Strategie die Abhängigkeiten zwischen Bootloader und Applikation so
gering wie möglich zu halten ist sinnvoll und entspricht am meisten den
realen Anforderungen.
Es geht hier also eher in eine philosophie Richtung weshalb ich schrieb:
Ausnahmen bestätigen die Regeln.
Letzendlich zählt doch nur eines: die Vielfalt an verschiedenen
Ansichten und Meinungen. Also kein Grund es zu persönlich zu nehmen.
Ich bin gespannt auf die Vervollständigung deines Artikels.
Gruß Hagen
Frank M. schrieb:> Es geht um einen Bootloader für ATtinys, der komplett in C realisierbar> ist. Ich will lediglich zeigen, dass dies eben auch in C möglich ist und> dass man nicht notwendigerweise in Assembler programmieren muss.>> Ich habe bisher keinen einzigen Bootloader für ATtinys gefunden, der in> C programmiert ist. Alle sind in Assembler geschrieben - eben weil sich> da noch keiner rangetraut hat.
Naja ich hätte auch meine Bootloader die ich in C programmiert habe hier
posten können aber warum sollte ich dies wenn die in Assembler
programmierten weit leistungsfähiger sind.
Schau: die Hauptaufgabe eines Programmieres ist das Abwägen bei der Wahl
der Mittel um ein Ziel effektiv und effizient zu erreichen. Ein
Programmier der zB. nur C als Sprache beherrscht und eines Tages vor dem
Problem steht das er nicht das richtige Werkzeug als Mittel zum
Erreichen eines Zieles beherrscht sollte sich eher frage warum er dieses
Werkzeug nicht beherrscht. Er sollte es anstreben das Werkzeug zu
beherrschen.
Desegen meine Ansicht das ein C Bootloader aus Sicht der maximal
machbaren Effizienz das falsche Werkzeug gewählt hat und eher
akademischer Natur ist. Dies zeigt auch deine Vorgehensweise in deinem
Artikel.
Was möchtest du mit der Aussage "ich beweise das man Bootloader mit C
programmieren kann" beweisen ? Das wissen wir doch schon längst, warum
sollte es mit C nicht möglich sein ? Das du das Vorhandensein von
ausschließlich in Assembler programmierten Bootloadern als Indiz dafür
wertest das es keine Programmierer gäbe die das könnten ist schlichtweg
ein Denkfehler der kausalen Zusammenhänge. Es ist so weil alle diese
Entwickler sich für das best geeignete Werkzeug entschieden haben, und
das ist ein Indiz das man in Assembler bessere Bootloader programmieren
kann.
Die Nichtexistenz eines C Bootloaders für Tinys zeugt davon das alle
ASM-Bootloader-Programmierer sich aus ihren Erfahrungen heraus Gedanken
gemacht haben und ihre besten Leistungen präsentieren möchten.
Glaubst du wirklich das all diese ASM Programmierer nicht in C hätten
programmieren können ? Nein, sie tun es in Assembler weil sie der
Meinung sind das das für die Lösung eines Problemes am besten ist.
Mein C-Prototyp eines Bootlaoders für Tinys/Megas hat nichtmal 50% der
Funktionalitäten meines ASM Bootloaders und verbracht dabei mehr als
doppelt zuviel FLASH. Warum sollte ich diese Krücke veröffentlichen
wollen ?
Gruß Hagen
Frank M. schrieb:> Es sind momentan ca. 1800 Bytes, also unter 2 KB. Das hört sich erstmal> nach viel an gegenüber einem in Assembler-Bootloader programmierten> Bootloader.
Mal eine Zahl von mir: der AVRootloader von mir benötigt in minimalster
Konfiguration ca. 360 Bytes mit SW-UART. In Maximalkonfiguration unter
1kB dann ist aber schon eine starke Kryptographie mit inklusive, neben
EEPROM, CRCs in der Kommunikation usw. usw. Physikalisch und
Protokolltechnisch kann er alle UART Protokolle wie 1/2 Wire,
invertiert/nicht invertiert, RS485, und auch 1-Wire Bussystem zur
Anbindung meherer verschiedener AVR auf einem Board mit gleichem
Bootloader an einer einzigen Leitung. Das alles schon ab 360 Bytes zu
haben.
Das wirst du niemals in C erreichen können. Praktisch gesehen ist also
dein Artikel ein akademsiches Projekt. Und das wiederum halte ich für
positiv und auch erforderlich, denn wir wollen alle ja was lernen. Und
da gebe ich dir vollkommen recht: ein ASM Bootloader bis aufs letzte
Byte mit Expertentricks übersäht ist kein wirklich gutes Lehrbeispiel.
Gruß Hagen
Hagen Re schrieb:> Das wirst du niemals in C erreichen können.
Da gebe ich Dir absolut recht. Ich will da auch keine "Konkurrenz" zu
den ASM-Bootloadern herstellen. Deshalb habe ich einige relevante Links
zu bereits existierenden Bootloadern auch direkt am Anfang des Artikels
eingestreut. Mit einem ASM-Bootloader ist man in den meisten Fällen
besser bedient - auch wenn man ihn vielleicht gar nicht versteht ;-)
> Praktisch gesehen ist also dein Artikel ein akademsiches Projekt.
Ja, so kann man es durchaus sehen, der Artikel ist vorwiegend
akademischer Natur. Ich werde dies im Artikel noch einmal ausdrücklich
erwähnen. Trotzdem ist er in der Praxis durchaus anwendbar - auch wenn
er gegenüber den ASM-Bootloadern bzgl. Speicherplatz der klare Verlierer
ist.
> Und da gebe ich dir vollkommen recht: ein ASM Bootloader bis aufs letzte> Byte mit Expertentricks übersäht ist kein wirklich gutes Lehrbeispiel.
Gut, dann sind wir uns ja einig :-)
Gruß,
Frank
Hagen Re schrieb:> Was möchtest du mit der Aussage "ich beweise das man Bootloader mit C> programmieren kann" beweisen ?
Natürlich kann man Bootloader in C programmieren. Für den ATmega ist das
ein Klacks in C. Da gibt es auch genügend Bootloader im Netz. Ich selbst
habe da auch schon ein halbes Dutzend Bootloader in C entwickelt, die
alle nicht der Rede wert sind.
> Das wissen wir doch schon längst, warum sollte es mit C nicht möglich sein ?
Es ging mir um ein spezielles Problem beim ATtiny: Wie stelle ich in C
einen Reset-Vektor (und die Interrupt-Vektor-Tabelle) an der Stelle
0x000 her? Das war das Hauptproblem bei bei der ganzen Geschichte. Beim
ATmega braucht man sich darum nicht zu kümmern. Hier hat der Bootloader
seine eigene Vektortabelle.
Gruß,
Frank
Läuft der Bootloader unter allen bekannten AVR-Compilern (IAR,
Codevision, GCC)?
Und unter welchen Versionen läuft er?
Frank M. schrieb:> Die> Applikation kann in keinem Fall Funktionen des Bootloaders benutzen,> welche das Flash beschreiben.
Braucht sie auch nicht. Bei den ATtiny und dem ATmeg48 kann die
Applikation direkt das SPM ausführen.
Peter
Peter Dannegger schrieb:> Läuft der Bootloader unter allen bekannten AVR-Compilern (IAR,> Codevision, GCC)?
Er läuft unter avr-gcc, das ist im Artikel auch erwähnt. Andere Compiler
habe ich nicht ausprobiert.
Der Artikel soll auch keinen konkreten Bootloader vorstellen, sondern
lediglich das allgemeine Konzept dafür erläutern, wie es beim ATtiny
überhaupt geht. Der konkrete Trick, einen Reset-Vektor an der Adresse
0x000 zu erzeugen ohne Assembler, obwohl die .text-Section "hinten im
Flash" liegt, ist avr-gcc-typisch und muss bei anderen Compilern anders
umgesetzt werden - falls das überhaupt möglich ist.
> Und unter welchen Versionen läuft er?
Ich selbst habe ihn unter avr-gcc (WinAVR 20100110) 4.3.3 programmiert
und getestet. Er sollte aber auch mit anderen avr-gcc-Versionen
funktionieren, wenn diese nicht gerade steinalt ist.
> Braucht sie auch nicht. Bei den ATtiny und dem ATmeg48 kann die> Applikation direkt das SPM ausführen.
Eben. Ein Bootloader für den ATtiny ist auch kein echter Bootloader im
strengen Sinne.
Gruß,
Frank
Frank du solltest bemerkt haben das in dieser Diskussion die praktischen
Anwendungsmöglichkeiten deines Vorhabens immer mehr schrumpfen.
Peter zielte mit seinen Bemerkungen korrekterweise auf die richtige
Fragestellung: Welchen realen Hauptvorteil bietet C gegenüber Assembler
? Unter der Annahme das der Programmierer die freie Wahl der Mittel hat,
er also sowohl in Asm als auch in C oder jeden anderen Sprache gleich
gut programmieren kann, besteht der Hauptvorteil in einer Hochsprache zu
programmieren letzendlich nur in der besseren Portierbarkeit und höheren
Effizienz bei der Fertigstellung der Software. Und exakt das sind die
einzigen realen Gründe die für Hochsprachen im Allgemeinen sprechen. Ein
Auftraggeber wählt die Manpower die er benötigt.
Desweiteren macht die Benutzung der Linker-Optionen, um eigene Sections
benutzen zu können, die oben angesprochene Portierbarkeit wieder zu
nichte.
Gleichzeitig stellte Peter fest das im Falle der Tinys sowieso die
Anwendung den FLASH umprogrammieren könnte und damit das Sharen dieser
Bootloader Funktionalität im Grunde überflüssig macht. Denn wenn wir
einen C Bootloader auf dem Tiny programmieren, dann verbraucht dieser
viel mehr zusätzlichn FLASH im Vergleich zu ASM, so das bei einem ASM
Bootloader soviel mehr an FLASH übrig bleibt, so das die Applikation mit
eigenen SPM Funktionen immer noch mehr FLASH zur Verfügung hätte. Das
trifft nach meinen Erfahrungen dann auf die komplette Bootloader
Funktionalität zu. Da meine Erfahrungen besagen das ein guter ASM Code
ca. 50% kompakter als WinAVR GCC ist und dabei noch mehr Funktionalität
besitzt. Mit anderen Worten: in ASM bekäme man die Bootloader
Funktionalität > 2 mal in den gleichen FALSH den ein vergleichbarer C
Bootloader benötigte. Mit einem ASM Bootloader hat man also in der
eigenen Applikation soviel zusätzlichen FALSH das man die Funktionalität
des Bootloader dort nochmal, aber dieses mal nach Bedürfnissen der
Anwendung, programmieren könnte.
Ich möchte wirklich nicht deine Arbeit und deine Motive schlecht machen,
ganz im Gegenteil: weil ich sehe wieviel Aufwand du in dieses Projekt
reinsteckst, weil ich sehe das du dein Wissen teilen möchtest, weil ich
also meine das Du meine Zeit wert bist, nehme ich mir diese Zeit und
diskutiere mit dir um dir ein bischen von meiner Sichtweise mit zu
geben.
So komme ich also zu dem Schluß das ein akademisches Projekt das
zusätzlich noch eine praktische Anwendungsmöglichkeit eröffnet immer
besser ist als ein akademsiches Projekt das nur das und nichts mehr ist.
Bei dieser Feststellung geht es mir um Dich, denn Du machst die gleichen
Fehler die ich in meiner Jugend machen musste, weil mich kein Erfahrener
darauf hinwies. Ich habe Zeit verschwendet mit akademischen Projekten
ohne praktische Ziele damit zu verfolgen. Es wäre für mich besser
gewesen wenn ich Zeit investiert hätte in Projekte die auch ein
praktisches Ziel verfolgten und dabei noch akademische, lehrreiche
Erfahrungen f´ür mich enthielten.
Ich bin also der Auffassung das es gut ist wenn junge Menschen ihre
Kreativität ausleben können, sich selbst auf die Suche machen und dabei
aber von erfahrenen Leuten manchmal in die richtige Richtung gestubst
werden, so das diese Jugend aus den Fehlern der Alten lernen können.
Gruß hagen
sorry für meine schlechte Grammatik/Rechtschreibung/krummen Finger aber
ich bin noch nicht ganz wach :)
Wie gedenkst du die Einsprungtabelle/-Funktionalität zu lösen ?
Gruß hagen
Hagen Re schrieb:> besteht der Hauptvorteil in einer Hochsprache zu> programmieren letzendlich nur in der besseren Portierbarkeit und höheren> Effizienz bei der Fertigstellung der Software
Und das letzendlich verlängert die Zeitspanne des Profites sowohl nach
vorne wie nach hinten. Nach vorne weil man schneller fertig ist, nach
hinten weil durch die Portierbarkeit sich der Lebenszyklus der Software
verlängern lässt und in die Breite weil mehr Plattformen in Zukunft
unterstützbar sind. Und bei Profit meine ich nicht nur das Geld sondern
das Wissen für Dich und Alle anderen, wenn man es denn teilen mag.
Es geht also nur um Zeit als wichtigsten Faktor.
Gruß Hagen
Hagen Re schrieb:> Frank du solltest bemerkt haben das in dieser Diskussion die praktischen> Anwendungsmöglichkeiten deines Vorhabens immer mehr schrumpfen.
Natürlich sind die praktischen Anwendungsmöglichkeiten begrenzt, das
habe ich nie bestritten. Aber auch ein Assembler-Programmierer, der
einen Bootloader für einen ATtiny schreiben möchte, kann die
Mechanismen, die im Artikel beschrieben werden, in seine
Lieblingssprache Assembler "übersetzen", das ist überhaupt kein Problem.
Ich will nur zeigen, wie es geht - mehr nicht.
Ich habe hier C gewählt, weil ich seit ca. 25 Jahren über
Assembler-Programmierung hinaus bin. Das Thema habe ich hinter mir. Ich
kann ein halbes Dutzend Assembler-Dialekte, angefangen bei Z80, das ich
heute noch als Hex-Code einfach so runterschreiben kann, über M68K bis
zu moderneren Prozessor-Architekturen. Auch PIC- und AVR-Assembler
beherrsche ich.
Der Artikel benutzt avr-gcc im konkreten, weil hier die Sprache C
lediglich ein anschauliches Werkzeug ist, um das Konzept eines
Tiny-Bootloaders umzusetzen. Ich hätte auch alles in Pseudo-Code
schreiben können. Assembler jedoch wäre hier eine schlechte Wahl
gewesen. Wie Du schon selbst geschrieben hast, ist Assemlber nicht immer
sehr verständlich.
Ich benutze grundsätzlich C auf AVRs - das gilt auch für Bootloader. Ich
kann zwar AVR-Assembler problemlos lesen und verstehen, jedoch weigere
ich mich, Assembler selber anzuwenden. Das ist aber reine Religion und
steht hier nicht zur Debatte. Wenn ich einen ATtiny85 zu demselben Preis
oder noch günstiger als einen ATtiny45 bekomme, warum soll ich mir dann
Assembler antun, nur um das Ganze noch in einen ATtiny45 oder -25 zu
quetschen?
(Der Attiny45 reicht übrigens für mein 60fach-µC-Projekt auch noch aus,
die eigentliche Applikation ist auch nicht größer als 2KB, so dass mir
4KB durchaus reichen)
> Peter zielte mit seinen Bemerkungen korrekterweise auf die richtige> Fragestellung: Welchen realen Hauptvorteil bietet C gegenüber Assembler> ?
Die Antwort ist einfach:
C ist lesbarer als Assembler - jedenfalls dann, wenn man sich bemüht,
lesbaren Code zu schreiben. Der Leser kann sofort nachvollziehen, was da
passiert.
> Unter der Annahme das der Programmierer die freie Wahl der Mittel hat,> er also sowohl in Asm als auch in C oder jeden anderen Sprache gleich> gut programmieren kann, besteht der Hauptvorteil in einer Hochsprache zu> programmieren letzendlich nur in der besseren Portierbarkeit und höheren> Effizienz bei der Fertigstellung der Software.
Auch von Peter habe ich schon desöfteren in der jüngeren Vergangenheit
gelesen, dass er prinzipiell C der Assembler-Programmierung vorzieht.
Wenn man sich Peters ältere Projekte anschaut, waren darunter sehr viele
in Assember programmierte Geschichten. Seine jüngeren Beiträge sind fast
allesamt in C geschrieben. Offenbar hat Peter da auch eine Entwicklung
durchgemacht.
> Desweiteren macht die Benutzung der Linker-Optionen, um eigene Sections> benutzen zu können, die oben angesprochene Portierbarkeit wieder zu> nichte.
Ich erhebe hier nicht Anspruch auf Portierbarkeit, sondern auf
Lesbarkeit. Bei Programmen für Unix-/Linux achte ich jedoch sehr auf
Portierbarkeit. Da lassen sich meine Programme auf so ziemlich allen
Unix-Derivaten ohne jegliche Anpassungen des Quellcodes übersetzen.
Auch mein IRMP-Projekt läuft sowohl auf AVRs, auf PICs, unter Unix,
unter Linux, unter Windows als auch auf diversen ARMs. Das ist überhaupt
kein Problem.
Aber bei einer so hardwarenahen Geschichte wie einem Tiny-Bootloader
tritt Portierbarkeit auf einen anderen C-Compiler in den Hintergrund.
Hier muss der Leser des Artikels die Gedankengänge auf seinen Compiler
bzw. seine Programmiersprache selbst adaptieren.
Assembler-Source kann noch so gut dokumentiert sein, nach 3 Jahren
versteht man seinen eigenen Source nicht mehr und muss sich komplett neu
einarbeiten ins eigene Programm und in die eigenen Gedankengänge, die
man damals hatte. Man muss alles wieder mühsehlig rekonstuieren. Bei C
erkenne ich auf einen Blick, was ich da vor 3 Jahren
"zusammengeschustert" habe.
> Gleichzeitig stellte Peter fest das im Falle der Tinys sowieso die> Anwendung den FLASH umprogrammieren könnte und damit das Sharen dieser> Bootloader Funktionalität im Grunde überflüssig macht.
Das ist nichts neues. Das habe ich Dir bereits gestern hier mitgeteilt,
dass die Applikation auf ATtinys tun und lassen kann, was sie will und
daher ATtinys "nicht sicher" sind.
> Denn wenn wir> einen C Bootloader auf dem Tiny programmieren, dann verbraucht dieser> viel mehr zusätzlichn FLASH im Vergleich zu ASM,
Es geht mir nicht um den Flash-Verbrauch, sondern um die Vorstellung
eines Konzepts. Und da ist C als Werkzeug das Mittel der Wahl.
Ich habe bereits heute morgen folgende Passage in den Artikel eingefügt,
nur damit sich die Assembler-Programmierer nicht angepisst fühlen, weil
ich "geheime Algorithmen" veröffentliche:
-------------------------- >8 schnipp) 8< ----------------------------
Da ein in Assembler geschriebener Bootloader in der Regel viel weniger
Speicherplatz benötigt und daher effizienter auf einem kleinen µC ist
als ein in C programmierter Bootloader, ist dieser Artikel eher
akademischer Natur. Hier sollen lediglich die Mechanismen, die nötig
sind, um für einen ATtiny einen Bootloader zu realisieren, ausführlichst
vorgestellt werden. Ein Einsatz in der Praxis ist durchaus möglich,
jedoch wird in den meisten Fällen ein in Assember geschriebener
Bootloader (auch wenn man ihn evtl. gar nicht versteht) die bessere Wahl
sein.
-------------------------- >8 schnapp) 8< ----------------------------
Ich hoffe, dass sich nun niemand mehr an den Karren gefahren fühlt, nur
weil er meint, ich wolle die bereits hier im Forum (speziell in der
Codesammlung) vorgestellten Bootloader komplett in Frage stellen.
> Ich möchte wirklich nicht deine Arbeit und deine Motive schlecht machen,> ganz im Gegenteil: weil ich sehe wieviel Aufwand du in dieses Projekt> reinsteckst, weil ich sehe das du dein Wissen teilen möchtest, weil ich> also meine das Du meine Zeit wert bist, nehme ich mir diese Zeit und> diskutiere mit dir um dir ein bischen von meiner Sichtweise mit zu> geben.
Ich fand die mir selbst gestellte Aufgabe, einen Tiny-Bootloader in C zu
realisieren, so ungeheuer spannend, dass ich mir dachte, dass der Weg,
um dorthin zu kommen, auch für andere interessant sein könnte. Dieses
mündete in den Artikel, der mit dem Wort "Konzept" beginnt. Ich hoffe,
dass die Leser dieses kleine aber wichtige Wörtchen zu schätzen wissen.
> Ich bin also der Auffassung das es gut ist wenn junge Menschen ihre> Kreativität ausleben können, sich selbst auf die Suche machen und dabei> aber von erfahrenen Leuten manchmal in die richtige Richtung gestubst> werden, so das diese Jugend aus den Fehlern der Alten lernen können.
Hagen, Du bist auf dem völlig falschen Dampfer. Ich habe bereits die 50
Jahre überschritten und programmiere seit 30 Jahren kommerziell in allen
möglichen Programmiersprachen. Ich habe sogar selbst schon
Programmiersprachen entwickelt, die kommerziell eingesetzt werden. Wenn
Du mal auf meine "Benutzerseite" geklickt hättest, würdest Du sehen,
dass ich ein ganz alter Hase bin. Du kannst mich aber trotzdem schubsen
- auch wenn Du mir nichts vormachen kannst ;-)
Gruß,
Frank
P.S.
Ab und zu stehen die Fragezeichen in Deinen Postings auf einer extra
Zeile, ist Dir das schon mal aufgefallen? Das sieht höchst komisch aus.
Plenken sollte man meiden ;-)
Hagen Re schrieb:> Wie gedenkst du die Einsprungtabelle/-Funktionalität zu lösen ?
Es ist eine Struct mit Pointern auf Funktionen. Diese wird über eine
definierte Adresse im Flash ausgetauscht - ganz einfach.
Alles, was im Artikel unter "TODO" steht, läuft bei mir längst. Die
Schreiberei des Artikels macht einfach Arbeit. Deshalb sind die Passagen
dort noch leer.
Gruß,
Frank
Frank M. schrieb:> Hagen Re schrieb:>> Frank du solltest bemerkt haben das in dieser Diskussion die praktischen>> Anwendungsmöglichkeiten deines Vorhabens immer mehr schrumpfen.>> Natürlich sind die praktischen Anwendungsmöglichkeiten begrenzt, das> habe ich nie bestritten. Aber auch ein Assembler-Programmierer, der> einen Bootloader für einen ATtiny schreiben möchte, kann die> Mechanismen, die im Artikel beschrieben werden, in seine> Lieblingssprache Assembler "übersetzen", das ist überhaupt kein Problem.> Ich will nur zeigen, wie es geht - mehr nicht.
Tja aber wie sinnvoll ist es dann solche Technologien in Assembler
umzusetzen wenn dadurch kein Vorteil mehr erlengt wird ?
> Ich habe hier C gewählt, weil ich seit ca. 25 Jahren über> Assembler-Programmierung hinaus bin.
Das war mein Risiko als ich abschätzen musste ob ich mit einem
erfahrenen Entwickler oder mit einem Jungsporn diskutiere ;)
> Ich benutze grundsätzlich C auf AVRs - das gilt auch für Bootloader. Ich> kann zwar AVR-Assembler problemlos lesen und verstehen, jedoch weigere> ich mich, Assembler selber anzuwenden. Das ist aber reine Religion...
Möö es ist Dummheit, genauer gesagt Ignoranz. Wenn Du selber von Dir
behuptest das du die freie Wahl der Mittel hast und nicht das Geeigneste
auswählst nach objektiven Erfordernissen, sondern auf Glaube basierend,
dann ist das Ignorranz.
> steht hier nicht zur Debatte. Wenn ich einen ATtiny85 zu demselben Preis> oder noch günstiger als einen ATtiny45 bekomme, warum soll ich mir dann> Assembler antun, nur um das Ganze noch in einen ATtiny45 oder -25 zu> quetschen?
Ah, und warum dann mit C arbeiten wenn man eh die freie Wahl hat und
dann in Assembler den 45'er nehmen kann was dann Kosten senken wird ?
> (Der Attiny45 reicht übrigens für mein 60fach-µC-Projekt auch noch aus,> die eigentliche Applikation ist auch nicht größer als 2KB, so dass mir> 4KB durchaus reichen)
Jo, die Fakten sich schön reden ;)
> C ist lesbarer als Assembler - jedenfalls dann, wenn man sich bemüht,> lesbaren Code zu schreiben. Der Leser kann sofort nachvollziehen, was da> passiert.
Denkfehler in den kausalen Zusammenhängen. Assembler ist genauso leicht
lesbar wie C wenn man es kann.
> Auch von Peter habe ich schon desöfteren in der jüngeren Vergangenheit> gelesen, dass er prinzipiell C der Assembler-Programmierung vorzieht.
Das tut ich auch, aber meine Prinzipien bei dieser Entscheidung heissen
das prinzipiel nach dem geeigneten Mittel gesucht wird und das auch
benutzt wird. Prinzipiell heist also aus objektiven Erwägungen heraus
und nicht aus Glauben heraus, mein Prinzip heist nicht glauben zu
wollen.
> Wenn man sich Peters ältere Projekte anschaut, waren darunter sehr viele> in Assember programmierte Geschichten. Seine jüngeren Beiträge sind fast> allesamt in C geschrieben. Offenbar hat Peter da auch eine Entwicklung> durchgemacht.
Tja, und was heist das jetzt ? Weil Peter der Meinung ist das C immer
besser wäre ? Oder nur das Peter seinen Lebenshorizont so wie ich
übrschritten hat und das Gefühl die eigene Zeit wird knapper kennt ?
> Ich erhebe hier nicht Anspruch auf Portierbarkeit, sondern auf> Lesbarkeit.
Dann wäre es geschickter Assembler als ein Mittel der Wahl den neulingen
näher zu bringen da es für diese Aufgabe desöfteren die bessere Wahl
ist.
>Bei Programmen für Unix-/Linux achte ich jedoch sehr auf> Portierbarkeit. Da lassen sich meine Programme auf so ziemlich allen> Unix-Derivaten ohne jegliche Anpassungen des Quellcodes übersetzen.
Du betrachtest geänderte Umweltbedingungen, hier geht es um Bootloader
und nicht allgmein um andere Projekte. Hier geht es um AVRs und nicht
UNIX PCs.
> Auch mein IRMP-Projekt läuft sowohl auf AVRs, auf PICs, unter Unix,> unter Linux, unter Windows als auch auf diversen ARMs. Das ist überhaupt> kein Problem.
Bestreitet ja keiner.
> Aber bei einer so hardwarenahen Geschichte wie einem Tiny-Bootloader> tritt Portierbarkeit auf einen anderen C-Compiler in den Hintergrund.
Ah, meine Rede ;)
> Hier muss der Leser des Artikels die Gedankengänge auf seinen Compiler> bzw. seine Programmiersprache selbst adaptieren.
Warum sollte er, es gibt genügend fertige Bootloader.
> Assembler-Source kann noch so gut dokumentiert sein, nach 3 Jahren> versteht man seinen eigenen Source nicht mehr und muss sich komplett neu> einarbeiten ins eigene Programm
Indiz für was ? Das der Entwickler an Alzheimer leidet ? das der
Entwickler nicht gut dokumentieren kann ?
> und in die eigenen Gedankengänge, die> man damals hatte. Man muss alles wieder mühsehlig rekonstuieren. Bei C> erkenne ich auf einen Blick, was ich da vor 3 Jahren> "zusammengeschustert" habe.
Und so könnte es auch in Assembler sein, die Freiheit für den Entwickler
in Asm sind größer als in C warum sollte dann C grundsätzlich loeichter
lesbar sein als Assembler ? Das liegt nicht in diesen Sprachen begründet
sondern in unseren Fähigkeiten. Das hat jeder selbst in der Hand und ist
unabhängig von der Programmiersprache.
Ändert aber nichts daran das Hochsprache eher auf das natürliche
menschliche Denken abgestimmt sind als Assembler.
>> Gleichzeitig stellte Peter fest das im Falle der Tinys sowieso die>> Anwendung den FLASH umprogrammieren könnte und damit das Sharen dieser>> Bootloader Funktionalität im Grunde überflüssig macht.>> Das ist nichts neues. Das habe ich Dir bereits gestern hier mitgeteilt,> dass die Applikation auf ATtinys tun und lassen kann, was sie will und> daher ATtinys "nicht sicher" sind.
Gut das Dir das klar ist nur dann verstehe ich nicht warum du der
Argumentation nicht folgen möchtest.
>> Denn wenn wir>> einen C Bootloader auf dem Tiny programmieren, dann verbraucht dieser>> viel mehr zusätzlichn FLASH im Vergleich zu ASM,>> Es geht mir nicht um den Flash-Verbrauch, sondern um die Vorstellung> eines Konzepts. Und da ist C als Werkzeug das Mittel der Wahl.
Das habe ich begriffen, ich zweifle den Nutzen dieses Konzeptes an.
> -------------------------- >8 schnipp) 8< ----------------------------> Da ein in Assembler geschriebener Bootloader in der Regel viel weniger> Speicherplatz benötigt und daher effizienter auf einem kleinen µC ist> als ein in C programmierter Bootloader, ist dieser Artikel eher> akademischer Natur. Hier sollen lediglich die Mechanismen, die nötig> sind, um für einen ATtiny einen Bootloader zu realisieren, ausführlichst> vorgestellt werden. Ein Einsatz in der Praxis ist durchaus möglich,> jedoch wird in den meisten Fällen ein in Assember geschriebener> Bootloader (auch wenn man ihn evtl. gar nicht versteht) die bessere Wahl> sein.> -------------------------- >8 schnapp) 8< ----------------------------
Schade eigentlich aber wahr. Schade weil das Konzept deines Artikels
schon innerhalb deines Artikels als fragwürdig dargelegt wird.
> Ich hoffe, dass sich nun niemand mehr an den Karren gefahren fühlt, nur> weil er meint, ich wolle die bereits hier im Forum (speziell in der> Codesammlung) vorgestellten Bootloader komplett in Frage stellen.
Hey, überlege mal logisch: warum sollte ich mich so fühlen als ob man
mir an den Karren gepisst hätte. Ich bin hier der Pisser ;)
> Ich fand die mir selbst gestellte Aufgabe, einen Tiny-Bootloader in C zu> realisieren, so ungeheuer spannend, dass ich mir dachte, dass der Weg,> um dorthin zu kommen, auch für andere interessant sein könnte. Dieses> mündete in den Artikel, der mit dem Wort "Konzept" beginnt. Ich hoffe,> dass die Leser dieses kleine aber wichtige Wörtchen zu schätzen wissen.
Exakt das hättest du vor deinem obigen Absatz in den Artikel schreiben
sollen. Es erklärt deine Motive und der geneigte Leser weiß sofort was
er zu erwarten hat und welchen Nutzen er rausziehen möchte.
>> Ich bin also der Auffassung das es gut ist wenn junge Menschen ihre>> Kreativität ausleben können, sich selbst auf die Suche machen und dabei>> aber von erfahrenen Leuten manchmal in die richtige Richtung gestubst>> werden, so das diese Jugend aus den Fehlern der Alten lernen können.>> Hagen, Du bist auf dem völlig falschen Dampfer. Ich habe bereits die 50> Jahre überschritten und programmiere seit 30 Jahren kommerziell in allen> möglichen Programmiersprachen. Ich habe sogar selbst schon
Jo das habe ich jetzt auch wahrgenommen, ich lache jetzt immer noch über
mich da meine Progonse das du ein Jungspunt wärest mal wieder, wie so
viele Prognosen im Leben, voll in die Hose gegangen ist;) Wie oben
gesagt, diese Risiko der Fehleinschätzung musst ich eingehen da die
Alternative eben schlechter ist. Es ist ein erfahrener Entwickler der
sich auf den Weg macht dieses Konzeopt zu entwickeln;)
> Programmiersprachen entwickelt, die kommerziell eingesetzt werden. Wenn> Du mal auf meine "Benutzerseite" geklickt hättest, würdest Du sehen,> dass ich ein ganz alter Hase bin. Du kannst mich aber trotzdem schubsen> - auch wenn Du mir nichts vormachen kannst ;-)
Das war ein Fehler meinerseits unbestritten, ich habe es schlicht
übersehen da ich mich inhaltilich auf deinen Artikel fokusiert habe.
> Ab und zu stehen die Fragezeichen in Deinen Postings auf einer extra> Zeile, ist Dir das schon mal aufgefallen? Das sieht höchst komisch aus.> Plenken sollte man meiden ;-)
Jo ist mir, blöde Forensoftware die solche Details nicht autom. regeln
kann. Und bitte, da gleich auf plenken zu schließen sieht schon nach
persönlichem Ehrgeiz aus. Wie gesagt: das Leben ist zu kurz, die eigenen
Fußspuren im WEB viel zu schnell verblasst, da sollte man schnell
lernen nichts persönlich zu nehmen ;)
>Es ist eine Struct mit Pointern auf Funktionen. Diese wird über eine>definierte Adresse im Flash ausgetauscht - ganz einfach.
Hm, und warum nicht deine Sections, die du ja als Kern des Lehrbeispiels
anführst, dafür benutzen ? Also eine Section in der diese Struct an
fester Adresse liegt ? In meinen AVRootloader befindet sich diese
Sprungtabelle direkt am Ende des FLASHs. Das Ende und die Anzahl der
Einträge sind bekannt, ergo stellt sich die Frage welchen Vorteil hat
deine dynamsiche Ermittlung dieser Adresse über eine eigene Funktion ?
Gruß Hagen
Frank M. schrieb:> Hagen Re schrieb:>> Wie gedenkst du die Einsprungtabelle/-Funktionalität zu lösen ?>> Es ist eine Struct mit Pointern auf Funktionen. Diese wird über eine> definierte Adresse im Flash ausgetauscht - ganz einfach.
Shit, entschuldige bitte ich habe das falsch interpretiert. Du gehst ja
damit schon den Weg den ich im vorherigen Posting ansprach.
Denoch nochmal zur Verfikation: Diese Struct ist deine Sprungtabelle und
wird im FLASH an fester und bekannter Adresse gespeichert. Es gibt also
keine weitere Funktion die nötig ist um diese Adresse zu ermitteln ?
Interessant ist dann nämlich die Frage an welche Adresse du diese
Sprungtabelle reallokieren möchtest und wie du das am geschicktesten dem
GCC beibringst, da ja Änderungen an dieser Sprungtabelle zu einer
geänderten Reallokation im Linker führen muß, also die nötige
Deklaration deisr Section dem Linker möglichst dynamisch beigebracht
werden muß.
Gruß Hagen
Hagen Re schrieb:>> steht hier nicht zur Debatte. Wenn ich einen ATtiny85 zu demselben Preis>> oder noch günstiger als einen ATtiny45 bekomme, warum soll ich mir dann>> Assembler antun, nur um das Ganze noch in einen ATtiny45 oder -25 zu>> quetschen?>> Ah, und warum dann mit C arbeiten wenn man eh die freie Wahl hat und> dann in Assembler den 45'er nehmen kann was dann Kosten senken wird ?
Ich bitte Dich, genau zu lesen, nicht meine Passagen zu überfliegen. Da
oben steht, dass ich entweder den ATtiny85 günstiger oder zumindest zu
demselben Preis wie einen ATtiny45 bekomme. Es senkt also keine Kosten,
wenn ich den Tiny45 nehme - ganz im Gegenteil: das Projekt wird teurer.
Zum Beispiel bei Mouser:
ATtiny85 1,07 + 19% MwSt
ATtiny45 1,36 + 19% MwSt
Also komm mir bitte nicht mit Kosten, die man mit Assembler einsparen
kann - ganz im Gegenteil: Deine Wahl ist teurer.
> Jo, die Fakten sich schön reden ;)
Die Fakten stehen da oben - in knallharten Euros.
> Denkfehler in den kausalen Zusammenhängen. Assembler ist genauso leicht> lesbar wie C wenn man es kann.
Das ist Geschmackssache. Ich könnte hier jetzt auch mit Ignoranz
Deinerseits zurückschießen, verkneife mir das aber. Diese Diskussion (C
vs Assembler) wird hier jeden Tag in irgendwelchen anderen Threads
geführt. Das Thema gehört hier einfach nicht hin. Ich habe die Freiheit,
mir meine Programmiersprache selbst auszusuchen. Punkt.
> Das tut ich auch, aber meine Prinzipien bei dieser Entscheidung heissen> das prinzipiel nach dem geeigneten Mittel gesucht wird und das auch> benutzt wird. Prinzipiell heist also aus objektiven Erwägungen heraus> und nicht aus Glauben heraus, mein Prinzip heist nicht glauben zu> wollen.
Ich sage dazu nur noch eins: Bootloader in C sind genauso
praxistauglich, wenn man vom Flash-Verbrauch absieht. Es gibt keine
sonstigen Nachteile, höchstens Vorteile.
> Du betrachtest geänderte Umweltbedingungen, hier geht es um Bootloader> und nicht allgmein um andere Projekte. Hier geht es um AVRs und nicht> UNIX PCs.
Ich wollte nur erläutern, wann ich wo welche Schwerpunkte setze. Diese
können von Projekt zu Projekt verschieden sein.
>> Aber bei einer so hardwarenahen Geschichte wie einem Tiny-Bootloader>> tritt Portierbarkeit auf einen anderen C-Compiler in den Hintergrund.>> Ah, meine Rede ;)
Na also. Hier ist mein Schwerpunkt nicht Portierbarkeit, sondern
Lesbarkeit.
> Warum sollte er, es gibt genügend fertige Bootloader.
Ja, besonders Deinen. Ich wusste genau, warum Du auf diesen Thread so
schnell angesprungen bist. Tut mir leid, dass ich den Link auf Deinen
Bootloader im Artikel vergessen habe. Habe ich nun nachgeholt.
Auf diesen Sch...-Satz habe ich die ganze Zeit gewartet. Gekränkte
Eitelkeit oder was soll das? Mit diesem Argument kannst Du alles
schlachten. "Warum baust Du Dir eine Uhr? Es gibt genügend fertige Uhren
auf der Welt!". Booah, nicht zu fassen.
Für die fertigen Tiny-Bootloader gibt es aber keine begleitenden Artikel
im Wiki. Oder hast Du vielleicht ausserhalb Deines Sources irgendwo
Deinen Bootloader derart dokumentiert, dass jemand die Technik, wie er
funktioniert, verstehen kann?
Ich verwende keine Software, die ich nicht verstehe. Ich möchte mir
nicht den Aufwand antun, einen fremden in Assembler programmierten
Bootloader zu verstehen, bis ich ihn verwende. Da ist mir die Zeit zu
schade. In der gleichen Zeit habe ich ihn in C neu geschrieben und habe
es selbst getan. Reicht dir das als Gegenargument?
> Das habe ich begriffen, ich zweifle den Nutzen dieses Konzeptes an.
Das bleibt Dir überlassen. Ich habe den Artikel nicht für Dich
geschrieben.
> Jo das habe ich jetzt auch wahrgenommen, ich lache jetzt immer noch über> mich da meine Progonse das du ein Jungspunt wärest mal wieder, wie so> viele Prognosen im Leben, voll in die Hose gegangen ist;)
Man sollte sich die Leute vorher genau anschauen, bevor man sich auf sie
einlässt. Ich kenne auch Deine Beiträge in diesem Forum ganz genau.
> Wie oben> gesagt, diese Risiko der Fehleinschätzung musst ich eingehen da die> Alternative eben schlechter ist. Es ist ein erfahrener Entwickler der> sich auf den Weg macht dieses Konzeopt zu entwickeln;)
Dieses Risiko gab es gar nicht. Meine Benutzerseite existiert schon seit
vielen Monaten.
> Jo ist mir, blöde Forensoftware die solche Details nicht autom. regeln> kann. Und bitte, da gleich auf plenken zu schließen sieht schon nach> persönlichem Ehrgeiz aus. Wie gesagt: das Leben ist zu kurz, die eigenen> Fußspuren im WEB viel zu schnell verblasst, da sollte man schnell> lernen nichts persönlich zu nehmen ;)
Man sollte als erstes vielleicht lernen, dass es viel mehr Arbeit für
tausende von Lesern ist, Deine falsche Punktuation beim Lesen im Kopf zu
korrigieren, als es für den einzelnen Schreiber Arbeit ist, das
Fragezeichen an die richtige Stelle zu schreiben. Du machst diese Arbeit
nur einmal, die Leser müssen es tausendfach tun. Das ist Verschwendung
von Ressourcen ohne Ende.
> Hm, und warum nicht deine Sections, die du ja als Kern des Lehrbeispiels> anführst, dafür benutzen ? Also eine Section in der diese Struct an> fester Adresse liegt ?
Das ginge auch, braucht aber mehr Flash. Ich speichere lediglich den
Pointer auf die Struktur, Du willst aber den Inhalt der Struktur im
Flash sehen. Hatte ich vorher auch mal so ausprobiert, hat mich aber
nicht ganz zufriedengestellt. Ich werde das nochmal überdenken, denn es
gibt dafür ein paar Für und Widers.
Viele Deiner Antworten zeigen mir, wer von uns beiden ignorant ist.
Größtes Manko ist bei Dir, dass Du nicht genau liest. Bis auf den
letzten Absatz in Deinem Posting halte ich den Rest lediglich gut genug
für die Tonne. Den letzten Absatz halte ich für konstruktiv, da sie der
Sache förderlich ist. Den Rest hier habe ich nur aus Gründen der
Höflichkeit beantwortet.
Ich werde auf Deine Provokationen in Zukunft nicht mehr eingehen und sie
einfach ignorieren. Wenn Du aber etwas konstruktives beizusteuern hast,
werde ich mich selbstverständlich darüber freuen.
Gruß,
Frank
Hagen Re schrieb:> Frank, wo finde ich den diesen Link auf deine private Seite ? Ich bin zu> blöd den im Artikel zu finden :(
Der Link steht in jedem meiner Thread-Beiträge. Du klickst einfach auf
das Blatt-Symbol rechts neben meinem Kürzel ukw:
Autor: Frank M. (ukw) [ ]
^
hier
Aber für Dich hier nochmal:
http://www.mikrocontroller.net/articles/Benutzer:ukw
Hagen Re schrieb:> Shit, entschuldige bitte ich habe das falsch interpretiert. Du gehst ja> damit schon den Weg den ich im vorherigen Posting ansprach.
Ja, eigentlich schon. Es gibt nur die Frage zu klären, ob der komplette
Inhalt der Struct oder nur der Pointer auf diese gespeichert werden
soll.
Die erste Alternative braucht mehr Flash, Zugriffe über Pointer sind
aber langsamer (und brauchen dann auch wieder mehr Flash, nämlich an
Code)
Um das zu erläutern:
boot.uart_getc ();
ist schneller und verbraucht weniger Flash als
boot->uart_getc ();
Ich werde wohl den Mittelweg gehen: Pointer auf die Struct im vorletzten
Wort des Flashs und ein Kopieren der Inhalte per memcpy_P(). Aber
eigentlich ist jedem Anwender das selbst überlassen, denn es betrifft
die Anwendung, nicht den Bootloader.
> Denoch nochmal zur Verfikation: Diese Struct ist deine Sprungtabelle und> wird im FLASH an fester und bekannter Adresse gespeichert.
Ja.
> Es gibt also> keine weitere Funktion die nötig ist um diese Adresse zu ermitteln ?
Ja.
> Interessant ist dann nämlich die Frage an welche Adresse du diese> Sprungtabelle reallokieren möchtest und wie du das am geschicktesten dem> GCC beibringst, da ja Änderungen an dieser Sprungtabelle zu einer> geänderten Reallokation im Linker führen muß, also die nötige> Deklaration deisr Section dem Linker möglichst dynamisch beigebracht> werden muß.
Eben deshalb mache ich es ohne Sections. Ich knalle einfach den Wert des
Pointers auf die existierende(!) Struct in das vorletzte Wort des
Flashs. Die Anwendung kann sich das einfach abholen mit:
Dann geschieht der Aufruf über boot.uart_poll() bzw. boot.uart_getc().
Das ist etwas effizienter, hat aber den Nachteil, dass die Struct 2x im
SRAM liegt - einmal im SRAM des Bootloaders und einmal im SRAM der
Applikation.
Danke Frank für die Infos mit dem kleinen Symbol neben den Namen ich
dachte das wäre der PN Button zusätzlich zum blauen Namen.
Sicherlich wirst Du verstehen können das keiner sich soviel Zeit nehmen
wird erstmal all diese Links soweit zu folgen bis der geneigte WEB
Besucher sich ausmalen kann wen er vor sich hat. Ich mache das niemals
da ich nicht die Zeit habe mich neben dem rein inhaltlichen noch mit
personellem zu befassen. Davon abgesehen stellt sich die Frage welchen
Nutzen ich dann von personalisiertem, gefärbtem Wissen haben sollte, bei
dem man nie die dahinter liegenden wahren Absichten der Personen
erkennen kann. Ausnahmen bestätigen diese Regel, aber dann lohnt sich
für mich der Zeitaufwand auch.
Ansonsten bitte ich dich um Nachsicht das meine Argumente dich so
persönlich verletzt haben, das war sicherlich nicht meine Absicht. Ich
bin deiner Einladung zu einer Diskussion gefolgt, einer Diskussion über
das Konzept und den Alternativen, also inhaltlich. Eben weil ich der
Meinung war das meine praktischen Erfahrungen von Interese sein könnten.
Die Kritik an meiner Schreibweise kann ich gut verstehen, was wäre wenn
du von mir wüsstest das ich Legastheniker bin, das ich im Praktikum im
Sägewerk 6 Finger verloren habe, würde das deine Meinung verändern?
Mein Schreibstil ist eine Frage meiner Persönlichkeit meiner eventuell
eingeschänkten Fertigkeiten und meiner Gechichte, aber der Inhalt ist
eine Frage des Geistes, Wissens, Ideen. Es macht keinerlei Sinn in
irgendeiner Form Aussagen im WEB persönlich zu nehmen oder persönliche
Aussagen als objektiv wahrzunhmen, Die inhaltliche Diskussion, Argumente
und Kritik sind es die zählen. Hast du meine Kommentare wirklich so
persönlich genommen? für mich unverständlich.
Egal: ich halte mich demnächst zurück und verfolge den Fortschritt
deines Artikels, Ehrenwort ;)
Gruß Hagen
Frank M. schrieb:> Hagen Re schrieb:>> Shit, entschuldige bitte ich habe das falsch interpretiert. Du gehst ja>> damit schon den Weg den ich im vorherigen Posting ansprach.>> Ja, eigentlich schon. Es gibt nur die Frage zu klären, ob der komplette> Inhalt der Struct oder nur der Pointer auf diese gespeichert werden> soll.>> Die erste Alternative braucht mehr Flash, Zugriffe über Pointer sind> aber langsamer (und brauchen dann auch wieder mehr Flash, nämlich an> Code)>> Um das zu erläutern:>> boot.uart_getc ();>> ist schneller und verbraucht weniger Flash als>> boot->uart_getc ();>> Ich werde wohl den Mittelweg gehen: Pointer auf die Struct im vorletzten> Wort des Flashs und ein Kopieren der Inhalte per memcpy_P(). Aber> eigentlich ist jedem Anwender das selbst überlassen, denn es betrifft> die Anwendung, nicht den Bootloader.
Aus eben diesen Erwägungen heraus kommt meine Frage. Die Größe dieser
Struct ist im Grunde nur abhängig von der Anzahl an Funktionen die aus
dem Bootloader exportiert werden sollen, also mit größter
Wahrscheinlichkeit fix. Du hast schon am Ende einen Sprung zur Main der
Applikation hinterlegt, warum davor/dahinter nicht auch alle andernen
Exporte ?
Der Vorteil akkumuliert sich dann beim Aufruf dieser Funktionen aus der
Anwendung heraus, schneller und weniger FALSH. Dieser Vorteil wächst mit
der Nützlichkeit undd amit höhren Häufigkeit deren Benutzung durch die
Applikation.
Auch entfällt der zusätzliche Speicherverbrauch an knappen SRAM und
FLASH um diese Sprungtabelle mit zusätzlichen MCU-Takten umzukopieren.
Davon abgesehen sehe ich diese "Umkopiererei" im Artikel ebenfalls als
zusätzliche unnötige Operationen die nur die Wahrscheinlichkeiten von
Fehlern inkrementieren. zB. ist das Tor geöffnet für Inkonsistenzen wenn
man die gleiche Tabelle gleich zweimal im SRAM kopiert hat.
Das Interessante für den Leser des Konzeptes ist nun wie man dem GCC
Linker möglichst transparent diese Reallokation beibringt.
Bitte! diese Worte sind inhaltlicher Natur, selbst wenn der Autor Gott
hiese wäre der mir egal, es geht um inhaltliche Alternativen.
Gruß Hagen
Hagen Re schrieb:> Sicherlich wirst Du verstehen können das keiner sich soviel Zeit nehmen> wird erstmal all diese Links soweit zu folgen bis der geneigte WEB> Besucher sich ausmalen kann wen er vor sich hat.
Ich halte es schon für wichtig. Wenn ich jemandem antworte, will ich
auch wissen, wen ich vor mir habe - das gilt hier auch wie im realen
Leben. Also werde ich mich schlaumachen... und kann dann mit dem
Gegenüber auf Augenhöhe diskutieren.
> Ansonsten bitte ich dich um Nachsicht das meine Argumente dich so> persönlich verletzt haben, das war sicherlich nicht meine Absicht.
Ich reagiere nur auf eines allergisch... nämlich, wenn es "von oben
herab" erscheint. Und es tut mir leid, Dir sagen zu müssen, dass ich
diesen Eindruck des öfteren hatte beim Lesen Deiner Antworten.
> Die Kritik an meiner Schreibweise kann ich gut verstehen, was wäre wenn> du von mir wüsstest das ich Legastheniker bin, das ich im Praktikum im> Sägewerk 6 Finger verloren habe, würde das deine Meinung verändern?
Selbstverständlich würde das meine Meinung ändern. Ich weiß aber, dass
Du weder Legastheniker bist noch jemals in einem Sägewerk gearbeitet
hast ;-)
> [...] Es macht keinerlei Sinn in> irgendeiner Form Aussagen im WEB persönlich zu nehmen [...]
Korrekt. Es macht aber auch keinerlei Sinn, sich im Web anders zu
benehmen als im realen Leben. Es ist ein Privileg, hier schreiben zu
dürfen. Dieses Privileg sollte man nicht missbrauchen, schon gar nicht,
um hier die Sau rauszulassen. Ganz im Gegenteil: man sollte dem Leser
den geeigneten Respekt erweisen. Das fängt schon mit der Sorgfältigkeit
des Schreibens (hinsichtlich Rechschreibung) an.
> Hast du meine Kommentare wirklich so> persönlich genommen? für mich unverständlich.
Die etwas größere Distanz über das Internet lässt einigen Leuten schon
mal schnell das eine oder andere Wort aus der Feder (... ähem Tastatur)
gleiten, was sie im realen Leben niemals dem jeweiligen Gegenüber ins
Gesicht gesagt hätten.
Mich störte - wie oben schon erwähnt - Deine Behandlung "von oben
herab". Sonst ist alles okay, mach Dir keine Gedanken ;-)
> Egal: ich halte mich demnächst zurück und verfolge den Fortschritt> deines Artikels, Ehrenwort ;)
Na prima. Wie gesagt: Kommentare zur Sache sind immer gern gesehen.
Gruß,
Frank
Hagen Re schrieb:> Aus eben diesen Erwägungen heraus kommt meine Frage. Die Größe dieser> Struct ist im Grunde nur abhängig von der Anzahl an Funktionen die aus> dem Bootloader exportiert werden sollen,
Korrekt.
> also mit größter Wahrscheinlichkeit fix.
Auch richtig.
> Du hast schon am Ende einen Sprung zur Main der Applikation hinterlegt,> warum davor/dahinter nicht auch alle andernen Exporte ?
Genau so mache ich es doch, hier ein Auszug aus meinem Source:
tinyboot.h:
Ich sehe schon, ich sollte das mal endlich in den Artikel reinschreiben,
bevor hier noch wilde Spekulationen auftreten ;-)
Okay, ich erläutere hier schon mal die oben genannten Funktionen, bevor
gleich wieder gefragt wird:
uart_getc() & uart_putc() sind klar. Mittels set_timer1_compa_isr() kann
die Applikation selbst eine Funktion anmelden, die im Falle des
Timer1-COMPA-Interrupts ausgeführt wird. Analoges gilt für
set_pcint0_isr(). Beide ISRs sind im Bootloader definiert. Die eine für
den Software-Uart, die andere zum Durchreichen an den nächsten ATtiny in
der Kette. Letztere ist projektspezifisch und wird daher im Artikel
nicht erwähnt werden.
Möchte die Applikation also eigene ISRs verwenden, muss sie in dem Fall,
wo diese schon im Bootloader genutzt werden (aber nur dann!) diese
Funktion anmelden. Der Bootloader tauscht nämlich nicht nur den
Reset-Vektor vorn im Flash gegen den eigenen aus, sondern natürlich auch
die Interrupt-Vektoren, die er selber braucht. Das habe ich bisher im
Artikel nicht erwähnt, weil es erst im Kapitel "Sharen von Interrupts"
von Relevanz ist.
> Das Interessante für den Leser des Konzeptes ist nun wie man dem GCC> Linker möglichst transparent diese Reallokation beibringt.
Da der Pointer auf die Struct at-Runtime gebildet wird, gibt es dieses
Problem momentan nicht.
> Bitte! diese Worte sind inhaltlicher Natur, selbst wenn der Autor Gott> hiese wäre der mir egal, es geht um inhaltliche Alternativen.
So habe ich es diesmal durchaus verstanden :-)
Gruß,
Frank
Frank M. schrieb:>> Du hast schon am Ende einen Sprung zur Main der Applikation hinterlegt,>> warum davor/dahinter nicht auch alle andernen Exporte ?>> Genau so mache ich es doch, hier ein Auszug aus meinem Source:
Sorry das ich widersprechen muß, Du machst es nicht so.
Du legst im FALSH nur eine Adresse auf eine einzige Funktion die als
Handler eine im SRAM-Stack liegende Struktur als eine Sprungtabelle
intialisiert.
Ich meine es so: lege vor der Adresse im FALSH an der du den Entrypoint
zur MAIN als 2 Bytes Opcode ablegst auch alle anderen vom Bootloader
exportieren Funktionsadressen ab.
Du sparrst:
- deine Funktion bootloader_functions; in der du erst zur Laufzeit eine
im SRAM liegende Struktur initialisierst, mein Vorschlag lässt das schon
zur Compile-/Linkertime erledigen
- die nötigen Taltzyklen in deiner bootoader_functions Funtion da diese
ja garnicht mehr benötigt wird
- die sich ergebende unnötige Redundanz der Einsprungpunkte fest im
FLASH gespeichert satt wie bei dir in SRAM Strukturen. Der Nutzer deiner
Funktionen kann diese SRAM Struktur mehrfach erzeugen, was garnicht
nötigt ist, es gibt nur einen FLASH mit festen Einsprungspunkten an
feste Funktionsadressen im Bootloader.
Das alles wird schon zur Compile/Linkertime erledigt und nicht erst
später zur Laufzeit des Bootlaoders.
- den Erklärungsaufwand an den Nutzer dieses APIs.
Ehrlich gesagt: ich finde den Weg sinnlos kompliziert.
Was spräche dagegen an einer festen FLASH Adresse im Code diese
Sprungtabelle komplett abzulegen ? So wie es bei den ISR Vektoren auch
der Fall ist ?
Es ändert sich später nichts mehr an den Adressen dieser Sprungtabelle,
dh. schon zur Compile/Linkerzeit sind diese fest reallokiert.
Der FLASH kann vor überschreiben geschützt werden (ja ich weiß Argument
Tiny, wir betrachten es mal akademisch) und damit kann diese
Sprungtabelle zur Laufzeit nicht mehr unbeabsichtigt manipuliert werden.
Das geht mit deiner dynamisch zur Laufzeit gefüllten SRAM Struktur aber.
Damit inkrementierst du die Fehleranfälligkeit, sowohl technologisch wie
auch auf Nutzerseite. Und das alles für welchen Nutzen ?
Gruß Hagen
Hm vielleicht nochmal in anderen Worten:
Du hast einen Zeiger im FLASH "bootloader_functions" der auf eine
Struktur im SRAM zeigt in der dann dynamisch zur Laufzeit die
Einsprungpunkte zu den Funktionen im FLASH zum Bootloader liegen.
Ich meine: du hast eine Sprungtabelle im FLASH bestehend aus dem Inhalt
der bei dir im SRAM liegt und dieser Inhalt wird schon zur Linkerzeit
erzeugt. Ohne Umwege über SRAM Strukturen, ohne Notwendigkeit diese zur
Laufzeit dynamisch erzeugen zu müssen.
Also exakt so wie es der WinAVR GCC sowieso bei den ISR Vektoren auch
macht.
Gruß Hagen
Frank M. schrieb:>> Du hast schon am Ende einen Sprung zur Main der Applikation hinterlegt,>> warum davor/dahinter nicht auch alle andernen Exporte ?>> Genau so mache ich es doch, hier ein Auszug aus meinem Source:
in diesem Sinne stimmt deine Aussage eben nicht, ich schrieb alle
Exporte.
Hagen Re schrieb:> Du legst im FALSH nur eine Adresse auf eine einzige Funktion die als> Handler eine im SRAM-Stack liegende Struktur als eine Sprungtabelle> intialisiert.
Nein, ich speichere den Pointer auf die Struktur BOOTLOADER_FUNCTIONS im
Flash an vorletzter Stelle ab. In dieser Struktur stecken dann die
Pointer auf die zu exportierenden Funktionen. Diese Struktur liegt im
SRAM.
> Ich meine es so: lege vor der Adresse im FALSH an der du den Entrypoint> zur MAIN als 2 Bytes Opcode ablegst auch alle anderen vom Bootloader> exportieren Funktionsadressen ab.
Wir meinen fast dasselbe. Du willst alle Pointer auf die zu
exportierenden Funktionen am Flash-Ende speichern, ich speichere dort
lediglich einen Pointer auf die Funktions-Liste (in Form einer
Datenstruktur). Ich komme daher mit 2 Bytes im Flash aus.
> Du sparrst:>> - deine Funktion bootloader_functions;
Es gibt keine Funktion bootloader_functions. Es gibt nur eine
Datenstruktur. Diese wird in main() des Bootloaders ganz am Anfang
initialisiert.
> in der du erst zur Laufzeit eine> im SRAM liegende Struktur initialisierst, mein Vorschlag lässt das schon> zur Compile-/Linkertime erledigen
Achso! Jetzt habe ich es verstanden. Der Compiler soll bereits at
CompileTime die Datenstruktur füllen. Sag das doch gleich ;-)
Alt:
1
staticBOOTLOADER_FUNCTIONSbootloader_functions;
2
3
bootloader_functions.uart_getc=uart_getc;
4
bootloader_functions.uart_putc=uart_putc;
Neu:
1
staticBOOTLOADER_FUNCTIONSbootloader_functions=
2
{
3
uart_getc,
4
uart_putc
5
};
Ja, das geht... und spart auch ein paar Bytes an. Werde ich so ändern.
> Was spräche dagegen an einer festen FLASH Adresse im Code diese> Sprungtabelle komplett abzulegen ? So wie es bei den ISR Vektoren auch> der Fall ist ?
Es spart Flash. Ich komme mit 2 Bytes aus, egal wieviele Funktionen in
der Struktur abgelegt werden - aber zu Lasten des SRAM. Die von Dir
vorgeschlagene Alternative braucht für jede Funktion 2 Bytes im Flash,
aber keinen SRAM. Wie gesagt, ich habe bereits beides vor Tagen
ausprobiert. Es gibt da Für und Wider - ich schrieb das schon heute
mittag. Hattest Du offenbar überlesen.
> Der FLASH kann vor überschreiben geschützt werden (ja ich weiß Argument> Tiny, wir betrachten es mal akademisch) und damit kann diese> Sprungtabelle zur Laufzeit nicht mehr unbeabsichtigt manipuliert werden.
Okay, das ist ein Argument, das ich sofort akzeptiere. Du hast mich
überzeugt: Ich lege die Struktur komplett ins Flash - statt nur den
Pointer darauf.
Ich werde das gleich mal testen und anschließend den Artikel anpassen.
Gruß,
Frank
Ja das bemerke ich immer wieder, die Kommunikation zwischen Menschen ist
primär von den eigenen Vorstellungen geprägt und unser Gehirn
"übersetzt" die Argumente der Anderen immer wieder, oft unbewusst für
uns, auf unsere eigenen Vorstellungen. Wir filtern das raus, bzw.
verbiegen was nicht in unseren Kram passt. Erst duch häufigeren Kontakt
können wir diese, zu Vorurteilen führenden, Denkfehler beseitigen, bzw.
erkennen.
Zurück zum Thema:
Bei deiner Methode muß der Compiler pro Initialisierung eines Zeigers in
der Tabelle folgenden Pseudocode minimal ausführen:
1
; in X Zeiger auf SRAM Struct
2
3
ldi rX, Low(FLASH_ADDRESS)
4
ldi rY, High(FLASH_ADDRESS)
5
sts X+0, rX
6
sts X+1, rY
Das sind also 4*2 Bytes an FLASH um einen Zeiger zu intialiseren, ohne
Berücksichtigung der Initialisierung der Basiszeiger X,Y,Z auf die SRAM
Struktur usw.
Das Ratio an FLASH Verbrauch der verschiedenen Lösungen muß also
mindestens 1 zu 4 sein.
Aber das ist nicht das was mich stören würde (schei. auf FLASH).
Schwerer wiegen für mich die Fakten das
1. der Compiler/Linker uns un-intelligente Arbeit abnehmen kann, wenn
wir schon ein solch intelligentes Monster nutzen dann richtig ;) ASM
Programmierer müssen das von Hand machen.
2. die HW-Fähigkeiten uns unterstützen bei der Ausführungssicherheit,
sprich FLASH ist wesentlich weniger auf Überschreiben anfälliger als
SRAM, also nutzen wir diesen Vorteil ohne Einbußen
3. es für den Nutzer viel transparenter ist, was dem Entwickler
Supportstreß spart und Freude schafft
und 4. finde ich es intuitiver. Das ist zwar höchst subjektiv würde man
meinen aber ich habe die Erfahrung gemacht das Dinge die man intuitiv
macht viel natürlicher, flutschiger sind. Sowohl wenn man sich später
daran nochmal versucht und auch wenn man es anderen erklären möchte.
Gruß Hagen
PS: das mit dem SRAM-Stack und eigener Funktion war eine
Fehlinterpretation die aber keine echte Relevanz für meine inhaltlichen
Argumente hatte. Ob du das in Main() und globaler SRAM Struct oder
Funktional mit SRAM Struct als Rückgabe im Stack machst ist vom Aufwand
her ähnlich. Das mit der Funktion und SRAM Struct auf dem Stack ist aber
denoch besser als die Lösung über eine dauerhafte globale SRAM Struct.
Da dort die Zeitspanne in der durch Fehler (Stackoverflow zB) diese
zerstört wird maximal ist, nämlich die komplette Laufzeit der Software.
Bei einer Lösung als Funktion und Rückgabe über den Stack wäre diese
Zeitspanne so kurz wie die aufrufende Funktion diese Infos benötigte.
Was natürlich zustzlich auch mehr SRAM für andere Aufgaben frei macht im
Gegensatz zu einer globalen SRAM Struct.
Es gibt also noch mehr Argumente die Dich überzeugen sollten ;)
Übrigens würde ich Dir empfehlen, im Gegensatz zu vielen ASM Bootloadern
die sowas machen, deine Sprungtabelle an den Anfang deiner Bootloader
Section zu legen. Wohl bemerkt alle diese Sprünge inklusive des Sprungs
zur Main(). Diese würde ich ganz am Anfang legen damit bei einem Fehler
in der Anwendung, der dazu führt das der PC in den Bootloader läuft, auf
diesen Jump nach Main() trifft, quasi ein Failsave Software Reset macht.
Nach diesem Sprung sollten die exportieren Bootloader Einsprungspunkte
kommen und danach Dein ISR Vector Clone.
Warum ? Weil du so besser dies dem GCC Linker beibiegen kannst. Dieser
reallokiert nämlich dann autom. und nahtlos deinen Bootloader Code
danach. Durch die Verlagerung an das Ende dieser Section hast du ein
Problem mit dem Linker.
1. musst du ihm die Adresse dieser Sprungtabelle separat beibringen
2. du musst diese Startadresse dieser Srungtabelle aufwendig berechnen
3. könnte dein Bootloader Code in diese Tabelle reinlaufen und der
Linker bekommt Probleme.
Exakt Punkt 3. bedeutet zukünftigen Supportstreß da viele Entwickler die
Erweiterungen einbauen, die den compilierten Bootloadercode größer
machen als die allokierte Section ist, mit der Anpassung des
Linkerscriptes Probleme haben.
Gruß Hagen
Hi,
ich habe nun den Artikel angepasst - selbstverständlich das Ganze vorher
getestet. Die Liste der exportierten Funktionen wird nun komplett im
Flash gespeichert. Dabei ist der Pointer auf die Applikation selbst mit
in die Struct gewandert. Dies spart Flash-Speicherzugriffe, weil ich
dann die Pointer auf die zu exportierenden Funktionen mitsamt dem
Start-Pointer auf die Applikation "in einem Rutsch" schreiben kann. Die
Funktion pgm_write_word() musste ich dafür durch die Funktion
pgm_write_block() ersetzen.
Diese Änderung betraf dann auch das Kapitel "Ansprung der Applikation",
also nicht nur das zuletzt gefüllte Kapitel "Sharen von Funktionen".
Nichtsdestotrotz muss die Applikation die Pointer ins RAM laden. Anders
lassen sich aus der Applikation die exportierten Funktionen nicht
aufrufen. Vor jedem uart_getc() extra ein pgm_read_word() zu machen, um
ad hoc den Pointer auszulesen, halte ich für übertriebenen Unsinn.
Sollte sich die Applikation ihr eigenes SRAM zerschießen, ist es auch
egal ob der Pointer dabei kaputtgeht oder nicht.
Gruß,
Frank
P.S.
Code habe ich durch die Maßnahme nicht gespart. Sowohl Bootloader und
Applikation sind in etwa gleich groß geblieben.
Hagen Re schrieb:> Übrigens würde ich Dir empfehlen, im Gegensatz zu vielen ASM Bootloadern> die sowas machen, deine Sprungtabelle an den Anfang deiner Bootloader> Section zu legen.
Am Anfang der Bootloader-Section liegt die vom Linker angelegte
Interrupt-Vektor-Tabelle. Also ganz am Anfang der Reset-Vektor, im
konkreten Beispiel ab 0x1800.
> Wohl bemerkt alle diese Sprünge inklusive des Sprungs> zur Main(). Diese würde ich ganz am Anfang legen damit bei einem Fehler> in der Anwendung, der dazu führt das der PC in den Bootloader läuft, auf> diesen Jump nach Main() trifft, quasi ein Failsave Software Reset macht.> Nach diesem Sprung sollten die exportieren Bootloader Einsprungspunkte> kommen und danach Dein ISR Vector Clone.
Das ist bereits so gegeben. Am Anfang der Bootloader-Section liegt der
Reset-Vektor auf den Bootloader. Damit wird in Deinem Fehlerszenario der
Bootloader aufgerufen... was besseres kann einem nicht passieren.
Empfängt der Bootloader keine Daten, führt er die Applikation aus. Daher
geht alles seinen geordneten Weg.
> Warum ? Weil du so besser dies dem GCC Linker beibiegen kannst. Dieser> reallokiert nämlich dann autom. und nahtlos deinen Bootloader Code> danach. Durch die Verlagerung an das Ende dieser Section hast du ein> Problem mit dem Linker.
Schau bitte in den Artikel, insbesondere in die oben erwähnten
neuformulierten Kapitel. Es gibt keine Linker-Probleme.
Gruß,
Frank
Frank M. schrieb:> Nichtsdestotrotz muss die Applikation die Pointer ins RAM laden. Anders> lassen sich aus der Applikation die exportierten Funktionen nicht> aufrufen.
Doch das geht ;) Ich suche mal in meinen Source nach der exakten C
Syntax. Wird aber erst morgen was werden und schaue mal ob ich die Zeit
finde ein Beispiel zu bauen.
Letzendlich deklarierst du die Prototypen dieser Funktionen in normaler
C Syntax und gibts deren FLASH Adresse an, statt einer Implementierung.
Es müsst sogar so gehen das man diese Sprungtabelle als Struct in den
FLASH deklariert.
SRAM benötigst du keinen dafür, ein FLASH lesen/schreiben zur Laufzeit
sollte komplett entfallen, und am Ende wird man mindestens 75% an FLASH
einsparen können.
Und das Beste daran: es erscheint dem Nutzer so als ob er eine reguläre
Funktion wie seine eigene aufrufen kann. Nur mit dem Unterschied das wir
dem Linker das manuell beibiegen müssen.
Gruß Hagen
Frank M. schrieb:> Schau bitte in den Artikel, insbesondere in die oben erwähnten> neuformulierten Kapitel. Es gibt keine Linker-Probleme.
Jo als ich meinen Beitrag schrieb hast du am Artikel geschrieben, wie
soll ich das wissen können ?
Hagen Re schrieb:> 1. musst du ihm die Adresse dieser Sprungtabelle separat beibringen
Nein, das ist eine Preprocessor-Konstante in tinyboot.h. Diese muss vom
Anwender angepasst werden, wenn die Größe des Flashs abweicht.
2. du musst diese Startadresse dieser Srungtabelle aufwendig berechnen
Nein, das macht der Preprocessor für mich. Heraus kommt eine konkrete
Zahl. Da muss nichts berechnet werden.
3. könnte dein Bootloader Code in diese Tabelle reinlaufen und der
Linker bekommt Probleme.
Der Bootloader könnte größer werden als die "sizeof (section_bootloader)
- sizeof (BOOTLOADER_FUNCTIONS)", ja. Das kann man aber leicht abbiegen.
Man definiert eine eigene Section die auf FLASHSIZE - sizeof
(BOOTLOADER_FUNCTIONS) beginnt. Dann bemerkt dieses der Linker, weil
sich zwei Sections überschneiden und wirft einen Fehler.
Ich sehe daher keinen Grund, vom skizzierten Layout (siehe Artikel)
abzuweichen.
Gruß,
Frank
Hagen Re schrieb:> Doch das geht ;) Ich suche mal in meinen Source nach der exakten C> Syntax.
Ohne Performance-Verschlechterung? Da bin ich mal gespannt ;-)
> SRAM benötigst du keinen dafür, ein FLASH lesen/schreiben zur Laufzeit> sollte komplett entfallen, und am Ende wird man mindestens 75% an FLASH> einsparen können.
75% von was? Ich kopiere Pointer ins RAM, das sind im Beispiel des
Artikels 3 x 2 = 6 Bytes. Genau diese 6 Bytes "verschwende" ich im
Flash.
> Und das Beste daran: es erscheint dem Nutzer so als ob er eine reguläre> Funktion wie seine eigene aufrufen kann. Nur mit dem Unterschied das wir> dem Linker das manuell beibiegen müssen.
Das hört sich so an, als ob Du die Funktionen als "irgendwo extern"
deklarieren willst und dem Applikations-Linker das MAP-File des
Bootloaders unterjubeln willst. Böse böse ;-)
EDIT:
Das hatte ich übrigens mal ganz am Anfang gemacht: Den Bootloader in der
separaten Section zur Applikation gelinkt und anschließend hat das
PC-Programm, welches die erzeugte Hex-Datei der Applikation einliest und
an den Bootloader schickt, die HEX-Daten ab 0x1800 einfach gekappt und
nicht mit übertragen. Dann musst Du aber penibel darauf achten, dass Du
die Applikation immer neu linkst, wenn Du den Bootloader veränderst. Das
wollte ich nicht und deshalb hab ich das ganze wieder separiert und die
Pointer-auf-Funktionen-Lösung eingebaut.
Frank M. schrieb:> Hagen Re schrieb:>> Doch das geht ;) Ich suche mal in meinen Source nach der exakten C>> Syntax.>> Ohne Performance-Verschlechterung? Da bin ich mal gespannt ;-)
Es verbessert die Performance weil: kein indirekter Sprung über eine
SRAM Tabelle mehr erfolgt sondern direkt durch den Linker diese Funktion
wie jede andere Funktion aufgerufen werden kann.
Übrigens ich bleibe dabei: die Sprungtabelle an das Ende der Bootloader
Section zu legen ist ungeschickt.
Gruß Hagen
Frank M. schrieb:> Das hört sich so an, als ob Du die Funktionen als "irgendwo extern"> deklarieren willst und dem Applikations-Linker das MAP-File des> Bootloaders unterjubeln willst. Böse böse ;-)
Nö warum sollte man sowas machen ?
Hagen Re schrieb:> Es verbessert die Performance weil: kein indirekter Sprung über eine> SRAM Tabelle mehr erfolgt sondern direkt durch den Linker diese Funktion> wie jede andere Funktion aufgerufen werden kann.
Dann ist die Applikation aber abhängig vom Versionsstand des
Bootloaders. Wenn sich uart_getc() im Flash durch eine Änderung im
Bootloader verschiebt, hast Du andere Adressen. Du kannst also nicht ein
und dieselbe Applikation auf 2 µCs schieben, auf denen eine
unterschiedliche Version des Bootloaders installiert ist. Daher halte
ich Deinen Lösungsvorschlag für suboptimal.
Komm mir bitte jetzt nicht damit, jede zu exportierende Funktion in eine
extra Section zu legen, damit sie immer an festen Adressen steht, das
ist wenig bis gar nicht praktikabel ;-)
> Übrigens ich bleibe dabei: die Sprungtabelle an das Ende der Bootloader> Section zu legen ist ungeschickt.
Das können wir gerne nochmal diskutieren, wenn der Artikel vollständig
ist. Zum jetzigen Zeitpunkt ist die Diskussion darüber kontraproduktiv.
Gruß,
Frank
Frank M. schrieb:> Dann ist die Applikation aber abhängig vom Versionsstand des> Bootloaders. Wenn sich uart_getc() im Flash durch eine Änderung im> Bootloader verschiebt, hast Du andere Adressen.
Wenn sich die Addresse der uart_getc() verschieben sollte dann
verschiebt sich noch lange nicht die Adresse des Einsprungpunktes in der
Sprungtabelle zur uart_getc() Funktion. Das ist ja der Sinn solcher
Sprungtabellen, exakt so wie bei den ISR Vektoren.
Gruß Hagen
Hagen Re schrieb:> Wenn sich die Addresse der uart_getc() verschieben sollte dann> verschiebt sich noch lange nicht die Adresse des Einsprungpunktes in der> Sprungtabelle zur uart_getc() Funktion. Das ist ja der Sinn solcher> Sprungtabellen, exakt so wie bei den ISR Vektoren.
Die ISR-Vektoren sind verkappte RJMPs. C-Funktionen werden aber nicht
über RJMP aufgerufen. Daher hinkt hier Dein Vergleich.
Ich benutze zur Zeit Pointer auf Funktionen, die kannst Du eher mit
einem indirekten Call vergleichen. Ich wüsste momentan nicht, wie Du das
über RJMP oder ähnliches anders realisieren könntest. Naja, ich bin auf
Deinen Lösungsvorschlag morgen gespannt ;-)
Hier ein Beispiel aus meiner Anwendung:
cmd = boot.uart_getc ();
320: e0 91 7e 00 lds r30, 0x007E
324: f0 91 7f 00 lds r31, 0x007F
328: 09 95 icall
Wie willst du das effizienter mit einer wie auch immer gearteten
Sprungtabelle im flash hinbekommen?
Hagen Re schrieb:> Wenn sich die Addresse der uart_getc() verschieben sollte dann> verschiebt sich noch lange nicht die Adresse des Einsprungpunktes in der> Sprungtabelle zur uart_getc() Funktion. Das ist ja der Sinn solcher> Sprungtabellen, exakt so wie bei den ISR Vektoren.
Hm, habe da jetzt eine Linkeroption gefunden:
--defsym externeFunktion=0xNNNN
Damit könnte es gehen. Es wird dann in der Applikation ein
rcall NNNN
ausgeführt. Bei NNNN könnte dann der RJMP stehen. Damit würde dann ein
Funktionsaufruf übersetzt werden als:
rcall NNNN ; in Applikation
rjmp OFFSET ; in Sprungtabelle des Bootloaders
Das sind dann nur 4 Byte Opcode und ist kürzer als das:
cmd = boot.uart_getc ();
was 10 Bytes an Opcode braucht. Eine Struct im SRAM wird dadurch unnötig
- zumindest in der Applikation.
Ich werde das mal testen.
Gruß,
Frank
leute, leute, was ist denn hier los :)
Ich finde Franks Ansatz interessant.
Er hat ja auch einen Link zu einem meiner Threads gepostet, der
prinzipiell immer noch aktuell ist.
Das Nuzen der Uart-Funktionalität des Bootloaders aus der Applikation
ist immer noch ein Wunsch. For allem die Tinys bringen ja teilweise
Features mit, die es bei den Megas (zunmindest bei denen in DIP) nicht
gibt, haben aber allerhöchstens 8k.
Wenn da 1k eingespart werden könnte, indem man die
Kommunikatiosnroutinen des Bootloaders mitnutzt, wäre das doch keine
schlechte Sache.
Nach meinen Vorstellungen Ideal wäre ein AVRootLoader mit C-Interface
für die Soft-Uart mit automatischer Baudraten-Anpassung.
Bisher ist es nicht selten bei mir so, dass auf dem AVR der AVRootloader
landet und dann separat eine C-SW-Uart-Lib. Die C-lib hat leider nicht
dieses tolle Feature der Baudratenerkennung (hab noch keine gefunden,
die das kann)
Das diese Kombination immer noch platzsparender ist, als Franks
Bootloader, spricht natürlich gegen das Konzept den BL unbedingt in C
implementieren zu wollen, aber aus rein akademischer Sicht - um die
Mechanismen, die nötig sind vorzuführen - ist sicher nichts dagegen
einzuwenden.
Vlad Tepesch schrieb:> leute, leute, was ist denn hier los :)
Och, ab und zu muss man sich mal kloppen, um das Revier abzustecken ;-)
Jetzt haben wir aber wieder Frieden.
> Wenn da 1k eingespart werden könnte, indem man die> Kommunikatiosnroutinen des Bootloaders mitnutzt, wäre das doch keine> schlechte Sache.
Genau. Ich habe eben mal alles projektspezifische rausgeworfen, der
Tiny-Bootloader hat jetzt inkl. SW-UART 1546 Bytes. Dabei geht das
meiste auf den SW-UART, der ziemlich fett ist, da er "nach Lehrbuch"
programmiert ist. Ein anderer SW-UART ist da bestimmt genügsamer, so
dass sich der Bootloader wohl noch auf 1KB oder schlimmstenfalls 1,2KB
drücken lässt.
> Nach meinen Vorstellungen Ideal wäre ein AVRootLoader mit C-Interface> für die Soft-Uart mit automatischer Baudraten-Anpassung.
Ja, das wäre ideal. Ich bin da immer noch auf der Suche nach einem
genügsamen SW-Uart in C, der auch eine Autobaud-Erkennung kann. Notfalls
in Assembler, den würde ich dann nach C umschreiben.
> Das diese Kombination immer noch platzsparender ist, als Franks> Bootloader, spricht natürlich gegen das Konzept den BL unbedingt in C> implementieren zu wollen, aber aus rein akademischer Sicht - um die> Mechanismen, die nötig sind vorzuführen - ist sicher nichts dagegen> einzuwenden.
Warten wir mal ab, wenn der Tiny-Bootloader an die 1K von der Größe
kommt und der SW-UART auch von der Applikation genutzt werden kann, kann
das Ganze durchaus auch für die Praxis interessant werden...
Ich bin dran,
Frank
Frank, so wie ich mir das mit der Sprungtabelle gedacht habe geht es in
purem C mit dem GCC leider nicht. Mit Borland C auf PCs garkein Problem
aber nicht mit dem GCC möglich.
Man müsste schon die integrierten Assemblerfähigkeiten des GCCs benutzen
aber ich denke das würde deinem Konzept widersprechen. Wobei, wenn man
es strikt betrachtet das jetzt schon der Fall ist.
Beispiele:
1
#define RJMP (0xC000U - 1) // opcode of RJMP minus offset 1
in deinem Source, das ist schon sehr assembler/Hardwarenah.
Dann die Verwendung der Funktionen wie pgm_write_word(). Die sehen im
Aufruf nach purem C aus sind aber in deren Sourcen in Assembler
geschrieben.
Man könnte also einen Kompromiß eingehen und quasi eine
Bootloader_Helper Source schreiben, sie als RTL deklarieren, und da über
zB. die inline ASM Fähigkeiten der C Sprache das machen was mir
vorschwebte.
Das änderte aber nichts am Problem mit der Konzeptionierung des
Artikels, alles in C damit es erklärbar wird.
Letzendlich gehts nur um par Takte und um par Bytes an FLASH. Wären es
zb. 10 exportierte Funktionen so ergäbe sich in ASM 20 Bytes FLASH und
in C 80 Bytes an FLASH. Die Mühe lohnt nicht.
Gruß Hagen
Sorry, kam erst heute wieder zu meiner Runde hier.
Hagen Re schrieb:> Letzendlich gehts nur um par Takte und um par Bytes an FLASH. Wären es> zb. 10 exportierte Funktionen so ergäbe sich in ASM 20 Bytes FLASH und> in C 80 Bytes an FLASH. Die Mühe lohnt nicht.
Im Moment bin ich auch dieser Meinung. Ich hatte zwar in der Applikation
rumgespielt mit dem --defsym und hatte auch einen Teilerfolg, nämlich
dass ich dann wirklich
ch = uart_getc()
statt
ch = boot.uart_getc()
schreiben konnte. Das sparte auch ca. 100 Byte in der Applikation ein.
Anschließend habe ich im Bootloader probiert, RJMPs in die Sprungtabelle
zu patchen. Leider ist mir da der Linker mit einem Overflow-Error
ausgestiegen.
Ich habe also dieses Teilproblem, ein paar Bytes durch ein paar fiese
Tricks herauszuholen, erstmal zurückgestellt. Das ist auch nicht so
wichtig, denn es geht ums Prinzip. Und das funktioniert auch :-)
Ich habe mittlerweile den Bootloader auf 1500 Bytes zusammenstauchen
können. Ich mache mich jetzt erstmal an die Vervollständigung des
Artikels...
First make it work, then make it fine ;-)
Gruß,
Frank
Frank M. schrieb:> Im Moment bin ich auch dieser Meinung. Ich hatte zwar in der Applikation> rumgespielt mit dem --defsym
Naja, am Linker rumzufummeln macht es auch nicht verständlicher für
deinen Artikel.
Interessant wird ja der nächste Schritt: ISRs sharen.
Gruß Hagen
Hagen Re schrieb:> Interessant wird ja der nächste Schritt: ISRs sharen.
wie machen dies denn die ganzen bootloader?
arbeiten die Tatsächlich alle ohne Interupts?
vom Prinzip her sollte Sharing ja nich so schwer sein.
Der bootloader lässt seine Sprungtabelle an der Origalstelle stehen und
schreibt die der Applikation an eine definierte Stelle in seinen
Bootloaderspeicher.
in der bootloader-ISR wird dann je nach Modus (Bootloader/App) der
Booloadercode ausgeführt oder weiter zu App gesprungen.
Vlad Tepesch schrieb:> wie machen dies denn die ganzen bootloader?
Auf dem ATmega ist das einfach: Da hat der Bootloader eine eigene
Interruptvektor-Tabelle. Die kann er mittels IVSEL-Bit umschalten. Hier
mal ein Beispiel-Code aus dem SOUNDRX-Bootloader, wo ich das nutze:
1
int
2
main(void)
3
{
4
...
5
temp=MCUCR;// set interrupt vectors to bootloader section
6
MCUCR=temp|(1<<IVCE);
7
MCUCR=temp|(1<<IVSEL);
8
sei();// enable interrupts
9
...// start bootloader, continue here if timeout
10
cli();
11
temp=MCUCR;// reset interrupt vectors (set to application section)
12
MCUCR=temp|(1<<IVCE);
13
MCUCR=temp&~(1<<IVSEL);
14
asmvolatile("jmp 0x0000");// jump to application
15
}
Genau diese Spielerei mit dem IVSEL-Bit gibt es nur auf den ATmegas,
aber nicht auf den ATtinys.
> arbeiten die Tatsächlich alle ohne Interupts?
Nein, aber es gibt Meinungen, dass man in einem Bootloader auch pollen
kann, wenn man sowieso nichts parallel machen muss. Ich finde, man
sollte Interrupts ruhig auch im Bootloader nutzen, wenn es den Code
einfacher macht.
> vom Prinzip her sollte Sharing ja nich so schwer sein.
Nein, ist ganz simpel. Geht auch wieder über Pointer auf Funktionen. Ich
schreibs gleich rein, dann gibts keine weitere Spekulationen ;-)
> in der bootloader-ISR wird dann je nach Modus (Bootloader/App) der> Booloadercode ausgeführt oder weiter zu App gesprungen.
So isses.
Gruß,
Frank
Vlad Tepesch schrieb:> wie machen dies denn die ganzen bootloader?> arbeiten die Tatsächlich alle ohne Interupts?
Ja.
Ein Bootloader hat eine klare einfache Aufgabe:
- Empfangen von Daten
- Schreiben in den Flash
Was soll da ein Interrupt?
Ein Empfang von Daten während des Programmieren ist eh nicht möglich, da
die ATmega <8kB und die ATtiny die CPU beim Flashen anhalten (~4ms).
Peter
Peter Dannegger schrieb:> Ein Bootloader hat eine klare einfache Aufgabe:> - Empfangen von Daten> - Schreiben in den Flash> Was soll da ein Interrupt?
Prinzipiell hast Du recht, man kann das (fast) immer mit Pollen
erledigen.
Wenn die Daten aber ohne Pause kontinuierlich an den µC gesendet werden
(z.B. bei SOUNDRX über die PC-Soundkarte), wird es sehr kompliziert, das
Timing exakt einzuhalten. Das geht mit einem Interrupt (Timer und/oder
PCINT) wesentlich komfortabler.
> Ein Empfang von Daten während des Programmieren ist eh nicht möglich, da> die ATmega <8kB und die ATtiny die CPU beim Flashen anhalten (~4ms).
Jepp. In dem Fall muss der Sender darauf Rücksicht nehmen und eine Pause
zwischen den einzelnen Pages einlegen, z.B. durch Warten auf eine
Antwort vom µC nach jedem Schreiben einer Page.
Gruß,
Frank
Frank M. schrieb:>> Ein Empfang von Daten während des Programmieren ist eh nicht möglich, da>> die ATmega <8kB und die ATtiny die CPU beim Flashen anhalten (~4ms).>> Jepp. In dem Fall muss der Sender darauf Rücksicht nehmen und eine Pause> zwischen den einzelnen Pages einlegen, z.B. durch Warten auf eine> Antwort vom µC nach jedem Schreiben einer Page.
das muss er auch bei Interrupts im Bootloader. Denn die
Programmierzeiten sind absolut. ISRs hätten nur dann einen Sinn wenn die
Datenübertragung viel langsammer wäre als das Programmieren des
FLASHs/EEPROMs. Denn nur dann lonht die Hintergrunddatenübertragung
innerhalb von ISRs. Wenn da nicht das Problem wäre das bei der FLASH
Programmierung nur unter bestimmten Bedingungen parallel Code im FLASH
ausgeführt werden kann und gleichzeitig Pages im FLASH programmiert
werden können.
Es verschärft sogar noch die Problematik des Programflusses. Denn mit
ISRs ist es ja das Ziel die Daten für die nächsten FLASH/EEPROM Pages
schon zu übertragen wenn man noch die aktuell empfangenen Daten in den
FLASH/EEPROM programmieen möchte. Sollte dabei ein Fehler auftreten dann
hat man einen Versatz im Programablauf. Dh. alles zurück auf vorherige
Datenbuffer, Fehler an PC Software gesendet, und die muß die schon
nächsten gesendeten Daten in ihrem Programablauf verwerfen.
Verkompliziert alles nur unnötig.
Kein Bootloader den ich kenne für MCUs arbeitet so. Alle empfangen einen
Datenblock, programmieren FLASH/EEPROM, senden ein ACK und so gehts mit
dem nächsten Datenblock weiter. Das ist aus Sicht des Programflusses wie
auch aus Sicht der Anforderungen der Nutzer am sinnvollsten. Denn
Sicherheit geht vor und man möchte sicher sein das auch alles korrekt
programmiert wurde. Ergo: no need for ISRs da ein Bootloader dann zu
diesem Zeitpunkt nur diese eine Aufgabe hat.
Gruß Hagen
Hagen Re schrieb:> Frank M. schrieb:>>> Ein Empfang von Daten während des Programmieren ist eh nicht möglich, da>>> die ATmega <8kB und die ATtiny die CPU beim Flashen anhalten (~4ms).>>>> Jepp. In dem Fall muss der Sender darauf Rücksicht nehmen und eine Pause>> zwischen den einzelnen Pages einlegen, z.B. durch Warten auf eine>> Antwort vom µC nach jedem Schreiben einer Page.>> das muss er auch bei Interrupts im Bootloader.
Nein, bei ATmegas mit >=8KB nicht. Da wird die CPU nicht angehalten, der
Bootloader läuft weiter, während im Hintergrund die Daten ins Flash
gebrannt werden. Genau darum ging es in Peters Aussage. Bei ATtinys muss
man immer warten - egal ob Interrupts oder nicht. Wo hast Du was anderes
gelesen???
Hagen, bitte genauer lesen, sonst entstehen Missverständnisse ;-)
> Denn die> Programmierzeiten sind absolut. ISRs hätten nur dann einen Sinn wenn die> Datenübertragung viel langsammer wäre als das Programmieren des> FLASHs/EEPROMs.
ISRs haben Sinn, wenn ich den SW-UART im Bootloader und in der
Applikation haben will. In der Applikation machen sie meistens Sinn, im
Bootloader muss ich sie dann zwangsläufig nehmen, wenn ich den
SW-UART-Code share. Lies bitte dazu das Interrupt-Kapitel in meinem
Artikel. Da steht diese Begründung ausdrücklich drin.
> Kein Bootloader den ich kenne für MCUs arbeitet so. Alle empfangen einen> Datenblock, programmieren FLASH/EEPROM, senden ein ACK und so gehts mit> dem nächsten Datenblock weiter.
Dann kennst Du noch nicht meinen SOUNDRX-Bootloader. Der hämmert mit
25KBit/sec die Daten ins Flash und hat keine Möglichkeit zu antworten.
Die Daten werden vom PC kontinuierlich ohne Pausen durchgesendet.
Natürlich funktioniert der nur auf ATmegas mit >= 8KB Flash.
> Ergo: no need for ISRs da ein Bootloader dann zu> diesem Zeitpunkt nur diese eine Aufgabe hat.
Siehe Begründung oben: Bei Sharen von Funktionen kann es plötzlich
notwendig sein, wenn man auf die Interrupts in der Applikation nicht
verzichten kann.
Gruß,
Frank
man könnte die SW-Uart/den Bootloader eventuell so schreiben, dass die
SW uart nicht selbst den Timer intialisiert und die ISR implementiert.
Das hätte für die App den Vorteil, sie kann selbst entscheiden, auf
welchen Timer das laufen soll.
DAs ist auch etwas, was ich schon öfters gemacht habe: die ISRs aus
irgendwelchen libs rausgezerrt und das ganze in einen normalen
Funktionsaufruf zu packen. Klar die Lib muss die Anforderung an die
Aufruffrequenz genau spezifizieren. imho ist es aber schlechtes design,
wenn man diese Hardwareabhängigkeit in die lib packt und damit auch
gleich die entsprechende Peripherie blockiert. Andererseits verstehe ich
auch, dass für Anfänger sehr viel einfacher ist, wenn nicht erst der
Initialisierungscode selbst geschrieben werden muss.
und für den Bootloader hätte es den vorteil, er könnte diese
Poll-Funktion direkt aufrufen mit passenden Delays dazwischen und
braucht dafür eventuell gar keine Ints mehr.
Vlad Tepesch schrieb:> man könnte die SW-Uart/den Bootloader eventuell so schreiben, dass die> SW uart nicht selbst den Timer intialisiert und die ISR implementiert.> Das hätte für die App den Vorteil, sie kann selbst entscheiden, auf> welchen Timer das laufen soll.> [...]> und für den Bootloader hätte es den vorteil, er könnte diese> Poll-Funktion direkt aufrufen mit passenden Delays dazwischen und> braucht dafür eventuell gar keine Ints mehr.
Okay, ohne Ints im Bootloader könnte es so gehen. Der Bootloader müsste
die im Artikel erwähnte Funktion uart_interrupt() einfach selbst mit
entsprechenden Delays aufrufen. Die Applikation muss dann einfach dafür
sorgen, dass uart_interrupt() im Bootloader regelmäßig aufgerufen wird.
Wie sie das macht (ob über eigenen Timer-Interrupt oder anders) ist ihr
dann überlassen.
Die Geschichte vergrößert aber den Code im Bootloader - wegen den
einzustreuenden Delays. Aber vielleicht wäre dies eine Alternative, die
man im Artikel zumindest erwähnen oder als alternatives Teilkonzept
vorstellen könnte.
Ich werde das am Wochenende mal im konkreten Projekt testen.
Frank M. schrieb:> Die Geschichte vergrößert aber den Code im Bootloader
tut es dies wirklich, wenn dafür die gesamte Intterupt-Replacement-Logic
wegfällt?
Das passt jetzt natürlich nicht zu deinem BL-Konzept, da hier ja
explizit gezeigt werden sollte, dass und wie es mit Ints ebend doch
geht.
Hallo Leute!
Interessanter Thread. Die bereits angesprochenen Grundsätze (weitgehende
Trennung zwischen Applikation und Bootloader, flexible Nutzung der
Ports, geeignetes Protokoll, Flash-Schutz, effektive Speichernutzung)
sind auf der Attiny-Plattform natürlich eine gewisse Herausforderung...
Die Assemblerlösungen haben zwei entscheidende Vorteile: Sie
funktionieren in der Realität und sind auch noch *unschlagbar
kompakt*. Das trifft sogar auf mein eigenes Projekt zu, auf das ich hier
einfach mal "off-topic" hinweise:
http://jtxp.org/tech/tinysafeboot.htm
Der Bootloader orientiert sich best-practice-mäßig an FastBoot vom Peter
Dannegger, hat aber einige sensationelle Extras und ist vor allem
flexibler und auch für Assembler-Hasser geeignet, da man für andere
ATtiny-Typen nichts neu assemblieren muss. Vielleicht ist das ja für den
einen oder anderen hier eine Alternative zum Rad-neu-Erfinden?
Hey, mir geht es darum, TinySafeBoot weiter zu verbessern, und für
Anregungen aus der C-Gemeinde habe ich aber immer ein offenes Ohr!
Viele Grüße,
Julien
Hallo Frank,
ich denke gerade laut ueber einen bootloader fuer die nrf24l01
Funkmodule nach. Im wiki stehen noch fette Todos. Kannst du dein
Beispielprojekt vielleicht noch posten? Es muss nicht den Standard des
restlichen Artikels erreichen, wuerde mir die Arbeit aber wesentlich
erleichtern.
Hallo,
avion23 schrieb:> ich denke gerade laut ueber einen bootloader fuer die nrf24l01> Funkmodule nach. Im wiki stehen noch fette Todos. Kannst du dein> Beispielprojekt vielleicht noch posten? Es muss nicht den Standard des> restlichen Artikels erreichen, wuerde mir die Arbeit aber wesentlich> erleichtern.
Ja, kann ich gern machen. Ich versuche diese Woche noch, die TODOs durch
Text zu ersetzen.
Viele Grüße,
Frank