Interrupt Driven Communications
Although the in-line Seatalk communications routines worked well, it was
decided to develop an interrupt-driven version so as to make their integration
into complex programs simpler. Although not needed for the initial
scope of the project (a remote control) it looked like being an interesting
thing to do.
The routines were designed around the same hardware, and to provide
exactly the same functions, as the basic routines described on the previous
page. It was decided to retain the same strategy as those routines
(ie. read single bytes, write entire datagrams).
If the main program is do any processing of received datagrams, it would
be more convenient to have the receive routine assemble the datagram and
flag the main program when this is complete. Since the seatalk
protocol incorporates the datagram length, this would be quite simple to
do, but was not in fact done mainly to simplify the receive test routine
that just echoes received bytes to the PC.
Software Design
The commented MPASM source code for this routine is given here.
The interrupt routine, which is driven by the Timer 2 interrupt (each
208us or 1 bit period at 4800 baud), implements a state machine with
4 basic states, reflected by flags in INT_STATUS. These
states are:
-
state IDLE (idle): monitors bus and keeps count of the time
it is idle. Sets up for writing and exits to state TXP if
the write request bit TXR is set by the main program and the bus
is free. The external PB0 interrupt is enabled during the state (only)
and hi-lo transition on the Seatalk bus causes a transition to state
RX1
-
state RX1 (receive start bit): entered by PB0 interrupt, waits
1/2 bit time so that reads are correctly synchronised. The next timer
interrupt causes a check for the start bit, and, if valid, changes the
state to RX2
-
state RX2 (receive data bits): in this state, each timer interrupt
shifts in a bit up to and including the stop bit. User interface
flags are set to indicate completion and possible errors. The state
is then reset to IDLE.
-
state TXP (transmit pending): In this state, bits are shifted
out to the Seatalk bus from a formatted byte buffer. which contains the
start bits, 8 data bits, command bit and stop bit (11 bits in all).
To maximise timing accuracy, this buffer is set up on completion of the
previous byte (while its stop bit is being sent), or during the IDLE
state for the first byte. Collision detection is performed at the
end of each bit period and simply resets the state to IDLE: since
the TXR flag is unchanged, this will result in the whole procedure
being repeated until it is successful, or the TXR bit is reset
by the main program. Succesful completion is indicated to the main
program by the TXR bit being reset by the interrupt routine.
Since all processing is done by the interrupt routines, it is transparent
to the user program, which thus "sees" a very simple interface reflected
by flag bits in TR_STATUS.
To read a byte:
-
wait for RDR (receive data ready) high. This flag needs
to be sampled at least once every byte period (2ms)
-
make private copy of REC_BYTE and TR_STATUS, possibly with interrupts disabled
(not strictly necessray)
-
set RDR low, and possibly also RDO
-
check the private copy of TR_STATUS for overrun (RDO) and framing
(RDF) errors as well as the command bit (RD9).
-
process the byte in REC_BYTE
To write a datagram:
-
set up datagram in DGRAM_BUF and DGRAM_SIZE
-
wait for TXR (transmit request) clear, if necessary clear it to
abort pending write
-
set TXR
The source listing also contains code to test the interrupt routine.
This just polls the RDR bit and echoes any received byte to the
PC, and then polls the UART receive flag for a command byte which it incorporates
into a "remote control" datagram and then sets the TXR flag.
Results and Comments
Testing followed the process described for the in-line routines with the
same positive results.
Updates
17th March 2003 minor bugfixes:
-
OPTION register setting for INTEDG was with incorrect
regsiter bank selection (did not matter since the power-on default was
used)
-
cleared TR_STATUS during initialization to prevent sending of
garbage after switch-on
-
adjusted value of SYNC_4800 to improve receive reliability