Misc

Ottimizzazione del codice nei microcontrollori

Autore: Laura McKinney
Data Della Creazione: 4 Aprile 2021
Data Di Aggiornamento: 16 Maggio 2024
Anonim
GDL Italia - Chrome DevTools in Azione! (parte 1)
Video: GDL Italia - Chrome DevTools in Azione! (parte 1)

Contenuto

L'autore ha completato il suo progetto di ingegneria dell'ultimo anno con i microcontrollori dsPic, ottenendo una visione approfondita di questi dispositivi.

Il codice in linguaggio C di un microcontrollore può richiedere l'ottimizzazione in alcune applicazioni avanzate. Questa ottimizzazione del codice viene praticata per ridurre due cose cruciali:

  1. Dimensione del codice: I microcontrollori possono memorizzare dati e istruzioni limitati a causa delle dimensioni limitate della loro RAM. Pertanto il codice deve essere ottimizzato, in modo che le istruzioni disponibili e la memoria dati possano essere utilizzate nel modo più efficiente.
  2. Tempi di esecuzione del codice: I microcontrollori sono dispositivi sequenziali che eseguono un'istruzione alla volta. Ogni istruzione di assembly consuma un certo numero di cicli di clock per eseguirsi. Pertanto il codice deve essere ottimizzato per garantire che esegua l'attività richiesta in un numero minimo di cicli di clock o istruzioni di assemblaggio. Meno cicli di clock vengono utilizzati da un codice, più velocemente viene eseguito. Ciò significa che le applicazioni possono essere eseguite più velocemente perché i tempi di elaborazione sono ridotti al minimo.

Questo articolo presenta suggerimenti e trucchi che possono essere utilizzati per ridurre le dimensioni e il tempo di esecuzione di un codice di microcontrollore.


L'IDE di sviluppo MplabX di Microchip verrà utilizzato per dimostrare esempi ove appropriato.

Come misurare sperimentalmente il tempo di esecuzione del codice

Per avere un'idea di quanto tempo impiega effettivamente il codice per essere eseguito in tempo reale, è necessario misurarlo sperimentalmente. Un analizzatore logico può essere convenientemente utilizzato per misurare il tempo di esecuzione del codice e coloro che sono interessati possono chiedere informazioni sul processo da me tramite e-mail. Dietro questo:

  • Alcuni compilatori hanno la capacità di contare i cicli di clock che un codice consumerà.
  • Alcuni debugger, ad esempio l'ICD 3 da microchip, possono misurare direttamente il tempo di esecuzione tramite un cronometro.

1. Conoscere la potenza di elaborazione e la dimensione della memoria del microcontrollore

Non è sempre la frequenza di clock (Mhz) che fornisce l'immagine reale della velocità di elaborazione di un microcontrollore, una misura più realistica è MIPS (mega istruzioni al secondo) o il numero di istruzioni che l'MCU può eseguire in un secondo.

Gli MCU di solito vanno da 60-70 MIPS nella categoria high-end a 20 MIPS AVR a 8 bit. È probabile che un microcontrollore MIPS alto sia più costoso di un dispositivo di fascia bassa, quindi qui hai un compromesso tra costo e velocità di elaborazione.


I microcontrollori hanno una memoria separata per la memorizzazione dei dati e del codice del programma. La dimensione di entrambi può essere trovata dalla scheda tecnica. Potrebbe essere necessario un MCU con dimensioni di memoria maggiori se il codice è sostanzialmente grande.

2. Scelta delle variabili per l'ottimizzazione della dimensione del codice

I microcontrollori hanno una memoria dati limitata, di solito compresa tra 1 e 4 Kbyte. In questo caso è opportuno scegliere il tipo di variabile più appropriato in base all'intervallo previsto della data da memorizzare. La tabella seguente riassume queste variabili:

Riepilogo delle variabili utilizzate nel linguaggio C.

Tipo variabileDimensioni in byteGamma

bool

1

Solo 0 o 1

char

1


Da -128 a 127

int

2

Da -32.768 a 32.767

unsigned int

2

Da 0 a 65.535

lungo

4

-2.147.483.648 a 2.147.483.647

galleggiante

4

Preciso fino a 6 cifre decimali

Doppio

8

