
.include "1200def.inc"
;
; dsuart.asm
; Simple software async uart for AVR processors. Compatible with all AVR
; processors: AT90S1200, AT90S8515, etc..
; This version assumes that the soft uart pins are connected directly to a
; serial device (TTL level) or connected to an RS232 device through an RS232
; line driver (e.g. MAX232). Direct serial output to an RS232 device without
; using an RS232 line driver could be accomplished by reversing the bit logic
; instructions: e.g. all sbi/sbis instructions change to cbi/sbic
; and vice versa.
;
; Note: All labels,equates, and defines begin with 'd_'. This allows you
; to have multiple copies of the soft uart by simply doing a global replace
; of the 'd_' with character(s) of your own choice. Each copy of the soft
; uart occupies 52 words of program memory
;
; Author: R.Bush 8-26-97 - PD release
;
	.org	0
	rjmp	start		;execute a simple echo back test
;
; Primary routines:
;------------------
; d_sersetup:	Call to setup I/O bits for uart. Must call prior to using the
;               following routines.
; d_writeser:	Call with byte to send in d_txrx.
; d_readser:	Call to read serial port, byte returned in d_txrx.
;
; Registers used by software uart, define as needed (must be >= r16)
;-------------------------------------------------------------------
.def	d_bcntr 	= r23		;bit counter
.def	d_srdel 	= r24		;delay loop variable
.def	d_txrx 		= r25		;async serial data byte transmit/received
;
; Equates defining software uart, define as needed
;-------------------------------------------------
.equ	d_sport 	= portd		;port supporting serial i/o
.equ	d_sin 		= 0		;bit within port for serial data in	
.equ	d_sout 		= 1		;bit within port for serial data out
.equ	d_spin		= pind		;port pins
.equ	d_sddr		= ddrd		;data direction register for port
;
; Bit delays calculations:
;-------------------------
; where: baudrate = bps, fosc = crystal frequency in HZ.
;        note: round result to nearest whole number.
;
; overhead = 20			 	;number of cycles to xmit a byte
; loopcount = 7 		 	;number of cycles, primary delay loop
;
; oscrate  = 1 / fosc 		 	;xtal time period
; bitrate  = 1 / baudrate 	 	;baudrate bit time period
; looprate = oscrate * loopcount 	;elapsed time per loop iteration 
; adjust   = (overhead * oscrate) / looprate ;loop adjustment factor
;
; d_full = (bitrate / looprate) - adjust ;delay loop count constant
;
; Note: d_full must be <= 255. Faster clocks and lower baudrates may necessitate
;	decreasing looprate by adding additional nop's to the primary delay
;	routine (d_bitdel). Each additional nop increases loopcount by one.
.equ	d_full		= 56		;example for 4 MHz, 9600 baud
.equ	d_half		= 56 / 2
;
d_sersetup:	sbi	d_sport,d_sout	;set output pin high
		sbi	d_sddr,d_sout	;output pin data direction
		cbi	d_sddr,d_sin	;insure input pin
		ret
;	
; Software uart (serial port) for RS232 comm link.
; Assumes hardware pins used for software uart are connected
; to a MAX232 or similar driver.
; Receive serial data on i/o pin, place into d_txrx.
;
d_readser:	sbic	d_spin,d_sin	;2/3 direct connect rs232 use sbic for MAX
		rjmp	d_readser	;2 wait for start bit
		rcall	d_sdelay	;3 delay for half bit time
;
		sbic	d_spin,d_sin	;2/3 test for bit still there
		rjmp	d_readser	;2
		ldi	d_bcntr,8	;1 length of byte
		clr	d_txrx	;1
;
d_recv:		rcall	d_bitdel	;3 delay one full bit
;
		sbis	d_spin,d_sin	;2/3 (skip) check for a '1' bit
		rjmp	d_rsz		;2 handle a zero bit
		sec			;1
		ror	d_txrx		;1
		rjmp	d_rsbin		;2
;
d_rsz:		nop			;1
		clc			;1
		ror	d_txrx		;1
		rjmp	d_rsbin		;2
;
d_rsbin:	dec	d_bcntr	;1
		brne	d_recv		;1/2
;		com	d_txrx		;compliment for direct RS232 connection
		rcall	d_bitdel	;end up in middle of stop bit
		ret			;4
;
; delay for 1/2 bit time
;
d_sdelay:	ldi	d_srdel,d_half	;1 half bit delay
		rjmp	d_bd1		;2
;
; delay for full bit time -- primary delay loop
;
d_bitdel:	ldi	d_srdel,d_full	;1 full bit delay
		rjmp	d_bd1		;2 (used to balance loop timing)
d_bd1:		nop			;1
		nop			;1
;
; If required, insert additional nop's here.
; 
		nop			;1
		nop			;1
		dec	d_srdel		;1
		brne	d_bd1		;2/1
		ret			;4
;
d_writeser:	ldi	d_bcntr,8	;bit count
;		com	d_txrx		;compliment xmit byte for direct RS232 connect
		cbi	d_sport,d_sout 	;set start bit
		rcall	d_bitdel
d_wslp:		ror	d_txrx		;1
		brcs	d_xmt1		;1/2
		cbi	d_sport,d_sout	;2
		rjmp	d_xmt2		;2
d_xmt1:		sbi	d_sport,d_sout	;2
		nop			;1
d_xmt2:		rcall	d_bitdel	;delay full bit period
		dec	d_bcntr	;1
		brne	d_wslp		;1/2
		sbi	d_sport,d_sout
		rcall	d_bitdel	;stop bit
		ret
;
; Simple echo back test loop
;
start:
		rcall	d_sersetup	;setup uart
test_loop:
		rcall	d_readser	;read serial port
		inc	d_txrx
		rcall	d_writeser	;echo back
		rjmp	test_loop	; forever
;
; End
;
