![]() |
Free Computer Shop |
#if SERIAL_PORT_TWO
byte newc;
short int fullness;
if (*UISR(2) & UIMR_RXRDY) {
@<process the newly arrived character 2@>
} else if ((*UISR(2) & UIMR_TXRDY) && Taking_TX_interrupts2) {
@<send a character or shutup 2@>
The Taking_TX_interrupts2 leads me to believe I'm not doing something to
allow TX interrupts (or is this just a flag in your code?).
Here is a further clip from the same program that shows how to initialize interrupts. I wish I could show the beautifully typeset Postscript or PDF version, but I have no time to figure out how to get that through my ISP, who doesn't support FTP. So here it is partially converted to HTML and partially in source form.
@d IMR SIM_register_word(0x0036)
@d IMR_UART1 0x1000
@d IMR_UART2 0x2000
@d IMR_TIMER2 0x0400
@<initialize and allow interrupts@>=
@<Properly locate Interrupt Vector Table@>;
@<initialize UART interrupts@>;
@<initialize Timer interrupts@>;
#if SERIAL_PORT_TWO
*IMR = (~IMR_UART1) & (~IMR_UART2) & (~IMR_TIMER2);
#else
*IMR = (~IMR_UART1) & (~IMR_TIMER2);
#endif
SetIntLevel(0);
We can choose which of several conditions will cause the UART
to generate an interrupt. This is done by setting bits in a mask
register. Right now, we want interrupts only when a new character
arrives, but this mask will be changed frequently as the program runs.
The same location is refered to as a mask register when it is written,
and as a status register when it is read.
@d UISR(n) UART_REGS(n,0x14)
@d UIMR(n) UART_REGS_UFAKE(n,0x14)
@d UIMR_RXRDY 0x02
@d UIMR_TXRDY 0x01
@<initialize UART interrupts@>=
#if MULTIDROP
*UIMR(1) = UIMR_RXRDY;
Taking_TX_interrupts = 0;
#else
*UIMR(1) = UIMR_RXRDY | UIMR_TXRDY;
Taking_TX_interrupts = 1;
#endif
@ @<initialize second UART interrupts@>=
*UIMR(2) = UIMR_RXRDY | UIMR_TXRDY;
Taking_TX_interrupts2 = 1;
The |vector_table| has been set up (in ROM, possibly copied to RAM)
so that interrupt
vector~64 points to the Interrupt Service Routine for the serial
port, |UARTinterrupt|. We also have to tell the UART hardware that
this is the interrupt to generate when something happens.
@d UIVR(n) UART_REGS(n,0x30)
@<initialize UART interrupts@>+=
*UIVR(1) = 64; /* UART Interrupt Vector Register */
@ @<initialize second UART interrupts@>=
*UIVR(2) = 65;
To initialize interrupts from the UART we must turn off the bit in
the Interrupt Mask Register that masks out UART interrupts. When the
interrupt priority mask level becomes low enough, interrupts will them
be enabled.
@<initialize UART interrupts@>+=
#if MULTIDROP
*UCR(1) = UCR_DISABLE_RX;
#else
*UCR(1) = UCR_ENABLE_RX;
#endif
TransmitterEnabled = 0;
@<initialize UART Interrupt Control Register@>
@ @<initialize second UART interrupts@>=
*UCR(2) = UCR_ENABLE_RX + UCR_ENABLE_TX;
The first UART interrupt is given level six, priority three.
@d ICR12 SIM_register_byte(0x001F)
@d ICR13 SIM_register_byte(0x0020)
@d UART_intlevel 6
@d UART_intprio 3
@d UART2_intprio 2
@<initialize UART Interrupt Control Register@>=
*ICR12 = (UART_intlevel<<2) + UART_intprio;
*ICR13 = (UART_intlevel<<2) + UART2_intprio;
@d UART_REGS(n,r) SIM_register_byte(UART1+(n-1)*(UART2-UART1)+r) @d UART_REGS_UFAKE(n,r) SIM_register_byte(UART1+(n-1)*(UART2-UART1)+UNIX_TEST*0x40+r)First we reset the serial port. This is done by putting a command into a Command Register.
@d UART1 0x140 @d UART2 0x180 @d UCR(n) UART_REGS(n,0x08) @d UCR_RESET_TX 0x30 @d UCR_RESET_RX 0x20 @d UCR_RESET_MR 0x10 @d UCR_RESET_ERROR 0x40 @d UCR_ENABLE_TX 0x04 @d UCR_ENABLE_RX 0x01 @d UCR_DISABLE_RX 0x02 @d UCR_DISABLE_TX 0x08 @<set up UART@>= *UCR(1) = UCR_RESET_TX; /* reset transmitter, */ *UCR(1) = UCR_RESET_RX; /*... the receiver, */ *UCR(1) = UCR_RESET_MR; /*...and mode register */ *UCR(1) = UCR_RESET_ERROR; @ @<set up second UART@>= *UCR(2) = UCR_RESET_TX; /* reset transmitter, */ *UCR(2) = UCR_RESET_RX; /*... the receiver, */ *UCR(2) = UCR_RESET_MR; /*...and mode register */ *UCR(2) = UCR_RESET_ERROR;Next set some basic operating modes.
@d UMR(n) UART_REGS(n,0x00) @d UMR_1_PM_NONE 0x10 @d UMR_1_PM_MULTI_DATA 0x18 @d UMR_1_BC_8 0x03 @d UMR_1_BC_7 0x02 @d UMR_2_TXRTS 0x20 @d UMR_2_STOP_BITS_1 0x07 @d UMR_2_STOP_BITS_2 0x0F @<set up UART@>+= #if MULTIDROP *UMR(1) = UMR_1_PM_MULTI_DATA + UMR_1_BC_7; /* mode register first write */ *UMR(1) = UMR_2_STOP_BITS_1 + UMR_2_TXRTS; /* mode register second write */ #else *UMR(1) = UMR_1_PM_NONE + UMR_1_BC_8; /* mode register first write */ *UMR(1) = UMR_2_STOP_BITS_1; /* mode register second write */ #endif @ @<set up second UART@>= *UCR(2) = UCR_RESET_MR; /*...and mode register */ *UMR(2) = UMR_1_PM_NONE + UMR_1_BC_8; /* mode register first write */ *UMR(2) = UMR_2_STOP_BITS_1; /* mode register second write */Set up the baud rate and timing.
For the 50MHz board:
@d UCSR(n) UART_REGS_UFAKE(n,0x04)
@d UBG1(n) UART_REGS(n,0x18)
@d UBG2(n) UART_REGS(n,0x1C)
@<set up UART@>+=
*UCSR(1) = 0xDD; /* Set the receive and transmit to timer mode. */
*UBG1(1) = 0x00; /* set 19200 bits per second */
*UBG2(1) = 0x51;
@ @<speed up UART@>=
*UBG1(1) = 0x00; /* set 38400 bits per second */
*UBG2(1) = 0x28;
@ @<set up second UART@>=
*UCSR(2) = 0xDD; /* Set the receive and transmit to timer mode. */
#if 1
*UBG1(2) = 0x00; /* set 19200 bits per second */
*UBG2(2) = 0x51;
#else
*UBG1(2) = 0x00; /* set 9600 bits per second */
*UBG2(2) = 0xA2;
#endif