Preciso fino a 15 cifre decimali

doppio lungo

10

Preciso fino a 19 cifre decimali

Esempio:

  • Se si devono aggiungere due variabili X e Y e il risultato deve essere memorizzato in Z ma si prevede che il valore di Z sia maggiore di 65.535 dopo l'aggiunta, Z può essere dichiarato lungo e X e Y possono essere dichiarati senza segno int, inoltre, non ci si aspetta che i valori di X e Y diventino negativi. Ciò salverà 04 byte nella memoria dati che altrimenti sarebbero stati utilizzati se tutte le variabili fossero state dichiarate così lunghe.
  • Devono essere divise due variabili X e Y, i cui valori dovrebbero essere in numeri interi, ma il risultato della divisione può restituire un decimale, quindi X e Y possono essere dichiarati int e il risultato può essere dichiarato float o double a seconda di la precisione richiesta.

La scelta del tipo di dati può essere cruciale quando si dichiarano array contenenti un numero elevato di elementi.

3. Scelta delle variabili per l'ottimizzazione nel tempo di esecuzione del codice

  • È un dato di fatto che i calcoli in virgola mobile richiedono più tempo dei calcoli in virgola fissa. Non utilizzare una variabile a virgola mobile in cui non è richiesto un valore decimale. Lavora con numeri interi senza segno ove possibile.
  • Le variabili locali sono preferite alle variabili globali. Se una variabile viene utilizzata solo in una funzione, deve essere dichiarata in quella funzione perché l'accesso alle variabili globali è più lento delle variabili locali.
  • Un MCU a 8 bit troverà una variabile della dimensione di un singolo byte più veloce da accedere e un MCU a 16 bit troverà una variabile a 2 byte più facile da accedere a causa della lunghezza dell'indirizzo generato.

4. Ottimizzazione delle operazioni aritmetiche

Le operazioni aritmetiche possono essere ottimizzate nei seguenti modi.

  1. Utilizzare tabelle di ricerca di valori precalcolati invece di valutare un seno o qualsiasi altra funzione trigonometrica o qualsiasi altra operazione il cui risultato può essere conosciuto in anticipo nel codice.
  2. Nel caso in cui una tabella di ricerca seno sia già memorizzata nella memoria, è possibile valutare un coseno facendo avanzare il puntatore di matrice equivalente a 90 gradi.
  3. Tra le quattro operazioni aritmetiche, la divisione e la moltiplicazione richiedono il tempo di elaborazione maggiore, in pratica può essere dell'ordine di centinaia di micro secondi circa in caso di valori in virgola mobile.
  4. Utilizzare istruzioni di spostamento di bit invece di divisione e moltiplicazione. Un'istruzione di spostamento a destra 3 serve per dividere per 23 dove come istruzione di spostamento a sinistra 1 servirà a moltiplicare per 21.

5. Utilizzare un microcontrollore compatibile con DSP per calcoli intensivi

Alcuni microcontrollori hanno un'unità di elaborazione DSP diversa dalla tradizionale ALU incorporata nella loro architettura. Questo motore DSP è progettato per eseguire calcoli aritmetici molto rapidamente nel minor numero di cicli di clock (uno nella maggior parte dei casi) molte volte più velocemente dell'ALU.

Le istruzioni che un processore DSP può eseguire più velocemente di una ALU sono:

  • Spostamento di bit e rotazione delle istruzioni.
  • Moltiplicazioni, divisioni e altre operazioni aritmetiche.
  • Valutazione di Sines e altre funzioni trigonometriche.
  • Tutte le operazioni DSP come FFT, DFT, convoluzione e filtraggio FIR.

L'utilizzo del motore DSP di un microcontrollore richiede che:

  • Librerie DSP separate sono incorporate nel progetto.
  • I nomi delle funzioni sono diversi dalla libreria matematica standard del linguaggio C. La documentazione di queste librerie e funzioni può essere utilizzata dal sito Web dei rispettivi produttori.
  • Il motore DSP utilizza un diverso tipo di variabile "frazionario". Scopri come utilizzare le variabili di tipo frazionario prima di procedere con le funzioni della libreria dsp.

Si noti che le funzioni della libreria matematica standard non richiameranno il motore DSP perché vengono tradotte in istruzioni di assemblaggio ALU.

