Contatore/Timer programmabile CTC
Z80
Gerarchia di priorità delle interruzioni
Si tratta di un contatore programmabile utilizzabile dallo Z80 per misurare intervalli di tempo attraverso il conteggio del clock del sistema , oppure eventi esterni (uscite di sensori, ecc.) attraverso le linee clock/trigger (vedi piedinatura). Un CTC contiene al suo interno, quattro contatori diversi numerati da 0 ad 1.
IL chip deve poter essere interfacciato con il microprocessore per cui presenta otto piedini per poter essere collegato al bus dati. Come ogni dispositivo collegabile al bus di una scheda a microprocessore, deve avere uscite di tipo three state, per cui necessita di un segnale di abilitazione da parte del microprocessore (CE\ Chip Enable). Al contatore arriva soltanto il segnale RD\: quando tale segnale è a zero , il microprocessore vuole leggere un dato dalla periferica, quando il segnale è ad uno, il microprocessore vuole leggere. Il CTC può generare interruzioni per cui presenta una linea INT\ che va alla linea omonima d’ingresso del microprocessore. Tale dispositivo programmabile è progettato per lavorare con le modalità di gestione delle interruzioni dello Z80, per cui necessita degli ingressi M1 e IORQ, in modo da sapere, dopo aver generato un’interruzione, quando il microprocessore esegue il ciclo di riconoscimento delle interruzioni. Il CTC può essere collegato in daisy chain con altri dispositivi per cui presenta l’ingresso IEI (interrupt enable input) e l’uscita IEO (interrupt enable output). Abbiamo accennato al fatto che all’interno del dispositivo sono presenti quattro contatori che possono essere programmati indipendentemente l’uno dall’altro. Occorre allora sapere a quale contatore il microprocessore voglia fare riferimento. Questa funzione è assolta dai piedini CS1 e CS0, secondo la seguente tabella
CS1 |
CS0 |
SIGNIFICATO |
0 |
0 |
CONTATORE 0 |
0 |
1 |
CONTATORE 1 |
1 |
0 |
CONTATORE 2 |
1 |
1 |
CONTATORE 3 |
Ogni contatore presenta un ingresso CLK/TRG (clock/trigger) che serve se il contatore funziona da contatore di eventi: il segnale associato all’evento da contare va inviato a tale ingresso. Ogni contatore presenta, poi, un segnale di uscita denominato ZC/TO (zero count/time out) che serve a segnalare all’esterno che il contatore ha terminato il suo conteggio. Da notare che il quarto contatore (il contatore tre) non ha segnale di uscita per cui può segnalare che ha terminato il suo conteggio soltanto tramite la generazione di un’interruzione. Il piedino di RESET esegue il reset dei contatori. Oltre all’azzeramento dei contatori e al blocco dei conteggi eventualmente in corso, le linee del CTC vengono poste in three-state e viene disabilitata la generazione delle interruzioni.
La struttura interna di un CTC è descritta nella figura seguente
la struttura di ogni singolo canale o contatore è la seguente
si può notare la presenza di un registro di controllo canale che conterrà la channel control word (vedi più avanti) la parola di controllo, cioè, che specifica i dettagli del funzionamento impostato per il contatore. Esiste poi un registro della costante di tempo destinato a contenere la costante di tempo cioè il numero che il contatore deve contare. Il nucleo del contatore è un contatore down a 8 bit. Il segnale ZC/TO è l’uscita di questo contatore down. Il segnale clock/trigger va direttamente al down counter mentre il segnale di clock di sistema non va direttamente al down counter ma passa per un prescaler: il senso di questa organizzazione apparirà chiaro quando parleremo delle modalità di funzionamento dei contatori.
Quando è impostato in modo timer un contatore assolve al compito di misurare intervalli di tempo mediante il conteggio degli impulsi di clock del sistema. Ricordiamo che tali impulsi non vanno direttamente al contatore ma ad un prescaler che è una sorta di contatore che può contenere soltanto i valori 16 o 256. se ad esempio, il prescaler è impostato a 16, esso conta 16 impulsi di clock ed invia un segnale al down counter. Dunque il numero contenuto nel down counter decresce di un’unità ogni 16 impulsi di clock. Se, ad esempio, nel down counter è impostata la costante di tempo 200, esso giungerà a fine conteggio dopo 16*200=3200 impulsi del clock del sistema. Se il sistema opera ad una frequenza, ad esempio, di 1 MHz, il periodo di clock è di 1 microsecondo, per cui il contatore, segnalando di aver terminato il conteggio, segnala che è trascorso un intervallo di tempo pari a 3200 microsecondi. I contatori 0, 1, 2 segnalano di essere arrivati a zero con un impulso di durata pari ad un ciclo di clock sull’uscita zerocount/timeout e, se sono abilitati, generano un’interruzione. Il contatore numero 3, non disponendo di un’uscita può generare soltanto un’interruzione. Quando il contatore termina il conteggio, la costante di tempo, conservata nel registro della costante di tempo viene caricata nuovamente nel contatore ed il conteggio riprende automaticamente.
Il contatore può essere programmato per partire appena si scrive la costante di tempo (partenza software) o su impulso dell’ingresso CK/TG che funziona da trigger (partenza hardware)
Dato un clock con frequenza di 1 megahertz e quindi periodo di 1 microsecondo, il massimo intervallo di tempo che un contatore del CTC può misurare si ottiene impostando il prescaler a 256 ed il contatore a 256
T=TCK*P*N=1μs*256*256=65536μs.
Gli intervalli di tempo
misurabili mediante CTC si possono aumentare ponendo più contatori in cascata
(vedi figura)
Il contatore zero del
primo CTC funziona da timer e conta gli impulsi di clock del sistema. Tutti gli
altri contatori funzionano da counter. L’uscita ZC/TO del contatore zero
rappresenta l’ingresso CK/TG del contatore 1. Il contatore zero invierà un
impulso al contatore uno ogni volta che avrà completato il suo conteggio, cioè
ogni 65536 μs. Supponendo che anche nel contatore uno sia caricato il
numero 256, si ha che esso giungerà a zero dopo un tempo pari a
T
= 65536μs*256 = 16777216 μs ~ 16.78 secondi
L’uscita ZC/TO del
contatore uno può essere inviata all’ingresso CK/TG del contatore due. Se la
costante di tempo di questo contatore è pari a 256, il contatore due arriverà a
zero dopo un intervallo di tempo pari a
T = 16.78*256 = 4295.68
secondi ~ 71 minuti
Collegando il contatore
due al contatore tre, quest’ultimo (ammesso che la sua costante di tempo sia
pari a 256) genera un’interruzione dopo un tempo
T = 256*71 = 18176 minuti
~ 303 ore.
Come si vede dalla figura
possiamo collegare più CTC in cascata e proseguire all’infinito.
In tale modo il contatore
deconta i fronti attivi del segnale CK/TG. In tale modalità possiamo usare il
CTC come contatore di eventi. Nell’esempio di figura il CTC conta i pacchi che
transitano sul nastro trasportatore. Quando un pacco attraversa il fascio
prodotto da una coppia di fotocellule, interrompendola, viene generato un
impulso inviato all’ingresso CK/TG del contatore del CTC.
gli eventi contati sono
naturalmente asincroni rispetto ai fronti del clock. Come si può vedere dalla
figura seguente, essi vengono registrati dal contatore in corrispondenza del
primo fronte di salita successivo del clock
ci sono, però, delle
specifiche da rispettare:
innanzitutto
l’impulso generato dall’evento deve avere una durata minima (200 nanosecondi
nella versione base del CTC),
il
fronte di salita del clock deve distare dal fronte attivo dell’evento almeno
210 nanosecondi, altrimenti esso verrà registrato sul fronte successivo del
clock (vedi figura)
inoltre
se gli eventi si susseguono troppo rapidamente il contatore non è in grado
registrarli, essi devono essere distanti almeno due cicli di clock (vedi figura
seguente)
Per programmare un CTC
occorre inviare al singolo CTC
una
channel control word (parola di controllo canale)
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
Dove
§
D0 è sempre pari ad 1
§
D1 ha significato nel
caso il contatore, all’atto della programmazione, stia già effettuando un conteggio: se il bit è pari a zero, la scrittura della nuova
parola di controllo non interrompe il conteggio in atto, se esso è pari ad 1,
la nuova channel control word determina un reset software del contatore, il suo
contenuto si azzera e per riprendere a funzionare il contatore deve attendere
una nuova costante di tempo
§
D2 uguale a zero indica
che non segue una costante di tempo per cui può essere utilizzato quando si
vuole riprogrammare il contatore senza modificare la costante di tempo,;: se il
bit è pari ad 1, indica che seguirà una costante di tempo per cui il canale
interpreterà il prossimo byte in arrivo come il numero da contare
§
D4 a zero indica che il
fronte attivo dell’ingresso clock/trigger è quello di discesa, se il bit è ad
uno indica che il fronte attivo è quello di salita
§
D6 sceglie la modalità
di funzionamento: se è a zero impone al contatore di funzionare come timer, se
è ad uno impone il funzionamento come counter
§
D7 pari a zero
disabilita la generazione di interruzioni, se è pari ad uno abilita la
generazione di interruzioni
§
D3 ha senso soltanto se
si vuole programmare il contatore in modalità timer (se si vuole programmarlo
in modalità counter il suo valore è indifferente): esso determina se il
conteggio si avvia con partenza software (bit a zero) o con partenza hardware
(bit a uno)
§
D5 ha senso soltanto se
si vuole programmare il contatore in modalità timer (se si vuole programmarlo
in modalità counter il suo valore è indifferente): esso imposta il valore del
prescaler a 16 (bit a zero) o a 256 (bit a 1)
Alla
channel control word segue (se il suo bit D2 è ad 1) la costante di tempo (time
constant word) che può valere da 0 a 255: va rilevato che lo 0 viene
interpretato come il numero 256
Al
contatore va inviato infine la interrupt control word, cioè la parte bassa del
vettore delle interruzioni, il byte che il contatore deve inviare al
microprocessore quando quest’ultimo esegue il ciclo di riconoscimento relativo
a un’interruzione del contatore. Nel caso del CTC vi è una particolarità: il
bit D0 è sempre a zero come ogni interrupt control word ma i bit D1 e D2 non
possono essere fissati a piacere in quanto il CTC vi inserisce un valore
corrispondente al canale in considerazione: se stiamo programmando il contatore
zero i due bit verranno posti automaticamente a 00, se stiamo programmando il
contatore 1 i due bit verranno posti a 01, se stiamo programmando il contatore
due avremo 10, se stiamo programmando il contatore tre avremo 11.
Il
particolare è molto importante. Supponiamo ad esempio, che la tabella dei
vettori delle interruzioni sia posta in memoria a partire dall’indirizzo 1A00,
e supponiamo di volere porre a questo indirizzo e a quello successivo
l’indirizzo della routine che gestisce l’interruzione del contatore due.
Il
contatore zero, in caso di interruzione, dovrebbe restituire dunque il byte 00.
Ne deriva che, quando si programma il contatore due, gli si dovrebbe inviare
come interrupt vector word, il byte 00H ma il CTC sostituisce automaticamente i
bit 1 e 2 con 10 per cui il byte diventa il seguente
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
pari
a 04H. il microprocessore, dunque, in caso di interruzioni da parte del
contatore due, non sarebbe in grado di recuperare l’indirizzo giusto della
routine che gestisce l’interruzione del contatore poiché andrebbe a leggere
nella tabella dei vettori delle interruzioni all’indirizzo 1A04 e non 1A00.
I quattro canali o
contatori del CTC sono in daisy chain fra loro per cui il contatore zero ha
priorità più alta rispetto al contatore 1, questo rispetto al contatore 2 e
così via.
Un esempio di
interfacciamento è quello della figura seguente.
Per attivare il decoder si
deve avere
Pin |
Valore |
A4 |
1 |
A3 |
0 |
A2 |
0 |
Per attivare il CTC si
deve attivare l’uscita 1 del decoder per cui deve essere
Pin |
Valore |
A7 |
0 |
A6 |
1 |
A5 |
0 |
I piedini A1 e
A0 individuano il contatore all’interno del CTC per cui gli indirizzi
diventano
A7 |
A6 |
A5 |
A4 |
A3 |
A2 |
A1 |
A0 |
Indirizzo |
Contatore |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
50h |
Contatore
0 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
1 |
51h |
Contatore
1 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
0 |
52h |
Contatore
2 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
0 |
53h |
Contatore
3 |