Cosa succede se, mentre sto gestendo un interrupt, ne arriva un altro? Viene messo in pausa il primo per eseguire il secondo? Oppure il secondo viene messo in coda? O peggio ancora, il secondo viene ignorato?
Mi pongo il problema perché devo gestire due segnali a interrupt che molto spesso avvengono nello stesso istante......
Janos:
Cosa succede se, mentre sto gestendo un interrupt, ne arriva un altro? Viene messo in pausa il primo per eseguire il secondo? Oppure il secondo viene messo in coda? O peggio ancora, il secondo viene ignorato?
Mi pongo il problema perché devo gestire due segnali a interrupt che molto spesso avvengono nello stesso istante......
Scusami LEO.
Quando avviene un interrupt viene chiamato la funzione di interrupt. Se ne arriva un secondo interrupt mentre l'Arduino é nella funzione di interrupt viene richiamato la funzione di interrupt, eseguita la seconda chiamata e terminata quella continuato con la esecuzione della prima chiamata della funzione. Poi finita la prima chiamata ritorna al programma interrrotto.
In poche parole un grande problema.
Risoluzione, se il segnale interrupt diventa LOW se attivo e é piú lungo della esecuzione della funzione interrupt (al limite si inverte e/o allunga con della elettronica supplementare): triggheri l' interrupt LOW e blocchi nella funzione altri interrupt. Cosí viene eseguito la funzione interrupt del tutto e poi una volta terminata e riattivato gli interrupt richiamata.
Vedi: http://arduino.cc/en/Reference/NoInterrupts e http://arduino.cc/en/Reference/Interrupts
ciao Uwe
Scusami Uwe ma i link che hai postato non riguardano questo caso perché fanno riferimento all'interazione degli interrupt con l'esecuzione del codice in Arduino.
Difatti NoInterrupts()/Interrupts() sono in pratica la versione Arduino della funzione ATOMIC_BLOCK delle librerie AVR che segnano un blocco di codice come non interrompibile da un interrupt. In pratica, prima dell'esecuzione di un determinato blocco di codice, viene messo a 0 il registro SREG, che è quello che abilita/disabilita l'esecuzione delle richieste di interrupt, così da esser sicuro che un particolare algoritmo possa essere eseguito tutto senza interruzioni dall'esterno.
Il caso di Janos è particolare perché lui chiede cosa succede al codice contenuto in una funzione di interrupt nel momento in cui un altro interrupt si solleva. In questo caso viene sempre in aiuto la libreria AVR che dice, relativamente all'esecuzione di un interrupt mediante ISR
Identical to an ISR with no attributes specified. Global interrupts are initially disabled by the AVR hardware when entering the ISR, without the compiler modifying this state.
Quando viene scritta una funzione di interrupt si usa normalmente ISR(vettore_int), che, senza parametri aggiuntivi, è equivalente a ISR_BLOCK che, come vedi, dice chiaramente che gli interrupt globali vengono disattivati prima di entrare nel blocco di codice ISR, quindi io capisco che durante l'esecuzione di un interrupt non può esserne eseguito un altro.
PS:
difatti, se ti ricordi, si dice che non si può usare il delay() all'interno di un interrupt. Perché il delay() è una funzione basata sull'INT0 e siccome all'interno di un interrupt sono disattivati gli altri interrupt, anche il delay non avanza.
leo72:
Scusami Uwe ma i link che hai postato non riguardano questo caso perché fanno riferimento all'interazione degli interrupt con l'esecuzione del codice in Arduino.
Difatti NoInterrupts()/Interrupts() sono in pratica la versione Arduino della funzione ATOMIC_BLOCK delle librerie AVR che segnano un blocco di codice come non interrompibile da un interrupt. In pratica, prima dell'esecuzione di un determinato blocco di codice, viene messo a 0 il registro SREG, che è quello che abilita/disabilita l'esecuzione delle richieste di interrupt, così da esser sicuro che un particolare algoritmo possa essere eseguito tutto senza interruzioni dall'esterno.
Il caso di Janos è particolare perché lui chiede cosa succede al codice contenuto in una funzione di interrupt nel momento in cui un altro interrupt si solleva. In questo caso viene sempre in aiuto la libreria AVR che dice, relativamente all'esecuzione di un interrupt mediante ISR
Identical to an ISR with no attributes specified. Global interrupts are initially disabled by the AVR hardware when entering the ISR, without the compiler modifying this state.
Quando viene scritta una funzione di interrupt si usa normalmente ISR(vettore_int), che, senza parametri aggiuntivi, è equivalente a ISR_BLOCK che, come vedi, dice chiaramente che gli interrupt globali vengono disattivati prima di entrare nel blocco di codice ISR, quindi io capisco che durante l'esecuzione di un interrupt non può esserne eseguito un altro.
PS:
difatti, se ti ricordi, si dice che non si può usare il delay() all'interno di un interrupt. Perché il delay() è una funzione basata sull'INT0 e siccome all'interno di un interrupt sono disattivati gli altri interrupt, anche il delay non avanza.
Se é cosí l'interrupt che viene durante l' esecuzione della funzione interrupt va perso.
ciao Uwe
Non va perso perché esiste un registro dei micro (vale per qualunque micro, dagli Atmega agli Attiny) in cui sono registrati gli interrupt che si sono scatenati. Fino a quando il micro non esegue la routine relativa all'interrupt chiamante, il relativo bit nel registro non viene azzerato. Ma finché ciò non è fatto, l'interrupt è "prenotato".
In caso di interrupt per cambiamento di stato su un pin, viene anche registrato il pin in un altro registro apposito.
Insomma, si tratta di una procedura complessa. Non a caso la gestione degli interrupt è un po' un casino...
Allora non ho capito tanto.
Praticamente durante l' esecuzione di un interrupt ci sono 2 registri che memorizzano che UN interrupt é prenotato e la fonte del interrupt. Un terzo interrupt pendente allora viene perso?
Ciao Uwe
Si di IRQ come vengono chiamati ne esistono di vari tipi e spesso hanno una priorità da esempio nei Pc esistono molti IRQ sia software che hardware ma si distinguono dalla loro priorità ossia quando viene rilevato una richiesta di interruzione che ha un codice (che gli viene assegnato), tali codici sono contenuti in una sorte di tabella che decide la priorità (preprogrammata) e se far proseguire quello che sta facendo o salvare tutto in memoria nello "stack" ed eseguire l'istruzione di priorità assegnata al quel IRQ. Gli IRQ si distinguono mascherabili o non mascerabili, ossia se sono mascherabili tramite software o hardware li si rende insensibili al processore, quelli non mascherabili lo dice la parola stessa vendono eseguiti ad esempio parlando di Pc se il controller del disco fisso lancia un IRQ ma a si deve rinfrescare la memoria RAM essendo un IRQ non mascherabile salva tutto nello "satck" (puntori e dati) in memoria, e parte il refresh totale della memoria RAM che è di priorità assoluta, altrimenti che succede niente di grave solo la perdita di tutti i dati presenti in memoria che vuoi che sia, operazione che dura circa dai 40 ai 70ns (dipende dalla memoria e dal processore in uso) una periferica può aspettare...e come!
Gli IRQ non mascherabili a parte il refresh della RAM per un pc sono dovuti a allarmi o controlli tipo alimentazione, timer, surriscaldamento del processore, ecc.
Nel caso di Arduino devo ancora conoscere la sua struttura....ma ci arriverò prima o poi
Ciao.....
L'applicazione che devo fare è di leggere, da un nostro di carta in movimento, delle tacche (Optical mark recognition - Wikipedia).
Il fatto è che ci sono due sensori che leggono tacche posizionate in posti diversi della pagina, ma molto spesso sono poste alla stessa altezza e quindi arrivano gli interrupt insieme... Inoltre devo gestire anche il conteggio di un encoder attraverso altri due ingressi a interrupt....
Ciao, non conosco ancora Arduino per darti una risposta precisa, ma potresti dare dei ritardi di lettura al micro usando dei latch (flipflop D) o "bufer" che ogni uno salva il dato del suo sensore e dando poi una priorità alla lettura al micro senza perdere il dato stesso ossia prendendolo uno alla vota (prima legge il latch A e poi il B ad esempio), mantenendo il dato nel lacth da li puoi prendere i dato che ti serve per il contatore o altre cose che ti servono.
si potrebbe anche far rilevare un solo IRQ con una opportuna logica o porte logiche che condiziona il micro a leggere i dati una determinata zona di memoria di entrambi i sensori i quali sensori mettono in un indirizzo di memoria specifico il loro dato ( se uno non è attivo e l'altro interdetto o vice versa o entrambi attivi o interdetti) un po come avviene normalmente nella gestione degli IRQ praticamente mappare gli ingressi in memoria.
sensore A -----
or ------ interput
sensore B -----
sempre al sensore A al lacth o memoria
sempre al sensore B al latch o memoria
dalla memoria o lacth A e B al contatore o altro......
Facilmente ho fatto un po di casino ma spero che tu possa capire cosa intendo.....
Sono fuso scusami ,Interrupt e non interput ..... e "sempre (al) dal sensore A al lacth o memoria
sempre (al) dal sensore B al latch o memoria" or si intende porta or o or logico......
Comunque non so se si può mappare in memoria gli ingressi o le uscite....
Ciao
Non mi posso permettere ritardi, proprio per questo uso gli interrupt. Pensa che devo leggere tacche di mezzo millimetro su carta che scorre a 4m/sec, e nel momento in cui ho l'interrupt devo memorizzare il valore del contatore dell'encoder.
Cioè in 10 secondi fai fuori 40 mt di carta, oppure c'è un errore ed è 4cm/s.
Deduco che la carta ha sia a destra che a sinistra dei fori allineati e lo spazio minimo tra questi e di 0.5 mm.
I fori quanto saranno grandi?
Poi in più è possibile che il foro a destra coincida con quello a sinistra.
devi attivare entrambe gli interrupt e quando entri nella ISR_(A) fai un test su B se positivo azzeri la richiesta di interrupt scatenata da B, se entra prima in B fai la cosa contraria. Questo da per sconstato che le richieste di interrupt avvengano a distanza minima di 4 cicli di clock, questo è il tempo che che impiega il micro per saltare alla ISR.
Dovresti anche darci più info sul aggegio che stai sviluppando, una foto della carta, che sensori usati per rilevare i fori ecc.
Cioè in 10 secondi fai fuori 40 mt di carta, oppure c'è un errore ed è 4cm/s.
Deduco che la carta ha sia a destra che a sinistra dei fori allineati e lo spazio minimo tra questi e di 0.5 mm.
I fori quanto saranno grandi?
Poi in più è possibile che il foro a destra coincida con quello a sinistra.
devi attivare entrambe gli interrupt e quando entri nella ISR_(A) fai un test su B se positivo azzeri la richiesta di interrupt scatenata da B, se entra prima in B fai la cosa contraria. Questo da per sconstato che le richieste di interrupt avvengano a distanza minima di 4 cicli di clock, questo è il tempo che che impiega il micro per saltare alla ISR.
Dovresti anche darci più info sul aggegio che stai sviluppando, una foto della carta, che sensori usati per rilevare i fori ecc.
Ciao
direi che serve la velocità reale del nasto, del sensore e vedere se nelle tempistiche arduino ce la fa.
leo72:
Non va perso perché esiste un registro dei micro (vale per qualunque micro, dagli Atmega agli Attiny) in cui sono registrati gli interrupt che si sono scatenati. Fino a quando il micro non esegue la routine relativa all'interrupt chiamante, il relativo bit nel registro non viene azzerato. Ma finché ciò non è fatto, l'interrupt è "prenotato".
In caso di interrupt per cambiamento di stato su un pin, viene anche registrato il pin in un altro registro apposito.
Insomma, si tratta di una procedura complessa. Non a caso la gestione degli interrupt è un po' un casino...
scusa ma quanti interrupt possono essere messi in coda? esiste un riferimento sulla bibbia dell'atmega (il datasheet?)
E' il perforatore dinamico. Le tacche che devo leggere non possono essere più piccole di 0,5mm e indicativamente distano fra loro 5mm. Quello che attiva o no la perforazione è una data combinazione di queste tacche (che sono trattini orizzontali stampati sulla carta).
Considera che devo essere in grado di lavorare carta a 300mt/min (al momento non si riescono a raggiungere quelle velocità, si arriva a 210mt/min ma c'è il progetto di arrivare a 250mt/min, però voglio starci largo).
Con la funzione micros() monitorizzo il tempo ciclo della funzione loop e siamo intorno ai 350us.
A banco l'abbiamo provato e funziona, però c'era l'encoder e un solo lettore di tacche. Non vorrei che con due inizino i casini.
300mt/m, e distanza tra inizio foro e successivo (se entrambi ad "uno") di 0,5mm + 5mm ovvero 0.0055mt
consideriamo una striscia di soli uno logici (o buchi), sono 300/0.0055=55000 buchi al minuto circa, o 909buchi al secondo, o 0.9buchi al millisecodo, quindi ci stai dentro alla grande...
a te i conti per vedere a quanto potresti arrivare
direi anche che non avrai MAI sovrapposizioni di interrupt in questo caso, dato che tra un buco e l'altro passa quasi un millisecondo (e gli interrupt, se tenuti snelli, non durano più di qualche decina di us), e che anzi, puoi pure NON usare interrupt, anche se una soluzione che li usa è molto più pulita!
comunque se gli interrupt si annidiavano e a voi interessava pure la posizione del "buco", diventava un problema perchè elaboravi prima il buco che veniva dopo, in oltre bisognerebbe fare attenzione perchè una sfilza di interrupt annidiati manderebbe in overflow lo stack
Non sono buchi, sono tacche stampate in nero... 8)
Il mio dubbio non è se c'è la possibilità che mi arrivino due interrupt sullo stesso canale ma due contemporanei da due canali diversi. Il sistema avrà 2 lettori di tacca e c'è molto spesso si troveranno a leggere in contemporanea.
P.S. Nell'interrupt ho messo proprio il minimo indispensabile, giusto il copiare il valore del contatore e attivare una variabile boolean, poi il resto viene eseguito con "calma" nel loop().