Datum:
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%...
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.
Datum:
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
Datum:
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
Datum:
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
Datum:
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
Datum:
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!
Datum:
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
Datum:
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
Datum:
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
Datum:
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
Datum:
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
Datum:
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
Datum:
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
Datum:
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
Datum:
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
Datum:
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
Datum:
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
Datum:
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 ;-)
Datum:
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
Datum:
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
Datum:
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
Datum:
Frank, wo finde ich den diesen Link auf deine private Seite ? Ich bin zu blöd den im Artikel zu finden :(
Datum:
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
Datum:
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
Datum:
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:
#include "tinyboot.h" struct BOOT_FUNCTIONS * boot; ... boot = (void *) pgm_read_word (BOOTLOADER_FUNCTIONS_ADDRESS); |
Fertig. Und schon kann er zugreifen auf boot->uart_poll() bzw. boot->uart_getc(). Alternativ ohne Pointer:
struct BOOT_FUNCTIONS boot; ... memcpy_P (&boot, (void *) BOOTLOADER_FUNCTIONS_ADDRESS, sizeof BOOTLOADER_FUNCTIONS); |
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.
Datum:
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
Datum:
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
Datum:
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
Datum:
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:
#define BOOTLOADER_APPL_ADDRESS (BOOTLOADER_ENDADDRESS - 2) #define BOOTLOADER_FUNC_ADDRESS (BOOTLOADER_ENDADDRESS - 4) typedef struct { uint8_t (*uart_getc) (void); void (*uart_putc) (unsigned char); void (*set_timer1_compa_isr) (void (*) (void)); void (*set_pcint0_isr) (void (*) (void)); } BOOTLOADER_FUNCTIONS; |
tinyboot.c:
static BOOTLOADER_FUNCTIONS bootloader_functions; int main () { ... bootloader_functions.uart_getc = uart_getc; bootloader_functions.uart_putc = uart_putc; bootloader_functions.set_timer1_compa_isr = set_timer1_compa_isr; bootloader_functions.set_pcint0_isr = set_pcint0_isr; ... pgm_write_word (BOOTLOADER_FUNC_ADDRESS, (uint16_t) (&bootloader_functions)); ... } |
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
Datum:
Ich habe nun das Kapitel "Sharen von Funktionen" im Artikel vervollständigt. Gruß, Frank
Datum:
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
Datum:
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
Datum:
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.
Datum:
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:
static BOOTLOADER_FUNCTIONS bootloader_functions;
bootloader_functions.uart_getc = uart_getc;
bootloader_functions.uart_putc = uart_putc;
|
Neu:
static BOOTLOADER_FUNCTIONS bootloader_functions =
{
uart_getc,
uart_putc
};
|
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
Datum:
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:
; in X Zeiger auf SRAM Struct ldi rX, Low(FLASH_ADDRESS) ldi rY, High(FLASH_ADDRESS) sts X+0, rX 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 ;)
Datum:
Ü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
Datum:
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.
Datum:
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
Datum:
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
Datum:
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 ?
Datum:
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
Datum:
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.
Datum:
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
Datum:
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 ?
Datum:
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
Datum:
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
Datum:
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 ;-)
Datum:
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?
Datum:
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
Datum:
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.
Datum:
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
Datum:
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:
#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.
Datum:
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
Datum:
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
Datum:
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.
Datum:
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:
int main (void) { ... temp = MCUCR; // set interrupt vectors to bootloader section MCUCR = temp | (1<<IVCE); MCUCR = temp | (1<<IVSEL); sei (); // enable interrupts ... // start bootloader, continue here if timeout cli (); temp = MCUCR; // reset interrupt vectors (set to application section) MCUCR = temp | (1<<IVCE); MCUCR = temp & ~(1<<IVSEL); asm volatile("jmp 0x0000"); // jump to application } |
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
Datum:
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
Datum:
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
Datum:
Ich habe nun das Kapitel "Sharen von Interrupts" vervollständigt. Es kann sein, dass ich dies im Laufe des Tages noch etwas "verschönere". Die nötigen Mechanismen stehen aber schon mal drin. Link auf das Kapitel: http://www.mikrocontroller.net/articles/Konzept_f%... Gruß, Frank
Datum:
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
Datum:
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
Datum:
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.
Datum:
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.
Datum:
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.
Datum:
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
Datum:
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.
Datum:
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