Misc

Codeoptimierung in Mikrocontrollern

Autor: Laura McKinney
Erstelldatum: 4 April 2021
Aktualisierungsdatum: 5 Kann 2024
Anonim
Code-It-Yourself! 3D Graphics Engine Part #4 - Texturing & Depth Buffers
Video: Code-It-Yourself! 3D Graphics Engine Part #4 - Texturing & Depth Buffers

Inhalt

Der Autor schloss sein letztes Ingenieurjahrsprojekt mit den dsPic-Mikrocontrollern ab und erhielt umfassende Einblicke in diese Geräte.

Der C-Sprachcode eines Mikrocontrollers muss in bestimmten erweiterten Anwendungen möglicherweise optimiert werden. Diese Codeoptimierung wird praktiziert, um zwei entscheidende Dinge zu reduzieren:

  1. Codegröße: Mikrocontroller können aufgrund der begrenzten Größe ihres Arbeitsspeichers begrenzte Daten und Anweisungen speichern. Daher muss der Code optimiert werden, damit der verfügbare Befehls- und Datenspeicher möglichst effizient genutzt werden kann.
  2. Code-Ausführungszeiten: Mikrocontroller sind sequentielle Geräte, die jeweils einen Befehl ausführen. Jeder Assemblierungsbefehl benötigt eine bestimmte Anzahl von Taktzyklen, um sich selbst auszuführen. Daher muss der Code optimiert werden, um sicherzustellen, dass er die erforderliche Aufgabe in der geringsten Anzahl von Taktzyklen oder Montageanweisungen ausführt. Je weniger Taktzyklen ein Code verwendet, desto schneller wird er ausgeführt. Dies bedeutet, dass Anwendungen schneller ausgeführt werden können, da die Verarbeitungszeiten minimiert werden.

Dieser Artikel enthält Tipps und Tricks, mit denen Sie die Größe und Ausführungszeit eines Mikrocontroller-Codes reduzieren können.


Die MplabX-Entwicklungs-IDE von Microchip wird verwendet, um gegebenenfalls Beispiele zu demonstrieren.

So messen Sie die Code-Ausführungszeit experimentell

Um eine Vorstellung davon zu bekommen, wie viel Zeit Ihr Code tatsächlich benötigt, um in Echtzeit ausgeführt zu werden, müssen Sie ihn experimentell messen. Ein Logikanalysator kann bequem verwendet werden, um die Ausführungszeit von Code zu messen, und Interessenten können sich per E-Mail bei mir nach dem entsprechenden Prozess erkundigen. Daneben:

  • Einige Compiler können Taktzyklen zählen, die ein Code verbraucht.
  • Einige Debugger, zum Beispiel der ICD 3 von Microchip, können die Ausführungszeit direkt über eine Stoppuhr messen.

1. Kennen Sie die Verarbeitungsleistung und die Speichergröße Ihres Mikrocontrollers

Es ist nicht immer die Taktfrequenz (MHz), die das wahre Bild der Verarbeitungsgeschwindigkeit eines Mikrocontrollers liefert. Ein realistischeres Maß ist MIPS (Mega-Befehle pro Sekunde) oder die Anzahl der Befehle, die die MCU in einer Sekunde ausführen kann.

MCUs reichen normalerweise von 60 bis 70 MIPS in der High-End-Kategorie bis zu 20 MIPS 8-Bit-AVRs. Ein Mikrocontroller mit hohem MIPS ist wahrscheinlich teurer als ein Low-End-Gerät. Hier haben Sie also einen Kompromiss zwischen Kosten und Verarbeitungsgeschwindigkeit.


Mikrocontroller verfügen über einen separaten Speicher zum Speichern von Daten und Programmcode. Die Größe beider können dem Datenblatt entnommen werden. Möglicherweise benötigen Sie eine MCU mit größerem Speicher, wenn Ihr Code sehr groß ist.

2. Auswahl der Variablen zur Optimierung der Codegröße

Mikrocontroller haben einen begrenzten Datenspeicher, der normalerweise zwischen 1 und 4 KB liegt. In diesem Fall ist es ratsam, den am besten geeigneten Variablentyp entsprechend dem erwarteten Bereich des gespeicherten Datums auszuwählen. Die folgende Tabelle fasst diese Variablen zusammen:

Zusammenfassung der in der C-Sprache verwendeten Variablen.

VariablentypGröße in BytesReichweite

Bool

1

Nur 0 oder 1

verkohlen

1


-128 bis 127

int

2

-32.768 bis 32.767

unsigned int

2

0 bis 65.535

lange

4

-2.147.483.648 bis 2.147.483.647

schweben

4

Präzise bis zu 6 Dezimalstellen

doppelt

8

Präzise bis zu 15 Dezimalstellen

langes Doppel

10

Präzise bis zu 19 Dezimalstellen

