Ottimizzare il codice per la velocità

Buongiorno a tutti, scusate la domanda…

Ho necessità di rendere una funzione il più veloce possibile (almeno nelle mie capacità)… Attualmente il codice è scritto in questo modo:

void eFire(unsigned int eTime){
  
  if(eTime>1000) eTime = 1000;
  if(eTime<70) eTime = 70;
  
  int eTimeMicro = (unsigned int)((1/eTime)*1000000);
  
  // Start first slider
  digitalWrite(FIRST, HIGH);
  delayMicroseconds(PULSE);
  digitalWrite(FIRST, LOW);
  
  delayMicroseconds(eTimeMicro);
  
  // Start 2nd slider
  digitalWrite(SECOND, HIGH);
  delayMicroseconds(PULSE);
  digitalWrite(SECOND, LOW);
}

C’è un modo? Cosa e come posso intervenire? In particolare mi chiedo quanto sono lenti i due if ed il calcolo di eTimeMicro? In teoria le digitalWrite potrei sostituirle con le rispettive istruzioni per la manipolazione delle porte… ma probabilmente non sono loro ad influire più di tanto.

Grazie.

E' una bella domanda. Bisognerebbe prendere il codice macchina generato dal compilatore e mettersi lì col datasheet per capire ogni istruzione che trovi quanto tempo di calcolo porta via e fare 2 somme.

leo72:
E’ una bella domanda. Bisognerebbe prendere il codice macchina generato dal compilatore e mettersi lì col datasheet per capire ogni istruzione che trovi quanto tempo di calcolo porta via e fare 2 somme.

Azz… grazie Leo! Mica cosa da poco…

Supponendo che la parte che a me interessa (quella dei digitalWrite) sia il più veloce possibile nel momento in cui mi serve, portar fuori questa parte di codice mettendolo in una variabile che poi passo alla funzione eFire()? In pratica calcolare eTime fuori dalla funzione, quando la velocità mi interessa meno… dentro la eFire mi risparmi questi calcoli e gli passo solo il valore…

  if(eTime>1000) eTime = 1000;
  if(eTime<70) eTime = 70;
  
  int eTimeMicro = (unsigned int)((1/eTime)*1000000);

GS88: In teoria le digitalWrite potrei sostituirle con le rispettive istruzioni per la manipolazione delle porte... ma probabilmente non sono loro ad influire più di tanto.

Invece pesano moltissimo, poco meno di 2 uS l'una, ovvero di più di quello che ci mette la if per fare il confronto e assegnare il valore, se le sostituisci con le relativa scrittura diretta dei pin tramite registri ci vuole solo un ciclo macchina (62.5 nS). C'è però da tenere in considerazione che dentro la funzione hai dei delay di svariati millisecondi, quindi non vale la pena perdere tempo a sostituire le digitalwrite che complessivamente incidono circa 10 us contro un delay minimo di 1 ms.

Altra cosa, questo calcolo è a dir poco assurdo, non funziona perché non puoi dividere 1 con un valore int e aspettarti un valore diverso da 0.

int eTimeMicro = (unsigned int)((1/eTime)*1000000);

Devi fare così:

unsigned int eTimeMicro = 1000000L/eTime;

Grazie :blush:

se le digitalWrite hanno quei tempi (credevo di più)... ho ben poco da fare.

scusate, ma vi preoccupate della velocità delle funzioni quando c'è una delayMicroseconds(eTimeMicro); di mezzo? secondo me quì c'è qualcosa che logicamente non funziona.

lesto:
scusate, ma vi preoccupate della velocità delle funzioni quando c’è una delayMicroseconds(eTimeMicro); di mezzo?
secondo me quì c’è qualcosa che logicamente non funziona.

in che senso logicamente non funziona?

Funziona tutto. Quello che volevo sapere è quanto quegli if, dentro questa funzione anzichè fuori, potessero influire sull’esecuzione della funzione stessa.

Ossia se, portandoli fuori e passando il parametro alla funzione anzichè far eseguire questi controlli al suo interno potesse dare qualche vantaggio.

Il codice che vedi esegue perfettamente quello che deve fare. E tutti i delay che ci sono devono per forza di cose esserci.

Al massimo, posso con delle prove limare le delayMicroseconds tra i due digitalWrite per vedere se riesco a togliere qualcosa.

il fatto che ci siano errori logici non vuol dire che una cosa non funzioni. Si può spingere una automobile, ma se prima togli il freno a mano è più facile non trovi?

in questo caso il rallentamento del freno a mano è provocato dalle delay che hai sparso nel codice, che puoi sostituire con delle millis() se il tempo di attesa è > del tempo di esecuzione di tutto il loop.

