CHANGE interrupt

Sto sperimentando metodi per leggere in maniera affidabile un segnale "veloce" e sto cercando di utilizzare un interrupt CHANGE sul pin 2. La domanda è: c'è un modo hardware per risalire, nella ISR, a quale tipo di change c'è stato? Intendo LOW -> HIGH o viceversa. Perché se il segnale è veloce (parlo di us), è possibile che ora che entro nella ISR e leggo la porta (dai registri), il segnale sia già cambiato!

Nel datasheet non mi pare di scorgere niente :confused:.

Di queste cose non ne so molto … ma se ora che entri nella ISR il segnale potrebbe essere cambiato, non fai prima a fare due chiamate consecutive allo stesso interrupt, una con rising ed una con falling (ognuna ovviamente con la sua ISR), in modo da sapere con certezza qual’e’ stato il cambio ? … (almeno, cosi a logica, non mi viene in mente altro)

Sarebbe bello ma non mi risulta si possano associare 2 funzioni allo stesso interrupt con trigger diversi. L'interrupt è unico, hai solo la possibilità di decidere quando scatta.

Sì potrebbe continuare a switcharlo tra RISING e FALLING dentro alla ISR, ma è un bel casino, l'ho già provato una volta.

Non mi sembra ci sia nulla ...
... probabilmente devi usare un qualche HW esterno per memorizzare il cambiamento sino ad un tuo reset.

Guglielmo

Ed usare due pin di interrupt (avendoli disponibili) assegnando ad uno rising ed all'altro falling ? ...

O sto dicendo una ca...volata ?

EDIT: collegati in parallelo, ovviamente (con tutti sti errori 502 e 504, mi ero dimenticato di aggiungerlo)

A quello avevo pensato anch'io, ma mi sembra una cosa talmente "sporca" che la terrei proprio come ultima soluzione :D.

Ora provo con una ISR naked.

Prova un PM a san @Astro :grin:

Per ora sono passato a una ISR “pura” AVR-style (no attachInterrupt()), ho ottimizzato a manetta il codice, lasciando nella ISR solo la lettura delle porte e il minimo di elaborazione necessario (la ISR deve eseguire una macchina a stati per capire in quale di 3 variabili salvare la lettura) e ci sto quasi dentro. La speranza è che, togliendo il codice che mi permette di vedere con l’analizzatore di stati logici il momento del campionamento, il timing sia sufficiente. Stasera ulteriori test :).

SukkoPera:
... ma mi sembra una cosa talmente "sporca" ...

... siamo in Italia, qui le cose "sporche" sono normali ... montecitterio docet :stuck_out_tongue: :smiley:

non vi è modo se non leggere lo stato della porta che comunque impega 0.5us

Eh, il problema è che il segnale dura 3-4 us, se ce ne metto già 2 a reagire all'interrupt... :frowning:

se dichiari l'interrupt naked e memorizzi il registro della porta su GPIOR salvi lo stato in meno di un us, dopo puoi fare ciò che ti pare e piace

Hai ragione, ho omesso di dire una cosa: con le varie ottimizzazioni di cui sopra riesco a leggere il valore della porta in tempo utile. Il problema ora è che ci sono "parecchie" cose da fare e sforo i 3 us.

C'è tempo solo per una 20ina di istruzioni e, ad essere onesti un po' di tempo viene perso nell'implementazione dello switch che comanda la macchina a stati: leggendo in giro pare che GCC dovrebbe generare una jump table, ma apparentemente mi trovo del codice abbastanza schifoso che fa una serie di jump alla rinfusa. Devo approfondire questa cosa.

aspetta un attimo, l'interrupt avviene ogni 3/4us?
se fosse così la mcu non ha tempo per fare altro l'unica soluzione è di passare ad una mcu più potente tipo una stm32f103

Più o meno, stasera posto qualche "disegno" :D.

troppo poco tempo, non so cosa deve fare il tuo codice ma devi valutare di scrivere tutto in Assembly altamente ottimizzato per avere qualche speranza di riuscire nel tuo intento.
Devi anche valutare il tempo di risposta dell'interrupt, perché in questo caso specifico potrebbe essere meglio non utilizzarlo.

[edit]
potresti valutare la sostituzione del quarzo con uno da 20MHZ per racimolare un briciolo di performance
comunque passare ad una bluepill costa 2.5€...
[/edit]

L’interrupt deve solo salvare PIND in una di 3 variabili globali, che vengono poi analizzate ed utilizzate altrove. Per capire quale delle 3 usare ad ogni invocazione deve eseguire una semplice macchina a stati guidata da un bit della porta stessa. Purtroppo serve anche qualche check perché la sequenza può essere interrotta da eventi “collaterali”.

Comunque il codice generato al momento non è così male, a parte la jump table mal gestita.

Ah, per la cronaca mi sono accorto che in Arduino 1.6.11 non funzionano più le variabili globali register :/.

Ho già la bluepill, teensy, Arduino Due e altre schede più veloci, ma vorrei cercare di rimanere su Arduino “classico” per ragioni di costi e diffusione, il progetto in questione è un’estensione di MegaDrive++ (vedi firma) per la compatibilità col joypad a 6 tasti.

Sukko, dai retta ... passa alla Teensy 3.6 (180 MHz ARM Cortex-M4) :slight_smile:

Guglielmo

spiega meglio, magari si trova qualche escamotage.
comunque la matematica non è un'opinione.
Diciamo che impieghi solo 1.5us per quell'interrupt il restante codice avrà a disposizione solo 1.5us prima di essere nuovamente bloccato.
Non mi sembra la soluzione migliore, io proverei in maniera diversa.

P.S. io non butterei i soldi in una scheda closed come la teensy ma aspetterei l'uscita della nuova Arduino octo (o come diavolo si chiama) oppure prenderei sempre una Cortex M4 ma Open, tipo le stm32f4 che si trovano sui 10€

È a 3.3V e questo è già un problema, ma poi in generale non posso proporre una mod per MegaDrive che costi più di un MegaDrive usato :D.