Arm Cortex-M3
# Arm Cortex-M3

Der Cortex-M3 ist ein Modell aus der Arm Cortex-M-Familie (Armv7-M) für Mikroprozessoren von ARM. Die Armv7-Architektur wurde ab dem Jahr 2004 eingeführt und kann als Nachfolger für die ARMv6-Architektur im Bereich der Mikrocontroller betrachtet werden.

## Hintergrund

Arm-Architekturen sind im Laufe der Zeit immer komplexer geworden. Der erste populäre Arm-Prozessor war (und ist immer noch) der ARM7, gefolgt vom ARM9 und ARM11 in unterschiedlichsten Ausführungen.

Die Einsatzgebiete für diese drei Prozessorfamilien lassen sich in etwa folgendermaßen einteilen:

    ARM7: Dies war ein Selbstläufer im Bereich der Mikrocontroller. Ursprünglich nicht für den Einsatz in Mikrocontrollern vorgesehen, hat sich dieser Prozessor dort etabliert. Eingesetzt werden ARM7-basierte Mikrocontroller dort, wo etwas mehr Rechenleistung erforderlich ist als z. B. ein 8-Bit-Prozessor liefern kann.
    ARM9: Bietet weit mehr Rechenleistung als ARM7 und wird u. a. in Echtzeitsystemen eingesetzt. Hier kommen Mechanismen wie z. B. MMU und MPU zum Einsatz.
    ARM11: High-End-Anwendungen im Bereich eingebetteter Systeme, die sehr viel Rechenleistung erfordern.

Seine neue Architektur teilte ARM in drei Zweige auf, um Nachfolger für alle drei Bereiche zu schaffen. Diese Aufteilung sollte einen noch breiteren Einsatz der neuen Architektur(en) in der Welt der Embeddedsysteme ermöglichen.

    Cortex-A: Application (betriebssystembasierte Anwendungen)
    Cortex-R: Realtime (Echtzeit­anwendungen)
    Cortex-M: Microcontroller (Cores für Mikrocontroller)

Die Cortex-M3-Architektur kann somit als Nachfolger für den ARM7 betrachtet werden und stellt mehr Rechenleistung als dieser bei geringerer Komplexität des Programmiermodells sowie kleinerer Chipfläche zur Verfügung. Andere Untergruppen, wie z. B. der M1, sind z. B. für die Implementierung auf einem FPGA verfügbar.

## Prinzipieller Aufbau

Der Entwurf der von ARM entwickelten Cortex-M3-Architektur zielt auf den Einsatzbereich der (klassischen) 8- und 16-Bit-Mikrocontroller durch einen leistungsfähigeren, aber zugleich vom Programmiermodell her weniger komplexen Prozessor. Wie alle vorherigen Arm-Architekturen hat auch der M3 intern eine 32-Bit-Architektur, arbeitet aber ausschließlich mit dem neuen Thumb2-Befehlssatz. (Andere ARM-Cores können zwischen ARM- und Thumb-Befehlssatz umschalten.)

Herzstück des Cortex-M3-Prozessors ist der Cortex-M3-Kern mit dreistufiger Pipeline, basierend auf der Harvard-Architektur. Es existieren also zwei getrennte Bussysteme (und zwei getrennte Speicher) zum Laden von Daten und Befehlen, d. h. der Prozessor kann gleichzeitig sowohl Daten als auch Befehle lesen (bzw. Daten in den Speicher zurückschreiben). Nach außen hin (Programmiermodell) ist der Cortex-M3 allerdings ein Von-Neumann-Modell, das bedeutet, dass sein ganzer (gemeinsam benutzter) Adressraum linear programmiert werden kann.

Bei einem 32-Bit-Prozessor ist der verfügbare Adressraum mit $2^{32}$ Adressen für einen Mikrocontroller überdimensional groß. Daher können beide Speicher in einem gemeinsamen Adressraum angesprochen werden. Die Programmierung wird somit erleichtert, da Daten, welche im Flash (Programmspeicher) abgelegt werden (zum Beispiel Konstanten) ohne zusätzlichen Aufwand direkt linear adressiert werden können.

