Wie System-Ticks funktionieren

English Deutsch

Wie System-Ticks funktionieren

Um zu verstehen, wie Verzögerungen funktionieren, müssen wir uns zunächst System-Ticks ansehen. Obwohl ChibiOS 3.x ein Feature namens Tickless Mode unterstützt, bleiben wir aus Gründen der Einfachheit bei einem einfachen Periodic-Tick-Modell.

Ein System-Tick ist einfach ein Timer, der den Mikrocontroller periodisch unterbricht und einige Kernel-Verwaltungsaufgaben ausführt. Bei einer System-Tick-Frequenz von 1 kHz (Systick) wird der Programmfluss beispielsweise jede Millisekunde unterbrochen. Bei der Unterbrechung prüft der Kernel unter anderem, ob ein Thread, der gerade schläft, geweckt werden muss. Wenn dein Thread also Code wie diesen enthält:

chthd_sleep_example.c
// [...]
chThdSleepMilliseconds(5);
// [...]

und der Kernel eine Systick-Frequenz von 1 kHz hat, setzt der Kernel deinen Thread in den Schlaf, wartet 5 System-Ticks (d.h. 5 ms) und weckt den Thread dann wieder.

In ChibiOS sind chThdSleep(delay) und chThdSleepMilliseconds(delay) nicht grundlegend verschieden: Letzteres ist definiert als chThdSleep(MS2ST(d)). MS2ST() ist ein Makro, das im Wesentlichen die Anzahl der Millisekunden mit der Systick-Frequenz multipliziert, um die Anzahl der zu verzögernden Systicks zu erhalten (es ist etwas komplizierter, da garantiert werden muss, dass der Wert aufgerundet wird).

Genau wie MS2ST() gibt es andere Makros wie S2ST() für Sekunden oder US2ST() für Mikrosekunden.

Welche Verzögerungswerte sind gültig?

Untergrenze

Da bei einer Frequenz von 1 kHz der Kernel die Verzögerung nur jede Millisekunde prüft, ist es offensichtlich, dass er einen Thread nicht nach weniger als einer Millisekunde wecken kann. Beispielsweise

chthd_sleep_microseconds_example.c
chThdSleepMicroseconds(500); // Verzögerung für eine halbe Mikrosekunde

führt nicht zu einer Verzögerung von 500 µs, sondern zu einer Verzögerung von 1 ms. Der Grund hierfür ist (wie in der Dokumentation gezeigt), dass US2ST() garantiert, dass der Wert auf volle Systicks aufgerundet wird. Da es einen Systick gibt.

Ebenso führt

chthd_sleep_microseconds_1001.c
chThdSleepMicroseconds(1001);

aufgrund des Aufrundens zu einer Verzögerung von 2 ms. Du kannst dies überprüfen, indem du die Werte in die US2ST()-Formel einsetzt.

Beachte, dass im Tickless-Mode, d.h. wenn CH_CFG_ST_TIMEDELTA != 0 (definiert in chconf.h), die Mindestverzögerung CH_CFG_ST_TIMEDELTA * CH_CFG_ST_FREQUENCY beträgt, also mindestens doppelt so groß ist wie die Mindestverzögerung im Periodic-Tick-Modus. Siehe die Dokumentation in chconf.h für Details.

Obergrenze

Mikrocontroller-Timer haben feste Auflösungen. Je nach Mikrocontroller (und dem Timer, der für den Systick verwendet wird, siehe mcuconf.h und chconf.h) ist der Timer 8-Bit, 16-Bit, 24-Bit (selten) oder 32-Bit breit.

Dies bedeutet, dass der Timer 2^8-1, 2^16-1, 2^24-1 oder 2^32-1 verschiedene Werte ohne Überlauf darstellen kann. Im Allgemeinen kann davon ausgegangen werden, dass ein RTOS-Kernel-Code nicht mehr Systicks als Verzögerung unterstützt als 2 hoch Timer-Bits minus eins (dafür gibt es verschiedene Faktoren, aber der Hauptgrund ist, dass bei einem 16-Bit-Timer eine Verzögerung von 2^16+5 Systicks nicht von einer Verzögerung von 5 Systicks unterschieden werden kann, ohne speziell dafür entwickelten Kernel-Code). Daher ist ein Timer mit mehr Bits normalerweise vorzuziehen (allerdings musst du die 32-Bit-Timer möglicherweise für andere Aufgaben in deiner Anwendung verwenden).

