MSX turbo R - MIDI interface van de GT

Last updated on: February 27, 2000

Een van de meest complexe en slechts gedocumenteerde onderdelen van de turboR GT is de ingebouwde MIDI controller. Het heeft me dan ook aardig wat moeite gekost om alle gegevens voor dit artikel bij elkaar te sprokkelen.

De MIDI verbinding die gebruikt wordt voor communicatie tussen twee synthesizers of tussen een synthesizer en een computer, is een zogenaamde asynchrone seriële data verbinding. Nu bestaan er in de computer industrie verschillende seriële controllers om zo'n verbinding mee op te bouwen. Panasonic heeft uit dit aanbod de 8251 Universal Asynchronous Receiver/Transmitter, welke ik verder aanduidt met UART, gekozen.

Helaas heb je voor een goede MIDI controle meer nodig dan alleen een seriële verbinding. Een MIDI apparaat moet namelijk ook de MIDI data met een bepaalde timing kunnen versturen om bijvoorbeeld de snelheid van de muziek af te kunnen regelen. Daarom heeft Panasonic in de GT ook nog de 8253 programmeerbare timer controller, welke ik verder met timer aanduid, ingebouwd. Deze chip combinatie wordt overigens ook in de officiële MSX RS232C interface gebruikt voor de seriële verbinding en de timing.

De aansluiting
De MIDI controller in de GT is op de volgende in/out poorten aangesloten:
Adres Omschrijving
0E8H UART data register
0E9H UART command/status register
0EAH Timer interrupt flag off
OECH Timer counter 0 dataport
0EDH Timer counter 1 dataport
0EEH Timer counter 2 dataport
0EFH TImer command register
De UART en de timer zijn op diverse manieren met elkaar en met de CPU verbonden om optimaal te kunnen samenwerken:

Een grafisch overzicht van de diverse verbindingen is te vinden in figuur 1. In die tekening heb ik overigens alle overbodige details met betrekking tot negatieve logica en gebruikte inverters weggelaten omdat die details de hele zaak alleen maar nodeloos complex zouden maken.
schema
Figuur 1

De UART mode instellen
De UART kan in twee modi werken; in een synchrone mode en in een asynchrone mode. In feite is de 8251 zelfs een USART, waarbij de S voor synchroon staat. Voor de MIDI controle is echter alleen de asynchrone mode nodig dus alleen die mode zal ik behandelen.

Voordat de UART gebruikt kan worden, moet hij in de goede mode gezet worden. Om dit te kunnen doen, dient de UART echter eerst nog gereset te worden. Dit laatste kan door achtereenvolgens driemaal een nul en eenmaal een vierenzestig naar de UART toe te schrijven via de commando poort op in/out adres 0e9h. De UART is overigens tijd kritisch; tussen het schrijven van twee waarden naar de commando poort moet ongeveer 4 micro seconden gewacht worden. Dit komt overeen met een verhoging met 1 van de teller op in/out adres 0e6h.

Nadat de UART gereset is, kan vervolgens de mode ingesteld worden door de goede mode waarde naar de commando poort te schrijven. Deze mode waarde is als volgt samengesteld:
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
S2 S1 EP PEN L2 L1 B2 B1

Voor een MIDI verbindingen is 1 stopbit nodig, geen pariteits controle, 8 bits karakter lengte en een baud rate van 31,25 kHz. De baud rate wordt ingesteld met behulp van counter 0 van de timer en de baud rate factor van de mode waarde. Als counter 0 van de timer bijvoorbeeld wordt ingesteld om een klok frequentie van 500 Khz te genereren, dient de baud rate factor op 16x te staan. Dit leidt dus samen tot een mode waarde van 01001110 binair ofwel 78 decimaal. Een MIDI programma dient voor een volledige initialisatie van de UART dus de volgende vijf getallen naar de commando poort te schrijven: 0, 0, 0, 64, 78, waarbij tussen het schrijven van twee opeenvolgende waarden 4 micro seconden gewacht moet worden.

