Variabili globali rallentano l'esecuzione del loop

Salve,
per scopi personali sto creando uno sketch per arduino mega che deve obbligatoriamente durare meno di 1 millisecondo. Il codice è già pronto perchè l’ho già fatto e testato in un PIC di caratteristiche quasi analoghe all’arduino mega, quindi il porting è stato semplice.

Il problema che il loop, a differenza del pic, ci mette MOLTO di più. Considerate che il pic ci metteva circa 300 us ed il mega 6000 us.

Il problema si trova nelle variabili globali. Se dichiaro delle variabili globali e le modifico dal loop, compaiono rallentamenti ASSURDI.
Se invece dichiaro delle variabili locali nel loop e le modifico, il tempo di esecuzione totale del loop scende ed arriva ai 300 us…
Il problema è che ho bisogno di almeno una variabile globale perchè nei pezzi successivi dello sketch è presente un interrupt in spi che deve inviare quella variabile.

Cercando di essere più chiaro, se dichiaro “contatore[20]” nel loop raggiungo l’obiettivo di stare sotto al millisecondo ma se lo dichiaro prima del loop, quest’ultimo arriva addirittura quasi a durare 6 millisecondi. Stessa identica cosa per la variabile “contatore0”. Se le dichiaro tutte e due fuori la situazione peggiora ulteriormente… Come è semplicemente possibile? Ho bisogno che “contatore0” sia per forza globale e addirittura volatile…

#define PC7 (PINC & 128) //PC7
#define PC6 (PINC & 64) //PC6
#define PC5 (PINC & 32)//PC5
#define PC4 (PINC & 16) //PC4
#define PC3 (PINC & 8) //PC3
#define PC2 (PINC & 4) //PC2
#define PC1 (PINC & 2) //PC1
#define PC0 (PINC & 1) //PC0

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

//SE LE DICHIARO QUI, IL LOOP DURA 6 MILLISECONDI
byte contatore[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
byte contatore0;

void loop() {
//SE LE DICHIARO QUI, IL LOOP DURA 300 MICROSECONDI
//byte contatore[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//byte contatore0;
  long t1 = micros();
  for (byte i = 0; i <= 250; i++) { // 460 us
    contatore[0] += !PC7;
    contatore[1] += !PC6;
    contatore[2] += !PC5;
    contatore[3] += !PC4;
    contatore[4] += !PC3;
    contatore[5] += !PC2;
    contatore[6] += !PC1;
    contatore[7] += !PC0;
    contatore[8] += !PC7;
    contatore[9] += !PC6;
    contatore[10] += !PC5;
    contatore[11] += !PC4;
    contatore[12] += !PC3;
    contatore[13] += !PC2;
    contatore[14] += !PC1;
    contatore[15] += !PC0;
    contatore[16] += !PC7;
    contatore[17] += !PC6;
    contatore[18] += !PC5;
    contatore[19] += !PC4;
  }
 contatore0 =  contatore[0];
   Serial.println(micros() - t1);

}

Buonasera e benvenuto sul forum, essendo il tuo primo post, nel rispetto del regolamento, ti chiedo cortesemente di presentarti QUI ([u]spiegando bene quali conoscenze hai di elettronica e di programmazione[/u] ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO ... Grazie.

Guglielmo

P.S.: Qui una serie di link utili, [u]NON[/u] necessariamente inerenti alla tua domanda: - serie di schede by xxxPighi per i collegamenti elettronici vari: ABC - Arduino Basic Connections - pinout delle varie schede by xxxPighi: Pinout - link [u]generali[/u] utili: Link Utili

Fatto, ora posso essere cortesemente aiutato?

il mio inglese è molto arrugginito, ma lo stesso problema mi sembra trattato anche qui: http://forum.arduino.cc/index.php?topic=477996.0

fratt: il mio inglese è molto arrugginito, ma lo stesso problema mi sembra trattato anche qui: http://forum.arduino.cc/index.php?topic=477996.0

Ahah sono sempre io quello che ha postato nella sezione inglese.

docsavage: io non sono molto esperto, ma hai pensato ad allocare spazio con una malloc?

oppure, non so se aiuta, ma per lavorare con sole variabili locali potresti aggiungere una funzione di lettura/aggiornamento, usando una variabile locale static

una cosa del tipo:

int leggiscrivi(argomento) { static int locale; if (argomento) { // nulla da fare } else { locale=argomento; } return locale; }

Scritta di getto qui, vedi se va

chiamata con argomento diverso da zero memorizza il valore

chiamata con argomento 0 riporta il valore memorizzato

e usa solo variabili locali

magari ti va bene, non so

Sai che magari hai ragione? Sto facendo delle prove!

basshunter: Ahah sono sempre io quello che ha postato nella sezione inglese.

già già... occhio che non se ne accorgano, altrimenti son guai...

La spiegazione del "mistero" è nell'architettura degli AVR e come lavora il compilatore, gli AVR dispongono di 32 sfr general purpose, fanno parte dei registri della cpu, che sono indirizzabili con istruzioni che richiedono un singolo ciclo macchina, il compilatore usa i 32 sfr per le variabili locali, almeno fino a che può allocarle li dentro, poi passa al heap, per contro le variabili globali sono allocate nella normale ram ed accedervi richiede l'uso di istruzioni che richiedono 2-3-4 cicli macchina. Per farla breve, se esegui un elevato numero di iterazioni usando, all'interno di una funzione, usando variabili globali il codice richiede molti più cicli macchina per essere eseguito e questo porta ad un allungamento dei tempi di esecuzione. Per risolvere crei come variabili globali quelle che realmente ti servono perché devono essere disponibili a tutto il codice, o sono volatile per gli interrupt, le copi dentro variabili locali se devi fare calcoli che richiedono cicli iterativi lunghi, poi copi il risultato dentro le globali. Con i PIC questo problema non esiste perché non hanno i 32 sfr però la stragrande maggioranza delle istruzioni richiede un solo ciclo macchina, in particolare quelle per l'accesso alla ram, pertanto usare variabili globali o locali non fa alcuna differenza ai fini dei tempi di esecuzione.

Occhio alla nomenclatura: gli SFR (Special Function Registers) sono quelli che controllano le periferiche, quelli di cui parli sono invece i 32 registri general purpose, r0-r31 :).

fratt:
già già… occhio che non se ne accorgano, altrimenti son guai…

… difatti !!!

>basshunter: in conformità al REGOLAMENTO, punto 13, il cross-posting è proibito (anche tra lingue diverse) e tu hai già posto la stessa domanda QUI.

Non solo, in quel thread ti stanno già rispondendo ed è veramente poco cortese abbandonare una discussione e chi ti stava aiutando, per venire di qua a porre la stessa domanda …

Pertanto, per rispetto verso chi ti stava già aiutando nell’altro thread, questo tuo thread viene chiuso e ti prego di continuare dove avevi cominciato. Grazie.

Guglielmo