Dr.Godfried-Willem RAES

Kursus Experimentele Muziek: Boekdeel 1: Algoritmische Kompositie

Hogeschool Gent - Departement Muziek en Drama


<Naar inhoudstafel kursus>

1132:

Timing door aansturing van de hardware

Wanneer je voor je algoritmische kompositie noch voor de real-time toepassingen problemen hebt met de eerder gegeven softwaremogelijkheden voor de hantering van tijd- en ritme, dan zullen volgende paragrafen aan jou niet of slecht zijn besteed. Zeldzaam zijn echter de 'composers inside electronics' die niet op een of ander moment tegen de klippen zijn gelopen van een onregelmatige of onprecieze timing.

Alvorens echter over te gaan tot de aanpak die we hier willen behandelen, moet er op gewezen worden dat volgende faktoren onregelmatigheden van de software tijd-gerelateerde funkties op de PC veroorzaken en/of beinvloeden:

1.- Multitaskers (bvb. Windows): probeer je software eens helemaal buiten Windows (onder DOS zelf dus en niet in een DOS-venster) te draaien.

2.- TSR's

3.- Cache-programma's (Smartdrive bvb.)

4.- Netwerksoftware

5.- Schermbesturingsroutines

6.- Serieel data-transport

7.- Timer-interrupts

Elke komputer beschikt in zijn hardware over ten minste één klok: het is immers een sekwentiele machine en de diverse instrukties worden in de maat van een centrale klok door de mikroprocessor afgehandeld. Deze klok is evenwel voor meting of bepaling van de tijd niet te gebruiken. Haar snelheid hangt af van de hardware en is van machine tot machine verschillend.

Naast deze 'klokfrekwentie' omvat een komputersysteem echter ook nog enkele andere telwerken, die helemaal niet afhankelijk zijn noch mogen zijn van de komputerklok zelf. Zo bvb. heeft het systeem, wanneer er seriele poorten zijn voorzien, nood aan een zgn. Baud-rate generator, die instaat voor het in de maat lopen van externe kommunikatie via het seriele kanaal.

Wanneer een komputer gebruik maakt van DRAM, dan heeft men alweer een klok nodig om ervoor te zorgen dat de bijzonder vluchtige geheugenchips zo'n 2 tot 3000 keer per sekonden opgefrist worden... Ook deze periodieke klok dient onafhankelijk te zijn van de processorklok.

Ook het biepje dat het interne luidsprekertje van een PC produceert zou niet kunnen bestaan wanneer het niet ergens in de machine door een klokje zou worden aangestuurd.

IBM-machines en hun klonen beschikken voor het opwekken van al deze klokken steeds over een hardware timer/klok (een 8253, 8254 of 82254-chip van Intel) die volkomen programmeerbaar is en via I/O instrukties in te lezen.

Naast deze 8254-chip -een driedubbele klok- , beschikken PC's eveneens -maar dit niet voor oudere XT's en AT's- over een zogenaamde 'real-time' klok, die ook doorloopt wanneer de komputer wordt afgezet, en daartoe een kleine lithium batterij omvat. Het is dit 'uurwerkje' dat ervoor zorgt dat we tijd en datum niet telkens opnieuw hoeven in te stellen bij het opstarten van de machine. Bij het opstarten van een PC leest de BIOS de tijd en datum uit, uit het geheugen van dit klokje en kopieert die naar de registers van een van de tellers (bijna steeds timer 0) uit de 8254-chip. Voor alle tijdsafhankelijk funkties maakt de PC dan verder uitsluitend gebruik van de tijdstelling door de 8254 die los loopt van de eigenlijke 'real-time' klok.

Deze teller is zo geprogrammeerd dat hij, uitgaande van een (hardware) kloksignaal van 1.192755 MHz cyclisch telt van &HFFFF naar 0 en telkens wanneer de teller bij 0 is aangekomen wordt een interrupt (IRQ0) gegenereerd die een software-routine start die de komputertijd een stapje vooruit doet springen.

Deze interrupt heeft een periodiciteit van 0.054s (f=18.2Hz), een waarde die ons vertrouwd in de oren zou moeten klinken, want zij komt precies overeen met de kleinste tijd die via de SOUND instruktie kan worden ingesteld. Het is immers precies de tijd tussen twee opeenvolgende Timer Interrupts.

