vorige:
[en] Pentaro Odyssey 2
MCCW nummer 93, juni-december 2000
Terug naar inhoud
volgende:
De Maiskoek/Bits and Pieces
Dit artikel is helaas alleen beschikbaar in het Engels.
how to control it?
MIDI interface of the GT

One of the least documented and most complex parts of the MSX turbo R GT is the built-in MIDI controller. Therefore, it has cost me a lot of time and effort to gather the data for this article.

 
Alex Wulms
 
Directory
Connection
Setting the UART mode
The UART commands
The UART Status register
Sending and receiving MIDI data
The timer
Counter initialisation
Reading the counter
The counter modes
The listing


References
1. http://www.inter.nl.net/u...


The MIDI link that is used for communication between two synthesizers or one synthesizer and a computer, is a so-called asynchronous serial data link. In the computer industry, there are several serial controllers to build such a link with. Panasonic uses the 8251 Universal Asynchronous Receiver/Transmitter, or UART.

    Unfortunately you need more than just a serial interface for a good MIDI link. A MIDI apparatus has to be able to send MIDI data with certain timing, for example to be able to control the tempo of the music. In the Panasonic GT that is done by the 8253 programmable timer controller, which I will simply call the ‘timer’. Both the 8251 and 8253 are also used to control the serial connection and timing of the official MSX RS232C interface.

Connection
The MIDI-controller in the GT is connected to the I/O ports as shown in the following table:

    

Connections MIDI controller to I/O ports
addressdescription
0E8hUART data register
0E9hUART command/status register
0EAhtimer interrupt flag off
0EBhtimer-counter 0 data register
0EChtimer-counter 1 data register
0EDhtimer-counter 2 data register
0EFhtimer command register

     The UART and the timer are connected with the CPU in several ways, to guarantee optimal cooperation:

  • The output of counter 0 of the timer is connected to the clock-input of the UART to get an adjustable baud rate.
  • The output of counter 2 of the timer is connected to a so-called flip-flop. This is set when counter 2 becomes 0 and it is reset when any value is written to the I/O register 0EAh.
  • The output of the flip-flop and the DTR output of the UART are connected to the input of an AND gate, so the output of the flip-flop is only passed if DTR is set.
  • The output of the AND gate is connected to the DSR input of the UART. This DSR signal can be read from the status register of the UART. As a result, the status register shows the status of counter 2.
  • The RxRDY output and the RTS output of the UART are connected to another AND gate. The RxRDY signal is thus only passed if RTS is set. The UART uses the RxRDY to signal that MIDI data have been received.
  • The outputs of the two AND gates are connected to the Interrupt input of the CPU. Thus, the CPU receives an interrupt request if MIDI data have been received, in which case RxRDY is set, and the CPU also receives an interrupt when counter 2 becomes 0.
  • The output of counter 2 is also connected to the input of counter 1.
  • The output of counter 1 is not connected to anything, so you cannot generate an interrupt request with counter 1. However, the value of counter 1 can be read through its data register on 0EDh.

See figure 1 for the connections.

Figure 1: This drawing shows how all these outputs and inputs are connected. Some details that would make the drawing needlessly complex have been omitted.