Beispiel:

  • Wenn zwei Variablen X und Y hinzugefügt werden sollen und das Ergebnis in Z gespeichert werden soll, der Wert von Z jedoch nach der Addition voraussichtlich höher als 65.535 sein soll, kann Z als lang und X und Y als vorzeichenlos deklariert werden int, es wird auch nicht erwartet, dass die Werte von X und Y negativ werden. Dadurch werden 04 Bytes im Datenspeicher gespeichert, die sonst verbraucht worden wären, wenn alle Variablen so lange deklariert worden wären.
  • Zwei Variablen X und Y, deren Werte in ganzen Zahlen erwartet werden, sollen geteilt werden, aber das Ergebnis der Division kann eine Dezimalzahl ergeben, dann können X und Y als int deklariert werden und das Ergebnis kann abhängig von float oder double deklariert werden die erforderliche Präzision.

Die Wahl des Datentyps kann entscheidend sein, wenn Arrays deklariert werden, die eine große Anzahl von Elementen enthalten.

3. Auswahl der Variablen zur Optimierung der Code-Ausführungszeit

  • Es ist erwiesen, dass Gleitkommaberechnungen länger dauern als Festkommaberechnungen. Verwenden Sie keine Gleitkommavariable, für die kein Dezimalwert erforderlich ist. Arbeiten Sie nach Möglichkeit mit vorzeichenlosen Ganzzahlen.
  • Lokale Variablen werden globalen Variablen vorgezogen. Wenn eine Variable nur in einer Funktion verwendet wird, muss sie in dieser Funktion deklariert werden, da der Zugriff auf globale Variablen langsamer ist als auf lokale Variablen.
  • Bei einer 8-Bit-MCU ist eine Variable mit einer Größe von einem Byte schneller zugänglich, und bei einer 16-Bit-MCU ist eine 2-Byte-Variable aufgrund der Länge der generierten Adresse leichter zugänglich.

4. Optimieren von Rechenoperationen

Arithmetische Operationen können auf folgende Weise optimiert werden.

  1. Verwenden Sie Nachschlagetabellen mit vorberechneten Werten, anstatt einen Sinus oder eine andere trigonometrische Funktion oder eine andere Operation auszuwerten, deren Ergebnis im Code vorher bekannt sein kann.
  2. Falls eine Sinus-Nachschlagetabelle bereits im Speicher gespeichert ist, kann ein Cosinus ausgewertet werden, indem der Array-Zeiger um 90 Grad vorgerückt wird.
  3. Unter den vier arithmetischen Operationen nehmen Division und Multiplikation die meiste Verarbeitungszeit in Anspruch, in der Praxis kann sie bei Gleitkommawerten im Bereich von etwa Hunderten von Mikrosekunden liegen.
  4. Verwenden Sie Bitverschiebungsanweisungen anstelle von Division und Multiplikation. Ein Rechtsverschiebungsbefehl 3 dient dazu, durch 2 zu teilen3 wobei als Linksverschiebungsbefehl 1 dazu dient, mit 2 zu multiplizieren1.

5. Verwenden Sie einen DSP-fähigen Mikrocontroller für intensive Berechnungen

Einige Mikrocontroller verfügen über eine andere DSP-Verarbeitungseinheit als die herkömmliche ALU, die in ihre Architektur integriert ist. Diese DSP-Engine ist darauf ausgelegt, arithmetische Berechnungen sehr schnell in der geringsten Anzahl von Taktzyklen (in den meisten Fällen einer) um ein Vielfaches schneller als die ALU durchzuführen.

Anweisungen, die ein DSP-Prozessor schneller als eine ALU ausführen kann, sind:

  • Anweisungen zum Verschieben und Drehen von Bits.
  • Multiplikationen, Divisionen und andere arithmetische Operationen.
  • Bewertung von Sinus und anderen trigonometrischen Funktionen.
  • Alle DSP-Operationen wie FFT, DFT, Faltung und FIR-Filterung.

Die Verwendung der DSP-Engine eines Mikrocontrollers erfordert Folgendes:

  • Separate DSP-Bibliotheken sind in das Projekt integriert.
  • Die Namen der Funktionen unterscheiden sich von der Standard-Mathematikbibliothek der C-Sprache. Die Dokumentation dieser Bibliotheken und Funktionen kann auf der Website des jeweiligen Herstellers abgerufen werden.
  • Die DSP-Engine verwendet einen anderen Variablentyp "Bruch". Erfahren Sie, wie Sie fraktionierte Typvariablen verwenden, bevor Sie mit den Funktionen der DSP-Bibliothek fortfahren.

Beachten Sie, dass Standardfunktionen der Mathematikbibliothek die DSP-Engine nicht aufrufen, da sie in ALU-Assembly-Anweisungen übersetzt werden.

6. Arbeiten Sie mit Interrupts

