uart.asm


;**** A P P L I C A T I O N   N O T E   A V R 3 0 5 ************************
;*
;* Title		: Half Duplex Interrupt Driven Software UART
;* Version		: rev. 1.2 (24-04-2002), reset vector added
;*			: rev. 1.1 (27.08.1997)
;* Last updated		: 24-04-2002
;* Target		: AT90Sxxxx (All AVR Device)
;*
;* Support email	: avr@atmel.com
;*
;* Code Size		: 32 Words
;* Low Register Usage	: 0
;* High Register Usage	: 4
;* Interrupt Usage	: None
;*
;* DESCRIPTION
;* This Application note contains a very code efficient software UART.
;* The example program receives one character and echoes it back.
;***************************************************************************

;;;#include "candle.h"
;;;#include "iodefs.h"

;***** Pin definitions

#define DDR(port) (port-1)
#define PINS(port) (port-2)
#define PORT(port) (port)

#define	RxD	4			/* Receive pin is PB4 */
#define	RxPort	PORTB
#define	TxD	4			/* Transmit pin is PB4 */
#define	TxPort	PORTB

/* ***** Global register variables */

#define	bitcnt	r25			/* bit counter */
#define	temp	r23			/* temporary storage register */

#define	Txbyte	r24			/* Data to be transmitted */
#define	Rxbyte	r24			/* Received data */

#define CLOCK 1600000
#define BAUD_RATE 19200
#define BAUD_RATE 38400

#define BIT_COUNT (((CLOCK + (BAUD_RATE/2))/BAUD_RATE - 8 + 1) / 3)

.cseg
;***************************************************************************
;*
;* "putchar"
;*
;* This subroutine transmits the byte stored in the "Txbyte" register
;* The number of stop bits used is set with the sb constant
;*
;* Number of words	:14 including return
;* Number of cycles	:Depens on bit rate
;* Low registers used	:None
;* High registers used	:2 (bitcnt,Txbyte)
;* Pointers used	:None
;*
;***************************************************************************
.equ		sb	=2		;Number of stop bits (1, 2, ...)

		.global putchar
putchar:	ldi	bitcnt,9+sb	;1+8+sb (sb is # of stop bits)
		sbi	DDR(TxPort),TxD	;TxD is output
		com	Txbyte		;Inverte everything
		sec			;Start bit

putchar0:	brcc	putchar1	;If carry set
		sbi	TxPort,TxD	;    send a '0'
		rjmp	putchar2	;else	

putchar1:	cbi	TxPort,TxD	;    send a '1'
		nop

putchar2:	
#if 0
		rcall UART_delay	;One bit delay
		rcall UART_delay
#else
		ldi	temp,BIT_COUNT
1:		dec	temp
		brne	1b
#endif

		lsr	Txbyte		;Get next bit
		dec	bitcnt		;If not all bit sent
		brne	putchar0	;   send next
					;else
		ret			;   return


;***************************************************************************
;*
;* "getchar"
;*
;* This subroutine receives one byte and returns it in the "Rxbyte" register
;*
;* Number of words	:14 including return
;* Number of cycles	:Depens on when data arrives
;* Low registers used	:None
;* High registers used	:2 (bitcnt,Rxbyte)
;* Pointers used	:None
;*
;***************************************************************************

		.global getchar
getchar:	ldi 	bitcnt,9	;8 data bit + 1 stop bit
		cbi	DDR(RxPort),RxD	;RxD is input

getchar1:	sbis 	PINS(RxPort),RxD	;Wait for start bit (high)
		rjmp 	getchar1
#if 0
		rcall UART_delay	;0.5 bit delay

getchar2:	rcall UART_delay	;1 bit delay
		rcall UART_delay		
#else
		ldi	temp,BIT_COUNT/2
1:		dec	temp
		brne	1b

getchar2:				;1 bit delay
		ldi	temp,BIT_COUNT
1:		dec	temp
		brne	1b
#endif

		clc			;clear carry
		sbis 	PINS(RxPort),RxD	;if RX pin low
		sec			;

		dec 	bitcnt		;If bit is stop bit
		breq 	getchar3	;   return
					;else
		ror 	Rxbyte		;   shift bit into Rxbyte
		rjmp 	getchar2	;   go get next

getchar3:	ret


;***************************************************************************
;*
;* "UART_delay"
;*
;* This delay subroutine generates the required delay between the bits when
;* transmitting and receiving bytes. The total execution time is set by the
;* constant "b":
;*
;*	3b + 7 cycles (including rcall and ret)
;*
;* Number of words	:4 including return
;* Low registers used	:None
;* High registers used	:1 (temp)
;* Pointers used	:None
;*
;***************************************************************************
; Some b values: 	(See also table in Appnote documentation)
;
; 1 MHz crystal:
;   9600 bps - b=14
;  19200 bps - b=5
;  28800 bps - b=2
;
; 2 MHz crystal:
;  19200 bps - b=14
;  28800 bps - b=8
;  57600 bps - b=2

; 4 MHz crystal:
;  19200 bps - b=31
;  28800 bps - b=19
;  57600 bps - b=8
; 115200 bps - b=2

//.equ	b	=31	;19200 bps @ 4 MHz crystal
//.equ	b	=14	;9600 bps @ 1 MHz crystal (3% error!)
//.equ	b	=69	;2400 bps @ 1 MHz crystal (66 nominal)
.equ	b	=32	;4800 bps @ 1 MHz crystal (31 nominal)
.equ	b	=50	;4800 bps @ 1.6 MHz crystal (49.6 nominal)

		.global UART_delay
UART_delay:	ldi	temp,b
UART_delay1:	dec	temp
		brne	UART_delay1

		ret

;***** Program Execution Starts Here

;***** Test program

		.global uart_reset
uart_reset:	cbi	TxPort,TxD	;Init port pins
		cbi	DDR(RxPort),RxD	;RxD is input

                cbi PORTB, 1    ; LED on
#ifdef CALIBRATE_OSC
1:
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                cbi PORTB, 1    ; LED on
                sbi PORTB, 1    ; LED on
                rjmp 1b
#endif
#if 0
2:
		ldi	Txbyte,'5'
		rcall	putchar
		rcall UART_delay
		ldi	Txbyte,' '
		rcall	putchar
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rcall UART_delay
		rjmp 2b
#endif

		ldi	Txbyte,'X'
		rcall	putchar

		ldi	Txbyte,'\r'
		rcall	putchar

		ldi	Txbyte,'\n'
		rcall	putchar

forever:	rcall	getchar
		mov	Txbyte,Rxbyte
		rcall UART_delay
		rcall UART_delay
		rcall	putchar		;Echo received char
		rjmp	forever


Back