Setting the UART mode
The UART can work in two modes: a synchronous mode and an asynchronous mode. In fact, the 8251 is a USART; the S standing for Synchronous. However the MIDI controller only needs asynchronous mode. That is the only one I will discuss here.

    Before the UART can be used, the right mode has to be set. Before we are able to do this, it will have to be reset. This is done by writing three zeroes and one sixty-four to the UART through the command register at address 0E9h. By the way, the timing is critical; between writing two values to the command register, you will have to wait 4ms (this is about 1 tick on the counter on I/O-address 0E6h.

    After the UART has been reset, the mode can be set by writing the appropriate value to the command register. The mode value is composed as follows:

b7b6b5b4b3b2b1b0
S2S1EPPENL2L1B2B1

  • S2/S1: number of stop bits:
    • 0 = invalid
    • 1 = 1 stop bit
    • 2 = 1.5 stop bits
    • 3 = 2 stop bits
  • EP: even/odd parity generation:
    • 0 = odd parity
    • 1 = even parity
  • PEN: parity enable:
    • 0 = no parity check or generation
    • 1 = parity check or generation
  • L2/L1: character length:
    • 0 = 5 bits
    • 1 = 6 bits
    • 2 =7 bits
    • 3 = 8 bits
  • B2/B1: baud rate factor:
    • 0 = synchronous mode
    • 1 = 1×
    • 2 = 16×
    • 3 = 64×

    For MIDI, 1 stop bit is needed, no parity check, eight bits character length and a baud rate of 31.25 kHz. The baud rate is set with counter 0 of the timer and the baud rate factor of the mode value. If, for example, counter 0 of the timer is set to a clock frequency of 500 kHz, the baud rate factor has to be set to 16×. This leads to a binary mode value of 0100110 (decimal value 78). For a complete initialisation of the UART, a MIDI program has to write the following five values to the command register: 0, 0, 0, 64, 78. Between writing two values it has to wait 4 ms.

The UART commands
After a mode has been set, all values that have to be written to the command register are interpreted as so called command values. In fact, resetting the UART with 0, 0, 0, 64 does in fact mean that four successive commands are written to the UART. The first three zeroes are only needed to synchronise the UART with the CPU, just in case the UART is in the middle of a multi byte command mode setting. The fourth value is the actual reset command. Note that these multi byte commands are not used in asynchronous mode, but it could be possible that a previous (non-MIDI) program has set the UART to synchronous mode.

    A UART command is composed as follows:

b7b6b5b4b3b2b1b0
EHIRRTSERSBRKRxEDTRTXE

  • EH: Enter hunt mode
    • This bit has no function in asynchronous mode
  • IR: Internal reset
    • 0 = do not reset UART
    • 1 = reset UART so that mode can be changed
  • RTS: request to send. This bit is linked to the RTS output of the UART and in the MSX turbo R GT is used to link the RxRDY to the interrupt request input of the CPU.
    • 0 = MIDI interrupt is off
    • 1 = MIDI interrupt is on
  • ER: Error reset
    • 0 = nothing
    • 1 = reset FE, OE and PE status flags
  • SRBK: Send break character
    • 0 = normal operation
    • 1 = pull the serial MIDI output down so a continuous stream of zero bits is sent
  • RxE = Receive enable
    • 0 = MIDI in is off
    • 1 = MIDI in is on
  • DTR: Data terminal ready. This bit is linked to the DTR output of the UART and in the MSX turbo R GT is used to mask the output of counter 2.
    • 0 = counter 2 is ignored
    • 1 = counter 2 can generate interrupts
  • TxE = Transmit enable
    • 0 = MIDI out is off
    • 1 = MIDI out is on

    To switch MIDI out and MIDI in both to on, the RTS, RxE and TxE bits have to be set. If counter 2 is used as a programmable interrupt generator for timing the recording or transmission of MIDI data, the DTR bit has to be set as well. All other bits can remain reset.

    The result is a binary command value 00100111, the decimal value 39. If no programmable interrupt generator is necessary, the binary value 00100101 suffices (decimal 37). And if no interrupts are needed when MIDI data have been received, the binary value 00000101 (decimal 5) is enough.

The UART Status register
The UART also has a status register that can be read through I/O port 0E9h. This status register is composed as follows:

b7b6b5b4b3b2b1b0
DSRBRKFEOEPETxEMRxRDYTxRDY

  • DSR: Data set ready
    • This bit is connected to the DSR input of the UART, which in the GT is connected to the output of counter 2 of the timer.
  • BRK: Break detect. A break signal is detected by checking the stop bit. If it has been 0 twice in a row, there is a break signal. Normally, the stop bit can only become 0 if the transmitter has set the SBRK bit of the command register. Break signals are not used in the MIDI protocol.
    • 0 = no break signal detected
    • 1 = break signal detected
  • FE: Framing error. A framing error is caused by a break signal or an error in the data transfer. With MIDI, a FE is always caused by an error in the data transfer, because break signals are not used.
    • 0 = no framing error
    • 1 = stop bit was 0
  • OE: Overrun error
    • 0 = no overrun error
    • 1 = the UART has received a new character while the CPU was not ready reading the previous character.
  • PE: Parity error. Since parity is not checked in the MIDI protocol, this bit is always 0 when transferring MIDI data.
    • 0 = no parity error
    • 1 = wrong parity
  • TxEM: Transmitter empty. If TxEM is 1, the TxEM will become 0 as soon as the CPU has written a new value to the data port.
    • 0 = the UART is sending data
    • 1 = the UART is ready sending the last byte
  • RxRDY: Receiver ready. This status bit is also connected to the RxRDY output of the UART, which in the GT, is combined with the RTS signal and connected to the interrupt input of the CPU.
    • 0 = no byte received
    • 1 = byte received
  • TxRDY: Transmitter ready. The TxRDY status bit is always equal to the TxEM status bit. The difference between these two bits is that the TxEM bit is directly connected to the TxEM output of the UART, and the TxRDY bit is masked with two other bits before it is connected to the TxRDY output of the UART. For the MSX programmer, this difference is irrelevant because these two UART outputs are not used in the GT.
    • 0 = the UART is not ready to send a new byte
    • 1 = the UART is ready to send a new byte

Sending and receiving MIDI data
After the UART and counter 0 of the timer have been initialised, it is possible to send MIDI data by sending it to I/O port 0E8h and to receive MIDI data by reading I/O port 0E8h. Before writing a byte to I/O port 0E8H, the program must wait until the TxRDY status bit is set.

    Receiving MIDI data can be done by an interrupt routine which is called every time a new byte comes in. Programmers who find interrupt routines too complex can leave the interrupt generation off by resetting the RTS bit to 0 when setting the UART command. Next, they can check when MIDI data arrives by testing the RDY status bit.

The timer
The 8253 programmable timer exists of three independent 16-bit counters. They can count in binary or BCD mode. The MSB and LSB of a counter can be independently set and read, so that they can also be used as 8 bit counters. They always count down. The mode of the counter can be set by writing a mode value byte to I/O port 0EFh. This command value is composed as follows:

b7b6b5b4b3b2b1b0
SC1SC0RL1RL0M2M1M0BCD

  • SC1/SC0: Select counter
    • 0 = select counter 0
    • 1 = select counter 1
    • 2 = select counter 3
    • 3 = not allowed
  • RL1/RL0: Read/load
    • 0 = counter latch operation. See below at ‘Reading the counter’
    • 1 = read/write only the LSB
    • 2 = read/write only the MSB
    • 3 = read/write the LSB followed by the MSB
  • M2/M1/M0: Mode (The counter modes are discussed below.)
    • 0 = mode 0
    • 1 = mode 1
    • 2,6 = mode 2
    • 3,7 = mode 3
    • 4 = mode 4
    • 5 = mode 5
  • BCD: Binary coded decimal
    • 0 = counter works as 16 bits binary counter
    • 1 = counter works as 4 digit BCD counter

Counter initialisation
A counter is initialised after the right number of bytes (determined by the RL bits) is written to the counter data port. In 16-bits mode (RL1/RL0 = 3) for example, the counter will only be initialised after two bytes have been written to the data port.

Reading the counter
A counter can be read by reading the right number of bytes from the data port. For a reliable result, the countdown must be paused before the counter is read. This can be done by setting the mode of the counter.

    To be able to read the counter during countdown, the timer has a special option: there is an internal 16 bits buffer for every counter. The value of each counter is copied to the buffer as soon as the RL1/RL0 bits of the mode register are both 0. The M2/M1/M0 and BCD bits of the mode register are ignored in this case, and directly after copying the counter to the internal buffer, the RL1/RL0 bits are restored to their original state. When the data port of the counter is read the next time, the value in the buffer is shown in stead of the value of the counter itself.

The counter modes
Every counter can work in 6 different modes. These modes can be set with the M bits.

  • Mode 0: Interrupt on terminal count
    After setting this mode, the output of the counter is low. After the counter has been set, the output remains low and the counter starts to count down. When the counter reaches 0, the output becomes high and stays high until a new value has been written to the counter or the counter mode as been set again. By the way, the counter will keep counting after reaching 0.
  • Mode 1: Programmable one shot
    This mode cannot be used in the GT because the so called gate input of both counters is connected to +5V.
  • Mode 2: Rate generator
    With the rate generator you can make a ‘divide by N counter’. After this mode has been set, the output of the counter becomes high and will remain high until the counter has been set with value N. After this, the output of the counter will become low for 1 clock pulse and the output will become high for the next N-1 clock pulses. This process keeps repeating itself until the mode is set again. If on the other hand the counter is set again during countdown, the automatic count-down process will continue. The new setting is only used after the counter has passed 0. This mode can be used for making a programmable interrupt generator using counter 2. If the DTR bit of the UART is set, every time counter 2 reaches 0, an interrupt signal is sent to the CPU. E.g. to make a 200 Hz interrupt generator, counter 2 can be set to mode 2 and to value 20000 (the clock frequency of the counter is 4 MHz).
  • Mode 3: Square wave rate generator
    By setting the counter to mode 3, you can make a square wave. If an even number N is written to the counter, the output will be high for N/2 clock pulses and low for N/2 clock pulses. The result is a symmetrical square wave. If an odd number M is written to the counter, the output will be high for (M+1)/2 clock pulses and low for (M-1)/2 clock pulses. This will result in an asymmetrical square wave. Mode 3 is needed to set a clock frequency for the UART, among others. E.g. to provide the UART with a 500 kHz clock, counter 0 can be set to mode 3 and be initialised with the value 8.
  • Mode 4: Software triggered strobe
    After mode 4 has been set, the output of the counter goes high. When the counter has been set, it starts counting down and if it reaches 0, the output goes low for 1 clock pulse and the counter will stop counting.
  • Mode 5: Hardware triggered strobe
    This mode can not be used in the GT.

The listing
Below is an example of a MIDI program. It sends all MIDI data that are received through to MIDI out. For this, the program first sets counter 0 to generate a 500 kHz square wave. Next, the UART is set to receive serial data and write data at a 31.25 kHz baud rate. After this, the program will wait for new data to come in and send it through to the MIDI out port.

    I have not been able to test this program though, since I do not have enough synthesizer equipment. Here it is:

ML-listing: TRMIDI.GEN

; Example MIDI program for GT which can be run under MSX-DOS(2)
; Written by Alex Wulms for MCCM
; 26-9-1995

UARTsend: equ	0e8h	; 8251 data send
UARTrecv: equ	0e8h	; 8251 data receive
UARTcmd:  equ	0e9h	; 8251 command/mode register
UARTstat: equ	0e9h	; 8251 status register

tm_int:	  equ	0eah	; timer interrupt flag off

timer0:	  equ	0ech	; 8253 counter 0 dataport
timer1:	  equ	0edh	; 8253 counter 1 dataport
timer2:	  equ	0eeh	; 8253 counter 2 dataport
tm_cmd:	  equ	0efh	; 8253 command

	  di
	  in	a,(0aah)
	  and	0f0h
	  or	7
	  out	(0aah),a	; select row 7 of keyboard

          ld	a,00010110b	; set timer 0 to
	  out	(tm_cmd),a	; generate a square wave
	  ld	a,8		; set a frequency
	  out	(tm_cmd),a	; of 200 kHz

	  ld	hl,UARTdata
	  ld	b,6
initUART: ld	a,(hl)		; initialize UART for
	  out	(UARTcmd),a	; MIDI data communication
	  inc	hl
	  call	waitUART
	  djnz	initUART
	  in	a,(UARTrecv)	; reset outstanding flags

main:	  in	a,(UARTstat)
	  and	2		; check RxRDY
	  call	nz,midithru	; data waiting
	  in	a,(0a9h)	; read keyboard
	  bit	2,a		; check ESC key
	  jr	nz,main		; not pressed
 
 	  xor	a
	  out	(UARTcmd),a	; set MIDI off
	  ret			; thats all

waitUART: in	a,(0e6h)	; wait 4 micro seconds
	  ld	c,a		; between two UART operations
waitUART2:in	a,(0e6h)
	  sub	c
	  jr	z,waitUART2
	  ret

midithru: in	a,(UARTrecv)
	  ld	b,a		; B = midi IN data
midithr2: in	a,(UARTstat)
	  and	1		; check TxRDY
	  jr	z,midithr2	; UART not ready
	  ld	a,b
	  out	(UARTsend),a	; write to MIDI out
	  ret

UARTdata: db	0,0,0,64,78,5

     More articles — including the original Dutch version of this one — can be found on Alex Wulms’ home page, see reference [1]

vorige:
[en] Pentaro Odyssey 2
MSX Computer & Club Webmagazine
nummer 93, juni-december 2000
volgende:
De Maiskoek/Bits and Pieces