Hallo, ich habe vor einigen Tagen mit der AVR-Assemblerprogrammierung angefangen. Mittlerweile sind bei mir jedoch ein paar Fragen aufgetaucht, vielleicht kann mir da ja jemand helfen... 1) Die Definitionsdateien (*.inc) der einzelnen uCs enthalten ja dutzende symbolische Namen für alle möglichen Register-/Port-/etc.-Adressen. Aber gibt es keine symbolischen Namen für die Adresse des Resetbehandlungsroutine? Ok, der Wert ist eh immer 0 - aber irgendwie fände ich es einfach schöner wenn ich an den Anfang meines Programmes etwas a la .org RESETaddr rjmp main schreiben könnte, genauso wie es für die Adressen der anderen Interruptvektoren ja auch symbolische Namen gibt... 2) Auch für die Adresse der ersten frei benutzbaren Speicherstelle (direkt nach der Interrupttabelle) gibt es scheinbar keinen symbolischen Namen, kann das sein? 3) Ich würde gerne bestimmte Funktionalitäten in eigene Dateien ausgliedern, z.B. eine Datei UARTlib.asm, die dann alle Funktionen für UART-Kommunikation enthält - so dass ich, wenn ich in einem Programm UART benutzen möchte, in der Hauptdatei einfach nur noch .include "UARTlib.asm" schreiben muss. Grundsätzlich ist das natürlich kein Problem. Aaaaber ich hätte das dann gerne so, dass die Interrupt-Vektoren für UART-Empfang etc. direkt in der Datei UARTlib.asm definiert werden. Das Problem das ich dabei sehe ist folgendes: Wenn ich am Anfang meiner Hauptdatei die Datei UARTlib.asm include, und in dieser Datei steht dann ... .org URXCaddr rjmp int_urxc int_urxc: [code] ... und in der eigentlichen Hauptdatei kommt dann sowas wie .org 0x0 rjmp main main: [code] dann scheint der Assembler den Code der Datei UARTlib.asm einfach zu überschreiben (oder irre ich mich da?) Ist es also irgendwie möglich, die Interrupt-Vektoren in verschiedenen Dateien festzulegen?
zu 1 und 2: wer hindert dich, die .inc-Dateien nach deinen besonderen Wünschen anzupassen? Richtig, niemand. zu 3: der Interrupt-Vektor der UART unterscheidet sich von Typ zu Typ
@crazy horst zu 1 und 2) Schon klar, dass ich mir die .inc Dateien selbst anpassen kann. Aber zum einen will ich das nicht (weil ich dann gleich alle .inc-Dateien anpassen müsste und ich, wenn ich jemandem ein Sourcefile schicken will, ich immer auch die .inc Datei mitschicken müsste), zum anderen war das ja bloss eine kruze Frage, OB es für diese Adressen tatsächlich keine vordefinierten Symbole gibt. Ich werte Deine Antwort also mal als "Nein" und kann damit gut leben (auch wenn mir nicht ganz klar ist, WIESO es keinen vordefinierten Wert für die erste freie Speicherstelle gibt...) zu 3) Offenbar hast Du da meine Frage nicht richtig verstanden, es ging überhaupt nicht um UART etc., das war ein Beispiel um meine Frage besser zu erklären
zu 3) Eine Möglichkeit wäre, alls Libs am Ende des Hauptmoduls zu includieren und dann folgenden Konstrukt zu verwenden: siehe Dateianhang Man definiert sich also am Ende jeden Moduls ein Label und setzt direkt dannach eine Variable (immer die selbe) mit .set auf diesen Wert. Am Anfang eines Moduls kann man dann mit .org die gewünschten Interrupt-Vektoren eintragen. Vor dem Beginn des eigentlichen Codes wird dann mit .org die Adresse wieder auf das mit .set gemerkte Ende des vorhergehenden Moduls gesetzt. Im Mainmodul muß man allerdings darauf achten, das der Code erst hinter dem letzen Interruptvektor beginnt (im Bsp. mit .org $030). Dadurch hat man gegbenfalls ein paar ungenutzte bereiche im Flash. Gruß Ingo
Die .inc Dateien sind kein Heiligtum, man kann die schon anpassen. Außerdem ist nirgendwo garantiert, dass die sich nicht im Laufe der Zeit ändern können. Damit läuft dann dein Programm vielleicht nicht mehr korrekt, wenn du es ohne die .inc weitergibst. Du kannst aber auch mehrere Dateien includen, denke zumindest mal. Du könntest also alle Ergänzungen oder Änderungen in eine eigene Datei auslagern. Weil Reset immer bei 0 liegt, hat man sowas wohl nicht definiert. Ich definiere mir eher eine Vorlage, wo schon sämtliche Interruptvektoren und weiteres angelegt ist, was immer so ist. Sozusagen einen Rahmen, den ich dann je nach Programm fülle.
Tausend Dank, Ingo, das ist genau die Idee die ich gebraucht habe! Ziemlich genau sowas hatte ich mir nämlich auch schon überlegt, aber mangels Programmiererfahrung ist mir keine Idee eingefallen wie die späteren Module wissen können wo der Code der vorherigen Module aufhört... aber die Idee mit Sprungmarke - klar, so geht's! Aber eine kleine Zusatzfrage hätte ich noch: Diese Lösung müsste doch auch dann funktionieren, wenn ich die externen Dateien gleich am Anfang include, oder? (z.B. indem ich statt MODUL_END ganz am Anfang der Hauptdatei eine Variable namens MODUL_START mit dem Wert 0x30 definiere, und jedes Modul setzt am Ende seines Codes diese Variable dann weiter (und auch das Hauptprogramm startet bei MODUL_START))
Ja, sollte auch so wie von Dir gesagt funktionieren. Ich mach es nur immer so, das ich die Module am Ende einbinde, deshalb mein Beispiel in der Form. Im Zweifellsfall würd der Assembler sowieso meckern, wenn sich Bereich im Flash überschneiden. Und wenn man ganz sicher gehen will, guckt man in das List-File, da sieht man dann sehr schnell, ob die Adresen stimmen. Gruß Ingo
Die verschiedenen AVRs haben ja soweit ich weiss unterschiedlich viele Interrupts. Was ist denn die momentane Maximalanzahl an Interrupts bei den AVRs? (Die kleinste Speicheradresse, die bei ALLEN AVRs für Code frei ist (= nicht im Bereich der Interrupttabelle liegt) müsste demnach ja 2 * [diese Anzahl] sein, oder?)
Ich hab mal alle .def Dateien abgeklappert, die höchste Adresse eines Interruptvektors hab ich beim AT90CAN128 gefunden: .equ SPMRaddr = $048 ; Store Program Memory Ready Interrupt Address Aber den gibt es ja nicht wirklich, oder doch? Ansonsten liegen Mega128/104/64 ebenfalls mit der SPMRaddr am höchsten: .equ SPMRaddr = $044 ; Store Program Memory Ready Interrupt Address Wobei man sich hier nicht wundern darf, die oben genannten µC haben nicht etwa so viel mehr Interrupts als die kleineren, sondern die Adressen liegen im 2er-Raster, also 4 Byte voneinander entfernt, wo es bei den kleinen nur in Einerschritten (2 Byte) weiterzählt. Man könnte also pauschal als erste Flashadresse für Programmcode $04a nehmen, verschenkt damit aber gegebenfalls einiges an Speicherplatz. Besser ist es wohl doch, die Startadresse jeweils im Projekt direkt einzutragen. Und damit man das nicht vergißt, könnte eventuell folgender Konstrukt helfen: ;------------------------------------------------- ; FLASH_START sollte auf die letzte verwendete ; Interruptvektor-Adresse +2 gestzt werden ; Bsp. für einen ATmega16: ; .equ FLASH_START = SPMRaddr+2 ;------------------------------------------------- .equ FLASH_START = -1 .if FLASH_START < 0 .error "FLASH_START hat einen ungueltigen Wert!" .endif .org $00 rjmp main .org FLASH_START ; Hauptprogramm main: ldi temp, LOW(RAMEND) out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ... Damit bekommt man dann zumindest eine Fehlermeldung. Gruß Ingo
Vielen Dank nochmal, Ingo! Da Flash-Speicher bei mir bisher eh noch kein Problem war, werde ich dann vorerst einfach immer ab 0x50 starten. Verstehe trotzdem nicht, wieso so ein doch recht interessanter Wert wie die erste frei verfügbare Speicherstelle nicht auch in der .inc Datei zu finden ist...
Eben bin ich nochmal über etwas gestolpert, wo ich mir nicht so ganz sicher bin. Ich habe jetzt erfolgreich meinen Code in "Module" gegliedert, und an den Anfang jedes Moduls habe ich eine Assembler-Direktive geschrieben a la .equ DELAY_AVAILABLE = 1 ; Flag that indicates that the DELAY module has been loaded Sinn des ganzen sollte sein, dass ein Modul, welches ein anderes benötigt, dieses bei Bedarf automatisch einbinden kann, sofern es nicht eh bereits eingebunden wurde. In meinem HD44780-Modul z.B. wollte ich das dann ungefähr so benutzen: .ifndef DELAY_AVAILABLE ; Check if the DELAY module is loaded .message "DELAY module not available, auto-including..." .include "delay.asm" .endif Schön gedacht, funktioniert nur leider nicht :-( Wenn besagtes Modul nicht eh eingebunden wurde, dann kommt beim Kompilieren nämlich nun dutzende Male der gleiche Fehler: "error : Internal - label changed between passes - conditoonal on forward reference?" - und das bei jeder Sprungmarke die ab diesem zeitpunkt kommt. Wo der Fehler herkommt, kann ich mir fast denken (Compiler ist verwirrt, weil zwischen zwei Läufen noch Code dazu gekommen ist), aber die grosse Frage ist: Gibt es auch dafür eine Lösung?
Man, der Reset- bzw. Power-On-Vector ist doch immer bei Adresse $000. Da braucht man wirklich keinen Symbolnamen für die Adresse $000. Halte es für Verschwendung und Unsinn mit dem Main-Prog immer bei Adresee $050 zu beginnen da es auch AVRS gibt mit nur 12 IRQ´s oder sogar weniger. Deine mit der Zeit gesammelten Routinen kannst Du ja ruhig in eine .inc Datei direkt oder als Macros ansammeln. Als Macro hats den Vorteil, das der Code innerhalb des Macros erst in den gesammten Code mit einbezogen wird, wenn der Name des Macros in der Hauptdatei gefallen ist. Wenn es mehr als 2 Words im Macro sind und es an verschiedenen Stellen aufgerufen wird dann sollte man den Macronamen in einem UP reinschreiben und im Hauptprogramm dieses UP aufrufen. Gruß Andi
@Ingo "hab ich beim AT90CAN128 gefunden, aber den gibt es ja nicht wirklich, oder doch?" Gibts schon, und sind auch recht nett :-)
zu 2) Du mußt ja bei kleinen Programmen, die keine oder nicht alle Interrupts verwenden, nicht die komplette Interrupt-Verktor-Tabelle ins Programm schreiben und kannst dementsprechend früher mit dem programmcode anfangen. Wäre eine feste Adresse füer den Codebeginn definiert, würde man in diesem Fall einige Bytes verschwenden.
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.