Mahlzeit,
ich habe ein Problem mit XOR unter Keil MDK-ARM 3.80a mit einem Cortex
LPC1768.
Ich würde gerne in dem Register LPC_GPIO1->FIOPIN das Bit 28 toggeln.
LPC_GPIO1->FIOPIN ^= (1<<28); -> funktioniert leider nicht.
LPC_GPIO1->FIOPIN &= ~(1<<28); -> löschen geht aber
LPC_GPIO1->FIOPIN |= (1<<28); -> setzen geht auch
Im Anhang seht ihr noch den passenden AssemblerCode zu den obigen drei
Zeilen. Für mich sieht das eigentlich alles i.O. aus.
Jemand eine Idee?
Da stimmt einiges nicht. Bist du sicher, dass Disassembly und Quellcode
synchron sind? Dass der Disassembly-Code tatsächlich zum gezeigten
Quellcode gehört?
Beispielsweise fängt der Interrupt-Handler mit einem Return an. Wenn
0x31C tatsächlich der Einstieg in den Interrupt-Handler ist, dann ist
der Rest hinter dem Befehl "BX lr" nur Makulatur.
Und dieser Rest ist ebenfalls kompletter Bockmist.
Kann es sein, das die register nicht richtig definiert sind, vermutlich
fehlt da ein sehr sehr wichtiges schlüsselwort "volatile"? oder das der
code zu stark optimiert wird vom kompiler?
hast du die register selber definiert, oder sind die von kail definiert
worden? (code posten wenn du es selber gemacht hast)
für die erste operation wird ein ldr durchgeführt, aber kein str.
Das ergebnis wird nicht in die HW zurückgeschrieben. für die 2.
operation wird wieder ausgelesen, und das ergebnis auch wieder
zurückgeschrieben.
für die 3. Operation, dein xor, wird der startwert von der 2. bzw 1.
operation genommen, und verknüpft und auf die hw zurückgeschrieben.
Ich vermute, das daher das komische verhalten herkommt, das du
beobachtest.
das heist, wen bei deimen xor die led wieder ausgehen sollte, aber
anbleibt, könnte das durchaus zu dem ASM code passen. wenn vorher die
LED aus war.
Michael Graf schrieb:
> für die erste operation wird ein ldr durchgeführt, aber kein str.
Yep, aber ein PC-relativer LDR, womit totsicher nicht der Port
angesprochen wird.
Das müsste doch eigentlich ein THAMB 2 Befehlssatz sein, von daher weiss
ich nicht, wie die genau addressieren.
Beim ARM Befehlssatz wird normalerweiserelativ addresiert. zumindest hab
ich so komische relative sachen zum pc schon öfter gesehen.
ok die ziehlposition sieht etwas komisch aus. 0x0000051C sieht nicht
nach hw aus, eher nach selbst definierter datenstruktur. daher
warscheinlich der volatile fehler.
Michael Graf schrieb:
> Beim ARM Befehlssatz wird normalerweiserelativ addresiert. zumindest hab> ich so komische relative sachen zum pc schon öfter gesehen.
Klar, aber was rauskommt wenn man zum Wert des PC 508 addiert steht ja
rechts daneben. Nämlich 0x51C. Und das liegt definitiv nicht im
I/O-Bereich, dazu muss ich nichtmal ins Datasheet schauen.
> nach hw aus, eher nach selbst definierter datenstruktur.
Yep, das könnte die Ursache sein. Aber dafür gibt's bei den CM3 das
CMSIS, muss man anders als bei den ARM7 nicht mehr selber machen.
Also das BX lr gehört sicher noch zur vorherigen Funktion. Die Zuordnung
von Assembler Instruktionen zu C Code hat seine Grenzen. Insbesondere
wenn Optimierung im Spiel ist.
Die PC-relative Adressierung greift mit Sicherheit auf die Adresse des
Registers zu. Stichwort: literal pool. Wenn wir mal einen größeren
Ausschnitt des Programms sehen könnten (inklusive des pools), dann wäre
das sicherlich hilfreich. Außerdem verwirrt die gemischte Darstellung
mehr als sie hilft, den Code zu verstehen. Haben wir ja bereits gemerkt
:-)
Bei diesem Zugriff scheint aber etwas schiefzugehen. Es scheint als
würde eine Stufe der Indirektion vergessen. Vorausgesetzt, es handelt
sich bei den Strukturen tatsächlich um die entsprechenden GPIO, bzw. SCB
Register. Bei mir heißen die etwas anders (MDK ARM 3.70).
Gruß
Marcus
http://www.doulos.com/arm/
Marcus Harnisch schrieb:
> Die PC-relative Adressierung greift mit Sicherheit auf die Adresse des> Registers zu. Stichwort: literal pool.
Gib mit mal einen Tip, wie du einen C Compiler dazu bringst, eine
Adresse mit |= zu verzieren, ohne dass er dich mit Fehler abwirft.
Würde mich aber auch sehr interessieren, wie er den Compiler dazu
dressiert hat, einen derart schrägen Code zu produzieren.
Marcus Harnisch schrieb:
> Also das BX lr gehört sicher noch zur vorherigen Funktion. Die Zuordnung> von Assembler Instruktionen zu C Code hat seine Grenzen. Insbesondere> wenn Optimierung im Spiel ist.
Wohl wahr. Aber die exakte Funktionsadresse sollte eigentlich schon
kennen, egal wie super er optimiert. Nö, ich glaube da erst einmal
garnix mehr, das ist einfach zu hirnrissig was da steht.
So, es gibt neue Erkenntnisse!
Wie Marcus schon richtig festgestellt hat, gehört das Return BX lr zu
vorigen Funktion. Synchronität sucht man wohl vergebens.
Scheinbar ist es die Laufzeit der ISR die hier Probleme macht.
void EINT0_IRQHandler(void)
{
LPC_GPIO1->FIOPIN ^= (1<<28);
LPC_SC->EXTINT |= (1<<1);
}
Verlängere ich die Laufzeit der ISR durch eine Countervariable, die ich
einfach hochzähle...
void EINT0_IRQHandler(void)
{
LPC_GPIO1->FIOPIN ^= (1<<28);
LPC_SC->EXTINT |= (1<<1);
irq_counter++;
}
funktioniert das Toggeln.