April 28, 2024, 02:25:53 AM

News:

Got VSA?  Want to use your Prop-SX?  Now you can!  See the VSA section of the Library forum for Prop-SX code that works with VSA.


"Background" Serial -- Separate TX and RX (with Timer!)

Started by JonnyMac, June 30, 2008, 06:49:29 PM

Previous topic - Next topic

JonnyMac

June 30, 2008, 06:49:29 PM Last Edit: April 04, 2009, 09:27:04 AM by JonnyMac
This is an updated framework program that provides for "background" serial (2400 to 38.4k baud) and has a background countdown timer that can be useful for scheduling events.  This program is useful for communicating with devices like the uMP3 and the VMUSIC player.

' =========================================================================
'
'   File...... Buffered_Serial_with_Timer.SXB
'   Purpose...
'   Author.... Jon Williams, EFX-TEK
'              Copyright (c) 2007-2009 EFX-TEK
'              Some Rights Reserved
'              -- see http://creativecommons.org/licenses/by/3.0/
'   E-mail.... jwilliams@efx-tek.com
'   Started...
'   Updated... 04 APR 2009 (updated for SX/B 2.00.xx)
'
' =========================================================================


' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------


' -------------------------------------------------------------------------
' Conditional Compilation Symbols
' -------------------------------------------------------------------------


' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

ID              "BufSioTm"

DEVICE          SX28, OSCHS2, BOR42
FREQ            50_000_000


' -------------------------------------------------------------------------
' I/O Pins
' -------------------------------------------------------------------------

TX              PIN     RA.3 OUTPUT             ' to PC
RX              PIN     RA.2 INPUT              ' from PC


' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

IsOn            CON     1
IsOff           CON     0

Yes             CON     1
No              CON     0


' Bit dividers for 5.208us interrupt

Baud2400        CON     80
Baud4800        CON     40
Baud9600        CON     20
Baud19K2        CON     10
Baud38K4        CON     5

Baud1x0         CON     Baud38K4                ' 1 bit period (ISR counts)
Baud1x5         CON     Baud1x0 * 3 / 2         ' 1.5 bit periods


LF              CON     10
FF              CON     12                      ' like CLS for terminals
CR              CON     13


' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

flags           VAR     Byte
isrFlag        VAR     flags.0
rxReady        VAR     flags.1                 ' rx byte waiting
tmrRun         VAR     flags.2                 ' 1 = running, 0 = stopped

tmpB1           VAR     Byte                    ' work vars for subs/funcs
tmpB2           VAR     Byte
tmpW1           VAR     Word

cdTimer         VAR     Byte (5)                ' countdown timer
tix_LSB        VAR     cdTimer(0)              ' 0.1 sec counter
tix_MSB        VAR     cdTimer(1)
tenths         VAR     cdTimer(2)              ' 0.1 sec units
secs           VAR     cdTimer(3)              ' seconds
mins           VAR     cdTimer(4)              ' minutes

rxSerial        VAR     Byte (16)
rxBuf          VAR     rxSerial(0)             ' 8-byte buffer
rxCount        VAR     rxSerial(8)             ' rx bit count
rxDivide       VAR     rxSerial(9)             ' bit divisor timer
rxByte         VAR     rxSerial(10)            ' recevied byte
rxHead         VAR     rxSerial(11)            ' buffer head (write to)
rxTail         VAR     rxSerial(12)            ' buffer tail (read from)
rxBufCnt       VAR     rxSerial(13)            ' # bytes in buffer

txSerial        VAR     Byte (16)               ' tx serial data
txBuf          VAR     txSerial(0)             ' eight-byte buffer
txCount        VAR     txSerial(8)             ' tx bit count
txDivide       VAR     txSerial(9)             ' bit divisor timer
txLo           VAR     txSerial(10)            ' holds start bit
txHi           VAR     txSerial(11)            ' tx output reg
txHead         VAR     txSerial(12)            ' buffer head (write to)
txTail         VAR     txSerial(13)            ' buffer tail (read from)
txBufCnt       VAR     txSerial(14)            ' # bytes in buffer