De UART commando's
Nadat eenmaal de mode is ingesteld, worden alle waarden die naar de commando poort worden geschreven, gezien als zogenaamde commando waarden. In feite bestaat het resetten van de UART, middels de sequentie 0, 0, 0, 64, zelfs uit het schrijven van vier opeenvolgende commando's. De eerste drie nullen zijn hierbij eigenlijk alleen nodig om de UART te synchroniseren met de CPU voor het geval dat de UART midden in een multibyte commando/mode instelling zat en de vierde waarde is het feitelijke reset commando. De multibyte commando's komen in asynchrone mode overigens nooit voor maar het zou kunnen dat een vorig (niet MIDI) programma de UART in synchrone mode had gezet.

Zo'n UART commando waarde is als volgt samengesteld:
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
EH IR RTS ER SBRK RxE DTR TxE

Om zowel MIDI in als MIDI out aan te zetten, dienen de RTS, RxE en TxE bits geset te worden. Indien ook nog counter 2 wordt gebruikt als programmeerbare interrupt generator om het opnemen of versturen van de MIDI data te timen, moet ook nog het DTR bit geset worden. Alle overige bits kunnen gereset blijven. Dit leidt dus tot een commando waarde van 00100111 binair ofwel 39 decimaal. Als er geen programmeerbare interrupt generator nodig is, voldoet de waarde 00100101 binair ofwel 37 decimaal. En als er ook nog geen interrupts nodig zijn als MIDI data ontvangen zijn, voldoet de waarde 00000101 binair ofwel 5 decimaal.

Het UART status register
De UART heeft ook nog een status register dat uit te lezen is via in/out poort 0e9h. Dit status register is als volgt samengesteld:
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
DSR BRK FE OE PE TxEM RxRDY TxRDY

MIDI data ontvangen en verzenden
Nadat de UART, en counter 0 van de timer, eenmaal geïnitialiseerd zijn, is het mogelijk om MIDI data te verzenden door die data naar in/out poort 0e8h te schrijven en MIDI data zijn te ontvangen door ze uit in/out poort 0e8h te lezen. Vóór het wegschrijven van een byte naar in/out poort 0e8H, dient de programmeur echter wel te wachten tot het TxRDY status bit geset is.

Het ontvangen van MIDI data kan via een interrupt routine gebeuren, die iedere keer aangeroepen wordt als er een nieuwe byte is binnengekomen. Programmeurs die interrupt routines te ingewikkeld vinden, kunnen ook de interrupt generatie uit laten staan -door het RTS bit op nul te laten staan bij het instellen van het UART commando- en vervolgens kijken wanneer er MIDI data binnenkomen door het RxRDY status bit te controleren.

De timer
De 8253 programmeerbare timer bestaat uit 3 onafhankelijke 16-bit counters die ieder in twee verschillende modi kunnen tellen; in binaire mode en in BCD mode. Het MSB en het LSB van een counter kunnen eventueel onafhankelijk ingesteld en uitgelezen worden. De counters zijn dus tevens als 8-bit counters te gebruiken. De counters tellen altijd omlaag.

De mode waarin een counter werkt, is in te stellen door een mode waarde naar in/out adres 0efh te schrijven. Deze commando waarde is als volgt samengesteld:
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
SC1 SC0 RL1 RL0 M2 M1 M0 BCD

Counter initialisatie
Een counter wordt pas ge-initialiseerd nadat het goede aantal bytes, bepaald door de RL bits, naar de counter datapoort poort zijn geschreven. In 16-bits mode (RL1/RL0 = 3) wordt een counter bijvoorbeeld pas ge-initialiseerd nadat er twee bytes naar de counter datapoort zijn geschreven.

Counter uitlezen
Een counter is uit te lezen door het goede aantal bytes uit de datapoort te lezen. Voor een betrouwbaar resultaat moet het aftellen van de counter echter uitgezet worden voordat de counter wordt uitgelezen. Dit kan bijvoorbeeld gedaan worden door de mode van de betreffende counter opnieuw in te stellen.

Om de counter toch te kunnen uitlezen tijdens het aftellen ervan, heeft de timer een speciale optie ingebouwd; er is voor iedere counter een interne 16-bits buffer beschikbaar, waar de waarde van de counter in wordt gezet zodra de RL1/RL0 bits van het mode register beiden op nul staan. De M2/M1/M0 en BCD bits van het mode register worden in dat geval genegeerd, en direct na het kopiëren van de counter naar de interne buffer, worden de RL1/RL0 bits weer hersteld op de oude waarde. Bij de eerstvolgende lees operatie van de datapoort van de counter, wordt vervolgens de waarde in de buffer teruggegeven in plaats van de waarde van de counter zelf.

