Interrupt contemporanei

Salve gente... durante l'ideazione di un progetto da realizzare con Arduino UNO (o eventualmente MEGA), sono sorte nella mia mente alcune problematiche a cui ho trovato solo parziale soluzione. Ho già iniziato a scrivere un po' di codice, con cui sono in grado di generare alcuni segnali PWM con frequenza prestabilita e sfasati fra di loro, facendo uso degli interrupt generati dal Timer1, configurato appositamente per le mie necessità. Il problema sorgerebbe quando dovrei sfruttare anche l'interfaccia seriale di Arduino UNO per trasmettere e ricevere dati con dispositivi esterni (probabilmente una Rasp), proprio perchè HardwareSerial sfrutta degli interrupt per la ricezione dei dati e a quanto pare anche per trasmetterne. Ora mi chiedo:

1) Che succede se vengono liberati due interrupt contemporaneamente o ne viene generato uno mentre una funzione eseguita a causa dell'altro è ancora in esecuzione? 2) Ho fatto le giuste considerazioni su HardwareSerial in termini di interrupt? 3) Rinunciando alla ricezione di dati sull'interfaccia seriale , posso fare in modo di sfruttare solo la trasmissione senza scatenare interrupt? (considerando che ci sia il problema)

Ovviamente già ho letto vari articoli nel Playground, quindi ho una mezza base teorica sugli interrupt e i timer, prescaler e altro, ma non ho trovato risoluzione a questi problemi... vi ringrazio in anticipo :)

1) L'esecuzione di codice interno a una ISR avviene per default con gli interrupt globali disabilitati. Terminata la ISR vengono riabilitati gli interrupt. In sostanza e come eseguire cli() all'ingresso e sei() alla fine della ISR.

2) Si

3) No

Per la (3) se scrivessi del codice per gestire la seriale senza interrupt dovresti anche verificare se gli interrupt della seriale sono disabilitati e se non lo sono provare a vedere cosa succede disabilitandoli. Temo però che si incasinino un bel poco di cose, ma per saperlo con certezza bisognerebbe analizzare il codice di Arduino core oppure provare e vedere cosa accade.

Ciao.

La risposta l'hai già data tu stesso: usa un MEGA che ha altre tre UART a disposizione. Come alternativa altrettanto valida potresti usare un LEONARDO od un MICRO: hanno entrambi una porta seriale USB (virtuale) per il Serial Monitor e lasciano libera la porta seriale (pin 0 ed 1) per altri scopi.

Inoltre gli interrupt non sono tutti uguali ma vengono eseguiti in base ad una scala di priorità: trovi l'ordine nel datasheet del micro. Se due interrupt vengono richiamati contemporaneamente sarà eseguito quello con priorità maggiore e il secondo messo in coda ed eseguito al termine del primo.

Karma++; //PaopoP

Perfetto ragazzi! MauroTec e PaoloP siete stai molto chiari... cyberhs forse non hai colto la questione, per ora non mi servono più UART fisiche, più che altro volevo capire come gli interrupt generati dall'acquisizione dei dati in seriale potrebbe inibire la generazione del mio segnale PWM o la sua distorsione. Ora però mi sorge solo un'altra domanda:

  • considerando che l'esecuzione di una ISR disabilita durante l'esecuzione altri interrupt... questi altri vengono accodati in qualche modo oppure l'esecuzione della ISR a cui sono legati viene inibita temporaneamente?

Dopo di questa penso che avrò le idee abbastanza chiare!

Vengono accodati, ogni interrupt setta un bit di flag nel registo apposito e quando è finita la risposta il rispettivo bit ritorna a 0, il controllo ritorna alla task interrotta ma se nel frattempo un'altro flag di interrupt è stato settato và subito alla sua risposta all'interrupt, esiste una priorità che avviene nel caso di interrupt contemporanei.

