Arduino Forum

International => Italiano => Software => Topic started by: psoftware on Apr 06, 2014, 10:04 pm

Title: Interrupt contemporanei
Post by: psoftware on Apr 06, 2014, 10:04 pm
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 :)
Title: Re: Interrupt contemporanei
Post by: Maurotec on Apr 07, 2014, 03:07 am
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.


Title: Re: Interrupt contemporanei
Post by: cyberhs on Apr 07, 2014, 03:57 am
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. 
Title: Re: Interrupt contemporanei
Post by: PaoloP on Apr 07, 2014, 09:53 am
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.
Title: Re: Interrupt contemporanei
Post by: icio on Apr 07, 2014, 12:02 pm
   Karma++;   //PaopoP
Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 07, 2014, 01:18 pm
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!
Title: Re: Interrupt contemporanei
Post by: icio on Apr 07, 2014, 02:00 pm
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... :smiley-mr-green:
Title: Re: Interrupt contemporanei
Post by: PaoloP on Apr 07, 2014, 02:09 pm

il programma si "autoinchiappetta" scusate il termine... :smiley-mr-green:


:smiley-mr-green: :smiley-mr-green: :smiley-mr-green:
Title: Re: Interrupt contemporanei
Post by: Maurotec on Apr 07, 2014, 02:58 pm
@psoftware
I dettagli li puoi cogliere studiando il datasheet del microcontroller, tutti gli ATmega di base si comportano allo stesso modo.
Quote
- 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.
Title: Re: Interrupt contemporanei
Post by: icio on Apr 07, 2014, 03:35 pm

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
Title: Re: Interrupt contemporanei
Post by: Maurotec on Apr 07, 2014, 03:48 pm
@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.
Title: Re: Interrupt contemporanei
Post by: gpb01 on Apr 07, 2014, 03:48 pm

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
Title: Re: Interrupt contemporanei
Post by: icio on Apr 07, 2014, 03:54 pm
Penso che ora la richiesta di psoftware è stata esaudita,
tutti gli atmel90 a 8 bit funzionano così
Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 07, 2014, 06:30 pm
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 :)
Title: Re: Interrupt contemporanei
Post by: PaoloP on Apr 07, 2014, 06:39 pm
Ecco....
Non usare digitalWrite dentro l'interrupt ma i registri del micro per cambiare stato al pin.
La DW è troppo lenta.
Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 07, 2014, 06:42 pm
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...
Title: Re: Interrupt contemporanei
Post by: PaoloP on Apr 07, 2014, 06:44 pm
Puoi pubblicare il pezzo di codice della ISR?
Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 07, 2014, 06:49 pm
E' abbastanza semplice...

Code: [Select]
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
Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 07, 2014, 07:09 pm
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  :smiley-mr-green:

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)
Title: Re: Interrupt contemporanei
Post by: gpb01 on Apr 07, 2014, 08:39 pm

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 (http://www.leonardomiliani.com/2013/manipoliamo-direttamente-le-porte-logiche-di-una-mcu/) ...

Guglielmo
Title: Re: Interrupt contemporanei
Post by: PaoloP on Apr 07, 2014, 10:29 pm
Dovresti fare una cosa del genere
Code: [Select]
volatile byte Cycle = 1;

ISR(TIMER1_COMPA_vect)//timer1 interrupt 1Hz toggles pin 13 (LED)
{
 switch (Cycle) {
   case 1:
     PORTD |= (1 << PORTD2); // HIGH
     PORTD &= ~(1 << PORTD4); // LOW
     PORTD |= (1 << PORTD7); // HIGH
     break;

   case 2:
     digitalWrite(7, LOW);
     break;

   case 3:

     digitalWrite(4, HIGH);
     break;

   case 4:
     digitalWrite(2, LOW);
     break;

   case 5:
     digitalWrite(7, HIGH);
     break;


   case 6:
     digitalWrite(4, LOW);
     Cycle = 0;
 }
 Cycle++;
}


Il resto la lascio a te.
Ti conviene definire lo stato di tutti e tre pin in ogni case.
Title: Re: Interrupt contemporanei
Post by: Maurotec on Apr 07, 2014, 11:39 pm
Se anziché PD2, PD4 e PD7 potessi usare PB0(8), PB1(9) e PB2(10) potresti semplificare molto
il codice, cioè si semplifica per il micro, ma si complica per il programmatore.
Se carichi 100110010011001101 e shifti di 3 a destra nei bit LSB ti ritrovi il codice della sequenza da imporre
direttamente alla porta B. Dopo sei volte shift a destra di tre devi ricaricare il valore 100110010011001101.

Più complicato a spiegarlo che a farlo.

Ciao.
Title: Re: Interrupt contemporanei
Post by: icio on Apr 08, 2014, 09:34 am
Praticamente stai realizzando un inverter trifase finalizzato a alimentatore trifase simile a questo ?

http://www.dmxpassion.altervista.org/pg010.html

Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 08, 2014, 10:32 am
Bravo Icio, esattamente in quel modo, ma uso come sorgente un mini impianto idroelettrico in continua :)

In ogni caso ho capito come usare direttamente i registri dell'ATMega, è relativamente molto semplice... ci sarei arrivato comunque da solo a quel sorgente. In ogni caso la problematica principale ancora non l'abbiamo risolta... come funziona la funzionalità busy dell'interfaccia seriale UART? Anche se non fosse implementata in HardwareSerial, come funziona in teoria?