De wijze waarop al deze hardware komponenten kunnen worden gebruikt en hoe zoiets kan gebeuren is geillustreerd in de volgende programmavoorbeelden. Opgemerkt moet worden dat niet alle hier gegeven kode zal werken op willekeurig welke machine. Een en ander hangt af van de juiste opbouw van de hardware, die immers niet steeds identiek is met het oorspronkelijke ontwerp van de IBM-PC.


Het Real-Time Klokje:

'REAL-TIME CLOCK':

Vaak voorkomende chips waarin alle logika is ondergebracht voor een heuse tijd en datum klok zijn o.m.:

MM58167 (National)

MM58174 (National)

MSM5832 (OKI)

MSM58321 (OKI)

MC146818 (Motorola)

Bijna al deze chips gaan uit van een kristalfrekwentie van 32768Hz, een frekwentie waaruit door deling eenvoudig onze even konventionele als idiote zestigtallige tijdsindeling kan worden afgeleid.

Timing routines onder gebruik making van de timer chip. wanneer deze in het I/O bereik terug is te vinden op het basisadres &H240 (met de zestien erop volgende adressen )

Uitleesbare gegevens zijn:

minuten

uren

dagen

jaren zijn ook beschikbaar maar hier 'niet direkt nuttig.

tientallen seconden

eenheden seconden

tienden seconden

hondersten seconden

duizendsten seconden

de duizendsten kunnen niet worden gebruikt omdat ze 'onregelmatig worden vanzodra we ze pogen uit te lezen ! Dit 'fenomeen heeft nogal wat gemeen met het Heisenberg-onzekerheids principe.

Kodevoorbeeld:

CLS

LOCATE 12, 10

PRINT "TIMER-CHIP UITLEZING:"

T:

LOCATE 13, 10

PRINT INP(&H242) \ 16;

PRINT INP(&H242) MOD 16;

PRINT INP(&H241) \ 16;

PRINT INP(&H241) MOD 16;

PRINT INP(&H240) \ 16GOTO T

Krijg je dit programma op jou machine niet aan de praat, dan is er waarschijnlijk een ander soort real-time klok chip gebruikt. In vele gevallen kan je het type vinden door aandachtig te zoeken op het moederbord van je komputer. Zoek in de onmiddellijke buurt van de back-up batterij (Lithium-cel of NiCad) en/of het erg kleine 32kHz kristal.

Gegevens over de programmering van de chip vind je in de application-notes en data-sheets van de fabrikant onder het overeenkomstige typenummer.

Voor een overzicht over enkele gebruikelijke real-time klokchips kan je ook volgend boek raadplegen:

LEIBSON, Steve "Handboek Microcomputer Interfacing" , p.217-238 (Cfr. bibiografie).

Op een van mijn machines (genaamd Abulafia) konden alleen zekere rezultaten worden bereikt met volgende aansturing:

' clock-test via CMOS-clock (Real-time clock)

CLS

DO

OUT &H70, 0

data$ = HEX$(INP(&H71))

IF data$ <> olddata$ THEN PRINT data$: olddata$ = data$

'FOR adres = 0 TO 12

' OUT &H70, adres

' data$ = HEX$(INP(&H71)) + " "

' PRINT data$;

'NEXT adres

LOOP UNTIL INKEY$ <> ""

END

Het rezultaat op mijn 80386DX Abulafia was dat alleen een sekonden-teller beschikbaar bleek op adres 0. De real-time klok voorziet duidelijk niet in kleinere eenheden, waardoor ze voor muzikale toepassingen onbruikbaar bleek.


 

De PIT: Programmable Interval Timer (8253,8254,82254...)

In de oorspronkelijke architektuur van de IBM-PC werd deze chip in het I/O bereik geplaatst op de hardwarematige adressen &H40,&H41,&H42,&H43. Wanneer we op die plaats 'iets zien of voelen' tikken, dan zijn we op goede weg voor de hierna beschreven programmaexperimenten met direkte aansturing van de timer.