Beachte, dass du bei einem 32-Bit-Mikrocontroller nicht automatisch 32-Bit-Timer hast. Viele kleinere 32-Bit-Controller wie der STM32F030 haben nur 16-Bit-Timer. Selbst wenn du einen 32-Bit-Timer hast, musst du ChibiOS so konfigurieren, dass er verwendet wird.

Nehmen wir einen 1-kHz-Systick und einen 16-Bit-Timer an (wie oben). Welche Verzögerung (in Sekunden) entspricht also der maximalen Verzögerung, die mit diesem Timer erreichbar ist?

systick_calc.c
(2^16-1) / 1000 Hz = 65.5 s

Wenn du also eine Verzögerung von mehr als etwa 65 Sekunden benötigst, musst du alternative Methoden wie unten beschrieben verwenden.

Warum nicht einfach die Systick-Frequenz erhöhen?

Bis zu einem gewissen Grad kannst du die Mindestverzögerung verbessern, indem du einfach die Systick-Frequenz erhöhst. Dieser Ansatz führt jedoch zu zwei Problemen:

Obwohl die Zahlen stark variieren, empfehle ich, die Systick-Frequenz auf nicht mehr als 100 kHz einzustellen. Frequenzen um 1-10 kHz sollten im Allgemeinen bevorzugt werden.

Wie man kürzere Verzögerungen erreicht

Mittel-kurze Verzögerungen: Polled Delays

Für genaue Verzögerungen (siehe auch den Abschnitt zu Einschränkungen unten), die kürzer sind als die oben berechnete untere Systick-Verzögerungsgrenze, aber nicht signifikant kürzer als eine Mikrosekunde oder etwa 100 ns für schnellere Mikrocontroller (siehe unten für eine Erklärung der Grenze), können wir eine Methode namens Polled Delaying verwenden, um die gewünschte Verzögerung zu erhalten.

Sie besteht aus drei einfachen Schritten (es gibt verschiedene Varianten, ich zeige nur eine vereinfachte):

ChibiOS enthält eine Implementierung dieser Strategie in gptPolledDelay()

Beispielcode:

gpt_polled_delay.c
static const GPTConfig gpt4cfg = {
  100000, // 1 MHz Timer-Takt.
  NULL, // Kein Callback
  0, 0
};

gptStart(&GPTD4, &gpt4cfg);
gptPolledDelay(&GPTD4, 10); // 10 µs Verzögerung

In diesem Fall verwenden wir den vierten Timer, z.B. TIM4 auf einem STM32. Du musst den GPT-Treiber in halconf.h und TIM4 in mcuconf.h aktivieren, damit dieses Beispiel kompiliert. Der zweite Parameter für gptPolledDelay(), 10, ist die Anzahl der zu wartenden Ticks. Achtung: Dies sind keine Systicks! In diesem Kontext sprechen wir von Timer-Ticks. Wir haben die Timer-Frequenz von TIM4 in der gpt4cfg-Struktur auf 1 MHz definiert, also entsprechen 10 Ticks 10 Mikrosekunden.

Beachte jedoch, dass es Hardware-Beschränkungen für die Frequenzen gibt, mit denen ein Timer laufen kann. Normalerweise ist die Timer-Frequenz eine interne Taktfrequenz (z.B. HCLK bei einigen ARM-Mikrocontrollern) geteilt durch eine ganze Zahl (Prescaler genannt). Je nach Mikrocontroller akzeptieren bestimmte Timer nur bestimmte Prescaler (z.B. nur Zweierpotenzen) und die interne Taktfrequenz ist ebenfalls begrenzt.

Siehe das Datenblatt oder Referenzhandbuch deines Mikrocontrollers für Details.

Timer-Interrupts

Anstatt eine Busy-Waiting-Schleife zu verwenden (die deinen Mikrocontroller zu 100% beschäftigt und daher nicht nur viel Strom verbraucht, sondern auch andere Threads am Laufen hindern könnte), kannst du einen Timer-Underflow-Interrupt verwenden (andere Interrupt-Typen sind ebenfalls möglich). Dieser Interrupt wird aufgerufen, sobald der Timer Null erreicht.

Im Interrupt-Handler kannst du entweder direkt eine erforderliche Aktion ausführen oder einfach deinen Thread wecken. Beispiel:

