;----------------------------------------------------------------------------- ; Full-duplex software UART ; ; This version is for the Scenix SX Microcontroller, and runs on the ; Parallax SX-Key Demo Board. Assemble with Microchip's MPASM assembler. ; ; Copyright 1996, 1998 Eric Smith ; ; Permission is granted to use this code or portions thereof for ; non-commercial purposes provided that the copyright notice is preserved ; intact and that credit is given to the author. For any other use, a ; license may be obtained from the author; send email to eric@brouhaha.com. ; ; $Id: fduart.asm,v 1.3 1998/11/05 06:35:07 eric Exp eric $ ;----------------------------------------------------------------------------- radix dec errorlevel -302 errorlevel -305 processor 16c57 ; really a Scenix SX, but MPASM doesn't ; know about those ;----------------------------------------------------------------------------- ; Scenix SX18AC/SX28AC register definitions ;----------------------------------------------------------------------------- indf equ 00h rtcc equ 01h pcl equ 02h status equ 03h fsr equ 04h porta equ 05h portb equ 06h portc equ 07h ; bits in status: c equ 0 z equ 2 ;----------------------------------------------------------------------------- ; ASCII characters ;----------------------------------------------------------------------------- lf equ 00ah cr equ 00dh ;----------------------------------------------------------------------------- ; Scenix instruction macros ;----------------------------------------------------------------------------- ret macro data 0ch ;RET ;return without destroying W register endm reti macro data 0eh endm retiw macro data 0fh endm pagex macro n ;(MPASM already uses "PAGE") data 10h|n ;PAGE ;write N into bits PA2:PA0 (N = 0-7) endm bankx macro n ;(MPASM already uses "BANK") data 18h|(n>>5) ;BANK ;write N into bits FSR7:FSR5 (N = 0-7) endm mode macro n data 50h|n ;MODE ;write N into MODE register (N = 0-F) endm ;----------------------------------------------------------------------------- ; target-specific definitions ;----------------------------------------------------------------------------- rx_ring_size equ 010h tx_ring_size equ 010h xtalfreq equ 50000000 b115200 equ -145 ; xtalfreq/(3*115200) rxport equ porta rxbit equ 2 rxinv equ 0 txport equ porta txbit equ 3 txinv equ 0 button_port equ portb maxbutton equ 4 porta_init equ 0ffh porta_tris equ (1<<rxbit) portb_init equ 0ffh portb_tris equ (1<<maxbutton)-1 ; button inputs portc_init equ 0ffh portc_tris equ 000h ;----------------------------------------------------------------------------- ; RAM usage ;----------------------------------------------------------------------------- org 008h ; globals rxbyte: res 1 ; this must be global rather than in ser_vars ; rxbyte may >only< be used in interrupt handler ser_temp: res 1 ; ser_temp must be global rather than in ser_vars ; ser_temp may not be used in interrupt handler msg_temp: res 1 ; this could be in main_vars temp: res 1 temp2: res 1 temp3: res 1 led_stat: res 1 ; this should be in button_vars, but I got lazy ; and referenced it directly from main org 010h main_vars = $ org 030h button_vars = $ but_press_cnt: res maxbutton but_mask: res 1 but_poll_cnt: res 1 but_stat: res 1 ; button status, 1 bit per button ; mainline code will clear bit to acknowledge org 050h ser_vars = $ uartspeed: res 1 uartstat: res 1 ; bits in uartstat: rbf equ 7 tbf equ 6 rxovr equ 5 rxfrm equ 4 rxphase equ 1 txphase equ 0 rx_ring_ip: res 1 rx_ring_op: res 1 rx_ring_cnt: res 1 tx_ring_ip: res 1 tx_ring_op: res 1 tx_ring_cnt: res 1 rxbits: res 1 rxbitcnt: res 1 rxmask: res 1 txbyte: res 1 txbitcnt: res 1 org 070h rx_ring: res rx_ring_size org 090h tx_ring: res tx_ring_size ;----------------------------------------------------------------------------- ; UART macros ;----------------------------------------------------------------------------- ringadv macro ptr,base,size local pow2,aligned,bit,val pow2 set !(size&(size-1)) aligned set pow2&&((base&(size-1))==0) if aligned val set size bit set 0 while val>1 bit set bit+1 val set val>>1 endw endif incf ptr if aligned&&!(base&(1<<bit)) bcf ptr,bit else movf ptr,w xorlw base+size movlw base btfsc status,z movwf ptr endif endm ;----------------------------------------------------------------------------- ; interrupt entry point ; all subroutine entry points must be in first page of ROM ;----------------------------------------------------------------------------- org 0 int call ser_int call but_int bankx ser_vars movf uartspeed,w retiw ;----------------------------------------------------------------------------- ; jump table ; all subroutine entry points must be in first page of ROM ;----------------------------------------------------------------------------- uartinit: goto uartinit_x xmit: goto xmit_x recv: goto recv_x rxavail: goto rxavail_x msgout: goto msgout_x buttoninit: goto buttoninit_x getbutstat: goto getbutstat_x clrbutstat: goto clrbutstat_x ;----------------------------------------------------------------------------- ; tables ;----------------------------------------------------------------------------- msg_table: addwf pcl banner equ $-(msg_table+1) dt cr,lf,"Hello, world!",cr,lf dt "This is a test to see if very long messages",cr,lf dt "lose characters. If they do, there must be",cr,lf dt "a problem with buffer management.",cr,lf,0 button_msg equ $-(msg_table+1) dt "button ",0 pressed_msg equ $-(msg_table+1) dt " pressed",cr,lf,0 ;----------------------------------------------------------------------------- ; button interrupt handler code ;----------------------------------------------------------------------------- but_int: bankx button_vars incf but_poll_cnt ; poll button every 256 ticks movf but_poll_cnt,w ; if but_poll_cnt > 3, return andlw 0fch btfss status,z ret movf but_poll_cnt,w ; must be between 0 and 3 addwf pcl goto but_set_input goto but_read_input goto led_set_output ret led_set_output: movf led_stat,w xorlw 0ffh movwf button_port movlw 0 tris button_port ret but_set_input: movlw (1<<maxbutton)-1 tris button_port ret but_read_input: movlw button_vars movwf fsr movlw 001h movwf but_mask butint1: movf button_port,w andwf but_mask,w btfss status,z goto butrel btfsc indf,5 ; already pressed? goto butint9 incf indf btfss indf,5 goto butint9 movf but_mask,w iorwf but_stat goto butint9 butrel: clrf indf butint9: incf fsr bcf status,c rlf but_mask btfss but_mask,maxbutton goto butint1 ret ;----------------------------------------------------------------------------- ; serial interrupt handler code ;----------------------------------------------------------------------------- ser_int: bankx ser_vars if rxbit==0 ; get current receive sample in one instruction rrf rxport,w ; if possible, otherwise three instructions else if rxbit==7 rlf rxport,w else bcf status,c btfsc rxport,rxbit bsf status,c endif endif rlf rxbits btfsc uartstat,rxphase goto rxint btfsc uartstat,txphase goto txint ; housekeeping phase bsf uartstat,txphase ; transmit phase next btfss uartstat,rbf ; has the receiver collected a byte? goto try_xmit_ring ; no, check transmitter movf rx_ring_cnt,w ; is the receive buffer full? xorlw rx_ring_size btfss status,z goto rx_ok ; no, go store the char bsf uartstat,rxovr ; yes, set the overrun flag goto try_xmit_ring ; and skip storing the char rx_ok: movf rx_ring_ip,w ; store character in receive buffer movwf fsr movf rxbyte,w ; rxbyte must be global!!! movwf indf bankx ser_vars ringadv rx_ring_ip,rx_ring,rx_ring_size incf rx_ring_cnt bcf uartstat,rbf try_xmit_ring: btfsc uartstat,tbf ; is the transmitter busy? ret ; yes, don't do anything movf tx_ring_cnt,w ; is there anything in the ring? btfsc status,z ret ; no, don't do anything movf tx_ring_op,w ; move one character from the ring to the movwf fsr ; transmitter movf indf,w bankx ser_vars movwf txbyte decf tx_ring_cnt ; decrement tx char count ringadv tx_ring_op,tx_ring,tx_ring_size ; advance pointer bsf uartstat,tbf ; now the transmitter will be busy ret rxint: bcf uartstat,rxphase ; housekeeping phase next if rxinv movlw 7 xorwf rxbits endif movf rxmask,w btfss status,z goto rxgetbit movlw 9 movwf rxbitcnt movlw 2 btfss rxbits,2 goto rxstart9 movlw 1 btfss rxbits,1 goto rxstart9 movlw 4 btfsc rxbits,0 ret rxstart10: incf rxbitcnt rxstart9: movwf rxmask ret rxgetbit: andwf rxbits,w ; extract the appropriate sample bit bcf status,c ; into the carry flag btfss status,z bsf status,c decfsz rxbitcnt ; is it a stop bit? goto rxdbit ; no, it's a data bit btfss status,c ; is the stop bit a 1 like it's supposed to be? bsf uartstat,rxfrm ; no, framing error! bsf uartstat,rbf btfss rxmask,2 ; could there be a start bit in this group? goto rxnost ; no btfsc rxbits,0 ; is there in fact a start bit? goto rxnost ; no movlw 4 ; yes, start up again movwf rxmask movlw 10 movwf rxbitcnt ret rxnost: clrf rxmask ret rxdbit: rrf rxbyte ret txint: bcf uartstat,txphase bsf uartstat,rxphase ; receive phase next movf txbitcnt ; are we transmitting? btfss status,z goto txputbit btfss uartstat,tbf ; is there a char awaiting transmission? ret if txinv bsf txport,txbit ; send start bit else bcf txport,txbit ; send start bit endif movlw 9 ; 8 data bits plus a stop bit movwf txbitcnt ret txputbit: bsf status,c rrf txbyte if txinv btfss status,c bsf txport,txbit btfsc status,c bcf txport,txbit else btfss status,c bcf txport,txbit btfsc status,c bsf txport,txbit endif decfsz txbitcnt ; any more bits to send? ret ; yes bcf uartstat,tbf ; no, the transmit buffer is now empty ret ;----------------------------------------------------------------------------- ; UART initialization ; caller must restore register bank ; returns with register bank 010h selected ;----------------------------------------------------------------------------- uartinit_x: bankx ser_vars clrf uartstat clrf rxmask clrf txbitcnt clrf rx_ring_cnt movlw rx_ring movwf rx_ring_ip movwf rx_ring_op clrf tx_ring_cnt movlw tx_ring movwf tx_ring_ip movwf tx_ring_op movlw b115200 movwf uartspeed clrf rtcc bankx 010h ret ;----------------------------------------------------------------------------- ; serial transmit character ; blocks until space if available in buffer ; returns with register bank 010h selected ;----------------------------------------------------------------------------- xmit_x: bankx ser_vars movwf ser_temp xmit0: movf tx_ring_cnt,w ; is there room for a character? xorlw tx_ring_size btfsc status,z goto xmit0 movf tx_ring_ip,w ; store char in buffer movwf fsr movf ser_temp,w ; must be global!!! movwf indf bankx ser_vars ringadv tx_ring_ip,tx_ring,tx_ring_size ; advance pointer incf tx_ring_cnt ; increment tx char count ; (this must not be done until after character ; has been stored in buffer) bankx 010h ret ;----------------------------------------------------------------------------- ; rxavail ; returns count of received characters available ; returns with register bank 010h selected ;----------------------------------------------------------------------------- rxavail_x: bankx ser_vars movf rx_ring_cnt,w bankx 010h ret ;----------------------------------------------------------------------------- ; serial receive character ; blocks until a character is available ; returns with register bank 010h selected ;----------------------------------------------------------------------------- recv_x: bankx ser_vars movf rx_ring_cnt btfsc status,z goto recv movf rx_ring_op,w movwf fsr movf indf,w ; get character from buffer movwf ser_temp ; must be global!!! bankx ser_vars ringadv rx_ring_op,rx_ring,rx_ring_size ; advance pointer decf rx_ring_cnt ; decrement rx char count ; (this must not be done until after character ; has been pulled from buffer) movf ser_temp,w bankx 010h ret ;----------------------------------------------------------------------------- ; message output ;----------------------------------------------------------------------------- msgout_x: movwf msg_temp msglp: movf msg_temp,w call msg_table xorlw 0 btfsc status,z ret call xmit incf msg_temp goto msglp ;----------------------------------------------------------------------------- ; button routines ;----------------------------------------------------------------------------- buttoninit_x: bankx button_vars clrf but_stat clrf led_stat bankx 010h ret ; return button state in W getbutstat_x: bankx button_vars movf but_stat,w bankx 010h ret ; clear buttons that are selected by bits set in W clrbutstat_x: bankx button_vars xorlw 0ffh andwf but_stat bankx 010h ret ;----------------------------------------------------------------------------- ; reset ;----------------------------------------------------------------------------- reset: clrf fsr movlw porta_init movwf porta movlw porta_tris tris porta movlw portb_init movwf portb movlw portb_tris tris portb movlw portc_init movwf portc movlw portc_tris tris portc movlw 0dfh option call uartinit call buttoninit movlw 09fh ; enable RTCC interrupt option ;----------------------------------------------------------------------------- ; main ;----------------------------------------------------------------------------- main: movlw banner call msgout loop: call rxavail btfsc status,z goto loop1 call recv call xmit loop1: call getbutstat btfsc status,z goto loop9 movwf temp call clrbutstat movf temp,w movlw 001h movwf temp2 movlw '0' movwf temp3 loop2: movf temp,w andwf temp2,w btfsc status,z goto loop3 movf temp,w xorwf led_stat movf ' ' ; don't know why, but this fixes the bug that call xmit ; loses the leading 'b' in the button message movlw button_msg call msgout movf temp3,w call xmit movlw pressed_msg call msgout loop3: incf temp3 bcf status,c rlf temp2 btfss temp2,maxbutton goto loop2 loop9: goto loop ;----------------------------------------------------------------------------- ; reset vector ;----------------------------------------------------------------------------- errorlevel -306 ; don't display "crossing page boundary" warning org 07ffh goto reset errorlevel +306 ;----------------------------------------------------------------------------- ; fuses ;----------------------------------------------------------------------------- _DEVICE equ 0x44e4fa errorlevel -220 ;don't display "address exceeds range" warning org 1010h data _DEVICE&0xfff ;configuration bits (TURBO, SYNC, OPTIONX, etc.) data _DEVICE>>12 ; (PINS, CARRYX, BOR40, BANKS, PAGES) errorlevel +220 ;restore warning message end
file: /Techref/scenix/lib/io/osi2/serial/fduart_asm.htm, 14KB, , updated: 2013/7/22 18:24, local time: 2024/8/14 13:22,
3.144.124.136:LOG IN
|
©2024 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://sxlist.com/techref/scenix/lib/io/osi2/serial/fduart_asm.htm"> scenix lib io osi2 serial fduart_asm</A> |
Did you find what you needed? |
Welcome to sxlist.com!sales, advertizing, & kind contributors just like you! Please don't rip/copy (here's why Copies of the site on CD are available at minimal cost. |
Ashley Roll has put together a really nice little unit here. Leave off the MAX232 and keep these handy for the few times you need true RS232! |
.