Assembler-Codierung für ARM (Cortex-M0 und M3): ist es möglich/praktisch?

Leider gibt es auf Stack überhaupt keine Fragen zu ARM und Assembler.

Mein Anliegen sind zeitkritische Geräte. Nehmen wir als Beispiel eines meiner AVR-basierten Geräte (mit GCC kompiliertes Programm), das etwas bis zum INT0-Interrupt tun sollte. Es arbeitete mit einem internen 8-MHz-Oszillator (125 ns pro Maschinenzyklus), aber es dauerte bis zu 5 Mikrosekunden, um auf den Interrupt zu reagieren. Nach der Code-Untersuchung kam ich zu dem Schluss, dass der Prozessor am Anfang der Interrupt-Service-Routine viel Arbeit macht, um seinen Zustand zu speichern, der für höhere Programmiersprachen (wie C) fast unkontrollierbar ist. Wenn ich Assembler verwenden würde, könnte ich zum Beispiel ganz am Anfang einen Pin-Wechsel werfen und den Rest der notwendigen Berechnungen danach behalten. Oder ich könnte viel mehr Kontrolle über die Verwendung der Register haben und daher viel weniger Zeit zum Speichern dieser Register haben.

Wenn ich zu ARM wechseln würde (was ich bald vorhabe), hätte ich einen viel schnelleren Prozessorkern mit viel mehr Registern und Speicherplatz, was vielversprechend aussieht. Aber werde ich jemals in der Lage sein, solche zeitkritischen Prozesse zu kontrollieren, um beispielsweise eine Reaktionszeit innerhalb von, sagen wir, hundert Nanosekunden zu erhalten?

Wenn Sie ARM sagen, sollten Sie (besonders wenn Sie über Assembler-Programmierung sprechen) genauer sein. ARMV7? CortecM0? macht einen großen Unterschied im Befehlssatz und im Interrupt-Handling! Eine Reaktionszeit innerhalb von 100 ns wird schwierig sein, ist aber möglicherweise möglich, abhängig vom genauen Chip, der Taktfrequenz und dem, was Sie tun möchten.
@WoutervanOoijen Das ist ein guter Punkt! Frage korrigiert.

Antworten (3)

Es ist sehr sinnvoll, ARM in Assembler zu programmieren. Es ist eine unkomplizierte RISC-Architektur mit wenigen Überraschungen und vielen Registern. Sie können C und Assembler mischen, vorausgesetzt, Sie haben ein gutes Verständnis der Aufrufkonventionen.

Es gibt einen speziellen ARM-Interrupt-Modus mit niedriger Latenz namens FIQ , der einige der Register auf eine Bank in Hardware auslagert, sodass sie nicht in der ISR gespeichert werden müssen. Eine Latenz von 100 ns, um etwas Nützliches zu tun, wird immer noch schwierig sein - bei 100 MHz sind das 10 Taktzyklen, und FIQ benötigt bis zu 12, bevor der erste Befehl ausgeführt wird.

Ja, es ist sicherlich möglich - der gesamte Startcode, den Ihr C-Programm verwendet, wird normalerweise in Assembler (.s-Dateien) geschrieben.

Viele der Dinge, die Menschen mit ARM-Prozessoren machen wollen, stützen sich auf die vorhandene Infrastruktur von Protokollstapeln und Grafikbibliotheken. Wenn Sie eigenständige Anwendungen schreiben und es wie einen Super 8051 oder PIC verwenden, können Sie Assembler sicherlich für alles verwenden (oder Ihre eigenen UDP-Stacks schreiben usw.). Sie können kritische Abschnitte natürlich von Hand codieren und C für den Großteil der Programmierung verwenden.

Ich habe mir vor einiger Zeit die ARM7DTMI-Core-Assembler-Codierung angesehen, und es sah ziemlich angenehm aus, damit zu arbeiten - ich schätzte, dass es nicht länger dauern würde, um auf Hochtouren zu kommen, als mit jedem anderen neuen Prozessor in Assembler (aber tatsächlich verwenden wir C ausschließlich mit ARM-Kernen - es ist eine sehr geeignete Lingua Franca für Domänenexperten, Junior-Folk und erfahrene Programmierer gleichermaßen).

Denken Sie daran, dass typische ARM-Implementierungen nicht so eng gekoppelt sind wie einfache Prozessoren – es gibt einen Peripheriebus, der mit einer anderen Frequenz als der Prozessorbus laufen kann. Sie können beispielsweise einen Port-Pin nicht so schnell umschalten, wie Sie es von der Taktfrequenz erwarten könnten. Wenn etwas wirklich zeitkritisch ist, ist es im Allgemeinen am besten, es autonom von einem Peripheriegerät handhaben zu lassen (oder ein Hilfs-FPGA zu verwenden).

Beachten Sie auch, dass zum Beispiel ganze Spiele wie Rollercoaster Tycoon (1 & 2) in x86-Assemblierung von Hand codiert wurden, was wohl noch komplexer ist als ARMv5- oder v6-Assemblierung. Sie können mehr als nur ein paar optimierte Schleifen im Assemblercode erstellen.

Dieser ist ein bisschen alt, verdient aber eine bessere Antwort. Die ursprüngliche Frage betraf die Interrupt-Latenz. Da die ursprüngliche Plattform ein AVR ist, wird das ARM-basierte Ersatzteil ein Cortex-M3/M4 oder M0 sein. Beide dieser Geräte haben eine Interrupt-Latenzzeit von höchstens 12 Befehlszyklen. Das ist die Zeit vom Stimulus bis zur Ausführung Ihres Codes.

In der Praxis wird es länger dauern, etwas Nützliches zu tun. Es ist schwierig, in viel weniger als 3-5 Befehlszyklen auf ein IO zu schreiben (Adresse laden, Wert laden, Wert speichern). Länger, wenn die Gerätebusse, RAM oder Flash zusätzliche Latenzen aufweisen.

Wenn Sie wirklich Latenzen im 0,1-us-Bereich benötigen, benötigen Sie eher Peripheriegeräte oder benutzerdefinierte Logik als Software. Wenn der tatsächliche Bedarf begrenzte/feste Antwortzeiten sind, können Sie dies mit der richtigen Konfiguration des Interrupt-Systems erreichen. Cortex-Ms verfügen über Funktionen, die die Interrupt-Latenz unter den richtigen Umständen (späte Ankunft und Tail-Chaining) auf 6 Zyklen reduzieren können. Das kann ausgeschaltet werden, wenn Sie eine feste Latenz von 12 Zyklen benötigen.