6. Lavora con gli interrupt

Utilizza gli interrupt per eseguire funzioni specifiche come:

  • Lettura dei valori ADC.
  • Invio e ricezione da UART.
  • Aggiornamento dei registri del ciclo di lavoro PWM.
  • Comunicazione CAN o I2C.

Gli interrupt serviranno queste funzioni rapidamente rispetto a eseguirle nel corpo principale tramite una chiamata di funzione o un codice inline.

Gli interrupt si attiveranno anche solo quando richiesto, mentre se codificati nel corpo principale, il codice verrà eseguito in ogni iterazione del ciclo while (1).

7. Utilizzare i migliori compilatori disponibili

I compilatori possono implementare automaticamente alcune delle ottimizzazioni discusse sopra durante la traduzione del codice dal linguaggio C al linguaggio assembly, se configurato correttamente. Cerca le opzioni di ottimizzazione nel tuo compilatore e, se possibile, aggiorna alle versioni professionali dei compilatori perché sono ottimizzatori di codice più potenti.

8. Usa le istruzioni condizionali in modo intelligente

  • Quando si utilizza una serie di istruzioni if-else, mantenere prima la condizione più probabile. In questo modo l'MCU non dovrà eseguire la scansione di tutte le condizioni dopo aver rilevato la condizione vera.
  • Un'istruzione switch-case è solitamente più veloce di an if-else.
  • Usa istruzioni if-else annidate al posto di una serie di istruzioni. Un blocco if-else con molte istruzioni può essere diviso in sotto-rami più piccoli per ottimizzare per la condizione peggiore (ultima).

9. Utilizzare le funzioni in linea

Le funzioni che devono essere utilizzate una sola volta nel codice possono essere dichiarate statiche. Ciò consentirà al compilatore di ottimizzare quella funzione in una funzione inline e quindi nessun codice assembly verrà tradotto per la chiamata di funzione.

  • Una funzione può essere dichiarata inline utilizzando la parola chiave "statica" con essa.

10. Usa cicli decrementati

Un ciclo decrementato genererà meno codice assembly rispetto a un ciclo incrementato.

Questo perché in un ciclo di incremento, è necessaria un'istruzione di confronto per confrontare l'indice del ciclo con il valore massimo in ogni ciclo per verificare se l'indice del ciclo raggiunge il valore massimo. Al contrario in un ciclo di decremento, questo confronto non è più necessario perché il risultato decrementato dell'indice del ciclo imposterà il flag di zero in SREG se raggiunge lo zero.

Dato che il ciclo deve iterare centinaia di volte, ridurre un'istruzione dal ciclo eviterà che venga eseguita cento volte, quindi è probabile che l'impatto sia più significativo quando il ciclo deve iterare molte volte.

Avvolgendo

Questi suggerimenti possono essere utili, ma la loro vera applicazione e potenza dipende dall'abilità del programmatore e dal comando che ha sul suo codice. Ricorda, le dimensioni del programma non sempre determinano i tempi di esecuzione, alcune istruzioni possono consumare più cicli di clock dell'altra, quindi ancora una volta le abilità del programma devono fare la loro parte.

Questo articolo è accurato e fedele al meglio delle conoscenze dell'autore. Il contenuto è solo a scopo informativo o di intrattenimento e non sostituisce consulenza personale o consulenza professionale in questioni aziendali, finanziarie, legali o tecniche.

La Nostra Raccomandazione

Nuovi Articoli

Budget da $ 500 Intel Core i3-8100 e Radeon RX 550 Gaming PC Review e benchmark
Computer

Budget da $ 500 Intel Core i3-8100 e Radeon RX 550 Gaming PC Review e benchmark

ono olo un ragazzo da poco che fa un lavoro normale come a i tente medico. La mia pa ione è co truire PC e te tare / rivedere l'hardware del PC.In que to articolo, di cuterò i benchmark...
I pro ei contro delle antenne a tromba
Industriale

I pro ei contro delle antenne a tromba

Tamara Wilhite è una crittrice tecnica, ingegnere indu triale, madre di due figli e autrice di articoli di fanta cienza e horror.Le antenne a tromba utilizzano generalmente una guida d'onda m...