De counter modes
Iedere counter kan in zes verschillende modi werken. Welke mode gebruikt wordt is afhankelijk van de M bits.

Mode 0: Interrupt on terminal count
Na het instellen van deze mode is de uitgang van de counter laag. Nadat de counter is ingesteld, blijft de uitgang laag en begint de counter omlaag te tellen. Zodra de counter nul is geworden, gaat de uitgang omhoog en hij blijft hoog totdat een nieuwe waarde naar de counter is geschreven of tot de counter mode opnieuw is ingesteld. De counter blijft overigens doorlopen nadat nul is bereikt.

Mode 1: Programmable one shot
Deze mode is in de GT niet te gebruiken doordat de zogenaamde gate ingang van de counters is verbonden met de +5V aansluiting.

Mode 2: Rate generator
Hiermee is een zogenaamde 'deel door N counter' te maken. Nadat deze mode is ingesteld, wordt de uitgang van de counter hoog gemaakt, en deze blijft hoog totdat de counter is ingesteld met een waarde N. Hierna gaat de uitgang van de counter voor de duur van 1 klokpuls omlaag en vervolgens gaat de uitgang weer omhoog voor de volgende N-1 klokpulsen. Dit proces blijft zich herhalen totdat de mode weer opnieuw wordt ingesteld. Als de counter daarentegen opnieuw wordt ingesteld tijdens een tel periode, blijft het automatische aftel proces doorgaan. De nieuwe instelling wordt dan pas gebruikt als de counter weer nul is geweest.

Deze mode is bijvoorbeeld te gebruiken om met behulp van counter 2 een programmeerbare interrupt generator te maken. Als het DTR bit van de UART geset is, wordt namelijk iedere keer dat de uitgang van counter 2 nul wordt, een interrupt signaal naar de CPU gestuurd. Om bijvoorbeeld een interrupt generator van 200 Hz te maken, kan counter 2 op mode 2 worden gezet, en ingesteld worden op de waarde 20000. Dit laatste omdat de klokfrequentie van de counter 4 MHz bedraagt.

Mode 3: Square wave rate generator
Door de counter in deze mode te zetten, is een blok golf te maken. Als er een even getal N naar de counter is geschreven, is de uitgang N/2 klokpulsen hoog en N/2 klokpulsen laag. Dit levert een blokgolf op. Als daarentegen een oneven waarde M wordt geschreven, is de uitgang (M+1)/2 klokpulsen hoog en (M-1)/2 klokpulsen laag. Dan krijg je dus een licht asymmetrische blokgolf.

Mode 3 is onder andere nodig om de klok frequentie voor de UART in te stellen. Om de UART bijvoorbeeld een klok van 500 kHz te geven, kan counter 0 op mode 3 worden ingesteld, en worden ge?nitialiseerd met de waarde 8.

Mode 4: Software triggered strobe
Nadat deze mode ingesteld is, gaat de uitgang van de counter omhoog. Zodra de counter is ingesteld, begint deze omlaag te tellen en als hij nul wordt, gaat de uitgang voor 1 klokpuls omlaag en stop de counter met tellen.

Mode 5: Hardware triggered strobe
Deze mode is, evenals mode 1, in de GT niet te gebruiken.

De listing
Een voorbeeld van een MIDI programma is te vinden in de listing. Het programma stuurt alle data die via MIDI in binnenkomen, door naar MIDI out. Het programma stelt hiertoe eerst counter 0 in om een blokgolf van 500 kHz te genereren en vervolgens wordt de UART ingesteld om seriële data te ontvangen en weg te schrijven op een baudrate van 31,25 kHz. Hierna gaat het programma in een lus zitten wachten op data die via MIDI in binnenkomen en die worden vervolgens doorgestuurd via de MIDI out poort.

Dit programma heb ik overigens zelf niet kunnen testen bij gebrek aan synthesizer apparatuur.