gpt_interrupt_example.c
static void gpt4cb(GPTDriver *gptp) {
  (void)gptp;
  // Führe deine Aktion hier aus
}

static const GPTConfig gpt4cfg = {
  100000, // 1 MHz Timer-Takt.
  timerCallback, // Kein Callback
  0, 0
};
gptStart(&GPTD4, &gpt4cfg);
gptStartOneShotI(&GPTD3, 100); // ~100 ns Verzögerung, dann Timer stoppen

Eine detaillierte Diskussion dieser Methode ist hardwareabhängig und geht über den Rahmen dieses Artikels hinaus. Siehe das Datenblatt und Referenzhandbuch deines Mikrocontrollers sowie die ChibiOS-Dokumentation und Beispiele für weitere Informationen.

Beachte, dass Interrupts eine hardware- und firmware-spezifische Verzögerung einführen können, bis der Interrupt-Handler aufgerufen wird. Im Allgemeinen kann davon ausgegangen werden, dass timer-interrupt-basierte Verzögerungen weniger genau und weniger reproduzierbar sind als polled Timer-Verzögerungen, besonders auf komplexeren Mikrocontrollern. Eine Diskussion der genauen Gründe hierfür geht über den Rahmen dieses Artikels hinaus.

Sehr kurze Verzögerung: Sequenz von NOP-Anweisungen

Was, wenn du eine sehr kurze Verzögerung von einigen zehn oder hunderten Nanosekunden einführen möchtest und dein Timer solche Frequenzen nicht unterstützt? Dieses Problem tritt häufig beim Bit-Banging spezifischer binärer Protokolle wie für den WS2812B oder 1-Wire auf.

Erstens: Ein Mikrocontroller mit 8 MHz kann niemals eine Verzögerung von weniger als 125 ns implementieren (1 geteilt durch 8 MHz), es sei denn, das Protokoll hat spezifische Hardware-Unterstützung. Du musst also prüfen, ob dein Mikrocontroller deine Verzögerung überhaupt implementieren kann. Beispielsweise sind Verzögerungen um 1 Nanosekunde einfach unmöglich auf Mikrocontrollern zu implementieren (da sie mit < 1 GHz laufen), es sei denn, es wird spezialisierte Schaltung dafür verwendet.

Diese Methode ist sehr einfach: Wir halten den Mikrocontroller mit NOP-Anweisungen beschäftigt (dies ist eine Anweisung, die nichts tut und daher normalerweise nur einen Taktzyklus benötigt), bis ein bestimmter Zeitraum vergangen ist.

Wie du die NOP-Anweisung aus C-Code aufrufst, ist compiler- und architekturabhängig. Ich verwende das ARM Cortex-Mx __NOP()-Intrinsic für dieses Beispiel.

Beispielsweise führt diese Sequenz zu einer Verzögerung von etwa 5 Taktzyklen

nop_sequence.c
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();

Um zu vermeiden, deinen Quellcode mit hunderten von __NOP()-Aufrufen zu überladen, kannst du auch Schleifen verwenden:

nop_loop.c
for(int i = 0; i < 27; i++) {
  __NOP();
  __NOP();
  __NOP();
  __NOP();
  __NOP();
}

Theoretisch würde diese Schleife 27 * 5 = 135 Taktzyklen verzögern, aber Achtung: Tatsächlich verzögert sie etwas länger: Die Schleife selbst führt zusätzliche Anweisungen in der Assembly ein (Zählen und Prüfen, ob die Schleifenbedingung erfüllt ist).

Es gibt mehrere Methoden, um die genaue Verzögerung zu bestimmen, die eine NOP-Sequenz einführt:

Aufgrund der inhärenten Zuverlässigkeit bevorzuge ich Empirisch A. Wenn ich keinen Zugriff auf ein Oszilloskop hätte, würde ich Empirisch B bevorzugen.

Beachte, dass diese Methode — genau wie der Polled-Delay-Busy-Waiting-Ansatz — deine CPU laufen lässt, während sie effektiv nichts Nützliches tut (außer warten). Dies ist jedoch die einzige

Wie man längere Verzögerungen erreicht

Erneut: Polled Delays und Timer-Interrupts

