Ottimizzazione del codice

Microcontrollori PIC e compilatori C di Hi-Tech: come ottimizzare il codice per massimizzare la velocità di esecuzione in applicazioni embedded. Come effettuare una conversione RS232/DMX con AVR.

Suggerimenti generici

Spesso, nelle applicazioni embedded, è necessario ottimizzare il codice per ottenere le massime prestazioni in termini di velocità di esecuzione. Una delle cause di rallentamento nell’esecuzione del codice usando microcontrollori PIC, è la commutazione dei banchi di memoria. In fase di inizializzazione è buona norma dunque inizializzare prima le variabili e i registri nel banco 0, quindi quelli del banco 1 e così via. Ecco di seguito altri suggerimenti utili:

  • Nelle espressioni aritmetiche cercare di utilizzare variabili dello stesso banco di memoria.
  • Quando possibile utilizzare aritmetica a 8 bit piuttosto che aritmetica a 16.
  • Nella gestione di array di dati preferire l’uso dei puntatori all’uso degli indici.
  • Tenere presente che comunque l’uso dei puntatori in cicli piuttosto brevi comporta una mole di operazioni che neutralizzano i vantaggi dei puntatori.
  • Preferire una sequenza di IF, ELSE IF, ELSE IF... ad un costrutto CASE.
  • Usando un costrutto CASE è buona norma utilizzare numeri sequenziali (senza gap) anziché le costanti per i valori con cui comparare la variabile.
  • A seconda dei cambiamenti di banco richiesti, il costrutto:
var=valore1;
if(!flag)
var=valore2;

genera un codice più ottimizzato rispetto all’uso del costrutto:

if(flag)
var=valore1;
else
var=valore2;
  • In ogni caso assicurarsi che la variabile var non venga utilizzata in una routine di interrupt mentre viene eseguito questo frammento di codice.
  • Tenere  presente  che  l’azzeramento,  l’incremento e il decremento di un registro sono operazioni che richiedono un solo ciclo istruzione, mentre  assegnare un  valore diretto  richiede due cicli istruzione.
  • Quando possibile usare bit piuttosto  che unsigned chars.
  • Le chiamate alle funzioni comportano un rallentamento (a causa delle operazioni di push e pop nello stack), per cui è preferibile utilizzare direttamente delle macro piuttosto che numerose funzioni di piccole dimensioni.
  • L’uso delle funzioni è preferibile solo se queste hanno un corpo piuttosto esteso: in questo caso usare le macro comporterebbe un maggiore spreco di spazio in memoria.

Meglio variabili signed o unsigned?

Analizzando il codice generato utilizzando variabili signed e unsigned si evince che nel primo caso, soprattutto  in operazioni di comparazione tra le variabili, è richiesto un numero maggiore di istruzioni. L’uso di unsigned integer o di char è dunque preferibile.

Operazioni cicliche

Al fine di minimizzare il codice e aumentare la velocità di esecuzione è sempre preferibile controllare i cicli finiti decrementando la variabile di conteggio quindi controllarne il raggiungimento al valore zero, piuttosto che incrementare la variabile e compararla con un valore predefinito. Ad esempio in un ciclo FOR è preferibile scrivere for(i=100;i!=0;i—) anziché for(i=0;i<100;i++).

Ottimizzazione delle operazioni di divisione

Una operazione di divisione utilizza da 13 a 23 byte nel banco 0 e alcuni byte in EPROM/flash. Se il divisore è una potenza di 2 è pertanto conveniente utilizzare una operazione di shift anziché la divisione vera e propria. Si ricorda infatti che lo shift a destra di un bit è equivalente alla divisione per 2. L’operazione di shift viene eseguita in un solo ciclo istruzione e non comporta l’occupazione di memoria.

 

Scarica subito una copia gratis

4 Commenti

  1. MARCOPACO 10 Settembre 2016
    • Maurizio Di Paolo Emilio Maurizio 11 Settembre 2016
  2. smania2000 smania2000 11 Settembre 2016
    • Emanuele Bonanni Emanuele 12 Settembre 2016

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend