;-----------------------------------------------------------------------------------------------; ; LICENSE AGREEMENT: ; ; This program is free software. You can redistribute it and/or modify it under the terms of ; ; the GNU General Public License as published by the Free Software Foundation, either version ; ; 2 of the License, or (at your option) any later version. No part of this code may be used ; ; in any commercial application without prior written permission. ; ; ; ; This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, ; ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ; ; See the GNU General Public License for more details. ; ; ; ; Copyright (c) September 5, 2005 David J. Brown ; ; ; ;-----------------------------------------------------------------------------------------------; ; ; TinyDisplay.asm ; developed for the ATTINY13 ; ; written by David J. Brown ; includes Ap Note AVR304 half duplex interrupt driven software uart code ; email: davebr@earthlink.net ; web: http://modularsynthesis.com ; ; created: September 5, 2005 ; revision 0.0 ; ; history: ; rev 0.0 initial code release ; ;------------------------ ; hardware ;------------------------ ; ; pb0 mosi / rx (not used) ; pb1 miso ; pb2 sck ; pb3 serial-0 to display ; pb4 blink-0 ; pb5 reset ; ;------------------------ ; registers ;------------------------ ; ; =r0 ;r0 not used ; =r1 ;r1 not used ; =r2 ;r2 not used ; =r3 ;r3 not used ; =r4 ;r4 not used ; =r5 ;r5 not used ; =r6 ;r6 not used ; =r7 ;r7 not used ; =r8 ;r8 not used ; =r9 ;r9 not used ; =r10 ;r10 not used ; =r11 ;r11 not used ; =r12 ;r12 not used ; =r13 ;r13 not used ; =r14 to r20 ;r14 - r20 are defined for uart global registers .def tmp =r21 ;r21 temp local register ; =r22 ;r22 not used ; =r23 ;r23 not used ; =r24 ;r24 delay counter ; =r25 ;r25 delay counter ; =r26 ;r26/xl not used ; =r27 ;r27/xh not used ; =r28 ;r28/yl not used ; =r29 ;r29/yh not used ; =r30 ;r30/zl not used ; =r31 ;r31/zh not used ; ;------------------------ ; assembler directives ;------------------------ ; .nolist .include "tn13def.inc" .list .listmac ; ;------------------------ ; ram ;------------------------ ; .dseg .org sram_start ; ; ;------------------------ ; interrupt vectors ;------------------------ ; .cseg .org 0x000 ; rjmp start ;0x000 reset rjmp ext_int0 ;0x001 int0 rjmp irq_none ;0x002 pcint0 rjmp tim0_ovf ;0x003 timer0 ovf rjmp irq_none ;0x004 ee rdy rjmp irq_none ;0x005 analog comp rjmp irq_none ;0x006 timer0 comp-a rjmp irq_none ;0x007 timer0 comp-b rjmp irq_none ;0x008 wdt ovf rjmp irq_none ;0x009 adc conversion ; irq_none: reti ; ;**** START OF APPLICATION NOTE AVR304 *********************************** ;* ;* Title: half duplex interrupt driven software uart ;* Version: 1.0 ;* Last update: Nov 5 2002, by ŘE ;* Target: AT90Sxxxx (All AVR Devices) ;* ;* Modified to ATTINY13 by Dave Brown ;* Sept 5, 2005 ;* ;* Interrupts used: external interrupt and timer/vounter0 overflow interrupt ;* ;* This application note describes how to make a half duplex software UART ;* on any AVR device with the 8-bit timer/counter0 and external interrupt. ;* ;* The constants N and R determine the data rate. R selects clock frequency as ;* described in the T/C Prescaler in the AVR databook. If the T/C prescaling ;* factor is denoted C, the following expression yields the data rate: ;* ;* XTAL ;* BAUD = ------ min. N*C = 17 ;* N*C max. N = 170 ;* ;* Absolute minimum value for N*C is 17 (which causes the interrupt flag to be ;* set again before the interrupt is finished). Absolute maximum is 170 (due ;* to the 1.5 bit-length necessary for receive bits). ;* ;* Since the uart is half duplex, it can either send or recieve data. It can't ;* do both simoutaneausly. When idle it will automatically receive incoming ;* data, but if it is transmitting data while incoming data arrives, it will ;* ignore it. Also, if u_transmit is called without waiting for the 'BUSY' bit ;* in the 'u_status' register to become cleared, it will abort any pending ;* reception or transmission. ;* ;* initialization ;* 1. call uart_init ;* 2. enable global interrupts (with 'sei') ;* ;* receive ;* 1. wait until RDR in 'u_status' becomes set ;* 2. read 'u_buffer' ;* ;* transmit ;* 0. initialize the usty (by executing uart_init and sei) ;* 1. wait until BUSY in 'u_status' becomes clear ;* 2. set 'u_buffer' ;* 3. call 'u_transmit' ;* ;* BAUD-rate settings ;* ;* @1MHz XTAL AND R=1 ;*.equ N=104 ; 9600 ;*.equ N=52 ;19200 ;*.equ N=26 ;38400 ;*.equ C=1 ;Divisor ;*.equ R=1 ;R=1 when C=1 ;* ;* 9600 @9.6MHz OSC ;N*C=1000 ;* .equ N=131 .equ C=1 .equ R=0x02 ;prescale by 8 ;* ;* uart pins ;* .equ rx_pin=0 ;Receive data pin (must be INT0) .equ tx_pin=3 ;Transmit data pin ;* ;* uart global registers ;* .def u_buffer =r14 ;Serial buffer .def u_sr =r15 ;Status-register storage .def u_tmp =r16 ;Scratchregister .def u_bit_cnt =r17 ;Bit counter .def u_status =r18 ;Status buffer .def u_reload =r19 ;Reload-register (internal - do not use) .def u_transmit =r20 ;Data to transmit ;* ;* bit positions in the uart status-register ;* .equ RDR=0 ;receive data ready bit .equ TD=6 ;transmitting data (internal - read-only) .equ BUSY=7 ;busy-flag (internal - read-only) ;* ;************************************************************************** ;* ;* external interrupt routine 0 ;* ;* This routine is executed when a negative edge on the incoming serial ;* signal is detected. It disables further external interrupts and enables ;* timer interrupts (bit-timer) because the uart must now receive the ;* incoming data. ;* ;* This routine sets bits in the GIMSK, TIFR0 and TIMSK0 registers. In this ;* code when the bits are set, it overwrites all other bits. This is done ;* because of the lack of available cycles when it operates at low clock ;* rate and high baud rates. ;* ;************************************************************************** ;* ext_int0: in u_sr,SREG ;save status register ldi u_status,1<7) is set rjmp tim0_stopb ;set so stop-bit-part sbrc u_buffer,0 ;check if lsb in buffer is 1 sbi PORTB,tx_pin ;1 so set transmit to 1 sbrs u_buffer,0 ;check if lsb in buffer is 0 cbi PORTB,tx_pin ;0 so set transmit to 0 lsr u_buffer ;shift buffer right ldi u_tmp,INTF0 out GIFR,u_tmp ;clear pending external interrupt out SREG,u_sr ;restore SREG reti ;* tim0_stopb: sbi PORTB,tx_pin ;generate stop-bit sbrs u_bit_cnt,0 ;check if u_bit_cnt=8 (stop-bit) rjmp tim0_ret ;yes so exit tim0_complete: ldi u_tmp,1<