Peter Verkaik says:
Unable to find an existing uart for 8 databits + parity I wrote one myself. I saw a few posts on the basic stamp forum about this so I share this. It is an assembly source.The program itself contains more than just the uart as it is written as a template to be extended for applications.
;*****************************************************************************************
; ELX1 board, co-procesor template
; ----------------------------------------------------------------------------------------
;
; version 0.9 beta
; december 9, 2004
; compile with SASM
;
; Author: Peter Verkaik
; Email: peterverkaik@boselectro.nl
;
; This program is a SX28 template providing a 2-wire host interface (halfduplex serial line +
; write enable line used for synchronization), and a 2-wire serial interface for terminal or
; other serial device. This terminal interface can be configured at runtime for:
; TX/RX with or without xon/xoff handshake, TX only with CTS handshake, RX only with RTS handshake
; four selectable baudrates (default 1200,2400,9600,19200)
; 7 or 8 databits
; parity odd, even or none
; powerup default is TX/RX without handshake, 1200 baud, 8 databits, no parity
; Port A is dedicated to the host and terminal.
; Ports B and C are not used and are available for the application.
; Code pages 2 and 3 are empty
; Ram banks 4, 5, 6 and 7 are empty
; 5 free global ram bank bytes
; four 8-byte buffers for terminal and host uarts
; Host command interface is expandable for up to 128 commands
;
;*****************************************************************************************
; Connection diagram. Both wires should have 4.7k-10k pullup resistor.
;
; MCU co-processor (this device)
; -------+ +------------------------+
; | | |
; pinWE o------o RA.1 = /WE |
; pinDQ o------o RA.0 = DQ |
; | | RC.0-RC.7 o-- application
; -------+ | RB.0-RB.7 o-- application
; | |
; | RA.2 o-- terminal TX (or RTS in case of RX/RTS)
; | RA.3 o-- terminal RX (or CTS in case of TX/CTS)
; +------------------------+
;
;*****************************************************************************************
; Communication protocol between this device and the host MCU.
;
; ------+ +-+ +------+-----
; pinWE S0 | S1 | S2 | | S3 | S4 | S5 | S0
; +-----+-------------------+ +-----+-----------------------+
; <--- pulled low by MCU ---> <- pulled low by this device ->
;
; ------+ +-+ +------+-----
; pinDQ <cmd> <param1>...<paramN> <rsp> <data1>...<dataN>
; - hiZ +- - - - - input - - - - -+-+ - - - - output - - - - - - -+ - - hiZ - -
;
; State S0: idle
; State S1: receive command byte
; State S2: receive parameter bytes
; State S3: transmit response byte
; State S4: transmit data bytes
; State S5: finalize
;
; Each command sequence starts at the H->L transition on pinWE.
; This may be follwed by <cmd> and <param> bytes.
; A L->H transition on pinWE (from MCU) is ALWAYS follewed by
; a H->L transition and <rsp>.
; <data> bytes are optional and determined by command or status.
; The command sequence stops after this device releases pinWE.
;
;-----------------------------------------------------------------------------------------
; program modules
;-----------------------------------------------------------------------------------------
device SX28,oschs1,turbo,stackx,optionx ;sx device options
irc_cal IRC_SLOW
id 'ELX1TMPL' ;Elx1 board template
reset reset_entry ;set reset vector
;select one of these freq
;freq 4_000_000
;freq 10_000_000
freq 20_000_000
;select according to freq
;RESONATOR equ 4
;RESONATOR equ 10
RESONATOR equ 20
ERROR p2w 'Assembled assuming a ' RESONATOR ' MHz oscillator'
; The host interface (pins ra.0 and ra.1) is used to accept commands and data
; from a host mcu and delivers status and data to that mcu.
; The terminal interface (pins ra.2 and ra.3) is used to accept key input from a terminal(program)
; and delivers display/control characters to that terminal(program).
;-----------------------------------------------------------------------------------------
; uart constants
;-----------------------------------------------------------------------------------------
IF RESONATOR = 20
;128*1200=64*2400=32*4800=16*9600=8*19200
;uartfs=128*1200=153600
;int_period=20000000/153600=130
uartfs equ 153600 ; uart's basic frequency 128*1200 = 153600
int_period equ 130 ; 6.5uS used as seed for uart baud rate.
THREADS equ 1
ENDIF
IF RESONATOR = 10
;64*1200=32*2400=16*4800=8*9600=4*19200
;uartfs=64*1200=76800
;int_period=10000000/76800=130
uartfs equ 76800 ; uart's basic frequency 64*1200 = 76800
int_period equ 130 ; 13uS used as seed for uart baud rate.
THREADS equ 1
ENDIF
IF RESONATOR = 4
;32*1200=16*2400=8*4800=4*9600=2*19200
;uartfs=32*1200=38400
;int_period=4000000/38400=104
uartfs equ 38400 ; uart's basic frequency 32*1200 = 38400
int_period equ 104 ; 26uS used as seed for uart baud rate.
THREADS equ 1
ENDIF
mscount equ ((2000*RESONATOR/int_period)+1)/2 ;number of int cycles for 1 msec
ERROR p2w '# of cycles per interrupt = ' mscount
XON equ 17 ;XON character (ctrl-Q)
XOFF equ 19 ;XOFF character (ctrl-S)
;The following baudrates are available
baud0 equ 1200
baud1 equ 2400
baud2 equ 4800
baud3 equ 9600
baud4 equ 19200
; 20MHz 10MHz 4MHz
divide0 equ uartfs / (baud0 * THREADS) ; 128 64 32
StDelay0 equ divide0 + (divide0 / 2) ; 192 96 48
divide1 equ uartfs / (baud1 * THREADS) ; 64 32 16
StDelay1 equ divide1 + (divide1 / 2) ; 96 48 24
divide2 equ uartfs / (baud2 * THREADS) ; 32 16 8
StDelay2 equ divide2 + (divide2 / 2) ; 48 24 12
divide3 equ uartfs / (baud3 * THREADS) ; 16 8 4
StDelay3 equ divide3 + (divide3 / 2) ; 24 12 6
divide4 equ uartfs / (baud4 * THREADS) ; 8 4 2
StDelay4 equ divide4 + (divide4 / 2) ; 12 6 3
hostDivide equ divide3 ;baud used by host
hostStDelay equ StDelay3
;-----------------------------------------------------------------------------------------
; Pin definitions & Port assignments
;-----------------------------------------------------------------------------------------
;host and term pin definitions
hostDQ equ 0
hostWE equ 1
pinDQ equ ra.hostDQ ;host uart transmit/receive
pinWE equ ra.hostWE ;host write enable input
termTX equ 2
termRX equ 3
pinTX equ ra.termTX ;term uart transmit
pinRX equ ra.termRX ;term uart receive
; ra changes output level by changing direction register!! Never drive output high!!
RA_latch equ %00000000 ;port A output latch init 1=high 0=low
RA_tris equ %11111111 ;port A direction register 1=input 0=output
RA_plp equ %00000000 ;port A pull up register 1=off 0=on
RA_lvl equ %11111111 ;port A level register 1=ttl 0=cmos
; rb changes output level by changing direction register!! Never drive output high!!
RB_latch equ %00000000 ;port B output latch 1=high 0=low
RB_tris equ %11111111 ;port B direction register 1=input 0=output
RB_plp equ %00000000 ;port B pull up register 1=off 0=on
RB_lvl equ %00000000 ;port B level register 1=ttl 0=cmos
RB_st equ %11111111 ;port B schmitt trigger register 1=off 0=on
RB_wken equ %11111111 ;port B wake up enable register 1=off 0=on ** KEEP OFF
RB_wked equ %11111111 ;port B wake up edge register 1=neg 0=pos
; rc changes output level by changing direction register!! Never drive output high!!
RC_latch equ %00000000 ;port C output latch 1=high 0=low
RC_tris equ %11111111 ;port C direction register 1=input 0=output
RC_plp equ %00000000 ;port C pull up register 1=off 0=on
RC_lvl equ %11111111 ;port C level register 1=ttl 0=cmos
RC_st equ %11111111 ;port C schmitt trigger register 1=off 0=on
;-----------------------------------------------------------------------------------------
; Code Locations
;-----------------------------------------------------------------------------------------
CODEPAGE_0 equ $0
CODEPAGE_1 equ $200
CODEPAGE_2 equ $400
CODEPAGE_3 equ $600
;-----------------------------------------------------------------------------------------
; Data Memory address definitions
;-----------------------------------------------------------------------------------------
global_org equ $08
bank0_org equ $10
bank1_org equ $30
bank2_org equ $50
bank3_org equ $70
bank4_org equ $90
bank5_org equ $B0
bank6_org equ $D0
bank7_org equ $F0
;-----------------------------------------------------------------------------------------
; Global Register definitions
;-----------------------------------------------------------------------------------------
org global_org
temp ds 1 ;for temporary use (buffers, calculation)
ra_dir_buf ds 1 ;holds value for ra direction register
status_flags ds 1
cmd_invalid equ status_flags.0 ;set if command invalid
cmd_parameter_missing equ status_flags.1 ;set if missing parameter
buffer_overrun equ status_flags.2 ;set if any buffer overrun
term_parity_error equ status_flags.3 ;set if parity error
free_global ds 5
;-----------------------------------------------------------------------------------------
; RAM Bank Register definitions
;-----------------------------------------------------------------------------------------
; Bank 0 - host uart bank, timer bank
;---------------------------------------------------------------------------------
org bank0_org
hu_bank = $ ;host uart bank
hu_rx_count ds 1 ;number of bits to receive
hu_rx_divide ds 1 ;receive timing counter
hu_rx_byte ds 1 ;received byte
hu_tx_count ds 1 ;number of bits to transmit
hu_tx_divide ds 1 ;transmit timing counter
hu_tx_low ds 1 ;low byte to transmit
hu_tx_high ds 1 ;high byte to transmit
hu_head ds 1 ;hinib=tx, lonib=rx: index of next free entry in buf
hu_tail ds 1 ;hinib=tx, lonib=rx: index of next byte to read from buf
hu_num ds 1 ;hinib=tx, lonib=rx: number of bytes in buf
hu_rx_full equ hu_num.3 ; set if hu_rx full (num=8)
hu_tx_full equ hu_num.7 ; set if hu_tx full (num=8)
hu_flags ds 1
hu_rx_data equ hu_flags.0 ;set if hu_rx not empty
hu_rx_overrun equ hu_flags.1 ;set if hu_rx overruns
hu_rx_enable equ hu_flags.2 ;set to enable host uart receive
hu_rx_flag equ hu_flags.3 ;set if byte in hu_rx_byte
hu_tx_data equ hu_flags.4 ;set if hu_tx not empty
hu_tx_overrun equ hu_flags.5 ;set if hu_tx overruns
hu_tx_enable equ hu_flags.6 ;set to enable host uart transmit
hu_tx_flag equ hu_flags.7 ;not used
hu_state ds 1 ;host state
; b2-b0: state of host_command_task routine
pinWE_present equ hu_state.6 ; current state of pinWE
pinWE_past equ hu_state.7 ; past state of pinWE
hu_command ds 1 ;received host command
cmd_done equ hu_command.7 ; set if command finished
timer_bank = $
timer_int ds 1 ;increments every isr
timer_1m ds 1 ;decrements every msec
free_bank0 ds 1
; Bank 1 - term uart bank
;---------------------------------------------------------------------------------
org bank1_org
tu_bank = $ ;term uart bank
tu_rx_count ds 1 ;number of bits to receive
tu_rx_divide ds 1 ;receive timing counter
tu_rx_byte ds 1 ;received byte
tu_tx_count ds 1 ;number of bits to transmit
tu_tx_divide ds 1 ;transmit timing counter
tu_tx_low ds 1 ;low byte to transmit
tu_tx_high ds 1 ;high byte to transmit
tu_head ds 1 ;hinib=tx, lonib=rx: index of next free entry in buf
tu_tail ds 1 ;hinib=tx, lonib=rx: index of next byte to read from buf
tu_num ds 1 ;hinib=tx, lonib=rx: number of bytes in buf
tu_rx_full equ tu_num.3 ; set if tu_rx full (num=8)
tu_tx_full equ tu_num.7 ; set if tu_tx full (num=8)
tu_flags ds 1
tu_rx_data equ tu_flags.0 ;set if tu_rx not empty
tu_rx_overrun equ tu_flags.1 ;set if tu_rx overruns
tu_rx_enable equ tu_flags.2 ;set if transmitted XON, cleared if transmitted XOFF
tu_rx_flag equ tu_flags.3 ;set if byte in tu_rx_byte
tu_tx_data equ tu_flags.4 ;set if tu_tx not empty
tu_tx_overrun equ tu_flags.5 ;set if tu_tx overruns
tu_tx_enable equ hu_flags.6 ;set if received XON, cleared if received XOFF
tu_rx_parity equ tu_flags.7 ;received parity bit
tu_state ds 1 ;term state (not implemented)
tu_command ds 1 ;received term command (not implemented)
tu_config ds 1 ;terminal configuration
; b1-b0 = baud (1200,2400,9600,19200)
tu_rts equ tu_config.2 ; 1 for rts handshake (TX used as RTS)
tu_cts equ tu_config.3 ; 1 for cts handshake (RX used as CTS)
tu_xonxoff equ tu_config.4 ; 1 for xon/xoff handshake (inter-character delay must be 1 msec at 9600 baud)
tu_7bits equ tu_config.5 ; 1 for 7 databits (0 = 8 databits)
tu_parity_even equ tu_config.6 ; 1 for even parity
tu_parity_odd equ tu_config.7 ; 1 for odd parity
tu_char ds 1 ;save received byte here
tu_bits ds 1 ;number of bits (startbit+databits+paritybit+stopbit)
; set by command TM_SET_CONFIG (bits is 9, 10 or 11)
; Bank 2 - host uart buffers
;---------------------------------------------------------------------------------
org bank2_org
hu_buf_bank = $
hu_rx_buf ds 8
hu_tx_buf ds 8
; Bank 3 - term uart buffers
;---------------------------------------------------------------------------------
org bank3_org
tu_buf_bank = $
tu_rx_buf ds 8
tu_tx_buf ds 8
; Bank 4 -
;---------------------------------------------------------------------------------
org bank4_org
free_bank4 ds 16
; Bank 5 -
;---------------------------------------------------------------------------------
org bank5_org
free_bank5 ds 16
; Bank 6 -
;---------------------------------------------------------------------------------
org bank6_org
free_bank6 ds 16
; Bank 7 -
;---------------------------------------------------------------------------------
org bank7_org
free_bank7 ds 16
;-------------- end of ram variables -----------------------------------------------------
;*****************************************************************************************
org CODEPAGE_0
;*****************************************************************************************
;-----------------------------------------------------------------------------------------
; Interrupt Service Routine
;-----------------------------------------------------------------------------------------
interrupt jmp _interrupt ;1
; hooks for application
;---------------------------------------------------------------------------------
app_isr retp ;change to jmp @myapp_isr if any
app_main retp ;change to jmp @myapp_main if any
; jump table for template
;---------------------------------------------------------------------------------
enqueue_hu_tx jmp _enqueue_hu_tx ;store byte for output to host
enqueue_hu_rx jmp _enqueue_hu_rx ;store byte received from host
dequeue_hu_tx jmp _dequeue_hu_tx ;retrieve byte for output to host
dequeue_hu_rx jmp _dequeue_hu_rx ;retrieve byte received from host
enqueue_tu_tx jmp _enqueue_tu_tx ;store byte for output to terminal
enqueue_tu_rx jmp _enqueue_tu_rx ;store byte received from terminal
dequeue_tu_tx jmp _dequeue_tu_tx ;retrieve byte for output to terminal
dequeue_tu_rx jmp _dequeue_tu_rx ;retrieve byte received from terminal
host_input_task jmp _host_input_task ;receives host bytes into hu_rx_buf
host_output_task jmp _host_output_task ;transmit host bytes from hu_tx_buf
; get term baud parameters as determined by tu_config.0 and tu_config.1
;---------------------------------------------------------------------------------
tu_divide
mov w,tu_config
and w,#$03
add pc,w
retw divide0 ;1200
retw divide1 ;2400
retw divide3 ;9600
retw divide4 ;19200
tu_StDelay
mov w,tu_config
and w,#$03
add pc,w
retw StDelay0 ;1200
retw StDelay1 ;2400
retw StDelay3 ;9600
retw StDelay4 ;19200
; host command task
; Wait for a command received from host MCU,
; execute command and transmit results to host MCU.
;---------------------------------------------------------------------------------
STATE_IDLE equ 0
STATE_RECEIVE_COMMAND equ 1
STATE_RECEIVE_PARAMETER equ 2
STATE_TRANSMIT_RESPONSE equ 3
STATE_TRANSMIT_DATA equ 4
STATE_FINALIZE equ 5
host_command_task
call @checkPinWE ;check for edges
bank hu_bank
mov w,hu_state
and w,#$07
add pc,w
jmp hostIdle ;0
jmp hostReceiveCommand ;1
jmp hostReceiveParameter ;2
jmp hostTransmitResponse ;3
jmp hostTransmitData ;4
jmp hostFinalize ;5
jmp hostIdle ;6 failsafe
jmp hostIdle ;7 failsafe
hostIdle
clrb hu_rx_enable
clrb hu_tx_enable
setb ra_dir_buf.hostDQ
setb ra_dir_buf.hostWE
retp
hostReceiveCommand
sb hu_rx_data ;any received data?
retp ;no
call dequeue_hu_rx
mov hu_command,w ;this is command
mov w,#$7F
snb cmd_done
mov hu_command,w ;make command $7F if b7 is set
clrb cmd_invalid
clrb term_parity_error
setb cmd_parameter_missing ;cleared by function
call @host_command_handler ;execute command
bank hu_bank
inc hu_state ;move to next state
retp
hostReceiveParameter
sb hu_rx_data ;any received data?
retp ;no
jmp @host_command_handler ;execute command
hostTransmitResponse
clrb ra_dir_buf.hostWE ;this device pulls pinWE low
mov w,hu_flags
and w,#$22 ;extract overrun flags
sz
setb buffer_overrun
bank tu_bank
mov w,tu_flags
and w,#$22 ;extract overrun flags
sz
setb buffer_overrun
mov w,status_flags ;transmit status flags
call enqueue_hu_tx
clrb hu_rx_overrun
clrb hu_tx_overrun
inc hu_state ;move to next state
bank tu_bank
clrb tu_rx_overrun
clrb tu_tx_overrun
clrb buffer_overrun
retp
hostTransmitData
snb hu_tx_data ;output buffer empty?
retp ;no
call @host_command_handler ;get next data
bank hu_bank
snb cmd_done ;all done?
inc hu_state ;yes, move to next state
retp
hostFinalize
snb hu_tx_data ;output buffer empty
retp ;no
test hu_tx_count ;transmitter ready?
sz
retp ;no
clrb hu_tx_enable ;disable transmitter
setb ra_dir_buf.hostWE ;release pinWE
and hu_state,#$C0 ;wait for new command
retp
;-------------- start of the Interrupt Service Routines ----------------------------------
_interrupt
; Update timers
;---------------------------------------------------------------------------------
inc_timer
bank timer_bank
inc timer_int ;increments every isr
cjne timer_int,#mscount,:it_done ; isr cycles for 1 msec
clr timer_int
dec timer_1m ;decrements every msec
:it_done
inc_timer_done
call app_isr ;call application isr routines
; Update ra with buffered data
;---------------------------------------------------------------------------------
mov w,ra_dir_buf
mov !ra,w
; Run uarts
;---------------------------------------------------------------------------------
hostVP
bank hu_bank
;host uart receive ;receive only when enabled
jnb hu_rx_enable,:hu_rx_done
:receive
sb pinDQ ; get current rx bit
clc
snb pinDQ
stc
test hu_rx_count ; currently receiving byte?
sz
jmp :hur1 ; if so, jump ahead
mov w,#9 ; in case start, ready 9 bits
sc ; skip ahead if not start bit
mov hu_rx_count,w ; it is, so renew bit count
mov w,#hostStDElay
mov hu_rx_divide,w
:hur1
decsz hu_rx_divide ; middle of next bit?
jmp :hu_rx_done
dec hu_rx_count ; last bit?
sz ; if not
rr hu_rx_byte ; then save bit
jnz :hur2 ; and exit
setb hu_rx_flag
:hur2
mov w,#hostDivide
mov hu_rx_divide,w
:hu_rx_done
;host uart transmit ;transmit only when enabled
jnb hu_tx_enable,:hu_tx_done
:transmit
decsz hu_tx_divide ; only execute the transmit routine
jmp :hu_tx_done
mov w,#hostDivide
mov hu_tx_divide,w
test hu_tx_count ; are we sending?
snz
jmp :hu_tx_done
clc ; yes, ready stop bit
rr hu_tx_high ; and shift to next bit
rr hu_tx_low
dec hu_tx_count ; decrement bit counter
snb hu_tx_low.6 ; output next bit
clrb ra_dir_buf.hostDQ ; update term_port_buf state
sb hu_tx_low.6 ; (pin change state occurs next interrupt)
setb ra_dir_buf.hostDQ
:hu_tx_done
termVP
bank tu_bank
;term uart receive
jb tu_cts,:term_rxdone ;only receive if rx is not cts
:receive
sb pinRX ; get current rx bit
clc
snb pinRX
stc
test tu_rx_count ; currently receiving byte?
sz
jmp :term_rx1 ; ;if so, jump ahead
mov w,--tu_bits ; in case start, ready bits
sc ; skip ahead if not start bit
mov tu_rx_count,w ; it is, so renew bit count
call tu_StDelay
mov tu_rx_divide,w
:term_rx1
decsz tu_rx_divide ; middle of next bit?
jmp :term_rxdone
dec tu_rx_count ; last bit?
jz :term_rx2 ; if not
rr tu_rx_byte ; then save bit
movb tu_rx_parity,C ; and save b0
jmp :term_rx3 ; and exit
:term_rx2
movb C,tu_rx_parity ;get last saved b0
movb tu_rx_parity,tu_rx_byte.7 ;save possible parity bit
sb tu_bits.1
rr tu_rx_byte ;adjust for 7 databits + no parity (tu_bits=9)
sb tu_bits.1
rr tu_rx_byte
snb tu_bits.0
rl tu_rx_byte ;adjust for 8 databits + parity (tu_bits=11)
snb tu_7bits
clrb tu_rx_byte.7 ;clear b7 for 7 databits
mov w,tu_rx_byte ;save byte to allow receive another byte
mov tu_char,w ; while processing this one
setb tu_rx_flag ;mark byte received
:term_rx3
call tu_divide
mov tu_rx_divide,w
:term_rxdone
;term uart transmit
jb tu_rts,:term_txdone ;only transmit if tx is not rts
:transmit
decsz tu_tx_divide ; only execute the transmit routine
jmp :term_txdone
call tu_divide
mov tu_tx_divide,w
test tu_tx_count ; are we sending?
snz
jmp :term_txdone
clc ; yes, ready stop bit
rr tu_tx_high ; and shift to next bit
rr tu_tx_low
dec tu_tx_count ; decrement bit counter
snb tu_tx_low.5 ; output next bit
clrb ra_dir_buf.termTX ; update term_port_buf state
sb tu_tx_low.5 ; (pin change state occurs next interrupt)
setb ra_dir_buf.termTX
:term_txdone
; Set Interrupt Rate
;---------------------------------------------------------------------------------
isr_end
mov w,#(-int_period)&$FF ; refresh RTCC on return
retiw ; return from the interrupt
;-------------- end of the Interrupt Service Routines ------------------------------------
;RESET VECTOR Program execution begins here on power-up or after a reset
;---------------------------------------------------------------------------------
reset_entry
; Initialise all port configuration
;---------------------------------------------------------------------------------
M_WKED equ $0A
M_WKEN equ $0B
M_ST equ $0C
M_LVL equ $0D
M_PLP equ $0E
M_TRIS equ $0F
mov m,#M_WKED ; point mode to WKED
mov !rb,#RB_wked
mov m,#M_WKEN ; point mode to WKEN
mov !rb,#RB_wken
mov m,#M_ST ; point mode to ST
mov !rc,#RC_st
mov !rb,#RB_st
mov m,#M_LVL ; point mode to LVL
mov !rc,#RC_lvl
mov !rb,#RB_lvl
mov !ra,#RA_lvl
mov m,#M_PLP ; point mode to PLP
mov !rc,#RC_plp
mov !rb,#RB_plp
mov !ra,#RA_plp
mov rc,#RC_latch ; init latches
mov rb,#RB_latch
mov ra,#RA_latch
mov m,#M_TRIS ; point mode to TRIS
mov !rc,#RC_tris
mov !rb,#RB_tris
mov !ra,#RA_tris
; Clear all Data RAM locations
;---------------------------------------------------------------------------------
mov fsr,#global_org
:zero_global
clr indf
inc fsr
cjne fsr,#$10,:zero_global
:zero_ram
clr indf
inc fsr
jz :zero_end
setb fsr.4
jmp :zero_ram
:zero_end
; Initialize registers
;---------------------------------------------------------------------------------
mov ra_dir_buf,#$FF
bank hu_bank
mov hu_state,#$C0 ;pin levels high
bank tu_bank
setb tu_tx_enable ;enable transmit
setb tu_rx_enable ;enable receive
mov tu_bits,#10 ;set correct bits for startup (8N1,1200)
; Setup option register.
;---------------------------------------------------------------------------------
RTCC_ON equ %10000000 ;Enables RTCC at address $01 (RTW hi)
;*WREG at address $01 (RTW lo) by default
RTCC_ID equ %01000000 ;Disables RTCC edge interrupt (RTE_IE hi)
;*RTCC edge interrupt (RTE_IE lo) enabled by default
RTCC_INC_EXT equ %00100000 ;Sets RTCC increment on RTCC pin transition (RTS hi)
;*RTCC increment on internal instruction (RTS lo) is defalut
RTCC_FE equ %00010000 ;Sets RTCC to increment on falling edge (RTE_ES hi)
;*RTCC to increment on rising edge (RTE_ES lo) is default
RTCC_PS_ON equ %00000000 ;Assigns prescaler to RTCC (PSA lo)
RTCC_PS_OFF equ %00001000 ;Assigns prescaler to WDT (PSA hi)
PS_000 equ %00000000 ;RTCC = 1:2, WDT = 1:1
PS_001 equ %00000001 ;RTCC = 1:4, WDT = 1:2
PS_010 equ %00000010 ;RTCC = 1:8, WDT = 1:4
PS_011 equ %00000011 ;RTCC = 1:16, WDT = 1:8
PS_100 equ %00000100 ;RTCC = 1:32, WDT = 1:16
PS_101 equ %00000101 ;RTCC = 1:64, WDT = 1:32
PS_110 equ %00000110 ;RTCC = 1:128, WDT = 1:64
PS_111 equ %00000111 ;RTCC = 1:256, WDT = 1:128
mov w,#RTCC_PS_OFF ;setup option register
mov !option,w
; Mainloop
;---------------------------------------------------------------------------------
mainloop
call host_input_task ;handle host data input
call host_output_task ;handle host data output
call host_command_task ;handle host command
call @term_input_task ;handle keypad input
call @term_output_task ;handle display output
call app_main ;call application mainloop
jmp mainloop
;put w into hu_tx_buf
;---------------------------------------------------------------------------------
_enqueue_hu_tx
bank hu_bank
snb hu_tx_full
setb hu_tx_overrun
snb hu_tx_full
retp
mov temp,w
mov w,<>hu_head
and w,#$0F
mov fsr,w ;calculate buffer address
mov w,#hu_tx_buf
add fsr,w
mov w,temp ;store received byte
mov indf,w
bank hu_bank
add hu_num,#16 ;adjust byte count
add hu_head,#16
clrb hu_head.7 ;wrap around head
setb hu_tx_data ;mark holding data
retp
;put w into hu_rx_buf
;---------------------------------------------------------------------------------
_enqueue_hu_rx
bank hu_bank
snb hu_rx_full
setb hu_rx_overrun
snb hu_rx_full
retp
mov temp,w
mov w,hu_head
and w,#$0F
mov fsr,w ;calculate buffer address
mov w,#hu_rx_buf
add fsr,w
mov w,temp ;store received byte
mov indf,w
bank hu_bank
add hu_num,#1 ;adjust byte count
add hu_head,#1
clrb hu_head.3 ;wrap around head
setb hu_rx_data ;mark holding data
retp
;get w from hu_tx_buf
;---------------------------------------------------------------------------------
_dequeue_hu_tx
bank hu_bank
sb hu_tx_data
retp
mov w,<>hu_tail ;get next byte from buffer
and w,#$0F
mov fsr,w
mov w,#hu_tx_buf
add fsr,w
mov w,indf
mov temp,w
bank hu_bank
sub hu_num,#16 ;adjust byte count
mov w,<>hu_num
and w,#$0F
snz
clrb hu_tx_data
add hu_tail,#16
clrb hu_tail.7 ;wrap around tail
mov w,temp
retp
;get w from hu_rx_buf
;---------------------------------------------------------------------------------
_dequeue_hu_rx
bank hu_bank
sb hu_rx_data ;test if any byte in buffer
retp ;if not then exit
mov w,hu_tail ;get next byte from buffer
and w,#$0F
mov fsr,w
mov w,#hu_rx_buf
add fsr,w
mov w,indf
mov temp,w
bank hu_bank
sub hu_num,#1 ;adjust byte count
mov w,hu_num
and w,#$0F
snz
clrb hu_rx_data ;mark buffer empty
add hu_tail,#1
clrb hu_tail.3 ;wrap around tail
mov w,temp
retp
;put w into tu_tx_buf
;---------------------------------------------------------------------------------
_enqueue_tu_tx
bank tu_bank
snb tu_tx_full
setb tu_tx_overrun
snb tu_tx_full
retp
mov temp,w
mov w,<>tu_head
and w,#$0F
mov fsr,w ;calculate buffer address
mov w,#tu_tx_buf
add fsr,w
mov w,temp ;store received byte
mov indf,w
bank tu_bank
add tu_num,#16 ;adjust byte count
add tu_head,#16
clrb tu_head.7 ;wrap around head
setb tu_tx_data ;mark holding data
retp
;put w into tu_rx_buf
;---------------------------------------------------------------------------------
_enqueue_tu_rx
bank tu_bank
snb tu_rx_full
setb tu_rx_overrun
snb tu_rx_full
retp
mov temp,w
mov w,tu_head
and w,#$0F
mov fsr,w ;calculate buffer address
mov w,#tu_rx_buf
add fsr,w
mov w,temp ;store received byte
mov indf,w
bank tu_bank
add tu_num,#1 ;adjust byte count
add tu_head,#1
clrb tu_head.3 ;wrap around head
setb tu_rx_data ;mark holding data
retp
;get w from tu_tx_buf
;---------------------------------------------------------------------------------
_dequeue_tu_tx
bank tu_bank
sb tu_tx_data
retp
mov w,<>tu_tail ;get next byte from buffer
and w,#$0F
mov fsr,w
mov w,#tu_tx_buf
add fsr,w
mov w,indf
mov temp,w
bank tu_bank
sub tu_num,#16 ;adjust byte count
mov w,<>tu_num
and w,#$0F
snz
clrb tu_tx_data
add tu_tail,#16
clrb tu_tail.7 ;wrap around tail
mov w,temp
retp
;get w from tu_rx_buf
;---------------------------------------------------------------------------------
_dequeue_tu_rx
bank tu_bank
sb tu_rx_data ;test if any byte in buffer
retp ;if not then exit
mov w,tu_tail ;get next byte from buffer
and w,#$0F
mov fsr,w
mov w,#tu_rx_buf
add fsr,w
mov w,indf
mov temp,w
bank tu_bank
sub tu_num,#1 ;adjust byte count
mov w,tu_num
and w,#$0F
snz
clrb tu_rx_data ;mark buffer empty
add tu_tail,#1
clrb tu_tail.3 ;wrap around tail
mov w,temp
retp
; host input task
;---------------------------------------------------------------------------------
_host_input_task
bank hu_bank
sb hu_rx_enable ;may we receive?
retp ;no
sb hu_rx_flag ;byte received?
retp ;no
mov w,hu_rx_byte
clrb hu_rx_flag
jmp enqueue_hu_rx ;store byte in buffer
; host output task
;---------------------------------------------------------------------------------
_host_output_task
bank hu_bank
sb hu_tx_enable ;may we transmit?
retp ;no
sb hu_tx_data ;byte to transmit?
retp ;no
test hu_tx_count ;transmitter ready?
sz
retp ;no
call dequeue_hu_tx ;get byte to transmit
not w ;ready bits (inverse logic)
mov hu_tx_high,w ;store data byte
setb hu_tx_low.7 ;set up start bit
mov w,#10 ;1 start + 8 data + 1 stop bit
mov hu_tx_count,w ;VP starts transmitting
retp
;-------------- codepage 0 end -----------------------------------------------------------
;*****************************************************************************************
org CODEPAGE_1
;*****************************************************************************************
jmp $ ;generates error if code above crosses page boundary
term_input_task jmp _term_input_task ;receives term bytes into tu_rx_buf
term_output_task jmp _term_output_task ;transmit term bytes from tu_tx_buf
; set parity and stopbits for byte in tu_tx_high (just about to transmit)
;---------------------------------------------------------------------------------
tu_set_parity
snb tu_7bits ;8 databits?
clrb tu_tx_high.7 ;no, ready stop bit
mov w,tu_tx_high
call even_parity
:odd
jnb tu_parity_odd,:even
movb C,/temp.0
jmp :parity
:even
jnb tu_parity_even,:exit
movb C,temp.0
:parity
sb tu_7bits ;7 databits?
retp ;no
movb tu_tx_high.7,C ;move parity into b7
:exit
clc ;ready stop bit
retp
; calculate even parity for w
; result in temp.0
;---------------------------------------------------------------------------------
even_parity
mov temp,w
;calculation code by John Payson, as found on sxlist.com
;This routine will leave the parity of temp in temp.0
;while blenderizing most of the rest of temp
mov w,<>temp ; temp = abcdefgh
xor temp,w
mov w,>>temp
xor temp,w
; at this point, the parity for half the bits
; (a, b, e, and f) is in bit 2 of temp, and the
; parity for the other half (bits c, d, g, and h)
; is in bit 0 of temp.
snb temp.2 ; if the parity of (a,b,e,f) is 0,
; then the parity of (a,b,c,d,e,f,g,h)
; is equal to the parity of (c,d,g,h)...
; which is already in bit 0, so skip ahead.
inc temp ; otherwise, the parity of (a,b,e,f) is 1,
; so the parity of (a,b,c,d,e,f,g,h) is
; NOT equal to the parity of (c,d,g,h).
; invert bit 0.
; at this point, bit 0 contains the parity of
; (a,b,c,d,e,f,g,h).
retp
; term output handshake off (inform remote deivce to stop transmitting)
; either RTS (on TX pin) or XON/XOFF
;---------------------------------------------------------------------------------
tu_hs_off
sb tu_rx_enable
retp ;hs already off
mov w,tu_config
and w,#$14 ;test if tu_xonxoff or tu_rts set
snz
retp ;no handshake
mov w,tu_num
and w,#$0F ;extract bytes in tu_rx_buf
jb tu_xonxoff,:tu_xoff ;xonxoff handshake
xor w,#$05 ;disable receive if 5 bytes in tu_rx_buf
sz
retp
clrb tu_rx_enable
setb ra_dir_buf.termTX ;turn off handshake
retp
:tu_xoff
xor w,#$02 ;disable receive if 2 byte in tu_rx_buf
sz
retp
:tu_xoff1
test tu_tx_count
jnz :tu_xoff1 ;wait for not busy
clrb tu_rx_enable
mov w,#XOFF ;send XOFF
jmp tu_output_w
; term output handshake on (inform remote deivce to start transmitting)
; either RTS (on TX pin) or XON/XOFF
;---------------------------------------------------------------------------------
tu_hs_on
snb tu_rx_enable
retp ;hs already on
mov w,tu_config
and w,#$14 ;test if tu_xonxoff or tu_rts set
snz
retp ;no handshake
mov w,tu_num
and w,#$0F ;extract bytes in tu_rx_buf
jb tu_xonxoff,:tu_xon ;xonxoff handshake
xor w,#$01 ;enable receive if only 1 byte in tu_rx_buf
sz
retp
setb tu_rx_enable
clrb ra_dir_buf.termTX ;turn on handshake
retp
:tu_xon
xor w,#$01 ;enable receive if only 1 byte in tu_rx_buf
sz
retp
setb tu_rx_enable
:tu_xon1
test tu_tx_count
jnz :tu_xon1 ;wait for not busy
mov w,#XON ;send XOFF
jmp tu_output_w
; term input task
;---------------------------------------------------------------------------------
_term_input_task
bank tu_bank
snb tu_cts ;test if rx is used as cts
retp ;yes, so do not receive
sb tu_rx_flag ;byte received?
retp ;no
clrb tu_rx_flag ;clear receive flag (byte in tu_char)
jnb tu_xonxoff,:tu_input ;jump ahead if no xon/xoff
mov w,tu_char
mov temp,w ;test for xon/xoff
xor w,#XON ;test if byte received is XON
snz
setb tu_tx_enable ;yes, so enable tx
snz
retp ;and exit (XON is not stored)
mov w,tu_char
xor w,#XOFF ;test if byte received is XOFF
snz
clrb tu_tx_enable ;yes, so disable tx
snz
retp ;and exit (XOFF is not stored)
:tu_input
jb tu_parity_odd,:parity
jb tu_parity_even,:parity
jmp :exit
:parity
mov w,tu_char
call even_parity
snb tu_parity_odd
not temp
and temp,#$01 ;extract calculated parity bit
addb temp,tu_rx_parity ;add received parity bit
snb temp.0 ;temp=0 or temp=2 if parity bits match
setb term_parity_error
:exit
mov w,tu_char
call @enqueue_tu_rx ;put byte in queue
jmp @tu_hs_off ;turn off handshake if required
; term output task
;---------------------------------------------------------------------------------
_term_output_task
bank tu_bank
snb tu_rts ;test if tx is used as rts
retp ;tx is handshake so do not send
sb tu_tx_data ;data to send?
retp ;no
test tu_tx_count ;transmitter busy?
sz
retp ;yes
jb tu_xonxoff,tu_hs_soft
jnb tu_cts,tu_output ;rx not used as handshake
tu_hs_cts ;test if handshake input on
jnb pinRX,tu_output ;if so then send
retp
tu_hs_soft
sb tu_tx_enable ;send only if enabled
retp
tu_output
call @dequeue_tu_tx
tu_output_w
not w ;ready bits (inverse logic)
mov tu_tx_high,w ;store data byte
setb tu_tx_low.7 ;set up start bit
call tu_set_parity
rr tu_tx_high ;shiftin parity bit or stop bit
rr tu_tx_low
mov w,tu_bits ;start + data + parity + stop
mov tu_tx_count,w
retp
; detect transition on pinWE
; actions when neg edge:
; - disable transmitter
; - clear buffers
; - initialize receive registers
; - enable receiver
; - move to state STATE_RECEIVE_COMMAND
; actions when pos edge:
; - disable receiver
; - initialize transmit registers
; - enable transmitter
; - move to state STATE_TRANSMIT_RESPONSE
;---------------------------------------------------------------------------------
checkPinWE
bank hu_bank
snb hu_tx_enable
retp
movb pinWE_past,pinWE_present
movb pinWE_present,pinWE
mov w,hu_state
and w,#$C0 ;extract pinWE states
xor w,#$40 ;L->H transition?
jz :init_transmit ; yes
xor w,#$C0 ;H->L transition
sz
retp ; no
:init_receive
clrb hu_tx_enable ;disable transmitter
clr hu_head ;clear buffers parameters (tx and rx)
clr hu_tail
clr hu_num
clrb hu_rx_data
clrb hu_rx_overrun
clrb hu_tx_data
clrb hu_tx_overrun
clr hu_rx_count ;initialize receive registers
clrb hu_rx_flag
setb hu_rx_enable ;enable receiver
and hu_state,#$C0 ;keep pin states
or hu_state,#STATE_RECEIVE_COMMAND ;move to state RECEIVE_COMMAND
retp
:init_transmit
clrb hu_rx_enable ;disable receiver
clr hu_tx_count ;initialize transmit registers
setb hu_tx_enable ;enable transmitter
and hu_state,#$C0 ;keep pin states
or hu_state,#STATE_TRANSMIT_RESPONSE ;move to state TRANSMIT_RESPONSE
retp
; Delay approx. 1 second
;--------------------------------------------------------------------
delay_1s00
mov w,#250
call delay_w
delay_0s75
mov w,#250
call delay_w
; Delay approx. 0.5 second
;--------------------------------------------------------------------
delay_0s50
mov w,#250
call delay_w
delay_0s25
mov w,#250
; Delay w milliseconds
;--------------------------------------------------------------------
delay_w
bank timer_bank
mov timer_1m,w
:wait
test timer_1m
jnz :wait
retp
; Host command handler.
; This is the host command dispatcher entry.
; It is always called when command or parameters are received.
;---------------------------------------------------------------------------------
HOST_COMMANDS equ $08 ;number of host commands
host_command_handler
bank hu_bank
snb cmd_done
jmp clear_input ;command already finished
csb hu_command,#HOST_COMMANDS
jmp invalid_host_command
mov w,hu_command
add pc,w
jmp _DV_GET_VERSION ;00 device get version
jmp _TM_SET_CONFIG ;01 terminal set configuration
jmp _TM_READ_DATA ;02 terminal read data
jmp _TM_WRITE_DATA ;03 terminal write data
jmp _IO_READ_PORTB ;04 i/o read port B
jmp _IO_WRITE_PORTB_DIR ;05 i/o write port B direction
jmp _IO_READ_PORTC ;06 i/o read port C
jmp _IO_WRITE_PORTC_DIR ;07 i/o write port C direction
;new commands here
; Invalid commands must remove input data to prevent hu_rx_buf overrun
;---------------------------------------------------------------------------------
invalid_host_command
setb cmd_invalid
clear_input
call @dequeue_hu_rx ;get rid of any input
; Mark command finished
;---------------------------------------------------------------------------------
host_command_exit
bank hu_bank
setb cmd_done
retp
; Command $00 - Get device version.
; Parameters - none
; Description - This command returns 8 bytes to the host
;---------------------------------------------------------------------------------
_DV_GET_VERSION
clrb cmd_parameter_missing
sb hu_tx_enable ;may we transmit?
retp ;no
and hu_head,#$0F ;reset hu_tx_buf parameters
and hu_tail,#$0F
and hu_num,#$0F
or hu_num,#$80
bank hu_buf_bank
mov hu_tx_buf+$0,#'T' ;co-processor identification
mov hu_tx_buf+$1,#'E'
mov hu_tx_buf+$2,#'M'
mov hu_tx_buf+$3,#'P'
mov hu_tx_buf+$4,#'L'
mov hu_tx_buf+$5,#'A'
mov hu_tx_buf+$6,#'T'
mov hu_tx_buf+$7,#'E'
bank hu_bank
setb hu_tx_data
jmp host_command_exit
; Command $01 - terminal set configuration
; Parameters - config (default value = 0)
; b7 b6 b5 b4 b3 b2 b1 b0
; | | | | | | +---+-- baud (0 to 3 -> see baud table)
; | | | | | +---------- 1 if TX used as RTS handshake
; | | | | +-------------- 1 if RX used as CTS handshake
; | | | +------------------ 1 if xon/xoff handshake
; | | +---------------------- 1 for 7 databits (default = 8 databits)
; | +-------------------------- 1 for even parity (default = no parity)
; +------------------------------ 1 for odd parity
; Description - set terminal baud, parity, handshake
;---------------------------------------------------------------------------------
_TM_SET_CONFIG
jb hu_tx_enable,:output ;prevent deadlock if not received byte
sb hu_rx_data
retp
clrb cmd_parameter_missing
call @dequeue_hu_rx
bank tu_bank
mov tu_config,w
mov tu_bits,#10 ;assume 8 databits and no parity
snb tu_parity_even
setb tu_bits.0 ;if parity set bits to 11
snb tu_parity_odd
setb tu_bits.0
snb tu_7bits
dec tu_bits ;if 7 databits decrement bits
:output
jmp host_command_exit
; Command $02 - read terminal data (one byte)
; Parameters - none
; Description - Return current terminal character, if any, else 0
;---------------------------------------------------------------------------------
_TM_READ_DATA
clrb cmd_parameter_missing
sb hu_tx_enable
retp
clr w
bank tu_bank
jnb tu_rx_data,:tm_rd
call @dequeue_tu_rx
:tm_rd
call @enqueue_hu_tx
bank tu_bank
call @tu_hs_on ;turn on handshake if required
jmp host_command_exit
; Command $03 - write terminal data
; Parameters - bytes to write
; Description - write one or more characters to term
;---------------------------------------------------------------------------------
_TM_WRITE_DATA
clrb cmd_parameter_missing
jb hu_tx_enable,:output
sb hu_rx_data
retp
call @dequeue_hu_rx
call @enqueue_tu_tx
retp
:output
jmp host_command_exit
; Command $04 - read port B
; Parameters - none
; Description - Return current port B input value to host
;---------------------------------------------------------------------------------
_IO_READ_PORTB
clrb cmd_parameter_missing
sb hu_tx_enable ;may we transmit
retp ;no
mov w,rb
call @enqueue_hu_tx
jmp host_command_exit
; Command $05 - write value to port B direction register
; Parameters - dirmask
; Description - Make port B pins low output (bit=0) or input (bit=1)
;---------------------------------------------------------------------------------
_IO_WRITE_PORTB_DIR
jb hu_tx_enable,:output ;prevent deadlock if not received byte
sb hu_rx_data
retp
clrb cmd_parameter_missing
call @dequeue_hu_rx
mov !rb,w
:output
jmp host_command_exit
; Command $06 - read port C
; Parameters - none
; Description - Return current port C input value to host
;---------------------------------------------------------------------------------
_IO_READ_PORTC
clrb cmd_parameter_missing
sb hu_tx_enable ;may we transmit
retp ;no
mov w,rc
call @enqueue_hu_tx
jmp host_command_exit
; Command $07 - write value to port C direction register
; Parameters - dirmask
; Description - Make port C pins low output (bit=0) or input (bit=1)
;---------------------------------------------------------------------------------
_IO_WRITE_PORTC_DIR
jb hu_tx_enable,:output ;prevent deadlock if not received byte
sb hu_rx_data
retp
clrb cmd_parameter_missing
call @dequeue_hu_rx
mov !rc,w
:output
jmp host_command_exit
;-------------- codepage 1 end -----------------------------------------------------------
;*****************************************************************************************
org CODEPAGE_2
;*****************************************************************************************
jmp $ ;generates error if code above crosses page boundary
;-------------- codepage 2 end -----------------------------------------------------------
;*****************************************************************************************
org CODEPAGE_3
;*****************************************************************************************
jmp $ ;generates error if code above crosses page boundary
;-------------- codepage 3 end ------------------------------------------------------
| file: /Techref/scenix/lib/io/osi2/serial/elx1tmpl.htm, 45KB, , updated: 2013/7/22 18:23, local time: 2025/10/24 10:21,
216.73.216.53,10-2-207-162:LOG IN
|
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://www.massmind.org/techref/scenix/lib/io/osi2/serial/elx1tmpl.htm"> SX RS232 Serial IO </A> |
| Did you find what you needed? |
Welcome to massmind.org! |
Welcome to www.massmind.org! |
.