Esiste anche un'altra situazione, non molto usata a dire il vero: l'interruzione di una risposta all'interrupt, cioè se l'interrupt viene riabilitato molto prima della fine della risposta può essere interrotto DURANTE LA STESSA RISPOSTA, è molto delicato in quanto l'ultima interruzione deve durare molto meno della prima e usare variabili non più usate nella prima interruzione altrimenti il programma si "autoinchiappetta" scusate il termine... :grin:

icio: il programma si "autoinchiappetta" scusate il termine... :grin:

:grin: :grin: :grin:

@psoftware I dettagli li puoi cogliere studiando il datasheet del microcontroller, tutti gli ATmega di base si comportano allo stesso modo.

  • considerando che l'esecuzione di una ISR disabilita durante l'esecuzione altri interrupt... questi altri vengono accodati in qualche modo oppure l'esecuzione della ISR a cui sono legati viene inibita temporaneamente?

Anche se ci fosse un buffer che tiene conto di IRQ non soddisfatte, il problema rimane. Prima che la ISR del timer venga eseguita deve terminare la ISR corrente e se questa monopolizza il micro per 100ms, la ISR del timer sarebbe eseguita con un ritardo di almeno 100ms. Si pensa che un IRQ non possa essere persa e che comunque sarà eseguita prima o poi, invece ciò può accadere più spesso di quanto non si pensi.

Se ci illustri per cosa usi il timer e come forse si può trovare una soluzione. Ricorda che il PWM una volta impostato viene generato dal timer in modo indipendente dalle altre operazioni eseguite. La tua applicazione potrebbe rientrare tra quelle dette mission-critical o soft-realtime o altro, riuscire a categorizzare la tua applicazione ti permette di decidere se ti serve un RTOS e il tipo di scheduler ecc.

Esempio, cosa accade se c'è uno slittamento dei tempi occasionale, se dei vincoli temporali occasionalmente non vengono rispettati? lo puoi accettare o e un disastro di proporzioni bibliche? :D

Ciao.

MauroTec: Si pensa che un IRQ non possa essere persa e che comunque sarà eseguita prima o poi, invece ciò può accadere più spesso di quanto non si pensi.

Accade PER ESEMPIO in questa situazione: il Timer0 produce un interrupt periodico a 10msec....risponde all'interrupt durante la risposta a Timer0 accade un interrupt della rs232, arriva il carattere "A" , non si risponde ad essa perchè la risposta a Timer0 deve ancora terminare, ACCADE UN'ALTRA RICHIESTA DI INTERRUZIONE SEMPRE DA RS232, arriva il carattere "B", al termine della richesta di timer0 risponde anche a alla rs232 ma prenderà solo il carattere "B" , il carattere "A" è perso con guai seri

tutto questo è reso possibile perchè la risposta al timer0 è durata più del tempo della ricezione tra i caratteri A e B è possibile parlare della soluzione per questo esempio che ho citato ma non è il caso

@icio Sintesi ottima. In molti casi ci viene in aiuto il buffer presente nel convertitore seriale, e il meccanismo busy della seriale, sempre se presenti in HardwareSerial.

Credo anche io che non sia il caso di approfondire principalmente perché ci sono molte possibili soluzione.

Ciao.

icio: Accade PER ESEMPIO in questa situazione: il Timer0 produce un interrupt periodico a 10msec. ...........

... non per nulla le ISR dovrebbero essere ridotte veramente ai minimi termini, facendo il minimo indispensabile e tornando immediatamente indietro ;)

Guglielmo

Penso che ora la richiesta di psoftware è stata esaudita, tutti gli atmel90 a 8 bit funzionano così

E' una discussione davvero interessante, spero riuscirò ad approfondire per bene tutti questi argomenti... ma ora ho le idee molto più chiare. Intanto ringrazio tutti i partecipanti per il contributo, poi vi spiego meglio cosa sto per fare.

