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.
Buon giorno,
Volevo sapere se è possibile programmare arduino mega2560 (caricare sketch ) utilizzando raspberry invece del pc .
Grazie
con un po’ di accorgimenti vari è possibile, installando ovviamente l’IDE per linux o win
Scusa, dici “…. utilizzando variabili signed e unsigned si evince che nel secondo caso…”, quindi nel caso degli unsigned “…. è richiesto un numero maggiore di istruzioni” …..quindi io interpreto che con gli unsigned ci sono più operazioni (cosa che mi par strana). Poi aggiungi “L’uso di unsigned integer o di char è dunque preferibile.”, quindi prima dici che con unsigned hai più operazioni e quindi è da preferirsi….mi sa che qualcosa non torna, forse intendevi “nel primo caso”….o sono io che non ho capito niente? Giusto per aggiungere ancora qualcosa, altrimenti sembra che sto solo qui a far critiche, volevo dire che nel caso degli AVR, il compilatore lavora decisamente bene nell’ottimizzazione del codice, riesce quasi sempre ad eguagliare gli “aggiustamenti manuali” ed è ben difficile fare di meglio.
Si, è un refuso! Nel PRIMO caso (ho corretto) quindi “signed” ci sono più operazioni (ovviamente visto che nei calcoli deve essere anche tenuto conto del segno).
Concordo sugli AVR, la loro architettura-istruzioni è C-oriented, che per un 8 bit è una caratteristica non da poco.