Velocità del loop Mega 2560

@Astro, mi rendo conto che non è proprio a vuoto, ma tu hai un oscilloscopio eheheh io non potevo farlo se non contando approsimativamente i secondi, grazie per la prova a banco (o l'avevi già fatta :slight_smile: )
é anche molto probabile che il mio millis che parte al reset è già abbastanza avanti, il valore di paragone che uso è comunque una costante dove lo stesso errore viene riportato ogni volta che aggiungo un pezzetto di prova.

Il mio programma su arduino 2560 è diventato quasi 2000 righe con un 60k circa occupati e ho notato tristemente che nel loop ci passa circa 23 volte al secondo cercavo di capire facendo piccoli pezzi alla volta quale fosse la procedura migliore per migliorarne le prestazioni

ciao

@tuxduino

Tempo medio: 230 ms
65000 / 0,230 = 282608 chiamate di loop() al secondo

A me il tuo sketch mi da meno della metà 131000 circa, allora sto arduino ha dei seri problemi!!!

ciao

Che velocità hai impostato per la seriale ?

9600 ma che importa, non la usa fino a quando l'if non è vero, tra l'altro l'attivo dopo....

void setup() {}
void loop() {
    cnt++;
    if (cnt > CNT_MAX)  {
       Serial.begin(9600);  
       Serial.println(millis() - prevMillis);
       Serial.end();
        cnt = 0;
        prevMillis = millis();
    }
}

ps .. ho provato anche con 115200 è uguale il risultato 0.495 anche Serial.begin nel setup, cambia nulla

Può darsi che la mega debba fare più cose e quindi più lenta tu di quale MCU parli?

pablos:
A me il tuo sketch mi da meno della metà 131000 circa, allora sto arduino ha dei seri problemi!!!

Con cosa l'hai alimentato durante le feste ?
Sicuramente si è ingrassato il quarzo e adesso è in sovrapeso pertanto corre più lento :grin:

astrobeed:
Con cosa l'hai alimentato durante le feste ?
Sicuramente si è ingrassato il quarzo e adesso è in sovrapeso pertanto corre più lento :grin:

:smiley: :smiley: :smiley:

La UNO ha 16Mhz, la Mega 16Mhz i due sistemi internamente sono un po' diversi da gestire, nella 2560 ci sarà molto da fare prima di darmi il risultato o ci sono dei pelandroni ]:D, se facciamo confronti con schede differenti, i risultati saranno diversi

pablos:
9600 ma che importa, non la usa fino a quando l'if non è vero, tra l'altro l'attivo dopo....

void setup() {}

void loop() {
   cnt++;
   if (cnt > CNT_MAX)  {
      Serial.begin(9600);  
      Serial.println(millis() - prevMillis);
      Serial.end();
       cnt = 0;
       prevMillis = millis();
   }
}




ps .. ho provato anche con 115200 è uguale il risultato 0.495 anche Serial.begin nel setup, cambia nulla

Può darsi che la mega debba fare più cose e quindi più lenta tu di quale MCU parli?

si ma continui a misurare i millisecondi mentre attivi la seriale... prima fai la differenza (e la relativa chiamata a funzione millis che non si è capito quanto dura) e poi attivi quello che vuoi e stampi quello che vuoi.
Proporrei anche un ciclo molto molto più lungo...

Ma hai visto bene dove chiamo Serial.begin() nel mio codice e dove lo chiami nel tuo ?

io farei (in pseudocodice, sono al lavoro)

unsigned int cont = 0;
unsigned long tempoInizioMs;
setup(){
 Serial.begin(9600); //mi aspetto molti meno interrupt/s dalla seriale
 tempoInizioMs = millis();
}

loop(){
  cont++;
  if (!cont){ //vediamo quanto impiega a overfloodare!
     Serial.println( millis()-tempoInizioMs );
     tempoInizioMs = millis();
  }
}

ATTENZIONE: la prima lettura non è "accettabile" perchè c'è il "salto" da setup a loop, anche questo mangia cicli. Come insegna astro (un post moolto tempo fa) anche il richiamo ciclico della funzione loop mangia cicli; confrontate il risultato con questa! (il tempo mabngiato equyivale a salvare lo stato macchina nello stack etc..

unsigned int cont = 0;
unsigned long tempoInizioMs;
setup(){
 Serial.begin(9600); //mi aspetto molti meno interrupt/s dalla seriale

}

loop(){
  tempoInizioMs = millis();
  while(1){
    cont++;
    if (!cont){ //vediamo quanto impiega a overfloodare!
       Serial.println( millis()-tempoInizioMs );
       tempoInizioMs = millis();
    }
  }
}

noterete anche che sempre per il motivo a richiamo funzione, l'errore del primo calcolo sarà più piccolo quì, poichè l'esecuzione di while(1){ è molto più leggera di un richiamo a funzione.

altro test: la mega ha molti più pin "speciali" e quindi più potenziali interrupt. provate a usare noInterrupts(): però attenzione ad attivarli per usare la seriale! quindi si fa il calcolo della millis, si riattivano l'interrupt, si stampa, si fa una serial.flush() (e una delay, la flush svuota il buffer software ma non l'hardware, è un issue che ho visto su github qualche giorno fa), si ridisattivano gli interrupt, si fa tempoInizioMs = millis(); e si ricomincia.

edit: interrupts(); per riattivare gli interrupt

unsigned int cont = 0;
unsigned long tempoInizioMs;
void setup(){
 Serial.begin(9600); //mi aspetto molti meno interrupt/s dalla seriale
 tempoInizioMs = millis();
}

void loop(){
 while(1){
  cont++;
  if (!cont){ //vediamo quanto impiega a overfloodare!
     Serial.println( millis()-tempoInizioMs );
     tempoInizioMs = millis();
    };
  };
}

senza while 494-495ms di media.
con il while... mi stampa tutti 0... :astonished: boo... adesso indagooo

mega 2560...

lesto:
edit: interrupts(); per riattivare gli interrupt

emmm.... nointerrupt no timer... :grin: sorry...

vero :blush: :blush:

si può risolvere conteggiando il tempo lato pc, ed eliminando il tempo stimato per l'invio su seriale
secondi da sottrarre = (caratteri inviati * (1/baudrate) )

oppure

microsecondi da sottrarre = (caratteri inviati * (1000000/baudrate) )

con il while... mi stampa tutti 0...

uhmm che sia una ottimizzazione del compilatore? però mi pare un pò troppo aggressiva... oppure l'ovreflow avviene in meno di un milis() :slight_smile: allora in quel caso prova con una micros() :slight_smile:

rispolverando il codice iniziale (più o meno)... noto 544ms... sta mega non si muove...

const unsigned int CNT_MAX = 65000;
long cnt=0;
unsigned long prevMillis = 0;
long dif = 0;

void setup() {
    Serial.begin(9600);
}


void loop() {
    cnt++;
    if (cnt > CNT_MAX)  {
       dif = millis() - prevMillis;
        Serial.println((int) dif);
        prevMillis = millis();
        cnt = 0;
    }
}

vedi sopra, la unsigned int è solo di 65535, quindi o la trasformi in long oppure passiamo ad usare la micros()

edit:

sta mega non si muove...

uhm qualche altra mega di confronto? sarebbe un bel problema se le mega avesserouna pesante perdita di prestazioni da qualche parte

unsigned int cont = 0;
unsigned long dif;
unsigned long tempoInizioMs;
void setup(){
 Serial.begin(9600); //mi aspetto molti meno interrupt/s dalla seriale
 tempoInizioMs = millis();
}

void loop(){
 while(1){
  cont++;
  
  if (cont == 65535){ //vediamo quanto impiega a overfloodare!
    dif = millis();
    dif = dif -tempoInizioMs;
     Serial.println( dif);
     tempoInizioMs = millis();
     cont =0;
    };
  };
}

a me sto codicice da i numeri... mi stampa solo 0.... secondo me qua il compilatore me la sta mettendo sul didietro...
l'ho un po' modificato ancora il codice qua sopra... lo so è un casino: non si fanno le prove così cambiando sempre qualcosa ma non va accidenti: ho provato il logico e l'illogico...

usa micros() al posto di millis() e lascia

if (!cont){ //vediamo quanto impiega a overfloodare!

se proprio non ti fidi equvale a: (quando overflodda la variabile torna ad essere 0)

if (cont == 0){ //vediamo quanto impiega a overfloodare!

lesto:
vedi sopra, la unsigned int è solo di 65535, quindi o la trasformi in long oppure passiamo ad usare la micros()

edit:

sta mega non si muove...

uhm qualche altra mega di confronto? sarebbe un bel problema se le mega avesserouna pesante perdita di prestazioni da qualche parte

ma no... quanti timer ha da gestire la uno? 3 ?
il mega? 6... il nostro ciclo impiega veramente pochi cicli di clock... ma i timer vanno tenuti aggiornati comunque...
c'è un modo per disattivarli (tranne il timer 0) ?

lesto:
usa micros() al posto di millis() e lascia

if (!cont){ //vediamo quanto impiega a overfloodare!

se proprio non ti fidi equvale a: (quando overflodda la variabile torna ad essere 0)

if (cont == 0){ //vediamo quanto impiega a overfloodare!

no no tranquillo che mi fido... tant'è che il primo test sul loop l'ho fatto con il !cont... solo che sai... quando non sai dove sbattere la testa le provi tutte... ed infatti con questa logica random ho provato a cambiare anche piattaforma: leonardo...

unsigned int cont = 0;
unsigned long dif;
int somma = 1;
unsigned long tempoInizioMs;
void setup(){
 Serial.begin(9600); //mi aspetto molti meno interrupt/s dalla seriale
 tempoInizioMs = micros();
}

void loop(){
 while(1){
  cont=cont +somma;


  
  if (!cont){ //vediamo quanto impiega a overfloodare!
    dif = micros();
    dif = dif -tempoInizioMs;
     Serial.println( dif);
     tempoInizioMs = micros();
     cont =0;
    };
  };
}

29070MICROsecondi... quindi 29.... leonardo ha 4 timer se non vado errato...
nota che ho cambiato il cont++.... ho tentato di imbrogliare il compilatore perchè con il cont++ lo stesso programma mi fa uscire 4microsecondi...

In conclusione imho la velocità del ciclo loop "semivuoto" è dettata dal numero di interrupt (...leggasi quindi timers) che l'arduino ha attaccato... questo perchè in se il loop è tradotto con poche istruzioni assembler abbastanza ottimizzate (...all'inizio dicevo 10-15 cicli di clock perchè penso che un incremento, un salto ed un test su long grossomodo quello impieghino) però il processore è ugualmente gravato dall'aggiornamento dei timers ed eventualmente di altri interrupt esterni.

la curiosità è che questo compilatore non smette mai di stupirmi... vedi ottimizzazione che lui si è fatto sul ciclo while(1) senza che nessuno gli dica nulla..

unsigned int cont = 0;
unsigned long dif;
int somma = 1;
unsigned long tempoInizioMs;
void setup(){
 Serial.begin(9600); //mi aspetto molti meno interrupt/s dalla seriale
 tempoInizioMs = micros();
}

void loop(){
// while(1){
  cont=cont +somma;


  
  if (!cont){ //vediamo quanto impiega a overfloodare!
    dif = micros();
    dif = dif -tempoInizioMs;
     Serial.println( dif);
     tempoInizioMs = micros();
     cont =0;
    };
 // };
}

completo... poi lascio e vado a mangiare.... 120.000 microsecondi il ciclo senza il while con il solo loop... e la differenza è veramente tanta... ma in teoria dovrebbe essere solo una chiamata ad una funzione quindi.... pochi cicli di clock... imho c'è qualcosa ancora sotto... da 29 a 120ms non vi sembra strano?

qsecofr ma che arduino hai?

cli(); // disable global interrupts
sei(); // enable interrupts

ma come si fa ad abilitarne o disabilitarne 1 o 2 soltanon non lo so....