Ein integraler Teil des Cortex-M3- Cores ist der „Nested Vectored Interrupt Controller“ (NVIC). Er ist skalierbar und wird vom Chiphersteller an die Anforderungen des Derivates angepasst. Jedem Interrupt entspricht eine Adresse in der Vektortabelle. Die ersten 15 Adressen sind für den NMI, mehrere Faults und Systemexceptions reserviert. Die Adressen darüber sind (aus Cortex-M3-Sicht) für externe Interrupts reserviert. Im Falle des STM- 32F10x sind hier 43 Interrupts für die STM32-Peripherie (Bild 2) implementiert.
Alle Interrupts können priorisiert werden, wobei drei Level zu unterscheiden sind: pre-empting, sub-priority und hardware-priority. Die beiden ersten sind per Software einstellbar, und es können vier Bits (16 Prioritätsstufen) auf die Pre-Empting- und Sub- Priority-Ebene verteilt werden. Die pre-empting priority bestimmt, ob ein Interrupt durch einen höher prioren unterbrochen werden darf. Bei gleicher Pre-Empting-Priorität entscheidet die sub-priority und dann bei Gleichheit die Hardware-Priorität, welcher Interrupt Vorrang hat. Auch das Interrupt-Handling wurde verbessert, was, wie bereits erwähnt, den Vorteil bringt, dass Interrupt Service Routinen (ISR) in reinem C geschrieben werden können und kein Assembler mehr nötig ist.
Die Harvard- Architektur wird genutzt, um den Prefetch der ISR-Instruktionen und Stack-Push-Zyklen gleichzeitig auszuführen. Selbst ein spät eintreffender höher priorer Interrupt kann noch eingeschoben werden, ohne dass die Stack-Push-Zyklen wiederholt werden müssen. Das komplementäre Verfahren am Ende einer ISR ist entsprechend optimiert. Auf den Performance- Gewinn wird in einem weiteren Artikel im Detail eingegangen. Durch die Integration des NVIC und des Debug- Interfaces in den Core kann ein Debugger auch Exceptions und Interrupts erkennen und darauf reagieren. Eine weitere Vereinheitlichung aller Cortex-M3-Derivate ist die Integration des Systick Timers.
Jedes Betriebssystem benötigt mindestens einen Timer als Zeitbasis. Mit der Integration des NVIC und des Systick sind an diese Zeitbasis angepasste Betriebssysteme auf allen Cortex-M3-Derivaten lauffähig. Der Systick besteht aus einem 24-bit-Zähler, der nach Ablauf mit einem programmierbaren Reload- Wert geladen wird und einen Interrupt erzeugen kann (Platz 15 der Vektortabelle). Im Falle des STM32 ist er an den Systemtakt oder den durch 8 geteilten Takt anschließbar.
Das neue Debug-Interface
ARM bietet mit dem Cortex-M3 ein skalierbares Debug-Interface an, aus dem die Chiphersteller sich ihre optimale Variante generieren können. Insbesondere für Low-Cost-Chips ist die Anzahl der Pins eine wichtige Eigenschaft. Für das JTAG-Interface eines ARM7 werden bereits fünf bis sieben Pins benötigt. Ist noch eine ETM (Embedded Trace Macrocell) implementiert, müssen weitere zehn Pins oder mehr für die Trace-Information reserviert werden. Der Cortex-M3 verfügt über einen Debug Access Port (DAP), der im JTAG-Modus oder in einem „Serial Wire Debug“-Modus mit nur zwei Leitungen (Clock und Data) betrieben werden kann.
Für Trace-Informationen gibt es die kleine Variante mit dem „Serial Wire Viewer“, die üblicherweise im STM32 implementiert ist, oder auch die große ETM-Lösung (Embedded Trace Macrocell), die bei den größeren Derivaten vorhanden ist. Der Serial Wire Viewer kann über ein bis vier Pins herausgeführt werden. Die Ein- Pin-Variante benutzt einen der frei werdenden JTAG-Pins, die Vier-Pin-Variante benötigt einen größeren Steckverbinder. Der Unterschied zwischen beiden Varianten ist nur die Datenrate, d.h. die Menge an Information, die aus dem Chip herausgeführt werden kann. Neben der Reduktion der Pin-Anzahl gibt es auch noch funktionelle Verbesserungen.
Jeder, der schon einmal Software für ein ARM-Derivat entwickelt hat, ist über die limitierte Anzahl der Hardware-Breakpoints gestolpert, von denen es nur zwei Stück gibt. Auch wenn hier mancher engagierte Tool- Hersteller mit Software-Breakpoints im Flash-Speicher etwas Abhilfe geschaffen hat (z.B. ist das in einem Tantino-Debugsystem im Standardumfang enthalten), war diese Einschränkung mehr als lästig. Der Cortex- M3 hat nun mehr Möglichkeiten: Als Debug-Ereignisse gibt es Breakpoints, Watchpoints, Fault Conditions und Exceptions. Die Anzahl der Breakpoints wurde auf acht erhöht, davon sind zwei Watchpoints mit je zwei Komparatoren. Da Faults und Exceptions zusätzlich überwacht werden können, werden hierfür keine Breakpoints benötigt. Als Besonderheit kann die Debug-Unit so geschaltet werden, dass sie auch in den verschiedenen Sleep-Modi noch ungestört funktioniert. Im Gegensatz zu den ARM-Controllern ist die Debug- Logik in der Lage, aus dem Speicher zu lesen oder in ihn zu schreiben, ohne die CPU zu benötigen. Dies ermöglicht Zugriffe auf den Speicher auch bei laufender Applikation (im Run-Modus).