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!
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.
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 :).
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
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.
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€