Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : C - les CIA
(Article écrit par Laurent Faillie et extrait d'Amiga News - juin 1994)
|
|
Aujourd'hui, nous allons continuer à explorer quelques points méconnus de l'Amiga : les CIA.
CIA 8520 et les timers (minuterie)
Le sujet du jour concerne les CIA 8520 et les timers en particulier :
la suite de l'article risque de paraître très technique pour beaucoup de
lecteurs car des connaissances en périphériques est nécessaire sinon un triple
Amiga News ne suffirait pas. Pour les connaisseurs donc...
Pour les applications courantes, il y a bien sûr le timer.device qui nous
permet de créer des attentes (voir les fonctions Delay() et Sleep()),
ou des chiens de garde. Comme toujours, du fait de la nature multitâche de
la machine, ce devise n'est pas suffisamment précis pour certaines applications
pointues comme les numérisations ou les échantillonnages. Heureusement,
nous disposons de plusieurs mécanismes qui permettent de générer des interruptions
de manière très précise :
- L'interruption VBL que nous avons déjà abordée avec les
manettes. Son utilisation est
très simple, elle se répète tous les 50e de seconde mais on ne peut
malheureusement pas la synchroniser par nous-même.
- Pour les cas de figure où le VBL ne suffit pas, nous disposons de quatre
timers contenus dans les CIA et qui sont totalement paramétrables.
Avant tout, étudions le mécanisme de gestion des interruptions qui est très
puissant sur notre machine et qui rentrent dans deux catégories :
- Les handlers (gestionnaires) : l'interruption ne déclenche l'exécution que
d'une seule routine, très spécifique. C'est le cas de celles qui se déclenchent
lorsqu'un échantillon est fini de jouer et où seul l'audio.device est concerné.
- Les serveurs : l'interruption dispose d'une liste de routines à lancer,
comme le VBL.
Il existe 14 interruptions sur notre machine :
- 0, handler TBE : tampon mémoire de sortie série vide.
- 1, handler Disk Block : un bloc de donnée a été lu depuis une disquette.
- 2, serveur (?) logiciel : interruption provenant d'un programme.
- 3, serveur CIAA : interruption du 8520 A.
- 4, serveur Copper.
- 5, serveur VBL : Vertical BLank, tout les 50e de seconde.
- 6, handler BLitter : le Blitter a fini son travail.
- 7, handler Audio 0.
- 8, handler Audio 1.
- 9, handler Audio 2.
- 10, handler Audio 3.
- 11, handler RBF : tampon mémoire de réception série plein.
- 12, handler Disk sync : synchronisation des lecteurs de disquette.
- 13, serveur CIAB : interruption du 8520 B.
Les numéros indiquent aussi la priorité. Ainsi, si deux interruptions provenant de
l'Audio 0 et de la synchronisation disquette arrivent simultanément,
c'est la synchronisation qui est exécutée la première. Comme on le voit,
les deux ClA sont capables de générer des interruptions dont on définit la
source dans le registre de contrôle d'interruption (ICR).
Bit du registre ICR (bit, nom, fonction) :
- 0, TA : le timer A vient de passer à 0.
- 1, TB : passage à 0 du timer B.
- 2, Alarm : fonction "alarm".
- 3, SP : registre de décalage plein en entrée ou vide en sortie.
- 4, FLAG : l'entrée FLAG du 8520 est mise à 0.
Explication
Commeçons par le plus simple, j'ai nommé le signal FLAG. Si la broche Flag du
8520 passe à 0, une interruption est générée.
Alarm : chacun des 8520 contient un "Even Counter" qui sont des compteurs 24 bits
auxquels sont associés des alarmes. Son utilisation est assez simple :
on met à 1 le bit 7 (alarm) du registre de contrôle B (CRB) et on place
dans l'Event Counter la valeur à laquelle l'alarme doit se déclencher.
Les timers : ce sont aussi des compteurs 16 bits (en fait, ils décomptent),
qui partent d'une valeur que nous fournissons et qui libèrent une interruption
lorsqu'ils arrivent à 0. A chaque minuterie sont associés trois registres : TxLO,
TxHI et CRx ("x" étant remplacé par A ou B suivant la minuterie). Les deux
premiers registres contiennent la valeur du timer (je rappelle que les 8520
sont des circuits 8 bits), respectivement valeur basse et haute, le troisième étant
le registre de contrôle qui est utilisé aussi par d'autres fonctions du circuit
que les timers.
Registre CRA (bit, nom, fonction) :
- 7, TOD in : fréquence de "l'Event Counter" (0 = 60 Hz, 1 = 50 Hz).
- 6, SPMode : 0= SP en entrée, 1= SP en sortie.
- 5, INMode : le timer A est décrémenté au rythme de l'horloge E du 68000 (0),
ou à chaque impulsion sur la broche CNT.
- 4, LOAD : c'est un bit de forçage (strobe), c'est-à-dire que les données contenues
dans les registres TxLO et TxHI seront chargées dans les compteurs lorsque nous
ferons un accès en écriture sur CRA avec ce bit à 1.
- 3, RUNMODE : ce bit à 1 signifie que le compteur s'arrêtera à 0 (one shot) alors que
dans le cas contraire, le compteurs redémarre à sa valeur initiale après être passée à 0.
- 2, OUTMODE : à chaque timer est associé un signal sur le port B (bit 6 pour la minuterie
et bit 7 pour la B), ce bit indique si une impulsion sera émise à chaque décrémentation
(OutMode = O) ou si la sortie correspondante sera inversée (OutMode = 1).
- 1, PBON : indique si les sorties correspondantes du port B seront modifiées (1) ou non (0).
- 0, START : si ce bit est à 1, cela signifie que le timer est en fonctionnement.
Registre CRB (bits, nom, fonction). Son contenu est identique à CRA sauf pour :
- 7, Alarm : à mettre à 1 pour donner la valeur de l'alarme pour l'Even Counter.
- 6 et 5, INMode :
- 00 : Horloge E.
- 01 : CNT.
- 10 : en association avec le timer A, devenant ainsi le poids fort d'un registre 32 bits.
- 11 : idem mais uniquement lorsque CNT est à un niveau "Haut".
Nous verrons dans l'exemple comment utiliser ces minuteries...
Certaines de ces ressources sont déjà utilisées par le système :
CIAA :
- Timer A : utiliser pour le test du clavier.
- Timer B : libre pour les tâches.
- Event Counter : compte les impulsions de 50 ou 60 Hz de l'alimentation, ce qui permet
d'avoir une horloge temps réel.
- SP : ce registre à décalage est utilisé pour lire les données en provenance
du clavier.
FLAG est relié à ACK du port parallèle Centronics pour indiquer que la donnée est
acceptée par le périphérique.
CIAB :
- Timer A : transfère série.
- Timer B : utilisé par le Blitter en mode synchrone.
- Event Counter : compte les impulsions de synchronisation vidéo horizontale,
c'est-à-dire les lignes de l'écran.
- SP : imprimante occupée. En fait, un registre à décalage est inutile ici
mais nous permet de créer facilement un second port série.
- FLAG : début de cylindre lors de la lecture d'un fichier sur disquette.
Rien ne nous interdit d'utiliser certaines ressources en prenant quelques précautions que
nous allons voir maintenant en étudiant les fonctions système associées et qui sont
accessibles à travers les ressources CIAA et CIAB.
oldinterrupt = AddICRVector(Resource, iCRBit, interrupt)
Nous voulons prendre possession d'une des interruptions du CIA dont nous donnons
le numéro par iCRBit (exemple 1 pour le timer A. Resource est... la ressource du
CIA ouverte par OpenResource() et qui sera placée dans le registre A6 comme les
bases des bibliothèques ! "interrupt" est la structure interrupt de notre code.
Cette fonction renvoie le pointeur sur la structure interrupt qui possède déjà cette
interruption ou NULL si elle est libre.
RemICRVector(Resource, iCRBit, interrupt)
...libère cette interruption pour d'autre tâche. Il est encore plus important de libérer
ces ressources que les autres car si notre tâche n'existe plus mais que l'interruption y
est toujours attachée, il peut y avoir des Gurus...
oldMask = AbleICR(Resource, mask)
...est une fonction qui permet d'activer ou de désactiver les interruptions.
oldMask = SetICR(Resource, mask)
Poke mask dans le registre ICR du CIA.
Détermination de la période d'échantillonnage
Le timer est décrémenté avec la fréquence d'horloge E (709379 Hz en PAL),
la période d'échantillonnage est donc de : 1/f = 1/E * vtim (f= fréquence d'échantillonnage,
vtim = valeur mise dans le timer) => vtim = E/F.
Comme vtim est un "UShort", la fréquence minimale est de 11 Hz (E/65535).
A chaque interruption, "cnt" est incrémenté. Comme il est lu toutes les secondes,
sa valeur correspond à la fréquence d'échantillonnage. Vous remarquerez que le printf()
n'affiche pas précisément cette valeur, ce n'est pas du aux interruptions qui sont
très régulières mais au Delay() qui peut être différé si le multitâche est surchargé.
A ce propos, les interruptions prennent pas mal de temps processeur à haute fréquence. Sur
mon Amiga 1000 avec un 68010 (vecteur VBR en mémoire Fast), un Workbench 2.1 avec pas mal
d'utilitaires qui tournent (DashBoard entre autres) et sous multitâche, on les remarque
à partir d'environ 3000 Hz. A 6000 Hz, il devient difficile d'arrêter la tâche par un
"Ctrl-C". Blocage total vers les 8000 Hz mais avec un oscilloscope, vous remarquerez que
le signal généré est toujours précis. On peut augmenter ces fréquences avec un microprocesseur
plus puissant (n'oubliez pas de placer le VBR en mémoire Fast pour plus de rapidité),
en coupant le multitâche et en dernier recours en coupant le DMA. Je n'ai pas fait de
tests complets, mais avec un simple Amiga à base de 68000, on peut atteindre des fréquences
plus élevées qu'un PC à base de 386 !
Voilà, vous savez tout sur l'utilisation des minuteries des 8520. La prochaine fois, nous
parlerons de choses plus accessible a tous...
|