Hi! Ich arbeite auf einem ATMEGA32 mit Bootloader. Die Interrupts sollen im Bootloader verarbeitet werden (das funktioniert soweit). Vom Bootloader getrennt soll es nun eine Applikation geben. Da aber die Interruptvektoren im Bootloader stehen, müssen diese auf die "Applikations-Tabelle" umgebogen werden, damit Interrupts auch in der Applikation abgearbeitet werden können. Also ergeben sich 2 Fragen: 1. Wie kann man die Interrupttabelle des Bootloaders ändern? Der RESET, UART_RECV und TIMER0_OVFL Interrupt sollen aber unverädert bleiben. Wenn ich versuche an der Stelle, wo die entsprechenden Interruptvektoren liegen (bei mir 0x7000-0x7054, 4k Bootsektor) eine Section anzulegen, meckert der Linker (Ist ja auch klar, da eine Adressüberschneidung vorliegt) Kann man nicht dem Linker die ISR-Func Adressen irgendwie manuell mitgeben? 2. Da vom Bootloader aus dann die Adresse 0x0000 angesprungen werden soll, darf das Startup in der Applikation nicht mehr ausgeführt werden! (Würde beim Rücksprung in den Bootloader alles schmeißen, da der SP, usw. falsch wären) Wie kann man verhindern, dass ein Startup-Code miteingebunden wird? Vielen Dank schon mal! MfG Tobi
Nachtrag: Hab vermutet, dass das mit der "gcrt1.S" (Startupcode) zusammnhängt, kann die Datei weder auf meinem Rechner (WIN-AVR 4.0 + GCC) noch im Netz fiden!!!
> Hab vermutet, dass das mit der "gcrt1.S" (Startupcode) > zusammnhängt, kann die Datei weder auf meinem Rechner (WIN-AVR > 4.0 + GCC) noch im Netz fiden! (Deine Ausrufezeichentaste klemmt. Eigentlich musst du das auch gar nicht ausrufen, wen willst du denn hier anschreien? ;-) So? Wo hast du denn da gesucht? Wenn du einfach nur den Sourcecode mit installiert hättest, hättest du diese Datei auf jeden Fall dabei gehabt. Was soll eigentlich "WIN-AVR 4.0 + GCC" sein? WinAVR enthält den GCC, compiliert für den AVR (auch bekannt als AVR-GCC), aber was dabei die Versionsnummer 4.0 soll, weiß ich nicht. WinAVR benennt seine Versionen nach Datum. Vom GCC gibt es zwar eine Version 4.0, aber die gilt besonders für das Target AVR noch als recht ,grün', sodass sie wohl selbst in der nächsten WinAVR-Version noch nicht dabei sein wird. > 1. Wie kann man die Interrupttabelle des Bootloaders ändern? Der RESET, > UART_RECV und TIMER0_OVFL Interrupt sollen aber unverädert bleiben. > Wenn ich versuche an der Stelle, wo die entsprechenden > Interruptvektoren liegen (bei mir 0x7000-0x7054, 4k Bootsektor) eine > Section anzulegen, meckert der Linker (Ist ja auch klar, da eine > Adressüberschneidung vorliegt) Wenn du sowas exotisches machen willst, dann solltest du dich zuvor wohl mit der Art und Weise, wie die Interruptvektoren in der avr-libc verwaltet werden, tiefgreifend auseinandersetzen. Vorab: ich denke, dass es die einfachste und sinnvollste Lösung wäre, im Bootloader einfach auf die Interrupts zu verzichten und dann die Vektortabelle in der Applikation zu belassen. Aber das ist deine Sache, wenn du den komplizierteren Weg gehen willst, musst du dir wohl oder übel die Mühe machen, den Krempel auch tiefgreifend erstmal zu verstehen. Bis zu gcrt1.S bist du ja zumindest schon vorgedrungen. Dass du aber nicht in der Lage warst, diese Datei sinnvoll zu finden, lässt mich ein wenig zweifeln, ob du die restlichen nötigen Details auch wirklich beherrschen werden könnst. Anyway, gcrt1.S definiert einfach in einer Schleife alle Interruptvektoren so, dass die auf __bad_interrupt zeigen. Alle diese Eintrittspunkte sind als `weak' deklariert, damit wird entsprechenden gleichnamigen Eintrittspunkten, die von der Applikation geliefert werden, dann vom Linker der Vorrang eingeräumt. (Ohne `weak' würde sich der Linker über die Doppeldefinition beklagen.) Die Vektoren sind übrigens nur einfach __vector_1 bis __vector_N durchnummeriert (das hättest du schon aus dem Aufbau des SIGNAL-Makros erfahren können). Du musst also letztlich in deinem Bootloader alle (dich interessierenden) Eintrittspunkte __vector_1 bis __vector_N belegen. > Kann man nicht dem Linker die ISR-Func Adressen irgendwie manuell > mitgeben? Im Prinzip sollte sogar das gehen, indem du auf der Linker- Kommandozeile entsprechende Symboldefinitionen übergibst. Ist natürlich je nach Prozessor einiges an Schreibarbeit, aber wenn du das unbedingt willst... Beispiele solltest du in der avr-libc-Doku (indirekt) finden, dort beispielsweise in der Erläuterung, wie man die Speicherallozierung von malloc() auf andere Bereiche (bspw. den externen SRAM) umbiegen kann. > 2. Da vom Bootloader aus dann die Adresse 0x0000 angesprungen werden > soll, darf das Startup in der Applikation nicht mehr ausgeführt > werden! (Würde beim Rücksprung in den Bootloader alles > schmeißen, da der SP, usw. falsch wären) Das leuchtet mir nun überhaupt nicht ein. Warum willst du denn zwischen Applikation und Bootloader hin- und herspringen? So ist das eigentlich nicht gedacht. Normalerweise fangen beide so an, als hätten sie den kompletten Prozessor und wären die alleinigen Programme auf dem Chip. Wenn der Bootloader mit dem Laden fertig ist, springt er einfach die Applikation an, und diese beginnt dann wie nach einem Reset. (Sie sollte sich lediglich dessen bewusst sein, dass die IO-Register nicht ,jungfräulich' sind.) Falls die Applikation den Bootloader anspringen will, beginnt der dann ebenfalls wieder ganz von vorn, d.h. die Applikation hat an dieser Stelle einfach die Steuerung aufgegegen. Es tut übrigens dabei nichts zur Sache, ob man ein wenig `shared code' nehmen will, also z.B. Funktionen des Bootloaders aus der Applikation aufrufen will. In diesem Falle hat halt die Applikation über den Stack die Oberhoheit, aber das ist ja überhaupt nicht tragisch. Lediglich bei Benutzung globaler Variablen muss man die Ressourcenverteilung manuell organisieren, falls der shared code auf solche zugreifen können soll. Das sollte sich aber durch Verschieben der .data-Section in einem von beiden Teilen machen lassen. > Wie kann man verhindern, dass ein Startup-Code miteingebunden wird? Das wird wirklich nur gehen, indem du deinen eigenen Startup-Code schreibst. Ehrlich gesagt: die am wenigsten wünschenswerte Variante. Ich würde sowas versuchen zu vermeiden, da es eine maintenance nightmare werden kann.
"2. Da vom Bootloader aus dann die Adresse 0x0000 angesprungen werden soll, darf das Startup in der Applikation nicht mehr ausgeführt werden! (Würde beim Rücksprung in den Bootloader alles schmeißen, da der SP, usw. falsch wären)" Soweit ich weiß, wird der Stack immer noch zweimal gesetzt, das 2. mal im Main. Das Main kann also weder rekursiv aufgerufen werden, noch irgendwohin zurückkehren. Da das kaum einen stört, wurde es bisher wohl nicht als Bug eingestuft. Es sind quasi 8 Bytes überflüssiger Code. Peter
btw, soweit ich weiß verbietet der C-Standard das Aufrufen der Funktion main() vom Benutzer-Code.
> An welcher Stelle verbietet er das? Mir ist keine bekannt.
Mist, schon wieder C++ mit C verwechselt (im Anhang C.1.2 im
C++-Standard stehts); in C++ darf man nichtmal die Adresse von main
nehmen.
Anhang C listet die Inkompatibilitäten von C++ zu C auf. Das heißt du
hast Recht, in C durfte man main() wohl rekursiv aufrufen.
Hi! @ Jörg: Vielen Dank für die ausführliche Antwort. Nein, anschreien will ich keinen :-) Meinte eigentlich das AVR-Studio 4.0 (zum debuggen) mit dem AVR-GCC.(Da hab ich einen Wurm reingebracht.) > Bis zu gcrt1.S bist du ja zumindest schon vorgedrungen. Dass du > aber nicht in der Lage warst, diese Datei sinnvoll zu finden, lässt > mich ein wenig zweifeln, ob du die restlichen nötigen Details auch > wirklich beherrschen werden könnst. Ja, ich zweifle auch dran, dass ich das hinbekomme. Ehrlich gesagt, bin ich recht neu IM AVR-Gewerbe. Ich kenn mich mit dem C505 recht gut aus und hab da mit der KEIL µ-Vision 2 Entwicklungsumgebung gearbeitet. Da hab ich sowas wie oben beschrieben bereits am Laufen :-) Da gibt's ja die "Startup.asm", die man leicht einbinden kann und damit lassen sich die Interruptvektoren umgebiegen und die restlichen Initialisierungen selbst einfügen. Nur sowas hab ich im GCC direkt noch nicht gefunden Das die Vektoren von 1 .. N im SIGNAL.H definiert sind, hab ich schon gewusst :-) Meine Idee war einen voll ohne Applikation laufenden Bootloader hinzubekommen. Dieser soll dann überprüfen, ob es eine gültige Applikation (durch Berechnung einer CRC16 Checksumme über den Application-Flash Bereich, die im EEPROM abgespeichert ist) gibt und diese dann "anspringen". Falls es keine Applikation gibt, läuft der Bootloader alleine. Das setzt vorraus, dass ich die Interrupts im Bootloader halten muß. Der Bootloader soll im Falle einer ungültigen Applikation über die UART dann die (nun gültige) Applikation empfangen und brennen. Man kann dann sich ganz leicht ein PC Programm (Denke mal, wenn ich hier erwähne, dass ich unter Windows programmiere gibt's Ärger :-)) )zaubern, das per UART mit dem Bootloader des ATMEGA quatscht. So kann ich Applikationen auf Controllerebene basteln und diese dann beqeuem und schnell in den ATMEGA brennen. Daher müssen die Interrupts (eigentlich ja nur der UART-Interrupt) im Bootloader stehen.
> Ich kenn mich mit dem C505 recht gut aus und hab da mit der KEIL > µ-Vision 2 Entwicklungsumgebung gearbeitet. Da hab ich sowas wie > oben beschrieben bereits am Laufen :-) Da gibt's ja die > "Startup.asm", die man leicht einbinden kann und damit lassen sich > die Interruptvektoren umgebiegen und die restlichen > Initialisierungen selbst einfügen. Prinzipiell kannst du das mit GCC/avr-libc auch machen, aber ich halte diese Vorgehensweise für grundlegend riskant. Zwischen C run-time startup (crt) und Compiler besteht eine Art ,Vertrag', die internen Details sind dabei Verhandlungssache zwischen diesen beiden und keine öffentliche Schnittstelle. Dadurch werden solche Dinge garantiert wie das Herstellen des normgerechten Zustands bis zum Start von main(). Falls in Absprache zwischen Compiler und Bibliothek daran mal aus irgendwelchen Gründen Änderungen vorgenommen werden sollten, möchten die beiden das tun können, ohne noch mit weiteren Partnern verhandeln zu müssen. In einem solchen Falle riskierst du nach einem Upgrade der Entwicklungsumgebung einfach, dass du diesen Vertrag brichst (da du dein eigenes, dann nicht mehr vertragsgemäßes startup benutzt). > Nur sowas hab ich im GCC direkt noch > nicht gefunden Braucht man eigentlich auch nicht. avr-libc hat sich die größte Mühe gegeben, alle Arten von customization als Optionen vorzusehen (durch Modifikation von globalen Linkersymbolen von der Kommandozeile aus oder durch Benutzung der .initN-Sections). Der einzige Mangel, der mir am derzeitigen gcrt1.S bekannt ist ist, dass man die Interruptvektoren nicht ausblenden kann (wäre für bootloader zum Platzsparen interessant). Das sollte sich aber auch noch einbauen lassen. > Das die Vektoren von 1 .. N im SIGNAL.H definiert sind, hab ich schon > gewusst :-) signal.h (Kleinschreibung) ;-) C ist case sensitive. > Meine Idee war einen voll ohne Applikation laufenden Bootloader > hinzubekommen. Dieser soll dann überprüfen, ob es eine gültige > Applikation (durch Berechnung einer CRC16 Checksumme über den > Application-Flash Bereich, die im EEPROM abgespeichert ist) gibt und > diese dann "anspringen". Falls es keine Applikation gibt, läuft der > Bootloader alleine. Das ist vernünftig. > Das setzt vorraus, dass ich die Interrupts im > Bootloader halten muß. Überhaupt nicht. Für das bisschen bootloader brauchst du keine Interrupts. Den reset-Vektor kannst du unabhängig von den restlichen Vektoren verbiegen, und das sollte genügen. Die UART-Routinen bekommst du auch ohne Interrupts schnell genug hin. Fülle einfach für jede ROM-Page einen internen Puffer und definiere in deinem Protokoll, dass nach jeder Page auf eine Bestätigung durch den Bootloader gewartet werden muss. Das erspart dir selbst irgendwelche Notwendigkeit für ein handshake. Beispiele für AVR910-style bootloader gibt's wie Sand am Meer. Es gibt auch ein oder zwei Beispiele für STK500-style loader, das ist besonders dann interessant, wenn man über einen USB-seriell-Wandler arbeiten will, da das STK500-Protokoll besser den Anforderungen des paketorientierten Datentransfers via USB gerecht wird als das dumme request-response-Protokoll von AVR910. Das beste mir bekannte Beispiel findest du bei Matthias Weißers USBisp, ein Bootloader, der in die 2 KB boot section eines ATmega8 passt und ein abgerüstetes STK500-Protokoll spricht. Die Software vom USBisp steht unter GPL. Wäre die Frage (die du Matthias sicher auch einfach selbst stellen kannst), selbst wenn man das Teil in einem kommerziellen Projekt benutzen will, sollte die GPL meiner Meinung nach dann erfüllt sein, wenn man seine Änderungen am Bootloader veröffentlicht, ohne dass die eigentliche Applikation davon berührt ist. Das wird in den meisten Fällen tolerabel sein, alternativ kannst du ja versuchen, ob du für den bootloader mit Matthias eine BSD-style license aushandeln kannst. (,Veröffentlichen' bedeutet in diesem Falle die Weitergabe deiner eigenen Änderungen im Sourcecode an diejenigen, denen du dein Gerät gibst, wobei diese es dann auch beliebig anders weitergeben oder veröffentlichen dürfen. Du musst den Sourcecode auch nur auf Anforderung hin weitergeben, musst aber den Empfänger auf sein Recht hinweisen.)
"und damit lassen sich die Interruptvektoren umgebiegen" Es scheint mir, als ob Du das Datenblatt nicht gelesen hast. Alle ATMega außer dem ATMega48 haben das IVSEL-Bit, womit bequem die Interrupts in den Bootloader und zurück geschaltet werden können. Den Startup-Code zu verbiegen, ist also nicht nötig. Peter
Nochmal Hi! @ Peter: Doch, das weiß ich. Würde bei meinem Konzept aber nicht viel helfen ... @ Jörg Aber jetzt muß ich mal mein Konzept überdenken, Danke!
Hi! Nur der Vollständigkeit halber: mit _attribute_((naked)) SIGNAL(...) { asm volatile("jump 0x0002"); } können die Interruptvektoren "verbogen" werden. Das kostet nicht viel Speicher und ist schön in der C-Datei unterzubringen. So konnte ich mein Problem wie oben beschrieben lösen...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.