Verwenden Sie Interrupts, um bestimmte Funktionen auszuführen, z.

  • ADC-Werte lesen.
  • Senden und Empfangen von UART.
  • Aktualisieren der PWM-Arbeitszyklusregister.
  • CAN- oder I2C-Kommunikation.

Interrupts werden diese Funktionen schnell bedienen, verglichen mit der Ausführung im Hauptteil über einen Funktionsaufruf oder einen Inline-Code.

Interrupts werden auch nur bei Bedarf ausgelöst, während der Code, wenn er im Hauptteil codiert ist, in jeder Iteration der while (1) -Schleife ausgeführt wird.

7. Verwenden Sie die besten verfügbaren Compiler

Compiler können einige der oben beschriebenen Optimierungen automatisch implementieren, während sie den Code bei ordnungsgemäßer Konfiguration von der C-Sprache in die Assemblersprache übersetzen. Suchen Sie in Ihrem Compiler nach Optimierungsoptionen und aktualisieren Sie nach Möglichkeit auf professionelle Versionen von Compilern, da diese leistungsstärkere Codeoptimierer sind.

8. Verwenden Sie bedingte Anweisungen intelligent

  • Wenn Sie eine Reihe von if-else-Anweisungen verwenden, behalten Sie zuerst die wahrscheinlichste Bedingung bei. Auf diese Weise muss die MCU nicht alle Bedingungen durchsuchen, nachdem sie die wahre Bedingung gefunden hat.
  • Eine switch-case-Anweisung ist normalerweise schneller als ein if-else.
  • Verwenden Sie verschachtelte if-else-Anweisungen anstelle einer Reihe von Anweisungen. Ein if-else-Block mit vielen Anweisungen kann in kleinere Unterzweige unterteilt werden, um die Worst-Case-Bedingung (letzte Bedingung) zu optimieren.

9. Verwenden Sie Inline-Funktionen

Funktionen, die nur einmal im Code verwendet werden sollen, können als statisch deklariert werden. Dadurch optimiert der Compiler diese Funktion in eine Inline-Funktion, und daher wird kein Assemblycode für den Funktionsaufruf übersetzt.

  • Eine Funktion kann inline deklariert werden, indem das Schlüsselwort 'static' verwendet wird.

10. Verwenden Sie dekrementierte Schleifen

Eine dekrementierte Schleife generiert im Vergleich zu einer inkrementierten Schleife weniger Assembler-Code.

Dies liegt daran, dass in einer Inkrementschleife eine Vergleichsanweisung erforderlich ist, um den Schleifenindex mit dem Maximalwert in jeder Schleife zu vergleichen und zu überprüfen, ob der Schleifenindex den Maximalwert erreicht. Im Gegensatz dazu wird dieser Vergleich in einer Dekrementierungsschleife nicht mehr benötigt, da das dekrementierte Ergebnis des Schleifenindex das Null-Flag in SREG setzt, wenn es Null erreicht.

Angesichts der Tatsache, dass die Schleife hundertmal iterieren muss, wird durch Reduzieren eines Befehls aus der Schleife vermieden, dass sie hundertmal ausgeführt wird, sodass die Auswirkung wahrscheinlich bedeutender ist, wenn die Schleife viele Male iterieren muss.

Einpacken

Diese Tipps mögen hilfreich sein, aber ihre wahre Anwendung und Wirksamkeit hängt von den Fähigkeiten des Programmierers und dem Befehl ab, den er in seinem Code hat. Denken Sie daran, dass die Größe des Programms nicht immer die Ausführungszeiten bestimmt. Einige Anweisungen verbrauchen möglicherweise mehr Taktzyklen als die anderen, sodass erneut die Fähigkeiten des Programms eine Rolle spielen müssen.

Dieser Artikel ist genau und nach bestem Wissen des Autors. Der Inhalt dient nur zu Informations- oder Unterhaltungszwecken und ersetzt nicht die persönliche Beratung oder professionelle Beratung in geschäftlichen, finanziellen, rechtlichen oder technischen Angelegenheiten.

Populäre Artikel

Beliebt

5 besten Robotik-Kits für alle Altersgruppen
Misc

5 besten Robotik-Kits für alle Altersgruppen

Phil arbeitet eit mehr al 10 Jahren al Web- und oftwareentwickler. Er teilt leiden chaftlich gerne Wi en und fördert da Erfahrung lernen., dann chau dir da zuer t an. In die er Li te ind fün...
So verhindern Sie, dass Telemarketer Ihre Nummer fälschen
Telefone

So verhindern Sie, dass Telemarketer Ihre Nummer fälschen

Laura i t freie chrift tellerin und lebt in Florida. ie hat einen Ma ter-Ab chlu in Engli ch.Zuer t bekam ich nur alle paar Tage ein paar Anrufe. Manchmal waren e zufällige Texte, die mich fragte...