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 ------------------------------------------------------