In pratica sfruttando il Timer1 riesco a generare tre segnali PWM (usando dei semplici DigitalWrite nella ISR e una struttura if) a 50hz "sfasati" tra di loro con cui, tramite un circuito di potenza, andrò a controllare dispositivi a tensione molto più alta (230-400v). Facendo le vostre considerazioni, rischio che questo "conflitto" di interrupt possa far si che i miei segnali non vengano generati nel modo che ho prestabilito, e vengano distorti in qualche modo...provocando qualche problema con i dispositivi che controllerò.

Contemporaneamente rischio che pure il trasferimento di dati in seriale, via UART, sia intaccato in qualche modo, causando come mi avete descritto perdita di caratteri e successivi problemi. Probabilmente mi proporrete di generare quei segnali con qualche circuito elettronico a sè, ma vorrei farlo direttamente con Arduino...

Da quello che dite si evince che dovrei trovare un modo per gestire in modo diverso trasmissione e ricezione dei dati via seriale. A questo punto ritorno alla terza domanda che avevo fatto nel post di introduzione a questa discussione: rinunciando alla ricezione di dati su Arduino, posso sfruttare solo la trasmissione evitando il liberarsi di interrupt diversi da quelli del timer1? Non capisco se la trasmissione via seriale implichi la generazione di qualche interrupt. Per la ricezione ormai è certo, se ci fosse una soluzione anche per questa sarebbe ben accolta.

In ogni caso vorrei capire bene la "teoria" prima di arrivare alla pratica, non c'è miglior modo :)

Ecco.... Non usare digitalWrite dentro l'interrupt ma i registri del micro per cambiare stato al pin. La DW è troppo lenta.

Si, avevo dimenticato di scriverlo e so con certezza che usare DigitalWrite rende l'esecuzione più lenta...specialmente perchè devo cambiare lo stato di tre pin contemporaneamente. Ma il tutto è ancora un mezzo abbozzo, devo ottimizzare per bene il sorgente...

Puoi pubblicare il pezzo di codice della ISR?

E' abbastanza semplice...

int Cycle;

ISR(TIMER1_COMPA_vect)//timer1 interrupt 1Hz toggles pin 13 (LED)
{
  if(Cycle==0)
  {
    digitalWrite(2, HIGH);
    digitalWrite(4, LOW);
    digitalWrite(7, HIGH);
  }
  else if(Cycle==1)
    digitalWrite(7, LOW);
  else if(Cycle==2)
  {
    digitalWrite(4, HIGH);
  }
  else if(Cycle==3)
  {
    digitalWrite(2, LOW);
  }
  else if(Cycle==4)
  {
    digitalWrite(7, HIGH);
  }
  else if(Cycle==5)
  {
    digitalWrite(4, LOW);

    Cycle=0;
    return;
  }

  Cycle++;
}

Nel loop non c'è niente...ho messo giusto qualche riga per acquisire dei dati in seriale e testare la "stabilità" dei segnali PWM tramite un oscilloscopio. In pratica questo codice genera tre PWM a 50hz su tre pin diversi, duty cycle al 50% percento, "sfasate" a 120 gradi tra loro... ovviamente "sfasate" fra virgolette perchè parliamo di mezze onde quadre e non di sinusoidi. I segnali sono generati correttamente, di questo almeno sono soddisfatto :D

Ovviamente il tutto può essere sistemato con un case, o sfasando i segnali in modo più “matematico”. Per questo dicevo che fosse solo un mezzo abbozzo :grin:

Le onde vengono generate come da allegato (scusate la bassa risoluzione dell’immagine e le modifiche che ho fatto, mi servivano per studiare come generare i tre segnali).

Gli interrupt sono generati alla frequenza di 50 [Hz]/6 , perchè appunto i segnali cambiano stato ogni 1/3 di P greco (studiando i pwm come se fossero sinusoidi)

Trifase Square.PNG

psoftware: E' abbastanza semplice...

Come ti è stato detto NON usare le digitalWrite() in una ISR ... sono lente ! Impara ad usare l'accesso diretto alle porte ... studia QUI ...

Guglielmo