In den Kern des Cortex-M3 wurden einige neue Features integriert. So gehören ein echter Nested Vectored Interrupt Controller, eine Art Sprungvorhersage und Multiplikation in nur einem Takt, dazu.

## Sprungvorhersage

Zum Laden eines Befehls werden nur 16 Bit benötigt, das Speicherinterface ist aber 32 Bit breit, und es werden immer zwei Befehle gleichzeitig geladen (fetch). Ein Befehl wird jeweils zwischengespeichert. Im Falle eines Sprungs ist erst in der Exec-Stufe (vgl. Pipelines) bekannt, ob der Sprung durchgeführt werden soll oder nicht. Wenn nicht, wird wie gehabt weitergearbeitet. Wenn ja, wird der gepufferte Befehl in die Pipeline geladen und damit weitergearbeitet. Somit geht bei der dreistufigen Pipeline nur ein Takt (anstelle von zwei) verloren.

## Thumb2

Der Prozessorkern arbeitet ausschließlich mit dem neuen Befehlssatz Thumb2, wodurch er um einiges effizienter arbeitet als ältere ARM-Prozessoren mit Thumb (bezogen auf die Ausführungszeit) und mit um etwa 30 % kompakterem Code operiert als ältere ARM-Prozessoren im ARM-Mode. Der Thumb2-Befehlssatz umfasst sowohl 16- als auch 32-Bit Befehle, die darauf ausgelegt sind, möglichst effizient mit Compilern zu arbeiten, d. h. z. B. C/C++-Code umzusetzen, aber natürlich auch unter Assembler verwendet werden können.

Fast alle klassischen ARM-Befehle sind (wie Thumb) nur 16 Bit lang. Das ermöglicht das Laden zweier Befehle in nur einem Takt.

Weitere große Neuerungen in Thumb2 sind z. B. native bitfield manipulation, Hardware-Division und If-Then-Anweisungen. Letztere ermöglichen eine bedingte Ausführung von Code (ohne Sprünge).

## Einfach gehaltenes Programmiermodell

Zur Programmierung einfacher Aufgaben werden keine genauen Kenntnisse des internen Aufbaus und der Struktur des Kerns und auch keine Assemblerkenntnisse zum Programmieren benötigt. Die Programmierung von Interrupthandlern wird durch das hardwarebasierte Interruptschema erleichtert.

## Peripherie

Der Cortex-M3 bringt bereits einige Peripherien mit sich. So sind z. B. ein echter Vectored-Interrupt-Controller (VIC), Memory-Protection, Timer und Debug- und Trace-Möglichkeiten in den Prozessor integriert.

Zusätzliche Peripherien, wie UART, weitere Timer, PWM, I2C, SPI usw., werden von den Chipherstellern entwickelt oder als IP (Intellectual Property) von ARM dazugekauft. Diese lassen sich – wie gewohnt – über Register ansprechen.

## Vectored Interrupt Controller

Mit der Implementierung des NVIC verwendet der Cortex-M3 eine echte Vektortabelle, d. h. dort stehen Sprungadressen (Vektoren) statt der zuvor bei ARM-basierten Controllern üblichen vollständigen Befehle. Über sein direktes Interface zum Core können diese Vektoren (Adressen) sehr schnell geladen und angesprungen werden.

Der Interruptcontroller ist beim Cortex-M3 sehr eng mit dem Kern verbunden. Der Prozessor sichert den Kontext automatisch. Weitere Besonderheiten wie „Late Arriving Interrupt“ und „Tail Chaining“, bei dem eine POP/PUSH-Sequenz eingespart wird (vgl. ARM7), ergeben ein sehr effizientes Interruptsystem. Allgemein kann jedem Interrupt eine Priorität zugewiesen werden, d. h. die Priorität wird nicht über die Position in der Vektortabelle fest vorgegeben. Die Prioritäten können in Gruppen organisiert werden. Interrupts in verschiedenen Gruppen können sich gegenseitig unterbrechen, innerhalb einer Gruppe unterbricht ein Interrupt höherer Priorität keinen niederpriorigen. Das ist wichtig, um Deadlocks bei gemeinsam verwendeter Hardware zu vermeiden.

