/* Name: sw-uart.S * Project: AVR USB driver for CDC interface on USB1.1 * Author: Osamu Tamura * Creation Date: 2006-05-12 * Tabsize: 4 * Copyright: (c) 2006 by Recursion Co., Ltd. * License: Proprietary, free under certain conditions. See Documentation. */ /* General Description: This module implements the assembler part of the USB-CDC driver. Note: This module violates the rule that interrupts must not be disabled for longer than a couple of instructions (see usbdrv.h). Running UART interrupt handlers with sei as the first instruction is not possible because it would recurse immediately (the cause of the interrupt has not been removed). If we collect the data and then call sei(), we win little. We therefore decide to violate the rule. The effect on USB operation is, that packages may be lost. This is equivalent to a package being dropped due to a CRC error. The host will therefore retry the transfer after a timeout. It is therefore very likely that no effect is seen at the application layer. */
#include "iarcompat.h" #ifndef __IAR_SYSTEMS_ASM__ /* configs for io.h */ # define __SFR_OFFSET 0 # define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ # include /* for CPU I/O register definitions and vectors */ #endif /* __IAR_SYSTEMS_ASM__ */ #include "usbdrv.h" /* for common defs */ #include "uart.h"
#if !UART_CFG_HAVE_USART
/* register names */ #define x1 r16 #define x2 r17 /* Some assembler dependent definitions and declarations: */ #ifdef __IAR_SYSTEMS_ASM__ # define nop2 rjmp $+2 /* jump to next instruction */ # define XL r26 # define XH r27 # define YL r28 # define YH r29 # define ZL r30 # define ZH r31 # define lo8(x) LOW(x) # define hi8(x) ((x)>>8) /* not HIGH to allow XLINK to make a proper range check */ extern tx_stage, bit_start # ifndef IVT_BASE_ADDRESS # define IVT_BASE_ADDRESS 0 # endif ASEG ORG PCINT0_vect + IVT_BASE_ADDRESS rjmp SIG_PIN_CHANGE ORG TIM1_COMPA_vect + IVT_BASE_ADDRESS rjmp SIG_OUTPUT_COMPARE1A ORG TIM0_COMPA_vect + IVT_BASE_ADDRESS rjmp SIG_OUTPUT_COMPARE0A RSEG CODE #else /* __IAR_SYSTEMS_ASM__ */ .text
.global SIG_PIN_CHANGE .type SIG_PIN_CHANGE, @function .global SIG_OUTPUT_COMPARE1A .type SIG_OUTPUT_COMPARE1A, @function .global SIG_OUTPUT_COMPARE0A .type SIG_OUTPUT_COMPARE0A, @function
#endif /* __IAR_SYSTEMS_ASM__ */
; ######################## RS-232C functions ########################
SIG_PIN_CHANGE: push x1 ;2 in x1, SREG ;1 push x1 ;2
lds x1, bit_start ;2
out TCNT1, x1 ;1
ldi x1, 9 ;1 set counter = 9
out OCR1C, x1 ;1
ldi x1, 7 ;1 start timer
out TCCR1, x1 ;1
in x1, GIMSK ;1 stop pin change interrupt
andi x1, ~(1 out GIMSK, x1 ;1
pop x1 ;2 out SREG, x1 ;1 pop x1 ;2 reti ;4 { ,24 }
SIG_OUTPUT_COMPARE1A: push x1 ;2 in x1, SREG ;1 push x1 ;2 push x2 ;2
in x1, TCNT1 ;1
in x2, OCR1A ;1
sub x1, x2 ;1
out TCNT1, x1 ;1
in x1, OCR1C ;1
dec x1 ;1
out OCR1C, x1 ;1
breq tm1_stopbit ;1/2
in x1, OCR1B ;1 data shift
lsr x1 ;1
#if UART_CFG_INVERT
sbis UART_PIN, UART_CFG_RXD ;1/2
#else
sbic UART_PIN, UART_CFG_RXD ;1/2
#endif
ori x1, 0x80 ;1
out OCR1B, x1 ;1
tm1_end:
pop x2 ;2 pop x1 ;2 out SREG, x1 ;1 pop x1 ;2 reti ;4 { 31,65 }
tm1_stopbit:
lds x2, iwptr ;2
inc x2 ;1
andi x2, RX_MASK ;1
lds x1, urptr ;2
cp x2, x1 ;1
breq tm1_full ;1/2 buffer full
push ZL ;2
push ZH ;2
ldi ZL, lo8(rx_buf) ;1
ldi ZH, hi8(rx_buf) ;1
lds x1, iwptr ;2
add ZL, x1 ;1
clr x1 ;1
adc ZH, x1 ;1
in x1, OCR1B ;1
st z, x1 ;2
sts iwptr, x2 ;2
pop ZH ;2
pop ZL ;2
tm1_full:
clr x1 ;1 stop timer1
out TCCR1, x1 ;1
in x1, GIFR ;1
ori x1, (1 out GIFR, x1 ;1
in x1, GIMSK ;1 enable pin-change interrupt
ori x1, (1 out GIMSK, x1 ;1
rjmp tm1_end ;2
SIG_OUTPUT_COMPARE0A: push x1 ;2 in x1, SREG ;1 push x1 ;2
lds x1, tx_stage ;2
subi x1, 1 ;1
sts tx_stage, x1 ;2
brne tm0_charbit ;1/2
clr x1 ;1
out TCCR0B, x1 ;1
rjmp tm0_end ;2
tm0_charbit:
cpi x1, 1 ;1
breq tm0_stopbit ;1/2
in x1, OCR0B ;1
sbrs x1, 0 ;1/2
#if UART_CFG_INVERT
sbi UART_CFG_PORT, UART_CFG_TXD ;2
#else
cbi UART_CFG_PORT, UART_CFG_TXD ;2
#endif
sbrc x1, 0 ;1/2
tm0_stopbit:
#if UART_CFG_INVERT
cbi UART_CFG_PORT, UART_CFG_TXD ;2
#else
sbi UART_CFG_PORT, UART_CFG_TXD ;2
#endif
lsr x1 ;1
out OCR0B, x1 ;1
tm0_end:
pop x1 ;2 out SREG, x1 ;1 pop x1 ;2 reti ;4 { ,27}
#endif /* UART_CFG_HAVE_USART */