Anstatt einen Hardware-Timer auf eine hohe Zählfrequenz einzustellen und für eine kurze Zeitspanne zu warten, können wir den Timer einfach auf eine sehr niedrige Frequenz einstellen (z.B. 0,1 Hz, falls vom Prescaler unterstützt, siehe oben), um einen maximalen Timer-Wert von 655350 für einen 16-Bit-Timer zu erhalten. Dieser Ansatz erhöht unsere maximale Verzögerung von 65,5 Sekunden (siehe obiges Beispiel) auf mehr als 7,5 Tage.

Dies bedeutet jedoch, dass (abgesehen von preemptiven Schedulern, die über den Rahmen dieses Artikels hinausgehen) deine CPU den Timer bis zu 7 Tage lang kontinuierlich prüft! Dies ist für die meisten Anwendungen nicht ratsam.

Daher ist es ratsam, Timer-Interrupts für mittellange Verzögerungen zu verwenden, wo genaue Verzögerungen erforderlich sind (siehe Abschnitt Timer-Interrupts oben). So wie es eine Untergrenze für die Timer-Verzögerung gibt, gibt es auch eine Obergrenze, definiert durch die Systemtaktfrequenz und den Prescaler-Bereich. Siehe die unten aufgeführten anderen Methoden für Alternativen.

Software-Prescaler

Eine sehr einfache Methode für längere Verzögerungen ist das Hinzufügen eines Software-Prescalers, d.h. wir führen einfach aus

Wir haben zuvor gezeigt, dass

chthd_sleep_seconds_example.cpp
chThdSleepSeconds(300); //5 Minuten Schlaf

für das 16-Bit-Systick-mit-1-kHz-Szenario nicht funktioniert. Was jedoch funktioniert, ist:

chthd_sleep_loop.c
for(int i = 0; i < 5; i++) { //5 Mal...
    chThdSleepSeconds(60); //1 Minute Schlaf
}

Im Wesentlichen gibt es keine Obergrenze dafür, wie lange du mit dieser Methode verzögern kannst. Für Verzögerungen, die nicht sehr genau sein müssen (d.h. einige Millisekunden mehr oder weniger sind akzeptabel und Verzögerungs-Jitter kein Problem darstellt), ist dies die bevorzugte Methode. Siehe auch den Abschnitt Einschränkungen unten. Für Firmwares, bei denen der MCU meist im Leerlauf ist, ist dies eine der bevorzugten Methoden zur Verzögerung.

Virtuelle Timer

Wenn du eine Verzögerung hast, die innerhalb des vom Systick-Timer erlaubten Bereichs liegt, und du den Hardware-Timer-Mechanismus nicht verwenden möchtest (möglicherweise, weil du nicht genug Timer hast), kannst du den Virtual Timer verwenden, der von ChibiOS/RT angeboten wird (ChibiOS/NIL unterstützt dieses Feature nicht).

Beispielcode:

virtual_timer_example.c
static virtual_timer_t vt;

static void onTimer(void *param) {
  (void)param;
  // Wenn wir den Timer hier erneut setzen, wird diese Funktion
  //  mit 10 ms Intervall aufgerufen, d.h. 100 Hz.
  chSysLockFromISR();
  chVTSetI(&vt, MS2ST(10), onTimer, NULL);
  chSysUnlockFromISR();
}

void startTimer() {
  chVTSet(&vt, MS2ST(10), onTimer, NULL);
}

Der Hauptvorteil ist, dass du praktisch unbegrenzt viele virtuelle Timer hast. Dieser Verzögerungstyp leidet jedoch unter den gleichen Nachteilen wie der System-Tick.

RTCs

Für sehr lange Verzögerungen, besonders wenn der Stromverbrauch wichtig ist, kannst du die RTC (Real-Time Clock, im Wesentlichen eine Weckeruhr und ein Kalender in Hardware) verwenden, die in größere Mikrocontroller eingebaut ist (oder eine externe RTC).

Du kannst die meisten RTCs so konfigurieren, dass sie den Mikrocontroller z.B. nach 3 Monaten wecken. Der Hauptvorteil hierbei ist nicht nur die lange Verzögerung, sondern dass die RTC im Wesentlichen unabhängig vom Haupt-MCU läuft (oft hat sie auch eine unabhängige Batterie) auf einem separaten Niederfrequenz-Oszillator (meistens ein 32,768-kHz-Quarzkristall). Dies bedeutet, dass

Einschränkungen

Besonders beim Versuch, genaue Verzögerungen zu erreichen, gibt es mehrere Faktoren, die deine Verzögerungen beeinflussen können. Eine umfassende Liste zu erstellen ist nahezu unmöglich, aber

