chiark / gitweb /
seriallib interface draft
authorian <ian>
Thu, 17 Nov 2005 18:50:15 +0000 (18:50 +0000)
committerian <ian>
Thu, 17 Nov 2005 18:50:15 +0000 (18:50 +0000)
detpic/seriallib.inc [new file with mode: 0644]

diff --git a/detpic/seriallib.inc b/detpic/seriallib.inc
new file mode 100644 (file)
index 0000000..af77a34
--- /dev/null
@@ -0,0 +1,211 @@
+;######################################################################
+; seriallib.inc - SERIAL LIBRARY - DECLARATIONS AND DOCUMENTATION
+;
+;============================================================
+; GENERAL INFORMATION
+
+; Purpose:
+; --------
+;
+; This library allows the PIC to communicate with the host via the
+; PIC's UART, configured for RS232 at 9600 8N1.  It implements
+; unidirectional flow control: the host may ask the PIC not to
+; transmit, but not vice versa.
+
+; Naming scheme:
+; --------------
+;
+;  serial_...  are for use by the rest of the program and
+;               are the entrypoints which enable use of the serial port
+;  serialu_... must be defined in the rest of the program
+;               with the functionality and behaviour described.
+
+; At all times following serial_init, the serial hardware in the PIC is
+; completely reserved to the routines defined in seriallib.asm.  Nothing
+; else is allowed to read or modify the PIC UART state.
+
+; Use of PORTB, RBIF etc.:
+; ------------------------
+;
+; The seriallib makes use of the PORTB `interrupt on change' feature,
+; and expects at all times after serial_init to have exclusive use of
+; that feature, including the RBIF flag.  Only seriallib is allowed to
+; make reads of PORTB directly; the main program must call
+; serial_portb_read instead.  The main program may freely write to
+; LATB.
+;
+; If any of RB5, RB6 or RB7 is an output which would be electrically
+; floating if left in tristate (Z state by the PIC) then before
+; calling serial_init the main program must have configured the
+; appropriate TRISB bit(s) as outputs - presumably, after having
+; configured the corresponding LATB bit(s).  This will avoid excessive
+; interrupts resulting from floating values.
+;
+; Registers and calling conventions:
+; ----------------------------------
+;
+; Unless otherwise stated, all routines accept any value in, and may
+; trash, W and the flags.  All other registers and locations not
+; specifically mentioned here will be preserved by the
+; serial_... routines (and are therefore reserved for the rest of the
+; program).  In all cases, routines are called with CALL or RCALL or
+; the equivalent, and routines are allowed to have subroutines (ie, to
+; use the call/return address stack).
+
+; serial_... routines except serial_interrupt will never _directly_ call
+; any serialu_... routine; when we say `causes' this means that the
+; relevant serialu_... routine will be called at some later point from
+; serial_interrupt.  serialu_... routines are allowed to call appropriate
+; serial_... routines (except serial_interrupt) directly if the context
+; and Tx State allows.
+
+; All routines except serial_init and serial_write_please
+; must be called only:
+;   * During a low-priority interrupt;
+;   * From the main loop with low-priority interrupts disabled; or
+;   * From within an serialu_... routine (which are always called
+;     from within serial_interrupt).
+; This is to avoid having one serial_... routine running in an interrupt
+; which interrupted the middle of another serial_... routine.
+
+; Some time between calling serial_init and waiting for the first event,
+; the main program should of course enable interrupts.
+
+;============================================================
+; COMMON ROUTINES and RECEPTION
+
+;--------------------
+ extern serial_init
+;
+; Initialises the serial port and library state appropriately.  Must
+; be called exactly once, which must be before any other
+; serial_... function.
+;
+;                              At call                 On return
+;   serial controller          any                     for use by seriallib
+;   PORTB                      any                     for use by seriallib
+;   serial interrupt config    any                     enabled, low priority
+;   Port B interrupt-on-change any                     enabled, low priority
+;   TRISB<5:7>                 any outputs configured  unchanged
+;   TRISB<4>                   any                     configured for input
+;   TRISB<0:2>                 any                     unchanged
+;   LATB                       any outputs configured  unchanged, use freely
+;   global interrupt enable    disabled                unchanged
+;   Tx State                   Not-in-use              Must-Notify
+;
+; Note that as soon as the interrupts are enabled, the serial port
+; will generate an interrupt, so that we go from Tx State Must-Notify
+; to Idle via call to serialu_writeable.  (See the Transmission
+; section below.)
+
+;--------------------
+ extern serial_portb_read
+;                              At call                 On return
+;   W                          any                     value from PORTB
+;
+; Provided to allow the main program to read any bits in PORTB which
+; it is using as inputs.  See the notes above about PORTB.
+
+;--------------------
+ extern serial_interrupt
+;
+; Must be called by the main program's low priority interrupt handler.
+; The main program's interrupt handler is responsible for saving W and
+; the flags register and other interrupt-related administrivia.  If
+; there is a serial interrupt, this routine will service it, taking any
+; necessary action including calling appropriate serialu_... routines,
+; and clear the interrupt flag[*].
+;
+;                              At call                 On return
+;   Tx State                   any except Not-in-use   may change
+;   serial interrupt state     any                     cleared[*]
+;
+; [*] The interrupt event on entry, if any, will be dealt with.  If
+; interrupt processing takes a long time, another interrupt will occur
+; and this may result in the serial interrupt flag being set on return
+; from serial_inerrupt.
+
+;--------------------
+ extern serialu_receive
+;
+; Called to notify the main program that a byte has been recieved from
+; the host.  The byte value is supplied.  There is no way for the PIC
+; to signal flow control to the host, to stop the host from sending
+; data.  It is up to the main program to do _something_ with the
+; received data (or to panic or to discard it).
+;
+;              Beforehand      At call
+;   W                          data byte from host
+
+;======================================================================
+; TRANSMISSION
+;
+; States:
+;                      [Not-in-use]
+;                            |
+;                           |init
+;                            V
+;             ,------------->+<-------------.
+;             |              |              |
+;             |         [Must-Notify]       |
+;             |              |              |
+;             |   write_ready|              |
+;             |              |             |
+;             |              V                     |
+;             |            [Idle]           |
+;             |              |         `-----------'
+;             |    write_byte|    write_please
+;             |              |
+;             |              V
+;             |            [Busy]<----------.
+;             |              |  `-----------'
+;             `--------------'    write_please
+
+; The seriallib will handle the host's requests for flow control.
+
+;--------------------
+ extern serialu_write_ready
+;
+; Called to notify the main program that the serial port is now ready
+; to transmit a byte.  The main program should call serial_write_byte,
+; or serial_write_please, either immediately or at some later point.
+;
+;              Beforehand      At call
+;   Tx State   Must-Notify     Idle
+
+;--------------------
+ extern serial_write_byte
+;
+; Provides a byte to be written to the serial port.
+;
+;                              At call         On return
+;   Tx State                   Idle            Busy
+;   W                          byte for host   any
+
+;--------------------
+ extern serial_write_please
+;
+; Asks to be re-notified if the serial port is ready for transmission.
+; This will regenerate the call to serialu_write_ready if applicable.
+;
+;                              At call         On return
+;   Tx State                   Idle            Must-Notify
+;   Tx State                   Busy            Busy
+;
+; serialu_write_ready will *not* be called directly from
+; serial_write_please, but only from serial_interrupt (as discussed
+; above).
+;
+; Exceptionally, serial_write_please is fully reentrant.  It need not
+; be called from interrupt context and need not be called with
+; interrupts disabled.  It is permissible for serial_write_please to
+; be interrupted by an invocation of serial_interrupt or vice versa.
+;
+; For example, if the main program has a buffer of characters for
+; transmission, serialu_write_ready would call serial_write_byte if
+; the buffer had something in it.  If it didn't then it would simply
+; return.  When something is put in the buffer, the main program would
+; call serial_write_please unconditionally, which would ensure that
+; serialu_write_ready will be called soon.
+
+;======================================================================