BeatMaster Support: Questions & Answers
Synchronization
actually, im very curious about what you did regarding note scheduling.
one of the problems i felt that i ran into when i was attempting to implement
a sequencer was the inherent port read/write delays of the mpu-401 card in
dumb uart mode. i was unable to find a balance between this send rate and
the timers interrupt rate. add to this the user interface overhead, and my
sequencer ran very poorly. it seemed at the time that the only solution was
to use smart uart mode, but all of the (scant) documentation that i had seemed
to brush this mode off as a chore, so i stuck with dumb uart.
Joe - Massachussetts
If you were doing all your MIDI-processing (MPU reads/writes etc) from
within the interrupt-handling mechanism (ie. with interrupts disabled),
that may have been a problem. As you know only too well, it takes time
to send every byte to the MPU and if you also have the user-interface
and everything else to deal with, you end up with a very busy interrupt
handler. If you delay the timer interrupt for too long by doing too
much inside it, either the clock slows down due to excessive 'dead time'
between ticks, or the interrupt blocks itself causing the clock to start
missing ticks completely (depending on the mode of the 8253 timer chip).
Bad news.
The way I dealt with this problem was to do the MIDI I/O asynchronously
during the interval between timer-tick interrupts. By doing this I
avoided any problems with synchronizing the timer and the MIDI port
(BeatMaster also uses the MIDI port in dumb UART mode). The UI is
updated in response to flags set by the tick-handler which are polled
by the main program loop. This effectively breaks the single process
of handling a tick into a hierarchy of three asynchronous threads of
execution:
Interrupt Processing
MIDI I/O
User-Interface
The interrupt processing section of the handler for a hardware-interrupt
(like the one triggered by the timer chip) is whatever it does before
sending an End-Of-Interrupt (EOI) signal to the programmable interrupt
controller (PIC) chip to re-enable hardware interrupts. Hardware
interrupt handlers do this before returning to an interrupted process
so that the device that triggered the interrupt knows that it has been
serviced and can reset itself. Once the EOI has been sent, the system
is back in normal processing mode and future interrupts can occur, even
if the handler does not return immediately. Any code after the EOI can
thus execute safely without slowing down the interrupt mechanism. You
can think of it as executing asynchonously 'during' an interrupt-interval
rather than 'in-between' interrupts.
The code before the EOI in my fast_tick() handler
is restricted to programming the timer-chip for the next interrupt:
- If the conditions for stopping the MIDI clock are met, the timer-chip
is re-programmed with its normal default settings and the original
DOS interrupt handler is restored.
- If the MIDI clock is running, the timer-chip is programmed in
'Interrupt-on-Terminal-Count' (ITC) mode, which causes it to fire
a 'single-shot' interrupt when its counter reaches zero.
Re-programming the timer after each tick prevents the handler
from interrupting itself and also simplifies the procedure for
changing the interval between interrupts.
The fast_tick() handler sends the EOI before calling the user_tick()
handler to do BeatMaster's real work (unless the current tick coincides
with a normal timer-tick [18.2/sec] when the original DOS tick-handler
is called which sends the EOI itself). This means that all the code in
the user-handler (MIDI-processing etc) operates in normal processing
mode and does not hold-up interrupts. This obviously means that the
next tick-interrupt might break into the code if it takes too long to
complete, but the danger of re-entry to the user_handler() is prevented
by the intick flag in fast_tick(), which effectively closes the door to
the handler before calling it.
If the user_handler() code takes so long talking to the MIDI port that
it gets interrupted by the next tick, that next tick is completely
skipped. The user_handler() has no way of knowing that the event even
occurred and the countdown is simply restarted. In practice, this does
not seem to be much of a problem since the MIDI port usually manages
to keep up.
The non time-critical code to update the user-interface is executed
by the main program loop and not by the interrupt handler. It does
this by responding to flags which are set by the user_handler()
function whenever a tick or a new beat occurs. Because DOS is a
single-task system, this means that the UI will only be updated when
no interrupt-driven MIDI I/O is occurring.
Eamonn
Go To:
BeatMaster Support