Sunteți pe pagina 1din 9

Textul și imaginile din acest document sunt licențiate

Attribution-NonCommercial-NoDerivs
CC BY-NC-ND

Codul sursă din acest document este licențiat


Public-Domain

Ești liber să distribui acest document prin orice mijloace consideri (email, publicare pe website /
blog, tipărire, sau orice alt mijloc), atât timp cât nu aduci nici un fel de modificări acestuia. Codul
sursă din acest document poate fi utilizat în orice fel de scop, de natură comercială sau nu, fără nici
un fel de limitări dar autorii nu își asumă nici o răspundere pentru pagubele pricinuite de
implementările realizate de utilizatori. Schemele și codul sursă au un rol educativ și nu sunt gândite
pentru a fi utilizate în mediu de producție (industrial, casnic sau comercial).
Optimizarea programelor în mediul
Arduino IDE

Optimizarea procesului de compilare

Mediul Arduino IDE utilizează compilatorul GCC. Pe


lângă procesul de compilare propriu-zis, mediul de
dezvoltare efectuează o serie de operații (pre-procesare) ce
permit implementarea funcțiilor specifice Arduino (de
exemplu includerea automată a definițiilor din Arduino.h).
Pentru detalierea procesului de compilare se poate parcurge
materialul „Arduino Build Process” [1].
Procesul de compilare este efectuat, invizibil pentru
programator, la un anumit nivel de optimizare (-Os sau -O2 în funcție de versiunea
mediului de dezvoltare). Pentru detalierea nivelurilor de optimizare recomandăm
parcurgerea materialului „Using the GNU Compiler Collection (GCC): Optimize
Options” [2]. Modificarea nivelului de optimizare la compilarea programului se poate
face la nivel de fișiere de configurare a mediului de dezvoltare [3] sau chiar la nivel de
program [4].

Prin introducerea unor directive de compilare putem modica nivelul de optimizare


pentru întregul program:

#pragma GCC optimize ("-O0")


#pragma GCC push_options
void setup() { }
void loop() { }
#pragma GCC pop_options

sau doar pentru o anumită secțiune, funcție sau procedură:

void loop() __attribute__((optimize("-O0")));


void loop() { }

https://www.robofun.ro/forum/
Optimizarea instrucțiunilor specifice mediului Arduino IDE

Unul din obiectivele principale ale mediului Arduino IDE este înlesnirea accesului
programatorului la diversele mecanisme interne ale microcontrolerului. Din aceste
motiv s-a efectuat rebotezarea pinilor și tot din același motiv au fost introduse
instrucțiuni specifice mediului Arduino IDE de tipul pinMode, digitalRead sau
digitalWrite. Din punct de vedere al procesului de învățare și dezvoltare aceste facilități
accelerează foarte mult timpul de lucru dar din punctul de vedere al eficienței execuției
aduc penalizări destul de mari. Cel mai bun exemplu, prezentat și în materialul
„Arduino Is Slow” [5], este înlocuirea instrucțiunii digitalWrite cu o instrucțiune de
modificare a registrului intern ce stochează starea pinului pe care dorim să-l
modificăm. Se poate testa diferența dintre timpul de execuție a celor două variante
rulând următorul exemplu de program:

void setup()
{
Serial.begin(9600);
}
void loop()
{
int initial = 0;
int final = 0;
initial = micros();
for(int i = 0; i < 500; i++)
{
digitalWrite(13,HIGH);
digitalWrite(13,LOW);
}
final = micros();
Serial.print("Time for digitalWrite(): ");
Serial.print(final-initial);
Serial.println("");
initial = micros();
for(int i = 0; i < 500; i++)
{
https://www.robofun.ro/forum/
PORTB |= _BV(PB5);
PORTB &= ~_BV(PB5);

}
final = micros();
Serial.print("Time for true c command: ");
Serial.print(final-initial);
while(1);
}

Programul înlocuiește instrucțiunea digitalWrite cu o scriere în registrul intern al


microcontrolerului (pinul 13 este pinul PB5). Rezultatul este destul de convingător:

Instrucțiunea digitalWrite nu este singura care poate fi înlocuită în cadrul programelor


Arduino pentru a obține performanțe mai bune. O altă instrucțiune ”delicată” ce poate
afecta funcționarea unor montaje mai complicate este instrucțiunea shiftOut. Dacă
examinăm fișierul wiring_shift.c din directorul Arduino putem vedea că această funcție
se bazează pe instrucțiunea digitalWrite deci poate fi accelerată prin înlocuirea acestei
instrucțiuni.

https://www.robofun.ro/forum/
void shiftOut(uint8_t dataPin, uint8_t clockPin,
uint8_t bitOrder, uint8_t val)
{
uint8_t i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 <<
(7 - i))));
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}

ATENȚIE!!! Optimizările prezentate conduc la pierderea portabilității programelor


între diverse plăci Arduino. Toate indicațiile se aplică direct doar pentru plăcile ce sunt
echipate cu un microcontroler ATmega328P (Arduino Uno de exemplu).

https://www.robofun.ro/forum/
Pentru exemplificarea optimizării instrucțiunii shiftOut vom considera următorul
montaj bazat pe o placă de dezvoltare Arduino Uno, un registru de deplasare 74HC595
și 8 leduri:

Programul propus va implementa un mini joc de lumini ce constă în aprinderea


succesivă a câte un led din cele 8. Programul obișnuit (ce utilizează instrucțiunea
shiftOut) este:

https://www.robofun.ro/forum/
const int latchPin = 4;
const int clockPin = 3;
const int dataPin = 2;

void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, 0);
digitalWrite(latchPin, HIGH);
}

void loop() {
int afisare = 1;
while (1) {
for (int i=0;i<8;i++) {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, afisare << i);
digitalWrite(latchPin, HIGH);
delay(500);
}
}
}

Varianta nouă ce nu folosește instrucțiunile shiftOut și digitalWrite este:

void joc3() {
int afisare = 1;
while (1) {
for (int i=0;i<8;i++) {
PORTD |= _BV(PD4);

https://www.robofun.ro/forum/
for (uint8_t b = 0; b < 8; b++) {
if(!!((afisare << i) & (1 << (7 - b)))) PORTD |=
_BV(PD2);
else PORTD &= ~_BV(PD2);
PORTD |= _BV(PD3);
PORTD &= ~_BV(PD3);
}
PORTD &= ~_BV(PD4);
delay(500);
}
}
}

Chiar dacă la prima vedere exemplul funcționează la fel, se poate justifica necesitatea
modificării codului prin imaginarea situației în care procesul de transmitere serială se
repetă de un număr suficient de mare de ori încât produce o întârziere inacceptabilă (de
exemplu încascadarea unui număr mare de registre de deplasare).

https://www.robofun.ro/forum/
Referințe on-line

[1] Build Process · arduino/Arduino Wiki · GitHub


https://github.com/arduino/Arduino/wiki/Build-Process

[2] Using the GNU Compiler Collection (GCC): Optimize Options


https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

[3] Arduino IDE 1.6.x Compiler Optimisations = Faster Code: 7 Steps


http://www.instructables.com/id/Arduino-IDE-16x-compiler-optimisations-faster-code/

[4] Modify Arduino Optimization Levels on the Fly | µC eXperiment


https://ucexperiment.wordpress.com/2017/05/20/modify-arduino-optimization-levels-on-the-fly/

[5] Arduino Is Slow - and How to Fix It!: 5 Steps


http://www.instructables.com/id/Arduino-is-Slow-and-how-to-fix-it/

https://www.robofun.ro/forum/