' =========================================================================
  INTERRUPT NOPRESERVE 192_000                  ' (4)   5.208 uSecs
' =========================================================================


Mark_ISR:
  \ SETB  isrFlag                               ' (1)


' -----------------------------------
' Update Countdown Timer when Enabled
' -----------------------------------
'
Process_Timer:
  ASM
    JNB   tmrRun, Timer_Done                    ' 2/4)  abort if not running
    BANK  cdTimer                               ' (1)   point to timer vars
    INC   tix_LSB                               ' (1)   update LSB
    ADDB  tix_MSB, Z                            ' (2)   update MSB
    CJNE  tix_MSB, #$4B, Timer_Done             ' (4/6) 0.1s elapsed?
    CJNE  tix_LSB, #$00, Timer_Done             ' (4/6)
    CLR   tix_MSB                               ' (1)   yes, reset 1-sec
    SUB   tenths, #1                            ' (2)   update tenths
    JC    Timer_Check                           ' (2/4) exit if no roll-under
    MOV   tenths, #9                            ' (2)   reset tenths
    SUB   secs, #1                              ' (2)
    JC    Timer_Done                            ' (2/4)
    MOV   secs, #59                             ' (2)
    SUB   mins, #1                              ' (2)
    JC    Timer_Done                            ' (2/4)
    CLR   mins                                  ' (2)

Timer_Check:                                    '       is timer expired?
    MOV   W, tenths                             ' (1)   get tenths
    OR    W, secs                               ' (1)   check tenths & secs
    JNZ   Timer_Done                            ' (2/4) about if not zero
    OR    W, mins                               ' (1)   check mins
    SNZ                                         ' (1/2) skip if not zero
     CLRB tmrRun                                ' (1)   clear running flag

Timer_Done:
  ENDASM


' -------
' RX UART
' -------
'
' UART code by C. Gracey, A. Williams, et al
' -- buffer mods by Jon Williams
'
Receive:
  ASM
    BANK  rxSerial                              ' (1)
    JB    rxBufCnt.3, RX_Done                   ' (2/4) skip if buffer is full
    MOVB  C, RX                                 ' (4)   sample serial input
    TEST  rxCount                               ' (1)   receiving now?
    JNZ   RX_Bit                                ' (2/4) yes, get next bit
    MOV   W, #9                                 ' (1)   no, prep for next byte
    SC                                          ' (1/2)
     MOV  rxCount, W                            ' (1)   if start, load  bit count
    MOV   rxDivide, #Baud1x5                    ' (2)   prep for 1.5 bit periods

RX_Bit:
    DJNZ  rxDivide, RX_Done                     ' (2/4) complete bit cycle?
    MOV   rxDivide, #Baud1x0                    ' (2)   yes, reload bit timer
    DEC   rxCount                               ' (1)   update bit count
    SZ                                          ' (1/2)
     RR   rxByte                                ' (1)   position for next bit
    SZ                                          ' (1/2)
    JMP   RX_Done                               ' (3)

RX_Buffer:
    MOV   W, #rxBuf                             ' (1)   point to buffer head
    ADD   W, rxHead                             ' (1)
    MOV   FSR, W                                ' (1)
    MOV   IND, rxByte                           ' (2)   move rxByte to head
    INC   rxHead                                ' (1)   update head
    CLRB  rxHead.3                              ' (1)   keep 0..7
    INC   rxBufCnt                              ' (1)   update buffer count
    SETB  rxReady                               ' (1)   set ready flag

RX_Done:
  ENDASM


