Velocità del loop Mega 2560

Ho voluto per curiosità vedere quanti cicli loop fa il mio arduino in un secondo con un programma a vuoto.
Possibile che su 16MHz di clock arrivo a 80Khz (80.000 cicli) ???
Dove vanno a finire tutti quei Mhz, va bene che ci sono un po' di cosette da gestire nel micro, ma secondo me è una perdita enorme di risorse.

ciao

Hai provato lo speed test? --> Arduino Playground - ShowInfo

PaoloP:
Hai provato lo speed test? --> Arduino Playground - ShowInfo

no non ho provato, a me interessa sapere quante volte mi esegue il loop

unsigned long preMillis=0;
unsigned long counter=0;

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

void loop (){

 counter++; 
   if(millis() - preMillis >= 1000) 
  {   
       preMillis = millis();       
       Serial.println((String)counter);
       counter=0;
  }
}

La curiosità è nata dal fatto che avendo una Mega con 70 pin utilizzabili, mi chiedevo se era davvero utile convertire tutti i cicli for di digital.write(x,0) e digital.read in PORTxx |= _BV(PORTxx); e PINxx

e direi proprio di si!! il tempo si dimezza quasi, un programma molto lungo, va ottimizzato al massimo, sapevo che era + veloce la manipolazione delle porte, ma non sapevo quanto :slight_smile:

unsigned long preMillis=0;
unsigned long counter=0;

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

void loop (){
//----------------------------------
  /* accendi il led */ //44
  //PORTL |= _BV(PORTL5);
  /* spegni il led */ //44         questo lo fa 76.123/sec
  //PORTL &= ~_BV(PORTL5);
//----------------------------------

//----------------------------------
  digitalWrite(44,1);
  digitalWrite(44,0);//            questo lo fa 38.324/sec
//----------------------------------

 counter++;
 
   if(millis() - preMillis >= 1000) 
  {   
       preMillis = millis();       
       Serial.println((String)counter);
       counter=0;
  }
}

La lentezza della digitalWrite è rinomata. La digitalWrite esegue diversi controlli, primo fra tutti vedere se stai lavorando su un pin PWM, nel caso disattiva il corrispondente segnale ecc... Alla fine tutta 'sta roba la paghi.

pablos:

PaoloP:
Hai provato lo speed test? --> Arduino Playground - ShowInfo

no non ho provato, a me interessa sapere quante volte mi esegue il loop

unsigned long preMillis=0;

unsigned long counter=0;

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

void loop (){

counter++;
  if(millis() - preMillis >= 1000)
 {  
      preMillis = millis();      
      Serial.println((String)counter);
      counter=0;
 }
}

però questo programma non è esattamente scevro di operazioni... incrementa un long chiama la millis (che chissà quante operazioni fa) , sottrae due long, compara... quanto impiega una funzione millis?
la seriale poi ... presumo venga gestita ad interrupt?

Bhe la seriale è l'unica istruzione che impegna il micro alla fine del secondo trascorso

leo72:
La lentezza della digitalWrite è rinomata. La digitalWrite esegue diversi controlli, primo fra tutti vedere se stai lavorando su un pin PWM, nel caso disattiva il corrispondente segnale ecc... Alla fine tutta 'sta roba la paghi.

Certo che è rinomata, ma sono quei miseri 80.000 cicli a vuoto che mi lasciano perplesso, tu stesso in qualche post non ricordo quale, hai detto che vengono impegnate librerie che non vengono usate, vabbè era un appunto nulla di grave :smiley: :smiley:

ciao

pablos:
Bhe la seriale è l'unica istruzione che impegna il micro alla fine del secondo trascorso

si quella non mi preoccupa... però sta all'ascolto sulla seriale... questo mi preoccupa di più ma non tanto...
imho il problema è il millis... e vorrei (ma ora no posso) fare un esperimento... 80000?

setup
cont = 0
oldmillis = millis


loop

cont ++
if cont > 100000
   serial print millis()-oldmillis
   oldmillis = millis
   cont =0 
endif

capito cosa vorrei fare? quanti millis impiega ad incrementare una variabile e testare la stessa 100000 volte?
vorrei quasi scommettere che questo ciclo te lo fa in un 10-15 clock... 1 megahz... stasera provo.

Per curiosità ho fatto qualche esperimento:

unsigned int cnt = 0;
const unsigned int CNT_MAX = 65000;

unsigned long prevMillis = 0;


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


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

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

Modificando le prime due righe in:

unsigned long cnt = 0;
const unsigned long CNT_MAX = 65000;

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

pablos:
Ho voluto per curiosità vedere quanti cicli loop fa il mio arduino in un secondo con un programma a vuoto.

Il tuo non è un programma a vuoto, contiene calcoli con valori long che richiedono molti cicli macchina.
Questo è un programma quasi a vuoto:

void setup() {
   pinMode(13, OUTPUT);      
}

void loop()
{
 PORTB = 0xff;
 PORTB = 0x00; 
}

Le due scritture dirette su PORTB richiedono solo 125 ns, come evidenziato nell'immagine allegata della misura sul pin 13 con un DSO, mi è toccato fare una foto al volo della schermata perché vicino al pc ho il Tektronix per il quale non tengo installato il software per scaricare le schermate.
Come si vede la frequenza per questo loop è 1.06 MHz, il periodo necessario per la sola loop, è di 875 ns - 62.5 ns = 812.5 ns = 13 cicli macchina.
Comunque no ha molto senso parlare di massima velocità della loop visto che in realtà dipende da quello che fai al suo interno a cui devi sommare 875 ns ( ~1.43 MHz) per la sua durata reale

@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.