Volevo provare la SRAM AS6C4008
con Arduino e per farlo avrei potuto banalmente scrivere un po' di dati
nelle locazioni della RAM per poi rileggerle ma ho fatto qualcosa di
più; ho progettato un sistema che memorizza nella RAM un ciclo di un segnale esterno e poi la legge
in loop continuo per ricreare in uscita lo stesso segnale con la
stessa ampiezza e frequenza, in più il segnale memorizzato nella RAM viene sincronizzato con quello esterno.
Il
segnale del quale si
memorizza un ciclo può avere qualsiasi forma, inoltre una volta posto
in uscita, per sincronizzarlo con
quello esterno, è necessario che i due abbiano la stessa frequenza, non
ha importanza invece la forma d'onda e l'ampiezza (quest'ultima entro
certi limiti, infatti essa non può scendere sotto i 200 mVpp valore
minimo necessario per poter far funzionare il comparatore correttamente).
Ad esempio nella foto sottostante è visualizzato un
segnale memorizzato in RAM di forma triangolare, una volta posto in
uscita ho cambiato la forma d'onda del segnale esterno da triangolare a
sinusoidale e come si vede i due rimangono comunque sincronizzati
tra loro.
La
foto successiva mostra un segnale memorizzato sinusoidale e quello
esterno al quale non è stata cambiata la forma d'onda.
Di
seguito un segnale memorizzato di forma sinusoidale e quello esterno al
quale è stata cambiata la forma d'onda da sinusoidale a quadrata..
Come funziona? Fare riferimento allo schema seguente.
Il
segnale esterno deve avere le seguenti caratteristiche, ampiezza
5 Vpp e offset 2.5 V, l'offset viene fornito dal mio generatore di
segnali, se non disponete di un generatore di segnali che possa fornire
l'offset dovrete polarizzare il segnale tramite un partitore resistivo.
Questa
polarizzazione serve per far funzionare correttamente l'ADC di Arduino
(pin A0). Il segnale oltre ad arrivare al pin A0 deve essere anche
letto sulla porta digitale al pin 21 e dato che il segnale può
avere qualsiasi forma e dato che Arduino accetta sulle porte digitali
solo segnali di forma quadrata occorre farlo passare per un comparatore
(IC1). Prima di giungere al pin 21, però, occorre
diminuirne la sua
frequenza della metà tramite flip - flop IC2, vedremo il perché più avanti.
La
situazione è raffigurata nella seguente figura dove sono rappresentate
le varie tensioni sui punti del circuito indicati da numeri. In questo
esempio è stato usato un segnale esterno di forma sinusoidale.
Il
segnale memorizzato una volta messo in uscita va convertito in
analogico e questo compito lo svolge il DAC IC3. Analizziamo
adesso il programma.
Salto a piè pari le definizioni, le
dichiarazioni, il void setup() per andare direttamente al cuore
del programma ovvero al void loop().
La prima istruzione che si
incontra alla riga 29 attende che il segnale al pin 21 (segnale 3 in
Fig 1) sia alto. Siccome si deve memorizzare un ciclo completo
del segnale esterno occorre avere un riferimento per l'inizio della
memorizzazione e per la sua durata, questo riferimento lo da il segnale
all'uscita del flip - flop che ha periodo doppio del segnale,
ovvero in metà periodo del segnale 3 (solo quando il segnale 3 è alto)
viene campionato un ciclo completo del segnale 1 (vedi Fig
1).
Appena il segnale 3 va alto (con un leggero ritardo di tempo in
realtà) il programma esce dal while e arriva alla riga 30, qui
c'è una istruzione "for" che ripete il ciclo contenuto nel suo corpo
per la memorizzazione completa del ciclo del segnale 1, ad ogni
interazione incrementa il registro "address" che contiene
l'indirizzo della locazione della memoria, il registro alla partenza
della conversione è azzerato.
La prima istruzione che si
incontra dolo la "for" è una "if", fintanto che il segnale 3 è alto
l'istruzione "if" non esegue la istruzione contenuta nel suo
corpo e il programma va alla istruzione alla riga 34 che
assieme alle quelle successive alle righe 35 e 36 pone sul bus
indirizzi della RAM l'indirizzo attuale. Essendo un indirizzo a 19 bit
occorrono tre porte a 8 bit, dell'ultima però, la C, si usano
solo 3 bit., occorre fare uno spostamento di bit per la porta B e per
la porta C affinché possano essere messi in uscita tutti i bit di
ordine superiore.
Nelle righe 37 e 38 viene predisposta la RAM a
ricevere il dato da memorizzare, in ordine deve andare basso prima il
segnale CE e poi WE, vedi foto sotto:
Alla
riga 39 il dato viene letto dal ADC interno ad Arduino e posto
sulla porta L scrivendolo sulla RAM, si moltiplica il dato
convertito per 0.25 per adattare una conversione a 10 bit dell' ADC di
Arduino agli 8 bit del DAC esterno.
Subito dopo (riga 40 e 41) viene disabilitata la scrittura in RAM.
Il
ciclo di scrittura seguita finché il segnale 3 va basso, quando questo
accade la "if" alla riga 32 esegue le istruzioni presenti nel suo
corpo, nello specifico carica il valore 2 nel registro "i" e il
programma esce dal loop della "for"; Il ciclo del segnale esterno è
stato memorizzato nella RAM.
Alla riga 43 viene predisposta la porta
L come ingresso, le successive due istruzioni, alla riga 44
e 45 predispongono la RAM alla lettura continua del dato al solo cambio
dell'indirizzo, ovvero non occorrono altri controlli, vedi figura sotto.
Alla
riga 46 il programma setta il registro address a zero, ovvero la RAM
inizierà ad essere letta dalla sua prima locazione. Alla riga 47 pone
il valore 1 nel registro "i", dopo vedremo a che serve questo registro.
Alla
riga 48 l'istruzione "while" attende che il livello del segnale 3 vada
alto, questo serve per sincronizzare il momento nel quale il segnale 3
va alto a quello nel quale inizia la lettura nella RAM.
Alla riga 49
c'è un'altra istruzione "while", questa crea un loop infinito perché la
RAM, da questo momento in poi, verrà continuamente letta senza alcuna
interruzione.
Alla riga 51 troviamo l'istruzione "if" che confronta
il livello del segnale 3 con il contenuto del registro "i". Come
funziona?.
Ammettiamo che il segnale 3 vada alto, la "if" controlla
il livello del segnale 3 con il contenuto del registro "i" che
all'inizio il programma ha impostato a 1. La "if" esegue il suo corpo
dove sono contenute la serie di istruzioni per leggere la RAM. Quando
il livello del segnale 3 va a zero il programma esegue la "else" nel
cui corpo ci sono le istruzioni per azzerare il registro "address" ed
il contenuto del registro "i".
Al prossimo ciclo la "if"
confronta il livello del segnale 3 che ora è basso con il contenuto del
registro "i" anch'esso basso ed esegue le istruzioni nel suo corpo, in
poche parole la lettura non si ferma mai ma in questo modo il segnale
esterno sincronizza quello memorizzato in RAM.
Vedi seguente figura.
Le
istruzioni contenute nel corpo della "if" sono simili a quelle
già viste prima, ci sono gli indirizzi che vengono posti sulle porte A,
B e C e l'incremento del registro "address", in più c'è una istruzione
di ritardo in microsecondi, questa serve per far si che il segnale
memorizzato in RAM venga posto in uscita con la stessa frequenza di
quello esterno. Ho trovato il valore giusto immettendo vari valori fino
all'ottenimento del giusto valore che è contenuto nel registro "uS".
Qui sotto i pin della RAM e successivamente la schedina fatta in casa dove l'ho montata.
Qui trovate il file del programma.
Ciao Fabio