Konfiguration der Taktquelle

Die von ChibiOS durchgeführten Frequenzberechnungen hängen von einer korrekten Konfiguration der Haupt-Taktquelle (z.B. Oszillator, Kristall oder Resonator) ab. Wenn du den internen Oszillator verwendest, kannst du praktisch nichts falsch machen, da ChibiOS Makros hat, die prüfen, ob deine Konfiguration korrekt ist (es könnte jedoch Bugs geben…).

Wenn du eine externe Taktquelle verwendest, musst du sicherstellen, dass du die richtige Frequenz eingestellt hast. Wenn du beispielsweise einen 12-MHz-Oszillator verwendest, aber einen 8-MHz-Oszillator konfiguriert hast, sind alle Verzögerungen falsch. In einigen Fällen könnte dies sogar deine Hardware beschädigen (wenn deine PLL-Ausgangsfrequenz die spezifizierten Werte erheblich überschreitet, siehe z.B. diesen Blogbeitrag)

Toleranz der Taktquelle

Besonders für sehr lange oder sehr genaue Verzögerungen werden Toleranz, Temperaturdrift oder sogar Alterung der Taktquelle die tatsächliche Verzögerung beeinflussen. Interne Taktquellen sind meistens RC-Oszillatoren, die eine Toleranz von mehreren Prozent über den gesamten Temperaturbereich haben.

Wenn du genaue Zeitmessungen benötigst, könntest du einen externen Quarzkristall verwenden. Jedoch können Lastkapazitäts-Fehlanpassungen, Fehlkonfigurationen oder sogar externe Einflüsse wie EMI die Genauigkeit beeinflussen (siehe z.B. diesen AppNote über Quarzkristalle). Nach meiner Erfahrung ist die Verwendung von Oszillatoren oder keramischen Resonatoren ein einfacherer Weg, um einen Takt für deinen MCU zu erzeugen, da es normalerweise weniger Fehlerquellen gibt. Das bedeutet jedoch nicht, dass diese narrensicher sind oder du sie in jedem Design verwenden solltest.

Die Diskussion hochgenauer Taktquellen überschreitet den Rahmen dieses Artikels erheblich — wenn du OCXOs, TCXOs oder sogar Rubidium-Referenz-Taktquellen benötigst, ist dieser Artikel sicher nicht ausreichend für dich.

Beachte, dass neben der Qualität der externen Taktquelle auch interne Einstellungen wie Spread-Spectrum-PLL im Down-Mode, verfügbar auf größeren MCUs wie dem STM32F4 (siehe z.B. Abschnitt 5.3.11 im STM32F407-Datenblatt), die beobachtete Frequenz leicht beeinflussen können.

Wenn elektrische Probleme in der Taktquelle auftreten (z.B. wenn ein Kristall falsche Widerstands-/Kondensatorwerte hat oder durch Schockereignisse beschädigt wurde), wird möglicherweise nur eine Teilmenge aller Taktzyklen tatsächlich von der Oszillator-Logik im Mikrocontroller erkannt. Wenn du vermutest, dass dies der Fall sein könnte, verwende die MCO (Master Clock Output)-Funktion deines Mikrocontrollers mit einem Oszilloskop, um den digitalen Takt auf Probleme zu prüfen. Wenn diese Funktion nicht verfügbar ist, versuche, einen GPIO-Pin in einer Schleife mit deterministischen Verzögerungen zwischen den Toggles zu togglen.

Jitter der Taktquelle

Jitter — die dynamische Variation der Frequenz über kurze Zeitintervalle — ist für die meisten Anwendungen kein Problem. Wenn du jedoch sehr genaue und sehr kurze Verzögerungen benötigst, kann die beobachtete Frequenz leicht variieren.

Eine weitere Quelle für beobachteten Jitter sind Spread-Spectrum-Oszillatoren (auch als dithered Oszillatoren bezeichnet), sowohl in Hardware-Takten (wie dem DS1090) als auch in Software, z.B. im oben erwähnten Spread-Spectrum-Feature des STM32F4-PLL. Dieses PLL ändert die PLL-Ausgangsfrequenz um bis zu 2% — dies bedeutet, dass deine Verzögerungen variieren können.

