Dubbio su Interrupt TIMER e Seriale (Arduino UNO)

Ciao a tutti!

Ho vari dubbi su un progetto d'esempio che ho realizzato per imparare ad usare i timer interni del microcontrollore ATMEGA328P.

Codice d'esempio che funziona bene e non da errori ma comunque ho dei dubbi che non riesco a capire se si possono verificare oppure no:

#define Debug_Led 13

int Cycle;

void setup() {

  delay(10);

  pinMode(Debug_Led, OUTPUT);

  Serial.begin(115200);

  TCCR2A = 0;
  TCCR2B = 0b00000011;

  TCNT2 = 0;

  TIMSK2 = 0b00000001;

  delay(100);

}

ISR(TIMER2_OVF_vect) {

  if (Cycle < 100) {
    Cycle++;
  } else {

    digitalWrite(Debug_Led, !digitalRead(Debug_Led));

    Serial.println("POPIPOPI");
    
    Cycle = 0;
  }

}

void loop() {

  delay(1000);

  Serial.println("Ciao a tutti!");

}

Il programma esegue una funzione ad interrupt ogni tot tempo che fa lampeggiare il led 13 e stampa su seriale il messaggio "POPIPOPI"

Poi nel void loop() ad ogni secondo, quindi un ciclo più lento, stampa un messaggio seriale che scrive "Ciao a tutti!"

DUBBI CHE MI CHIEDO:

1)Quando parte l'interrupt per ogni tot tempo, se il programma, dentro l'interrupt stesso, è molto lento più di quanto è il tempo di richiamo dell'interrupt succede che si auto richiama? E fa pasticci?

2)Quando scrivo un messaggio via seriale il singolo invio dei byte viene fatto tutto d'un colpo?
O può succedere che se invio un stringa di tanti caratteri succede che mi vengono stampati i primi tot poi capita l'interrupt e poi riprende a stampare?

3)La seriale print() e write() sono gestite da un interrupt prioritario?

4)Il programma che ho allegato sembra funzionare e non noto che il messaggio "POPIPOPI" venga spezzettato pensando di vedere per esempio:

POPIPOPI
POPCiao a tuIPOPItti! < Quello che penso succeda :frowning:
POPIPOPI
POPIPOPI
Ciao a tutti!
POPIPOPI
ecc ecc

Ho letto dei post che avevano dubbi simili e qualcuno diceva che aveva pasticci con la seriale e con gli interrupt con i timer... BHO...

Grazie a tutti dell'aiuto possibile :slight_smile:

Stai violando TUTTE le regole di una ISR ... la quale DEVE essere la più veloce possibile, NON deve usare la seriale né altre cose che usano interrupts ... per cui ... è normale che tu abbia malfunzionamenti!

Nella ISR pochissime cose ... l'incremento di un contatore, l'ouput su un pin, il set di una flasg e poco altro, il resto ... FUORI dalla ISR.

Guglielmo

Scusa Guglielmo ma hai letto TUTTO il mio post? :smiley:
Se mi dici che è normale che abbia malfunzionamenti quando HO SCRITTO CHE FUNZIONA c'è qualcosa che non va ahah...

Ho detto che il programma funziona perfettamente NON che non funziona.

I miei sono SOLO dei dubbi non un fatto reale.

NON cambia quello che ti ho scritto ... è cosa che NON si deve fare e ... se funziona è un caso (ma comunque dubito che in situazioni più complesse funzioni correttamente).

Come ho scritto sopra quella ISR è concettualmente SBAGLIATA ... poi fai come vuoi ... :roll_eyes:

Guglielmo

P.S.: Studiati QUESTA pagina ... priôprio all'inizio ci sono le "regole fondamentali" :wink:

... ha, dimenticavo, NO, non ho letto il tuo post, ho letto il codice e ... sono sobbalzato quando ho visto la ISR fatta in quel modo :smiling_imp:

Guglielmo

Grazie Guglielmo, hai ragione comunque...
il progetto è semplicemente una prova ma evidentemente non capita...

Ma la pratica corretta è utilizzare dei flag che poi nel loop principale fanno girare il codice delle seriali?

Le seriali quindi (visto che avevo fatto delle domande in merito) gestiscono la trasmissione dei dati ad interrupt?

Ho letto le info che mi hai linkato e non ho capito perché è meglio usare delle variabili di tipo volatile e non "normali" :frowning:

E' il modo più pulito che si usa spessissimo, ad esempio, quando c'è di mezzo un RTOS ... si chiama "deferred interrupt" ... nell'interrupt alzi una flag per indicare che l'interrupt è avvenuto, altrove verifichi la flag e, se la trovi attiva, fai quello che devi fare :wink:

SI, per non perdere caratteri e velocizzare il tutto, normalmente si usano gli interrupt nella gestione di vari bus, incluso le trasmissioni seriali via UART.

