Guten Tag, mein Programm für die Fernrohrsteuerung ist jetzt schon >2k und in ASM geschrieben. Obwohl das AVR-Studio keine Fehlermeldung ausgibt, springt der Programmcounter beim Aufrufen von bestimmten Funktionen immer auf Reset. Durch umschichten der Include-Dateien konnte ich zwar das Problem beheben, aber das war wohl keine Lösung. So habe ich mir die Funktion RCALL genau angesehen und siehe da die Reichweite ist +/-2k. Also gut nehme ich CALL. Und da liegt meine Frage: Kann ich ohne Probleme das RCALL durch CALL ersetzen oder muß ich noch etwas beachten. Bis jetzt weiß ich aus der Hilfe das CALL nur nach vorwärts hüpfen kann (0 ≤ k < 64K ). Wenn das so ist, wie löse ich dann Sprünge zurück? Ich meine nicht "ret" sondern den Aufruf einer Routine XXXXXX (im liegt Speicher z.B. bei 3k). Innerhalb der Routine XXXXX wird die Routine YYYYY aufgerufen. Diese liegt im Speicher ganz am Anfang. -> Größer 2k zurück. Geht das überhaupt mit Call? Gruß Stevko
Rufus, das habe ich auch gedacht aber er springt mit Call in die Routine. z.B. Call Temp_Messung , funktioniert aber das ist vorwärts. Ich möchte nicht alle Rcall's tauschen ohne es genau zu wissen. Gruß Stevko
Da der Speicher bei 0 beginnt und das Ziel absolut ist, gibt es beim call keine Unterscheidung zwischen vorwärts und rückwärts. Wie Rufus Frage impliziert, spring er einfach an jede beliebige Stelle im RAM, egal ob die vor oder nach deinem call Aufruf liegt.
Hi, CALL verlangt als Operand die absolute Zieladresse. Das bedeutet, dass 0 <= k <= 64K am Anfang des Speichers loszählt und nicht an deiner aktuellen Position. Somit geht es damit vor und zurück.
RCALL deckt beim AVR den Adressraum +- 2k Worte ab. Bei Controllern mit <= 8k Flash ist der gesamte Adressraum mit RCALL erreichbar. Daher ist die Int-Tabelle auch nur single word orientiert. Bei >8K Flash muß für RCALL die Zieladresse innerhalb von +-2K Worten liegen, sonst ist der Befehl CALL zu verwenden.
Achso habe ich vergessen ATMega 32 ist der Proz. Da das Call bei mir vorwärts funktioniert und der Aufruf nach ca.20Bytes erfolgt(nicht bei Null), nehme ich an das der Kompiler automatisch die absolute Adresse in den Code einfügt. Sehe ich das richtig so? Gruß Stevko
Hallo alle zusammen! Genau dieses Problem hat mich auch schon mal mächtig Nerven gekostet: Absolut nicht zu erklärende Resets beim Aufruf bestimmter Unterfunktionen bei einem Assemblerprogramm. Auch hier wurde das AVR-Studio benutzt. Eine nähere Betrachtung mit dem Simulator brachte zu Tage, dass der liebe Assembler beim "rcall" nicht prüft, ob das Ziel ausserhalb der Reichweite liegt. Die im Befehl codierte Adresse war schlichtweg falsch (der höherwertige Teil wurde einfach abgeschnitten), ohne das jemals eine entsprechende Fehlermeldung ausgegeben wurde. Ich weiß leider die genaue Versionsnummer des Assemblers nicht mehr, eventuell mal eine neuere Version des AVR-Studios probieren. @Stevko: Schau Dir einfach mal im simulator an, wohin die einzelnen Funktionsaufrufe springen. Da könnte die Überraschung warten. Bei uns wurden jedenfalls aus Sicherheitsgründen alle "rcall"-Befehle gegen "call" ausgetauscht. MfG Stefan Widmann
Alle AVRs bis 8kB (Mega8, Mega8515 usw.) können mit rjmp / rcall vollständig adressiert werden. Erst ab Mega16 muß man call / jmp nehmen. Peter
Der AVR-Assembler prüft schon, ob ein rcall reicht, man muss ihn aber auch lassen. Bei den Assembler-Options gibt es schon seit langem ein Kästchen mit der Bezeichnung "wrap relative jumps". Wenn dort ein Hacken drinn ist, springt der assembler bei langen Sprüngen ausserhalb seiner 2kWorte Reichweite einfach -Sprungweite zurück. Bei AVRs bis zu 8kB Flash funktioniert das auch problemlos. Nur für die größeren MUSS man den Hacken rausnehmen, will man nicht auf die Nase fallen. Jörg
Ok, Danke an alle. Und wenn es der Peter sogar bestätigt, werde ich heute Abend alle RCALL's gegen CALL austauschen und kann hoffentlich ruhig schlafen. Gruß Stevko
@plitzi Na das ist doch ein guter Tip. Werde es auch auprobieren. Denn bei mir war offensichtlich der Hacken drin, da ich keine Fehlermeldung bekam. Gruß Stevko
Wieso ist bei rcall und Sprungadressen von +-2k bei 4k (Word) Programmspeicher IMMER der gesamte Programmspeicher adressierbar? Wenn mein rcall bei Adresse 4000 steht und ich auf Adresse 1000 springen will, dann sind dies mehr als 2048 Adressen und es ist trotzdem nicht mehr als 4096 Programmspeicheradressen verbraucht worden.
Till Xxx schrieb: > Wenn mein rcall bei Adresse 4000 steht und ich auf Adresse 1000 springen > will, dann sind dies mehr als 2048 Adressen und es ist trotzdem nicht > mehr als 4096 Programmspeicheradressen verbraucht worden. 4000 + 1096 = 1000 4000 1111 1010 0000 + 1096 0100 0100 1000 = 1000 (1) 0011 1110 1000 Gruß Jobst
Till Xxx schrieb: > Wieso ist bei rcall und Sprungadressen von +-2k bei 4k (Word) > Programmspeicher IMMER der gesamte Programmspeicher adressierbar? Weil die Mathematik des Zweierkomplements zusammen mit dem Wraparound am Programmspeicherende das halt hergibt. > Wenn mein rcall bei Adresse 4000 steht und ich auf Adresse 1000 springen > will, dann sind dies mehr als 2048 Adressen 4000d= FA0 1000d= 3E8 Die nötige Sprungdistanz: 3E8 -FA0 ---- F448 = -3000d modulo Prgrammspeichergröße F448 &07FF ----- 448 = +1096d gesprungen wird als 1096 Adressen nach vorn statt 3000 nach hinten. Probe: FA0 +448 ---- 13E8 modulo Programmspeichergröße 13E8 &07FF ----- 3E8 = 1000d Voilá, wir sind da, wo wir hinwollten.
Hi Ich habe ein wenig mitgelesen und wenn ich eine bereits gegebene Antwort gebe, hab ich sie einfach überlesen. Der Befehl "RCALL" ist ein relativer Befehl und sollte vom Compiler auch als solcher berechnet werden. Verschiebt sich der Speicher aus irgendeinem Grund, so ist die Distanz immer noch vorhanden. Bei einem Absoluten Sprung ist dies natürlich nicht der Fall. Also, ein Programm ruft an Adresse 1000 einen RJmp zu 1200. Demnach setzt das Programm an der Speicherstelle aktuelle Adresse+200, also der Distanz, fort. Aus irgendwelchen Gründen wird nun das gesamte Programm um 1000 Speicherzellen verschoben, ohne neu übersetzt zu werden. Dann steht der Aufruf an der Adresse 2000. Der relative Sprung erfolgt nun zur Adresse 2200. Wäre es ein einfacher JMP gewesen, würde immer noch die Adresse 1200 angesprungen. In der Regel ist das auf einem AVR mit Flash-Speicher nicht so relevant, aber bei Controllern mit Programm in einem RAM gibt es schon dahingehend Unterschiede. So werden Programmblöcke vom Programmierer gar nicht erkennbar mal nach x, mal nach y geladen. Dein absoluter Sprung im Programm ist dann das AUS. Ich glaube, dein Programmfehler liegt woanders, denn eine Bereichsüberschreitung meldet der Compiler. Grad wenn man in ASM programmiert, übersieht man schon ganz gern mal ein Register, welches in einer ISR verändert wird und auf den Stack gehört. So zum Beispiel ein Unterprogramm, aufgerufen aus einer ISR. Die Register innerhalb der Subroutine müssen auch gesichert werden! Gruß oldmax
oldmax schrieb: > aber bei Controllern mit Programm in > einem RAM gibt es schon dahingehend Unterschiede. So werden > Programmblöcke vom Programmierer gar nicht erkennbar mal nach x, mal > nach y geladen. Dein absoluter Sprung im Programm ist dann das AUS. Deshalb gibt es bei solchen Systemen ja auch Mechanismen, die für absolute Sprünge die Adresse korrigieren, bevor das Programm ausgeführt wird. Dafür gibt es Tabellen, in denen steht, an welchen Positionen die Startadresse hinzuaddiert werden muss. Gruß Jobst
oldmax schrieb: > So werden > Programmblöcke vom Programmierer gar nicht erkennbar mal nach x, mal > nach y geladen. Warum sollte das so sein? Zufallsgenerator im Startup-Code? Wo das z.B. vorkommen kann, sind Programme, die dynamisch gelinkt sind.
Jobst M. schrieb: > oldmax schrieb: >> aber bei Controllern mit Programm in >> einem RAM gibt es schon dahingehend Unterschiede. So werden >> Programmblöcke vom Programmierer gar nicht erkennbar mal nach x, mal >> nach y geladen. Dein absoluter Sprung im Programm ist dann das AUS. > > Deshalb gibt es bei solchen Systemen ja auch Mechanismen, die für > absolute Sprünge die Adresse korrigieren, bevor das Programm ausgeführt > wird. Das geschieht aber nicht dadurch, daß absolute Sprünge vom (dynamischen) Linker korrigiert werden. Stattdessen wird bereits beim Compilieren des Codes und Erstellen der .dll / .so dafür Sorge getragen, daß entsprechender Code erzeugt wird. Beim GCC z.B. mittels -fpic oder -fpie. Beides wird z.B. vom avr-gcc nicht unterstützt.
Johann L. schrieb: > Das geschieht aber nicht dadurch, daß absolute Sprünge vom > (dynamischen) Linker korrigiert werden. Doch, gibt es auch. Gruß Jobst
Hi Wenn man euch so zuhört, dann fragt man sich, wofür die Erbauer der Befehlscodes den RCALL und RJMP-Befehl erfunden haben. Weil relativ adressieren schneller ist? Na ja, RCALL = 3Takte, CALL = 4Takte. Bei JMP und RJMP ist ebenfalls 1 Takt weniger beim relativen Aufruf, aber ist das wirklich der Grund? Na ja, mir ist es egal. Relativ heißt für mich immer noch, das mein Code ab jeder beliebigen Stelle im Speicher laufen kann, solange kein direkter Sprung innerhalb des Blocks programmiert ist. Ist zum Beispiel auch gegeben, wenn eine bereits compilierte Subroutine in das Programm eingegliedert wird. Ok, ich bin kein Profi, also werd ich mich jetzt dem WE widmen. Gruß oldmax
Verschieblichkeit des fertig erzeugten Binärcodes ist bei der Konzeption solcher Mikrocontroller völlig irrelevant. Das betrifft nur Systeme, die Programme dynamisch laden, nicht solche, in denen das Programm aus dem Flash-ROM ausgeführt wird. RCALL ist aber kürzer als CALL, spart also neben einem Takt auch Platz. Über kurze Distanzen kann man RCALL statt CALL verwenden. Darum geht es. Manche Mikrocontroller verwende(te)n statt PC-relativer kurzer Sprünge solche innerhalb der aktuellen Codeseite. Das ist zwar technisch etwas einfacher, sorgt aber für geharnischte Flüche bei Programmierern und Compiler-Autoren, also ist man davon abgekommen.
:
Bearbeitet durch User
oldmax schrieb: > i > Wenn man euch so zuhört, dann fragt man sich, wofür die Erbauer der > Befehlscodes den RCALL und RJMP-Befehl erfunden haben. Weil mehr nicht in eine Standard-16-Bit-Instruktion reingepaßt hat. JMP ist dann einer der wenigen besonderen Ausnahme-Befehle, die 32 Bit breit sind. Den gibt's dann auch nur auf Prozessoren, die ihn wirklich brauchen. > Na ja, mir ist es egal. Relativ heißt für mich immer noch, das mein Code > ab jeder beliebigen Stelle im Speicher laufen kann, solange kein > direkter Sprung innerhalb des Blocks programmiert ist. Beim RCALL heißt das aber auch, daß alle Funktionen, die dein Code aufruft, sich gemeinsam mit diesem auch immer mitverschieben müssen.
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.