Cortex-M4F FPU-Probleme

Ich schreibe etwas Code für ein Stellaris Launchpad-Board von Texas Instruments (ein Cortex-M4F, der Chip ist ein LM4F120H5QR ). Ich verwende die IRMP- Bibliothek für die Infrarot-Decodierung, die gut funktioniert, solange ich keine Gleitkomma-Mathematik außerhalb ihrer ISR verwende. Nur eine einzige Operation wie in

MAP_SysCtlDelay((MAP_SysCtlClockGet())/ 30.0);

bricht die IRMP-Bibliothek. Der Chip läuft noch, IRMP ruft alle benötigten Funktionen auf, UART-Übertragungen funktionieren, aber IRMP kann keinen Infrarot-Empfang mehr entschlüsseln.

Ganz oben in meiner mainFunktion habe ich:

  // Enable FPU
  MAP_FPULazyStackingEnable();
  MAP_FPUEnable ();

Wenn ich diese Zeilen auskommentiere, bleibt die Software tatsächlich während der Initialisierung hängen.

Ich habe verschiedene Varianten dieser FPU-Aktivierungsfunktionen (ROM_, MAP_, FPUStackingEnable, FPULazyEnable) ausprobiert, aber nichts scheint das Problem zu beheben.

Die letzten 4 Stunden des Googelns haben sich als nutzlos erwiesen, also hatte ich gehofft, hier eine Antwort zu finden.

Bearbeiten: Mehr Verrücktheit: Wenn ich mit -O0 kompiliere, dekodiert IRMP auch nichts. Sobald ich die Optimierungen auf O1 oder höher stelle, funktioniert es wieder (sofern außerhalb der Timer-ISR-Routine und der von ihr aufgerufenen Funktionen keine Gleitkomma-Arithmetik stattfindet).

Oh, und falls es hilft, arm-none-eabi-gcc --versiongibt:

arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.7.3 20121207 (release) [ARM/embedded-4_7-branch revision 194305]

Ich kompiliere mit den folgenden Optionen:

-DPART_LM4F120H5QR -DARM_MATH_CM4 -DTARGET_IS_BLIZZARD_RA1 -I$SOMEDIR/stellarisware 
-Os -Wall -std=gnu99 -c -fmessage-length=0 -fsingle-precision-constant -mcpu=cortex-m4 
-mfpu=fpv4-sp-d16 -mthumb -mfloat-abi=softfp -ffunction-sections -fdata-sections

Bearbeiten 2: Ich sollte hinzufügen, dass im IRMP-Code keine tatsächlichen Gleitkommaberechnungen stattfinden. Das heißt: Alle Variablen sind ganze Zahlen. Es gibt jedoch viele Definitionen, die Zwischenfloaten sind, z.

#define IRMP_KEY_REPETITION_LEN (uint16_t)(F_INTERRUPTS * 150.0e-3 + 0.5)

uint16_tDiese Konstanten werden im eigentlichen Code mit anderen Typen verglichen . Ich bin mir nicht ganz sicher, warum dies FP-Arithmetik im Laufzeitcode erfordert, es sind alles feste Werte, die in Ganzzahlen gefaltet werden können.

Antworten (1)

Warum versuchen Sie nicht, alle Gleitkommaberechnungen aus den Interrupt-Service-Routinen zu entfernen? Viele Leute würden darauf hinweisen, dass es überhaupt nicht dort sein sollte.

Berechnen Sie Gleitkomma-Dinge im Hauptcodefluss vor, sodass sie nicht in der ISR sein müssen. Dies erfordert möglicherweise ein Überdenken der verwendeten Algorithmen, führt jedoch häufig zu robusterem und schlankerem Code.

+1, ich bin mit dieser Plattform nicht vertraut genug, um sicher zu sein, aber es hört sich so an, als ob die FPU-Operationen nicht atomar sind und sie in einem undefinierten Zustand belassen. Eine andere (langfristig nicht gute) Sache wäre, Interrupts zu deaktivieren, während Sie den gesamten FPU-Code in Ihrem Hauptcode ausführen, nur um zu sehen, ob dies das Problem löst.
Ich stimme zu, dass der ISR nicht der ideale Ort für FP-Berechnungen ist. Wenn also alles andere fehlschlägt, muss ich das wohl tun. Ich möchte jedoch lieber, dass die Bibliothek funktioniert, anstatt den gesamten Code durchwühlen und lahmlegen zu müssen, nur um ihn zum Laufen zu bringen.
Da die FPU-Operationen nicht atomar sind: Die Existenz der Funktion FPUStackingEnable() würde etwas anderes nahelegen. Außerdem kann ich den Code brechen, indem ich eine einzelne FP-Operation ausführe, noch bevor ich die IRMP-Bibliothek initialisiere. Danach ist mein main() nur noch eine leere Besetztschleife.
@Michael Karas: Ich bin den Code durchgegangen, da ist sowieso keine FP-Arithmetik drin. Siehe mein Update Nr. 2 in der ursprünglichen Frage.
@Darhuuk - Entschuldigung, wenn ich für Ihre spezielle Situation falsch geantwortet habe. Mein Kommentar steht immer noch dafür, Interrupt-Timecode zu machen, da es im Allgemeinen eine schlechte Praxis ist, Dinge wie Gleitkommazahlen in einer ISR zu machen. Für die meisten Programmierungen dieser Art ist es am klügsten, den Code, der bei jedem Interrupt ausgeführt wird, auf ein Minimum zu beschränken. Das bloße Aktivieren der Option zum angeblichen Aktivieren des Gleitkommas in ISRs stellt eine große Belastung für jede Interrupt-Routine dar, da viele große Register auf den Stack verschoben werden müssen. Schauen Sie sich den Demontagecode an ... autsch.
@Darhuuk - Haben Sie nachgesehen, ob Ihr Programm möglicherweise beschädigt wird, wenn die STACK-Größe und der Speicherort so groß werden, dass es zu groß wird oder in einen anderen kritischen Datenbereich gerät?
@Michael Karas: Kein Problem, ich verstehe, was Sie sagen wollen, und ich stimme zu, dass es in den meisten Fällen nicht wirklich angemessen ist, FP-Mathematik in einem ISR zu machen. Obwohl mit der FPU in einem M4F der langsamste FP-Befehl "nur" 14 Zyklen dauert und mein Anwendungsfall überhaupt nicht zeitkritisch ist, sollte es keine große Rolle spielen.
@Michael Karas: Ich habe die Stapelgröße auf 8 KB erhöht und nichts ändert sich, also mache ich entweder etwas im Linker-Skript falsch oder es ist ein anderes Problem.
@Michael Karas Das Problem stellte sich als stapelbezogen heraus. Der Wechsel zu einem anderen Linker-Skript hat das Problem behoben. Wenn Sie Ihrer Antwort so etwas hinzufügen, werde ich es gerne akzeptieren;).