## Registersatz

Klassische ARM-Cores besitzen einen Satz von über 37 32-Bit-Registern, die sich auf verschiedene Modi aufteilen. Je nach Modus sind verschiedene Register sichtbar. Das erspart das Sichern von Registern z. B. für den FIQ (Schattenregister R8 bis R14 überdecken die Register aus dem User-Mode).

Der Cortex-M3 besitzt nur noch einen Satz von Registern (R0 bis R12, SP, LR, PC und CPSR) und einen zusätzlichen Stackpointer (SP). Beim Sprung in eine ISR sichert der Core automatisch die acht Register PC, CPSR, LR R0 bis R3 und R12.

## Silizium

ARM ist ein Fabless-Unternehmen, stellt also selbst keine Chips her, sondern entwickelt Prozessorarchitekturen (auch Peripherie) und lizenziert diese an andere Firmen.

Das Startup-Unternehmen Luminary Micro nahm die erste Implementierung von Cortex-M3 in einen Mikrocontroller vor. Luminary Micro ist ebenfalls ein Fabless-Unternehmen und Hersteller der „Stellaris“-Mikrocontrollerfamilie (LM3S811, LM3S828, u. a). Eine Vielzahl von Peripherien wurde auf dem Chip implementiert; neben den gängigen Elementen wie UART, Timer etc. findet sich z. B. eine komplexe 3-Phasen-Motorsteuerung.

Die STM32-Familie von STMicroelectronics basiert ebenfalls auf dem Cortex-M3-Kern von ARM und umfasst viele Peripherieelemente, zum Beispiel zur 3-Phasen-Motorsteuerung, Hall- bzw. Inkrementalgeber-Interface, DMA, 12-Bit-ADC, sowie einiges an Standardperipherien. Aspekte dieser Implementierung sind z. B. das vom Core getrennte Debug-Modul, das auch bei fehlerhafter Programmierung des Clock Trees den Zugriff auf den Core ermöglicht, sowie eine Clock-Security-Schaltung, die einen Ausfall der externen Takts (z. B. des Quarzes) bemerkt und auf einen internen Oszillator umschalten kann – ohne dass der Core „abstürzt“. Ein sauberes Programmiermodell für die Peripherals und ein System aus Headerfiles für das Registermapping, das eine einfache Programmierung des Cores auch ohne Driver-Library ermöglicht, runden diesen Mikrocontroller ab.

## Arm Cortex Microcontroller Software Interface Standard (CMSIS)

Um eine gemeinsame Basis für die Programmierung von Cortex-M-basierten Mikrocontrollern zu ermöglichen, wurde am 12. November 2008 von ARM eine Standard-HAL veröffentlicht. Sie ist in Zusammenarbeit mit den Partnern der Industrie entstanden und bietet auf dem Layer1, der Abstraktion der Register sowie deren Abbildung auf das Speicherlayout eine gemeinsame, einfach zu verwendende Programmierbasis. Bisher gab es zu der Vielzahl von Implementationen jeweils eigene Ansätze des Programmiermodells, von #defines auf einzelne Register bis hin zu komplexen Strukturen. Die HAL verwendet das Konzept der komplexen Strukturen, wobei für jedes Peripheral eine Struktur existiert, welche die Register des jeweiligen Peripherals komplett abbildet. Die Strukturen werden an die Adressen der Peripherals gemappt, was den Zugriff Peripheral→Register = Value bzw. value = Peripheral→Register ermöglicht.

Ein Layer 2, ein sehr effizienter Layer aus Inline-Funktionen, bietet weitere Helferfunktionen zum einfachen NVIC-Handling sowie ein SystemTick-Timer-Setup, welches auf die Belange von Echtzeitbetriebssystemen abgestimmt ist.