Leute verwenden dithered Oszillatoren, um schmalbandige abgestrahlte EMI (erneut würde eine detaillierte Erklärung den Rahmen dieses Artikels überschreiten) in breitbandige EMI umzuwandeln. Wenn jedoch geringer Verzögerungs-Jitter bevorzugt wird, könnte es ratsam sein, das Dithering zu deaktivieren.

Interrupts und preemptive Kernel

Einer der Hauptfaktoren, die die Verzögerungsgenauigkeit beeinflussen, ist, dass der Mikrocontroller (und Kernel) jederzeit deinen Thread unterbrechen kann (z.B. wegen eines Systicks) und daher die verbleibende Codeausführung verzögern. In der Praxis erhöht dies die beobachtete Verzögerung — manchmal signifikant.

Beispielsweise, wenn dein Code in der Mitte einer 100-ns-Verzögerungs-NOP-Sequenz unterbrochen wird, ist es möglich, dass der Kernel für die nächsten zehn Sekunden einen Thread mit höherer Priorität ausführt, was zu einer 10.00000001-s-Verzögerung führt — viele Größenordnungen größer als die erwartete Verzögerung. Für preemptive Kernel mit Round-Robin-Scheduling bei

Dieses Problem betrifft Timer-Interrupts nicht so stark wie Active-Waiting-Ansätze. Die Interrupt-Priorität muss jedoch berücksichtigt werden: Ein Interrupt mit höherer Priorität kann einen Timer mit niedrigerer Priorität blockieren, entweder durch Verzögern seines Starts oder durch Unterbrechen während der Ausführung. Auch auf MCUs ohne priorisierende Interrupt-Controller (wie AVR) kann ein Interrupt einen anderen blockieren, wenn er eine signifikante Ausführungszeit benötigt.

Es gibt zwei allgemeine Strategien, um diese Probleme zu lösen:

Achtung jedoch: Diese Lösungen sind sehr gefährlich und dürfen niemals ohne Nachdenken angewendet werden: Besonders für komplexe Firmwares kannst du nicht einfach alle Interrupts für hunderte von Millisekunden deaktivieren, ohne signifikante Probleme in der Kommunikation oder sogar im Kernel selbst zu verursachen. Beachte, dass beim Deaktivieren von Interrupts nicht einmal der Kernel-Scheduler laufen kann (nur nicht-maskierbare Interrupts — aka NMIs — können). Je nach Anwendung kann dies gewünscht sein oder nicht.

Bezüglich Interrupt-Priorität: Ein Interrupt mit hoher Priorität kann andere zeitkritische Codezonen blockieren (es sei denn, sie deaktivieren Interrupts, natürlich), aber es sei denn, der Interrupt wird sehr oft aufgerufen, ist dies selten ein Problem, wenn der Interrupt-Handler sehr kurz ist.

Flash-Latenz

Für hochgeschwindigkeits-Mikrocontroller wird das Abrufen der Anweisungen aus dem Flash-Speicher zu einem signifikanten Flaschenhals. Komplexere und sehr schnelle Kerne wie der STM32F4 implementieren daher Features wie den ART-Accelerator, der adaptives Prefetching durchführt (siehe Abschnitt 3.5.2 im Referenzhandbuch für Details).

Wenn die CPU nicht rechtzeitig Zugriff auf die entsprechende Anweisung hat, wird ein Wait State eingeführt, d.h. sie wartet, bis die Anweisung verfügbar wird. Normalerweise haben Mikrocontroller eine maximale 0-Wait-State-Frequenz — unterhalb dieser Frequenz sind keine Wait States und kein Accelerator erforderlich. Einige Mikrocontroller (insbesondere einfache & langsame wie AVRs) arbeiten generell unterhalb dieser Frequenz.

Während der ART-Accelerator normalerweise zu einer 0-Wait-State-Ausführung führt, kann er auch Nichtdeterminismus einführen in dem Sinne, dass hysteretisch abhängig von der Code-Ausführungshistorie der jüngsten Vergangenheit das Ausführen eines bestimmten Blocks von Anweisungen Wait States erfordern kann oder nicht. Für sehr genaue Verzögerungen mit wenig erlaubtem Jitter können Features wie der ART die Verzögerungsgenauigkeit in einigen Fällen tatsächlich negativ beeinflussen. Es wird empfohlen, dies nur von Fall zu Fall zu prüfen, wenn Verzögerungs-Jitter beobachtet wird.


Check out similar posts by category: Electronics, Embedded