De laatste tijd is het resultaat van deze werkwijze echter heel erg onzeker geworden, omdat veel hardware fabrikanten dedicated chips (ASIC'S) zijn gaan gebruiken waarvoor deze hardware-adressen niet langer geldig zijn.

Als je veel geluk hebt, tref je we een I/O map aan in de dokumentatie van je hardware, zoniet wordt het een zoektocht...

Een volledige beschrijven van de 8254 zou ons op deze plaats te ver voeren, ook al omdat het een van de best gedokumenteerde chips betreft. Een exemplaar van het data-sheet is in deze kursus o.m. opgenomen bij de bespreking van de Elektuur ADC-kaart (boekdeel 2), waarop ook een dergelijke chip wordt gebruikt. Bijna alle met een timer uitgeruste data-aquisitiekaarten zijn overigens van dit type chip voorzien. Wanneer je erover beschikt is het veel beter hiervan gebruik te maken dan van de gelijknamige chip in je komputer. Immers, deze chip wordt dan niet voor time-keeping door het OS (operating system) gebruikt en is volkomen vrij programmeerbaar.

In grote lijnen gaat de programmatie in zijn werk alsvolgt:

Het &H43-adres wordt gebruikt als kommando-register. Dit wil zeggen dat de wijze waarop de drie in de chip aanwezige tellers hun werk zullen doen geprogrammeerd kan worden door het schrijven van een bepaalde bit- kombinatie (een byte) naar dit adres. De funktie van de verschillende bits is alsvolgt:

D0 = Binaire teller(0) of BCD teller (1)

D1 = Mode bit 1

D2 = Mode bit 2

D3 = Mode bit 3

D4 = ReadWrite modus bit 1

D5 = Readwrite modus bit 2

D6 = Teller selektiebit 1

D7 = Teller selektiebit 2

Teller 0 wordt geselekteerd door D6=0, D7=0, terwijl de teller kan worden gelezen en zijn initiele telwaarde geprogrammeerd via adres &H40.

Teller 1 wordt geselekteerd door D6=1, D7=0. Het read/write adres os &H41. Teller 2 tenslotte wordt geselekteerd via D6=0, D7=1 waarbij het read/write adres &H42 is. D6=1 en D7=1 is een illegale toestand.

Volgende programmavoorbeelden -zo hopen we- mogen een en ander verduidelijken:

1. 8254-0.bas:

' test direct programming of 82254 -timer - channel0

' Hardware one-shot mode!

' this works and yields time-units ca. 0.4 ms per increment

' milliseconds_value * 2.5= tijd

' tijd <= 1 byte !!!

' maximum tijd-interval = 255 x 0.4ms = 100ms = 0.1s !!!!!!!!!!

' NADEEL: deze routine maakt de TIMER instruktie onbruikbaar, want

' legt de interne klok geheel stil!

' (Dit kan soms erg bruikbaar zijn natuurlijk...)

DEFINT L-M

lus = 0

DO:

tijd = 200: ' =200 x 0.4ms

OUT &H43, &H22: ' kommando: Binair=00-10-001-0

OUT &H40, tijd: ' send msb

DO

OUT &H43, &H2: ' kommando- latch 00-00-001-0

OUT &H43, &H22: ' 1-byte read MSB kommando

MSB = INP(&H40)

LOOP UNTIL MSB = 0

lus = lus + 1

LOOP UNTIL INKEY$ <> ""

PRINT lus * tijd

END

2.8254-2.BAS:

' test direct programming op 82254 -timer - channel2

' Hardware one-shot mode!

' 16-bit experiment: erg onregelmatig - vooral onder Windows.

DEFINT L-M

DO

tijd = 32000: '16-bit

OUT &H43, &HB2: ' kommando: Binair=10-11-001-0

OUT &H42, tijd MOD 256: ' send lsbOUT &H42, tijd \ 256: ' send msb

t1 = TIMER

DO

OUT &H43, &H82: ' kommando- latch 10-00-001-0

'OUT &H43, &HB2: ' 2-byte read kommando

LSB = INP(&H42): MSB = INP(&H42)

LOOP UNTIL (MSB OR LSB) = 0

t2 = TIMER

PRINT "Time over"; MSB; LSB; t2 - t1; "Cycle-timein ms="; ((t2 - t1) / tijd) * 1000

LOOP UNTIL INKEY$ <> ""

END

3. 82254-2.BAS

' this works and yields time-units ca. 0.33 ms per increment

' milliseconds_value * 3 = tijd

' tijd mag niet groter zijn dan 1 byte !!!

' maximum tijds-interval = 255 x 0.33ms = 84ms = 0.084s !!!!!!!!!!

' NADEEL: WERKT absoluut NIET op de 80486 laptop!!!

' Afhankelijk van de hardware-architektuur.

CONST Zero = 0

DEFINT L-M

1 :

lus = 0

DO:

tijd = 200: ' =200 x 0.33ms 150= 50ms

OUT &H43, &H22 + 128: ' kommando: Binair=10-10-001-0

OUT &H42, tijd: ' send msb only

DO

OUT &H43, &H2 + 128: ' kommando- latch 10-00-001-0

'OUT &H43, &H22 + 128: ' 1-byte read MSB-only kommando

LOOP UNTIL (INP(&H42)) = Zero: ' read timer. Zero reached?

lus = lus + 1

LOOP UNTIL INKEY$ <> ""

PRINT lus * tijd * .33; "ms"

END

2 : ' een nog sterkere konstruktie voor de loop (waarbij een gemiste 0-lezing kan vermeden worden gaat zo:

lus = 0

DO:

tijd = 200: ' =200 x 0.33ms 150= 50ms

OUT &H43, &H22 + 128: ' kommando: Binair=10-10-001-0

OUT &H42, tijd: ' send msb only

DO

'OUT &H43, &H2 + 128: ' kommando- latch 10-00-001-0

byte% = INP(&H42)

'OUT &H43, &H2 + 128: ' kommando- latch 10-00-001-0

LOOP UNTIL (INP(&H42)) > byte%: ' read timer. Zero crossed?

lus = lus + 1

LOOP UNTIL INKEY$ <> ""

PRINT lus * tijd * .33; "ms", "lussen="; lus

END


Zoektocht naar de tijd in RAM...

  Wanneer geen van bovenstaande experimentele wegen tot een bruikbaar rezultaat aanleiding geeft kan natuurlijk ook nog een omweg worden bewandeld. Immers het BIOS van de PC kopieert op regelmatige tijden de inhouden van diverse I/O tellers in het RAM geheugen zelf. Daarvoor moeten we natuurlijk wel iets te weten kunnen komen over de indeling van het (laag) geheugen in onze PC. Hoewel het onmogelijk is enige garantie te geven dat deze aanpak op andere machines en op gelijke geheugenadressen vergelijkbare rezultaten oplevert, geef ik hierbij enkele kode-voorbeelden die op een groot aantal machines in elk geval wel werkend te krijgen zijn:

1. CLKTIM.BAS:

' poging tot tijdsbenadering via BIOS geheugenadressen...

' ref.: XT programmers reference Tandy 1000 - p.233

' volgende routine werkt prima maar heeft een absolute fout van 0.1s.

1 :

DEF SEG = &H40

begin:

tijd = 100: i = 0

DO

IF NOT (PEEK(&H6C) AND PEEK(&H6C)) THEN i = i + 1

LOOP UNTIL i >= tijd

BEEP

PRINT i

GOTO begin

DEF SEG

END

2 :

DEF SEG = &H40

DO

CLS

LOCATE 10, 5

' 100sec 10sec sec tienden.

PRINT HEX$(PEEK(&H6F)); " "; HEX$(PEEK(&H6E)), HEX$(PEEK(&H6D)); " ";

PRINT HEX$(PEEK(&H6C)); " "; SPACE$(8);

LOCATE 12, 5

PRINT PEEK(&H6F); " "; PEEK(&H6E), PEEK(&H6D); " "; PEEK(&H6C); SPACE$(8);

LOOP UNTIL INKEY$ <> ""

DEF SEG

' deze klok tikt slechts 18.2 x per sekonde!!!

' hondersten en millisec. zijn niet in het geheugenbereik beschikbaar.

' daarvoor moet I/O gebruikt worden (8254-chip)

END

3. ' test voor een RAM-based counter in 0.054 s units

DEF SEG = &H40

t1 = TIMER

start:

tel% = PEEK(&H6C)

DO: LOOP UNTIL tel% <> PEEK(&H6C)

i% = (i% + 1) AND &HFFFF

IF TIMER - t1 <= 60 THEN GOTO start

PRINT i% / 60; "tikken per sekonde"DEF SEG


Timer Interrupt...

Hoewel we er verder nog uitvoeriger zullen op ingaan, kan hier ook nog gewezen worden op de mogelijkheid om de timer-interrupt (dit is steeds IRQ0) buiten werking te stellen. Hiertoe moeten we een register van de interruptcontroller (de PIC) herprogrammeren. Meer bepaald bit 0 op I/O adres &H21 bepaalt of de betreffende interrupt al dan niet aktief is (0=enable, 1=disable).

De kode om de timer interrupt (18.2 keer per sekonde) buiten werking te stellen is:

OUT &H21, INP(&H21) OR 1

Aktivering van de interrupt kan via:

OUT &H21, INP(&H21) AND (255-1)

Onder het Windows platform leidt dit tot een onvermijdelijke systeemcrash. De heer Gates bezit je systeem, niet jij...


[Filedate: 921107]

Terug naar de inhoudstafel: <Index Kursus>

Naar homepage dr.Godfried-Willem RAES