' -------
' TX UART
' -------
'
' UART code by C. Gracey, A. Williams, et al
' -- buffer mods by Jon Williams
'
Transmit:
  ASM
    BANK  txSerial                              ' (1)
    TEST  txCount                               ' (1)   transmitting now?
    JZ    TX_Buffer                             ' (2/4) if txCount = 0, no
    DEC   txDivide                              ' (1)   update bit timer
    JNZ   TX_Done                               ' (2/4) time for new bit?
    MOV   txDivide, #Baud1x0                    ' (2)   yes, reload timer
    STC                                         ' (1)   set for stop bit
    RR    txHi                                  ' (1)   rotate TX char buf
    RR    txLo                                  ' (1)
    DEC   txCount                               ' (1)   update the bit count
    MOVB  TX, txLo.6                            ' (4)   output the bit
    JMP   TX_Done                               ' (3)

TX_Buffer:
    TEST  txBufCnt                              ' (1)   anything in buffer?
    JZ    TX_Done                               ' (2/4) exit if empty
    MOV   W, #txBuf                             ' (2)   point to buffer tail
    ADD   W, txTail                             ' (1)
    MOV   FSR, W                                ' (1)
    MOV   txHi, IND                             ' (2)   move byte to TX reg
    CLR   txLo                                  ' (1)   clear for start bit
    MOV   txCount, #10                          ' (2)   start + 8 + 1 stop
    INC   txTail                                ' (1)   update tail pointer
    CLRB  txTail.3                              ' (1)   keep 0..7
    DEC   txBufCnt                              ' (1)   update buffer count

TX_Done:
  ENDASM

  RETURNINT                                     ' (4)


' -------------------------------------------------------------------------
' Subroutine / Function Declarations
' -------------------------------------------------------------------------

DELAY_TIX       SUB     2, 2, Word              ' delay in 6.51us units
DELAY_MS        SUB     2, 2, Word              ' replaces PAUSE

RX_BYTE         FUNC    1, 0                    ' receive a byte

TX_STR          SUB     2, 2, Word              ' transmit a string
TX_BYTE         SUB     1                       ' transmit a byte

UCASE           FUNC    1, 1                    ' convert to uppercase

START_TIMER     SUB     3, 3, Byte, Byte, Byte  ' set and start the timer


' =========================================================================
  PROGRAM Start
' =========================================================================

Start:
  PLP_A = %1100
  PLP_B = %00000000
  PLP_C = %00000000

  TX = 1                                        ' set to idle state
  DELAY_MS 5                                    ' clear terminal RX buffer


Main:

  GOTO Main


' -------------------------------------------------------------------------
' Subroutine / Function Code
' -------------------------------------------------------------------------

' Use: DELAY_TIX duration
' -- delay in ISR "ticks"
' -- 5.208us if ISR rate is 192_000

SUB DELAY_TIX
  '{$IFUSED DELAY_TIX}
  tixDuration   VAR     __WPARAM12

  DO WHILE tixDuration > 0
    ASM
      CLRB  isrFlag                             ' clear isr flag
      JNB   isrFlag, @$                         ' wait for next
    ENDASM
    DEC tixDuration                             ' update duration timer
  LOOP
  '{$ENDIF}
  ENDSUB

' -------------------------------------------------------------------------

' Use: DELAY_MS duration
' -- replaces PAUSE
' -- assumes ISR rate of 192_000

SUB DELAY_MS
  '{$IFUSED DELAY_MS}
  msDuration    VAR     __WPARAM12
  msTimer       VAR     __PARAM3

  DO WHILE msDuration > 0
    msTimer = 192                               ' (re)load 1ms timer
    DO WHILE msTimer > 0
      ASM
        CLRB  isrFlag                           ' clear isr flag
        JNB   isrFlag, @$                       ' wait for next
        DEC   msTimer                           ' update 1ms timer
      ENDASM
    LOOP
    DEC msDuration                              ' update duration timer
  LOOP
  '{$ENDIF}
  ENDSUB

' -------------------------------------------------------------------------

' Use: aByte = RX_BYTE
' -- returns "aByte" from 8-byte circular buffer
' -- will wait if buffer is presently empty
' -- rxBufCnt holds byte count of receive buffer (0 to 8)

