Author: robhamerling
Date: Tue Sep 23 11:58:19 2008
New Revision: 330

Added:
    trunk/unvalidated/include/peripheral/usart/serial_hw_int_cts.jal

Log:
Serial library with buffered interrupt driven I/O, and CTS flow control

Added: trunk/unvalidated/include/peripheral/usart/serial_hw_int_cts.jal
==============================================================================
--- (empty file)
+++ trunk/unvalidated/include/peripheral/usart/serial_hw_int_cts.jal    Tue  
Sep 23 11:58:19 2008
@@ -0,0 +1,290 @@
+-- ===================================================
+-- Title: serial_hw_int_cts.jal. Interrupt driven buffered serial  
interface with flow control.
+--
+-- Author: Rob Hamerling, Copyright (c) 2008..2008, all rights reserved.
+--
+-- Adapted-by:
+--
+-- Compiler: =2.4h
+--
+-- This file is part of jallib  (http://jallib.googlecode.com)
+-- Released under the BSD license  
(http://www.opensource.org/licenses/bsd-license.php)
+--
+-- Description: Serial communications
+--              - receive and transmit data transfer is interrupt driven
+--              - receive and transmit data transfer uses circular buffers
+--              - automatic CTS flow control with spare free space for  
FiFo buffer
+--
+-- Sources:
+--
+-- Notes:
+--
+-- The RS232 interface chip may be any converter chip.
+-- A MAX202 or similar with small or no external capacitors is preferred.
+--
+-- The PIC ports use positive logic:
+-- '1' is positive voltage, '0' is ground.
+--
+-- In the RS232 standard:
+-- - Negative voltage ('mark') means OFF for control signals, and
+--   indicates 1 (one) for data signals (start-, data-, stop-bits).
+-- - Positive voltage ('space') means ON for control signals and
+--   0 (zero) for start-, data- and stop-bits.
+-- - Signal levels: 'mark' = -3V to -15V,  'space' = +3V to +15V
+--
+-- The MAX202 is not only a voltage level CONverter (between TTL and RS232)
+-- but also a signal INverter. You should be aware of the following:
+-- - The inversion of PIC data-in and data-out by the MAX202 is required
+--   to convert data-, start- and stop-bits to/from the corresponding
+--   RS232 polarity. So nothing special has to be done in the program
+--   because the USART of the PIC uses 'inverted' signal levels!
+-- - For CTS the inversion by the MAX202 is NOT desired.
+--   Therefore the program has to use inverted signalling for CTS:
+--   'FALSE' is used for ON and 'TRUE' for OFF!
+--   As a reminder for this 'inverted' logic the signal is called
+--   serial_cts_inv (e.g. serial_CTS_inv = true means CTS is false!).
+--
+-- Remember also: RxD of RS232-plug connects to TX of PIC via MAX202
+--                TxD of RS232-plug connects to RX of PIC via MAX202
+--
+-- Available procedure/function for application programs:
+--
+--  - serial_setup()
+--  - serial_send_byte(byte out <byte>)
+--  - serial_receive_byte(byte in <byte>) returns bit
+--
+--
+-- =======================================================================
+
+-- Application program must specify _before_ including this library:
+
+--  const   SERIAL_XMTBUFSIZE  = 32             -- size of transmit buffer
+--  const   SERIAL_RCVBUFSIZE  = 64             -- size of receive buffer
+--  const   SERIAL_DELTA       = 17             -- spare receive buffer  
space
+--
+--  const   SERIAL_BPSRATE     = 9600           -- host communications
+--                                              -- (range 9600..57600)
+--
+--  var  bit  serial_ctsinv            is pin_B4   -- incoming flow ctl
+--  var  bit  serial_ctsinv_direction  is pin_B4_direction
+
+-- Notes: - The pins above are given as example for a 16F88.
+--        - The pins for data transmit and receive are selected  
automatically.
+
+-- =======================================================================
+
+-- Circular buffers for communications with PC via UART:
+
+var    byte  _serial_xmtbuf[SERIAL_XMTBUFSIZE]   -- circular output buffer
+var    byte  _serial_rcvbuf[SERIAL_RCVBUFSIZE]   -- circular input buffer
+
+-- Offsets in circular buffers:
+
+var    byte  _serial_offsetxmthead               -- offset next byte from  
appl
+var    byte  _serial_offsetxmttail               -- offset next byte to  
port
+var    byte  _serial_offsetrcvhead               -- offset next byte from  
port
+var    byte  _serial_offsetrcvtail               -- offset next byte to  
appl
+
+
+-- =======================================================================
+-- - UART - serial transmit interrupt handling
+-- =======================================================================
+
+procedure  _serial_transmit_interrupt_handler() is
+
+   pragma interrupt
+
+   var  byte  x;
+
+   if ((PIR1_TXIF == TRUE) & (PIE1_TXIE == TRUE)) then  -- UART xmit  
interrupt
+      if (_serial_offsetxmttail != _serial_offsetxmthead) then  -- data in  
xmit buffer
+         x = _serial_xmtbuf[_serial_offsetxmttail]              -- next  
byte to xmit
+         _serial_offsetxmttail = _serial_offsetxmttail + 1      -- next  
position
+         if (_serial_offsetxmttail >= SERIAL_XMTBUFSIZE) then   -- beyond  
buffer
+            _serial_offsetxmttail = 0           -- wrap to begin
+         end if
+         if (_serial_offsetxmttail == _serial_offsetxmthead) then  -- last  
byte xmt'd
+            PIE1_TXIE = FALSE                   -- disable xmit interrupts
+         end if
+         TXREG = x                              -- actually xmit byte
+      end if
+   end if
+
+end procedure
+
+
+-- =======================================================================
+-- - UART - serial receive interrupt handling
+-- =======================================================================
+
+procedure  _serial_receive_interrupt_handler() is
+
+   pragma interrupt
+
+   var  byte  x;
+
+   if  (PIR1_RCIF == TRUE)  then                -- UART receive interrupt
+
+      if ((RCSTA_OERR == TRUE) | (RCSTA_FERR == TRUE)) then  --  
frame/overr error
+         x = RCREG                              -- flush hardware buffer
+         while RCSTA_OERR == TRUE loop          -- overrun state
+            RCSTA_CREN = FALSE                  -- disable UART
+            RCSTA_CREN = TRUE                   -- re-enable UART
+            x = RCREG                           -- \  flush hardware  
buffers
+            x = RCREG                           -- /
+         end loop                               -- until no more overrun
+         _serial_offsetrcvtail = 0              -- \  flush circular buffer
+         _serial_offsetrcvhead = 0              -- /
+         serial_ctsinv = FALSE                  -- ensure CTS true
+
+      else                                      -- data without errors
+         _serial_rcvbuf[_serial_offsetrcvhead] = RCREG      -- move byte  
to rcv buffer
+         x = _serial_offsetrcvhead + 1          -- update offset
+         if x >= SERIAL_RCVBUFSIZE then         -- buffer overflow
+            x = 0                               -- wrap
+         end if
+         if (x != _serial_offsetrcvtail) then   -- buffer not yet full
+            _serial_offsetrcvhead = x           -- update offset
+         end if                                 -- (else discard byte,
+                                                --  CTS flow control has  
failed)
+         if (serial_ctsinv == FALSE) then       -- CTS is TRUE
+            if _serial_offsetrcvhead > _serial_offsetrcvtail then  --  
offset difference
+               x = SERIAL_RCVBUFSIZE - _serial_offsetrcvhead +  
_serial_offsetrcvtail
+            else
+               x = _serial_offsetrcvtail - _serial_offsetrcvhead
+            end if
+            if (x < SERIAL_DELTA) then          -- circular buffer almost  
full
+               serial_ctsinv = TRUE             -- set CTS FALSE
+            end if
+         end if
+      end if
+
+   end if
+
+end procedure
+
+
+-- --------------------------------------------------------------
+--  Return byte (if any) from circular receive buffer for UART
+--
+--  input:   nothing
+--
+--  output:  received byte (if any)
+--
+--  returns: true  when byte returned
+--           false if no byte available
+--
+--  notes: - Rises CTS when receive buffer has more than <DELTA>
+--           bytes free space after delivering byte to caller.
+--
+-- -----------------------------------------------
+
+function  serial_receive_byte(byte out data) return bit is
+
+   var  byte  x                                 -- for buffer management
+
+   if (_serial_offsetrcvtail == _serial_offsetrcvhead) then  -- receive  
buffer empty
+      return false                              -- no data available
+   end if
+
+   data = _serial_rcvbuf[_serial_offsetrcvtail]  -- first available byte
+   _serial_offsetrcvtail = _serial_offsetrcvtail + 1
+   if (_serial_offsetrcvtail >= SERIAL_RCVBUFSIZE) then  -- buffer overflow
+      _serial_offsetrcvtail = 0                 -- wrap
+   end if
+   if (serial_ctsinv == TRUE) then              -- CTS is FALSE
+      if (_serial_offsetrcvhead > _serial_offsetrcvtail) then
+         x = SERIAL_RCVBUFSIZE - _serial_offsetrcvhead +  
_serial_offsetrcvtail
+      else
+         x = _serial_offsetrcvtail - _serial_offsetrcvhead  -- offset  
difference
+      end if
+      if (x >= SERIAL_DELTA) then               -- enough free space now
+         serial_ctsinv = FALSE                  -- make CTS TRUE
+      end if
+   end if
+
+   return true                                  -- byte available
+
+end function
+
+
+-- --------------------------------------------------------------
+--  Put a single byte in circular transmit buffer for UART
+--
+--  input:   byte to transmit
+--
+--  returns: transmitted byte
+--
+--  notes: - Initiates transmission (interrupt handler)
+--           when not currently transmitting
+--         - spin when transmit buffer full
+--           (wait for free buffer space)
+--
+-- -----------------------------------------------
+
+function  serial_send_byte(byte in data) return byte is
+
+   var  byte  new_serial_offset                 -- offset in circular  
buffer
+
+   if (_serial_offsetxmthead == _serial_offsetxmttail  &  -- nothing  
buffered
+       PIR1_TXIF == true) then                  -- and UART not busy
+      PIE1_TXIE = FALSE                         -- disable xmt interrupt
+      TXREG = data                              -- transmit byte  
immediately
+   else                                         -- use circular buffer
+      _serial_xmtbuf[_serial_offsetxmthead] = data  -- put byte in buffer
+      new_serial_offset = _serial_offsetxmthead + 1   -- offset next char
+      if (new_serial_offset >= SERIAL_XMTBUFSIZE) then  -- beyond buffer  
boundary
+         new_serial_offset = 0                  -- wrap to begin
+      end if
+      while (new_serial_offset == _serial_offsetxmttail) loop   -- buffer  
full!
+         -- nothing                             -- spin until something  
xmit'd
+      end loop
+      PIE1_TXIE = TRUE                          -- (re-)enable xmit  
interrupts
+      _serial_offsetxmthead = new_serial_offset  -- update offset now
+   end if
+
+   return data                                  -- transmitted byte!
+
+end function
+
+
+-- -----------------------------------------------------------------------
+-- Serial_Setup - procedure to initialize serial communications
+-- -----------------------------------------------------------------------
+
+procedure serial_setup() is
+
+   serial_ctsinv_direction = output             -- input: UART CTS->PC
+
+   _serial_offsetxmthead  = 0                   -- offset next byte from  
appl
+   _serial_offsetxmttail  = 0                   -- offset next byte to port
+   _serial_offsetrcvhead  = 0                   -- offset next byte from  
port
+   _serial_offsetrcvtail  = 0                   -- offset next byte to appl
+
+   RCSTA                  = 0b0000_0000         -- reset
+   RCSTA_SPEN             = enabled             -- serial port enable
+   RCSTA_CREN             = enabled             -- continuous receive  
enable
+
+   TXSTA                  = 0b0000_0000         -- reset (8 bit, asyn)
+   TXSTA_TXEN             = enabled             -- UART transmit enabled
+   TXSTA_BRGH             = true                -- high baud rate
+   SPBRG                  = (target_clock / 16 / SERIAL_BPSRATE * 10 - 5)  
/ 10
+
+   PIE1_RCIE              = enabled             -- UART receive int. enable
+                                                -- (PIE1_TXIE dynamically)
+   INTCON_PEIE            = enabled             -- periferal
+   INTCON_GIE             = enabled             -- general
+
+   serial_ctsinv          = false               -- CTS true: accept PC data
+
+end procedure
+
+
+-- -----------------------------------------------------------------------
+-- Initialize serial communications
+-- -----------------------------------------------------------------------
+
+serial_setup()
+
+-- =======================================================================
+

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"jallib" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/jallib?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to