Non è meglio, è OBBLIGATORIO ... devi avvisare il compilatore che quella variabile può essere modificata indipendentemente dal flusso del programma (es. all'interno della ISR che non fa parte del normale flusso del programma). Inoltre eviti che, durante la fase di ottimizzazione del compilato, magari non vedendo nulla che la modifica (ad esempio la modifica avviene in una ISR che non fa parte del regolare flusso del programma) la elimini o faccia ... altri danni :grin:

Guglielmo

1 Like

Ahnnnnnnnn che cose INTERESSANTI !!

GRAZIE GUGLI!

1 Like

Guglielmo scusa un ultima cosa:

posso fare i ISR che mi legge i dati dalla seriale per far chi che il buffer non venga riempito a prescindere dalla velocità del loop ?

O neanche la lettura seriale posso fare?

Avevo letto che è una pratica comune per leggere dati MIDI se si vuole realizzare un controller MIDI o altro che usa tale protocollo... BHO :frowning:

NO, se vai a vedere come funziona nel "core" Arduino UNO la ricezione di dati dalla seriale, vedrai che è fatta ad interrupt, ma ... essendo tu già in una ISR e NON avendo le MCU AVR una gestione prioritaria a livelli degli interrupts, gli interrupt sono disabilitati fino a quando non esci dalla ISR e quindi NON puoi usare altre cose che usano gli interrupts.

La cosa sarebbe differente su MCU più complesse (tipicamente a 32 bit) che sono in grado di gestire più livelli di interrupt con vari gradi di priorità ... :roll_eyes:

Guglielmo

però succede che se leggo i dati seriali nel loop() principale ed è troppo lento come faccio?

vuol dire che quello che spiegano alle università è sbagliato :frowning: uffa

Mmmm ... evidentemente perdi troppo tempo nel loop() ... puoi provare a mettere le mani nel "core" Arduino della UNO per aumentare le dimensioni del buffer seriale (studiandoti il file HardwareSerial.h ed applicando li la modifica), anche se è cosa che io sconsiglio sempre (possibilità di introdurre errori, obbligo di dover rifare la modifica ogni volta che Arduino aggiorna il "core", ecc.), oppure ... cambiare scheda e passare a schede più veloci, con più memoria e con buffer seriali di maggiori dimensioni.

Comunque qui parecchi usano la UNO per il MIDI e nessuno ha mai lamentato i tuoi problemi quindi ... rivedi bene il tuo programma, perché forse va migliorato/corretto.

Guglielmo

Ho letto tutti gli interventi e qui c'è da chiarire.
All'interno della ISR puoi usare Serial.read(), Serial.available().
Se ci sono dati nel buffer ring che vive in memoria ram otterrai i dati.

Durante la ISR non potranno essere inseriti dati nel buffer ring ecco anche perché la ISR dovrebbe impegnare pochi cicli di CPU e terminare.

Ciao.

ah ecco vedi grazie :smiley:

quindi leggo il messaggio seriale lo metto in una variabile globale dichiarata volatile per poi leggerla nel loop() :smiley: giusto?

poi intendi che quando la cpu esegue l'interrupt per leggere i dati seriali nel buffer in quel preciso momento essa non puo' riceve altri dati seriali provenienti dall'esterno? :frowning:

avevo letto che la recezione dei bytes seriali è di tipo hardware non gira su software... poi il software gestisce la lettura effettiva dei dati nel buffer nella memoria ram dedicata per tali dati...

Stai solo creando confusione ...
... la ricezione dei dati avviene via interrupt e quindi, quando si è in una ISR NON si ricevono dati. Ovvio che, se PRIMA di entrare nella ISR sono arrivati dei dati e NON sono stati letti, stanno nel buffer, ma NON stai ricevendo dei dati, stai leggendo un'area di memoria.

Dato che il suo problema è ricevere dati all'interno di una ISR (e non semplicemente svuotare il buffer circolare) ... NON si risolve il suo problema.

Continua a dire che c'è un problema nel suo programma, qui tantissimi usano MIDI con la UNO senza tutti questi problemi ... :roll_eyes:

Guglielmo

Aspetta che faccio un po a cazzotti con @Guglielmo.

Si tratta dello stesso utente?

Lo è ovvio per noi, ma come puoi leggere non lo è per niente per @MizzardNet.

@gpb01 Questo l'ho letto, tu lo hai letto.
@gpb01 non mi fare disperare, sto cercando di capire e non trovo alcuna discussione sul Midi.

Vabbe dimmi cosa mi sfugge perché io non trovo alcun post di questo utente che faccia riferimento al MIDI.

Tranne questo che non vuol dire che sta cercando di sviluppare un applicazione MIDI. O mi sbaglio?.

Ciao.

Si la periferica UART è hardware, ma riguardo al buffer hardware questo è grande un solo byte, il nome di questo buffer hardware è UDR0 che sostanzialmente è un registro mappato su RAM. Quando un byte viene ricevuto da UART viene messo in UDR0 e se abilitati (gli interrupt) la UART solleva una IRQ specifica, alla IRQ è associata una ISR che ha il compito di leggere UDR0 e salvarlo nel buffer ring.

ISR (Interrupt Service Routine)
IRQ (Interrupt Request)

Trovi tutti i dettagli nel datasheet della MCU ATmega328P
Ciao.

Controllando il "profilo" direi di SI.

... bah ...

... scherzi? vai nella radice Italiana, metti MIDI nella casella di ricerca, digli di cercare in Italiano e ... vedrai le discussioni che escono.

Mi sembra proprio di capire che deve lavorare con una trasmissione seriale proveniente da un'interfaccia MIDI :roll_eyes:

Guglielmo

Cribbio, fallo tu. Dal 2019 ad oggi non esce un post con MIDI.

Ciao.

Togli l'after 2019 ... è roba più vecchia ... ed in un thread che riguardava un MIDI controller ... rispondesti proprio TU :grin:

Guglielmo