FUNC RX_BYTE
  '{$IFUSED RX_BYTE}
  ASM
    JNB   rxReady, @$                           ' wait if empty
    BANK  rxSerial
    MOV   FSR, #rxBuf                           ' point to rxBuf(rxTail)
    ADD   FSR, rxTail
    MOV   __PARAM1, IND                         ' get byte at tail
    INC   rxTail                                ' update tail
    CLRB  rxTail.3                              ' keep 0..7
    DEC   rxBufCnt                              ' update buffer count
    SNZ                                         ' exit if not zero
     CLRB rxReady                               ' else clear ready flag
    BANk  $00
  ENDASM
  '{$ENDIF}
  ENDFUNC

' -------------------------------------------------------------------------

' Use: TX_STR [String | Label]
' -- pass embedded string or DATA label

SUB TX_STR
  '{$IFUSED TX_STR}
  strAddr       VAR     tmpW1
  strChar       VAR     __PARAM1

  strAddr = __WPARAM12                          ' get string address

  DO
    READINC strAddr, strChar                    ' read a character
    IF strChar = 0 THEN EXIT                    ' if 0, string complete
    TX_BYTE strChar                             ' send the byte
  LOOP
  '{$ENDIF}
  ENDSUB

' -------------------------------------------------------------------------

' Use: TX_BYTE aByte
' -- moves "aByte" to 8-byte circular buffer (when space is available)
' -- will wait if buffer is presently full
' -- txBufCnt holds byte count of transmit buffer (0 to 8)

SUB TX_BYTE
  '{$IFUSED TX_BYTE}
  ASM
    BANK  txSerial
    JB    txBufCnt.3, @$                        ' prevent buffer overrun
    MOV   W, #txBuf                             ' point to buffer head
    ADD   W, txHead
    MOV   FSR, W
    MOV   IND, __PARAM1                         ' move byte to tx buf
    INC   txHead                                ' update head pointer
    CLRB  txHead.3                              ' keep 0..7
    INC   txBufCnt                              ' update buffer count
    BANK  $00
  ENDASM
  '{$ENDIF}
  ENDSUB

' -------------------------------------------------------------------------

' Use: result = UCASE char
' -- if char is lowercase alpha it is converted to uppercase

FUNC UCASE
  '{$IFUSED UCASE}
  ASM
    CJB   __PARAM1, #"a", @UC_Exit
    CJA   __PARAM1, #"z", @UC_EXIT
    CLRB  __PARAM1.5

UC_Exit:
  ENDASM
  '{$ENDIF}
  ENDFUNC

' -------------------------------------------------------------------------

' Use: START_TIMER mins, secs, tenths
' -- loads and starts background timer
' -- tmrRun flag cleared to 0 when timer expires

SUB START_TIMER
  '{$IFUSED START_TIMER}
  tmrRun = IsOff                                ' stop while reloading
  ASM
    BANK  cdTimer
    MOV   mins, __PARAM1                        ' capture minutes
    MOV   secs, __PARAM2                        ' capture seconds
    MOV   tenths, __PARAM3                      ' capture tenths

Check_Secs:
    CJB   secs, #60, @Check_Tenths              ' validate secs
    MOV   secs, #59                             ' set to max if bad

Check_Tenths:
    CJB   tenths, #10, @ST_Exit                 ' validate tenths
    MOV   tenths, #9                            ' set to max if bad

ST_Exit:
    CLR   tix_LSB                               ' reset 0.1s timer
    CLR   tix_MSB
    BANK  $00
  ENDASM
  tmrRun = IsOn                                 ' start the timer
  '{$ENDIF}
  ENDSUB


' -------------------------------------------------------------------------
' User Data
' -------------------------------------------------------------------------

CrLf:
  DATA  CR, LF, 0                               ' CR + LF
Jon McPhalen
EFX-TEK Hollywood Office