Ho provato a fare dei test... avvio la generazione dei segnali ma nel frattempo invio dei caratteri alla scheda e me li faccio reinviare indietro... non ho notato grossi problemi, nè in ricezione e nè in trasmissione. Devo approfondire i test
Title: Re: Interrupt contemporanei
Post by: PaoloP on Apr 08, 2014, 10:38 am

Se anziché PD2, PD4 e PD7 potessi usare PB0(8), PB1(9) e PB2(10) potresti semplificare molto
il codice


Credo abbia scelto quei pin perche gli altri della stessa porta sono PWM.
Forse gli servono.
Title: Re: Interrupt contemporanei
Post by: leo72 on Apr 08, 2014, 10:58 am
Manco 2 gg e mi perdo queste discussioni interessanti  ;)

Togli tutte quelle digitalWrite dalla ISR così essa verrà eseguita molto più velocemente.
Poi sarebbe da capire cos'è che fa il resto del circuito, perché se non hai molte necessità potresti eliminare tutti gli altri interrupt e lasciare solo quello del timer in uso.

PS.
tornando un attimo all'inizio del thread, non è che se la CPU sta eseguendo una ISR i segnali degli interrupt in arrivo vengono accodati. Non c'è un buffer. Esistono (come qualcuno ha detto) dei bit che registrano questi interrupt. Alla fine della ISR, viene controllato che non ci sia da eseguire un'altra ISR di un interrupt arrivato nel frattempo. Il problema dei bit è che se arrivano 2 segnali dello STESSO interrupt, il micro registra solo che c'è stato un segnale, non quanti segnali sono arrivati. Per cui 3 INT0 sono registrati sempre con lo stesso bit, per cui la CPU sa solo che c'è da eseguire la relativa ISR. Non che la deve eseguire 3 volte.
Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 08, 2014, 12:41 pm
Uhm...perfetto, sei stato molto chiaro, ora capisco meglio come funziona, erano questioni che mi ponevo da un po' di tempo.
Il problema è che bisogna capire se è possibile accomunare il funzionamento di quella ISR con gli interrupt generati da HardwareSerial. Da quello che si evince devo far si che l'esecuzione della ISR relativa ai PWM venga eseguita il più velocemente possibile, così che ci siano meno possibilità che gli interrupt generati dalla trasmissione/ricezione seriale vengano "scartati" o eseguiti in ritardo a causa dell'esecuzione prolungata della ISR.

Ho fatto un po' di test ma non ho avuto grossi problemi... la ricezione/trasmissione seriale avviene con successo, l'ho testata con una baudrate di 115200, mentre i segnali pwm vengono generati. Invio dei caratteri alla scheda, da cui me li faccio reinviare.
Per i segnali è un po' difficile fare dei test, perchè la frequenza è troppo alta ed è impossibile analizzare gli errori del segnale con un semplice oscilloscopio...
Title: Re: Interrupt contemporanei
Post by: icio on Apr 08, 2014, 01:22 pm
I maggiori problemi nella costruzione del tuo inverter per turbina idroelettrica non la incontrerai nel software ma nell'hardware, 
circuito di controllo spwm, controllo della tensione e corrente di uscita, protezioni, scelta o costruzione dei giusti trasformatori o della reattanza AC trifase etc..

Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 08, 2014, 08:26 pm
Naah... non per caso studio nell'indirizzo Elettrotecnica ed Automazione (elettronica compresa), e sto studiando per bene il circuito elettronico che sarà pilotato da Arduino. Per le protezioni non ci sono problemi, sto trovando solo qualche difficoltà nel circuito di amplificazione ma ho quasi risolto... l'unica cosa che mi preoccupa ora è solo che il segnale venga generato senza difetti
Title: Re: Interrupt contemporanei
Post by: icio on Apr 08, 2014, 08:42 pm
Va bene  ma che te ne fai di 3 onde quadre sfasate? Devi generare 3 sinusoidi!
Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 08, 2014, 08:58 pm
Certo... c'è il circuito anche per quello :) ho già progettato tutta quella parte, tranne una piccola cosa a cui ancora devo trovare soluzione. In pratica dai pwm genero delle sinusoidi che verranno amplificate ed eventualmente fornite all'avvolgimento primario di qualche trasformatore step up, che mi forniranno una tensione più alta... e poi posso pilotare che voglio :D

Ovviamente con Arduino farò tutta una serie di controlli sulle potenze, sulle tensioni e correnti alternate, controlli all'avvio dell'impianto ed altro...insomma mi voglio divertire non poco  :smiley-mr-green:
Title: Re: Interrupt contemporanei
Post by: icio on Apr 08, 2014, 09:08 pm
Insomma in SPwm come ho fatto io.  S vuoi possiamo scambiarci qualche informazione quì senza problema
Title: Re: Interrupt contemporanei
Post by: psoftware on Apr 08, 2014, 09:20 pm
Magari...riesci a trovare risoluzione al mio problema? Come posso amplificare una onda sinusoidale a dei valori determinati di picco?
Sto provando con una configurazione pushpull, ma ho problemi perchè non riesco ad ottenere un'alimentazione duale e comunque non riesco a cambiare il valore di tensione di riferimento dei pin di arduino...