Article View: comp.sys.atari.st
Article #35616Summary of responses on MIDI interrupt handling
From: HC Johnson
Date: Fri, 06 Jan 1989 17:27
Date: Fri, 06 Jan 1989 17:27
223 lines
7334 bytes
7334 bytes
I Previously posted:
| I have tried, without success to implement an interrupt driven
| send to MIDI. (Receive is working fine.)
|
| The problem area seems to be in getting the acia chip to pull down
| TXRDY, when I am down sending.
I received mail from two very helpful people:
Mike Russell ucbvax!pixar!mike
And
John Stanley (dynasoft!john@stag.UUCP)
This work was done to produce a MIDI driver for MINIX/ST.
John wrote:
| ..I'm not surprised you're having trouble with this, the docs available,
|even from the chip manufacturer, are in a word 'lousy'... My sympathy if
|you're having to figure this out on your own... I had to myself.. :)
|
|
|> Anyone out there have a code sample that shows how to use the
|> transmit interrupt?? Thanks.
|
| Since I've done this, I can can assure you that it can be done.
|Unfortunately, since the code I wrote was while under contract to write a
|propriatary local area network, I can't send you source. Sorry...
|
| On the other hand, I can answer questions... The 'trick' is to disable
|the TXRDY just before you toss the last character in the buffer out the
|port, not when you receive the next interrupt and have nothing left to
|send... it's too late at that point. This also means that when you are
|loading the buffer, you have to enable TXRDY after you add a character to
|the buffer.
|
This is the Ultimate information on the crummy ACIA chip. The info works.
The consequence to me is that the output of a singe byte cannot have an
interrupt.
Mike sent a program. Considering John's info, I think this program works
by delaying until the last char is output before coercing the interrupts.
| Here you go:
|
|
| ---------------------- include file for Atari ST/Mega ACIA
| /* aciareg.h - definitions for Atari ST serial communications chip */
|
| #define ACIA_MIDI (aciareg *)0xfffffc04
| typedef struct aciareg {
| char csr;
| char filler;
| char data;
| } aciareg;
|
| /* control bits, write only */
| #define C_RESET 0x3 /* master reset */
| #define C_DIV1 0x0 /* divide clock by 1 */
| #define C_DIV16 0x1 /* divide clock by 16, normal for MIDI */
| #define C_DIV64 0x2 /* divide clock by 64 */
|
| #define C_7EVEN2 0x00 /* seven bits, even parity, 2 stop bits */
| #define C_7ODD2 0x04 /* seven bits, odd parity, 2 stop bits */
| #define C_7EVEN1 0x08 /* seven bits, even parity, 1 stop bit */
| #define C_7ODD1 0x0c /* seven bits, even parity, 1 stop bit */
|
| #define C_8NONE2 0x10 /* eight bits, no parity, 2 stop bits */
| #define C_8NONE1 0x14 /* eight bits, no parity, 1 stop bits */
| #define C_8EVEN1 0x18 /* eight bits, even parity, 1 stop bit */
| #define C_8ODD1 0x1c /* eight bits, odd parity, 1 stop bit */
|
| #define C_NO_RTS 0x40 /* disable RTS */
| #define C_TIENA 0x20 /* enable transmit interrupts */
| /* note: CTL_NO_RTS|CTL_TIENA sends a break */
| #define C_RIENA 0x80 /* enable reveive interrupts */
|
| #define INIT_MIDI (C_RIENA|C_8NONE1|C_DIV16) /* init MIDI */
| #define INIT_KBD (C_RIENA|C_8NONE1|C_DIV64) /* init keyboard */
|
| /* status bits, read only */
| #define S_RDATA 0x01 /* received data is present */
| #define S_XEMPTY 0x02 /* transmitter is ready */
| #define S_NOCARR 0x04 /* no carrier */
| #define S_CTS 0x08 /* no clear to send signal */
| #define S_FE 0x10 /* framing error */
| #define S_OVRN 0x20 /* reveive overrun */
| #define S_PE 0x40 /* parity error */
| #define S_IRQ 0x80 /* interrupt request */
|
| #define S_ERROR (S_FE|S_OVRN|S_PE) /* a receive error has occurred */
| ---------------------- interrupt handler for Atari ST/Mega MIDI
| #include <osbind.h>
| #include <aciareg.h>
|
| typedef int (func)();
|
| static func *imidiin, *imidiout; /* i/o interrupt handlers */
| static func *omidisys; /* original midi vector */
|
| static nullfunc() {}
|
| midisys() /* MIDI interrupt handler */
| {
| register aciareg *acia = ACIA_MIDI;
| char c;
| static xmitloop; /* transmitter interrupt loop detector */
| #define XMITMAX 1000
|
| if(acia->csr&S_RDATA && (c = acia->data) != (char)0xfe) {
| (*imidiin)(c);
| }
| if(acia->csr&S_XEMPTY) {
| if(imidiout) {
| (*imidiout)();
|
| /* guard against transmitter interrupt loop */
| if(acia->csr&S_XEMPTY) {
| if(++xmitloop>XMITMAX)
| acia->csr = INIT_MIDI;
| } else {
| xmitloop = 0;
| }
| } else {
| acia->csr = INIT_MIDI;
| }
| }
| }
|
| func *
| MidiISubr() { return imidiin; } /* get current input interrupt func */
|
| func *
| MidiOSubr() { return imidiout; } /* get current output interrupt func */
|
| MidiSys(isubr, osubr)
| func *isubr; /* MIDI input interrupt handler or zero */
| func *osubr; /* MIDI output interrupt handler or zero */
| /*
| ** Set up the MIDI ACIA to call C function isubr for input interrupts
| ** and osubr() for output interrupts. May be called while MIDI is
| ** active (but be ready for lost characters). Call with both functions
| ** set to zero to reset the first existing MIDI vector.
| */
| {
| register aciareg *acia = ACIA_MIDI;
| register kbdvecs *kv = Kbdvbase();
| long osp;
|
| imidiin = isubr?isubr:nullfunc;
| imidiout = osubr?osubr:nullfunc;
|
| if(isubr || osubr) {
| if(!omidisys)
| omidisys = kv->midisys; /* save the original vector */
| kv->midisys = midisys; /* replace it with our own */
| } else {
| if(omidisys)
| kv->midisys = omidisys; /* restore the original vector */
| }
|
| osp = Super(0L);
|
| /* if output function specified, enable transmit interrupts */
| if(osubr)
| acia->csr = INIT_MIDI|C_TIENA;
| else
| acia->csr = INIT_MIDI;
| Super(osp);
| }
| #ifdef MAIN
| #include <stdio.h>
| int booby;
| ifunc()
| {
| booby++;
| }
|
| main()
| {
| int obooby = 0;
|
| setbuf(stdout, NULL);
| MidiSys(ifunc, 0L);
| while(booby < 30) {
| if(obooby != booby)
| printf("%d\n", obooby = booby);
| }
| MidiSys(0L, 0L);
| }
| #endif MAIN
Finally, for you MINIX fans, here is the fix for handling the combined
MIDI and KBD interrupts that make TOS code so nasty:
/*===========================================================================*
* aciaint *
*===========================================================================*/
PUBLIC aciaint()
{
MFP->mf_ierb &= ~IB_AINT;
do {
if (KBD->ac_cs & A_IRQ)
kbdint();
if (MDI->ac_cs & A_IRQ)
mdiint();
} while ((MFP->mf_gpip & IO_AINT)==0);
MFP->mf_ierb |= IB_AINT;
}
The secret is the mask of the ierb register, NOT the imrb.
Turning on the bit in the ierb restrobes the input and will produce
a new interrupt even if the request stays up.
Thankyou again to Mike and John for their responses.
Howard Johnson
ATT-BL
lzaz!hcj
Technical Details
Message-ID:
<355@lzaz.ATT.COM>Path:
arc1-ca.pugleaf.net!utzoo!utgpu!attcan!uunet!lll-winken!lll-ncis!helios.ee.lbl.gov!pasteur!ucbvax!decwrl!labrea!rutgers!att!lzaz!hcjShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!attcan!uunet!lll-winken!lll-ncis!helios.ee.lbl.gov!pasteur!ucbvax!decwrl!labrea!rutgers!att!lzaz!hcj From: hcj@lzaz.ATT.COM (HC Johnson) Newsgroups: comp.sys.atari.st,comp.os.minix Subject: Summary of responses on MIDI interrupt handling Keywords: MIDI Interrupts Message-ID: <355@lzaz.ATT.COM> Date: 6 Jan 89 17:27:46 GMT Organization: AT&T ISL Lincroft NJ USA Lines: 223