gli if difficilmente sono ottimizzabili senza usare il codice macchina, ma per le digitalwrite puoi usare sbi & cbi (se non erro) che sono delle macro straveloci. se le cerchi nel forum dovresti trovare il codice in varie discussioni.

lesto: in questo caso il rallentamento del freno a mano è provocato dalle delay che hai sparso nel codice, che puoi sostituire con delle millis() se il tempo di attesa è > del tempo di esecuzione di tutto il loop.

Che poi è la stessa cosa che gli ho detto io visto che c'è almeno un delay lungo come minimo 1 ms (eTime = 1000) e come massimo 14.28 ms (eTime = 70), quindi assolutamente trascurabili i tempi di esecuzione delle if e delle digitalwrite.

La strada del datasheet con le istruzioni assembly è la strada del dolore. Io in genere simulo con AVR Studio e controllo direttamente quanto impiegano le funzioni, molto comodo.

Ciao

flz47655: Io in genere simulo con AVR Studio e controllo direttamente quanto impiegano le funzioni, molto comodo.

Con AvrStudio puoi simulare molto poco visti gli enormi limiti del suo simulatore, al limite lo fai tramite un ICE via hardware debug oppure con un DSO, meglio con un analizzatore di stati logici, utilizzando un pin come out per un impulso. C'è sempre il sistema semplice di utilizzare la micros per misurare quanti microsecondi passano tra due punti distinti del programma.

astrobeed: C'è sempre il sistema semplice di utilizzare la micros per misurare quanti microsecondi passano tra due punti distinti del programma.

Anche io opterei per questa opzione ed in base a quello che ottieni ti regoli per fare quello che ti serve

Cerco di spiegare cosa fa il programma perchè non comprendo che vantaggi avrei andando ad usare la millis().

Allora, a parte le if che servono per calcolarmi i microsecondi di ritardo visualizzando dei valori 'leggibili' (sicuramente da chi userà il tutto), i delay servono per 'caricare' delle bobine. I tempi son quelli, sotto le bobine non vengono caricate.

Qual'è il vantaggio che avrei usando millis()?

La delayMicroseconds(eTimeMicro) mi serve per definire il ritardo di attivazione di una bobina rispetto all'altra. Anche qui quale vantaggio avrei ad usare una millis()?

Grazie.

attivi il pin, con la millis registri il tempo di attivazione, fai altro nel codice, nel frattempo ogni tanto (ogni loop di solito, ma puoi fare anche una funzione apposta che chiami quando ne hai voglia) controlli se hai superato il tempo di attesa, a quel punto disattivi il pin, ed eventualmente avvisi l'utente. Come vedi ottieni una sorta di parallelismo, non sei bloccato nell'attesa ma puoi fare altro.

GS88: Qual'è il vantaggio che avrei usando millis()?

Nessuno ti ha detto di usare la millis(), ti è stato detto che il tempo minimo, 1 ms, del delay all'interno della tua funzione è talmente grande che è irrilevante il tempo necessario per eseguire le altre istruzioni della funzione.

astrobeed: Nessuno ti ha detto di usare la millis(), ti è stato detto che il tempo minimo, 1 ms, del delay all'interno della tua funzione è talmente grande che è irrilevante il tempo necessario per eseguire le altre istruzioni della funzione.

si, probabilmente ho solo bisogno di fare delle prove per trovare i minimi valori di delay per i quali le due bobine vengono caricate e fatto quello ridurrò di qualcosa il tempo della funzione. Il resto quello è.

legacy: E per curiosita', e l'app finale cosa e' ?

se mi dici dove contattarti ti mando un video... è un po' grossino da caricare. Funziona già tutto ma volevo capire se potevo guadagnare ancora un pochettino.

Se poi vuoi velocizzare i digital reading-write http://www.arduino.cc/en/Reference/PortManipulation Ciao Niko

Il simulatore l'ho utilizzato con profitto in diverse occasioni, l'unico problema che può dare è con gli sleep perchè diciamo che è emula molto lentamente la MCU ma si risolve commentando tali istruzioni e tenendone in considerazione nei tempi. Usare un debugger hardware sarebbe la soluzione migliore ma poco praticabile per un hobbista.

Ciao

flz47655: Usare un debugger hardware sarebbe la soluzione migliore ma poco praticabile per un hobbista.

Con 60€ ti prendi un AVR Dragon: http://www.ebay.it/itm/Atmel-AVR-Dragon-USB-Programmer-Emulator-NEW-model-ATAVRDRAGON-/220998525470?pt=LH_DefaultDomain_3&hash=item337489e21e#ht_5128wt_1139