Source file: /~heha/basteln/PC/kvm/usbconv.zip/usbh2313.asm

;------------------------------------------------------------------------------
; usbh2313 for AT90S2313  Ver 0.1  2004.03.19 by K.Ishikawa
;------------------------------------------------------------------------------

	.include "2313def.inc"

;------------------------------------------------------------------------------
;	AVR Port Assign List
;
;	PortB bit0  LED0
;	      bit1  LED1
;	      bit2  LED2
;	      bit3  LED3
;	      bit4  LED4
;	      bit5  (MOSI)
;	      bit6  (MISO)
;	      bit7  (SCK)
;	PortD bit0  RxD
;	      bit1  TxD
;	      bit2  USB BUS D+
;	      bit3  USB BUS D-
;	      bit4  
;	      bit5  
;	      bit6  

;------------------------------------------------------------------------------

	.def	icount		= r19
	.def	connect		= r20
	.def	tcount		= r21
	.def	arg1		= r22
	.def	arg2		= r23
	.def	tmp1		= r24
	.def	tmp2		= r25

	.equ    RAMSTART	= $60	; Start On-Chip SRAM Location
	.equ    INTERVAL	= 10	; Interrupt Inverval(ms)

;------------------------------------------------------------------------------


;------------------------------------------------------------------------------

	rjmp	MAIN		; Reset Handler
	rjmp	EXT_INT0	; IRQ0 Handler
	rjmp	EXT_INT1	; IRQ0 Handler
	rjmp	TIM1_CAPT	; Timer1 Capture Handler
	rjmp	TIM1_COMP	; Timer1 Compare Handler
	rjmp	TIM1_OVF	; Timer1 Overflow Handler
	rjmp	TIM0_OVF	; Timer0 Overflow Handler
	rjmp	UART_RXC	; UART RX Complete Handler
	rjmp	UART_DRE	; UDR Empty Handler
	rjmp	UART_TXC	; UART TX Complete Handler
	rjmp	ANA_COMP	; Analog Comparator Handler

;------------------------------------------------------------------------------

EXT_INT0:
EXT_INT1:
TIM1_CAPT:
TIM1_COMP:
TIM1_OVF:
UART_RXC:
UART_DRE:
UART_TXC:
ANA_COMP:
	reti

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

DATA_EOP:
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_ACK:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x04, 0x04
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_SETUP_TOKEN_0:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x08, 0x08, 0x04, 0x04, 0x08, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x04, 0x08, 0x04, 0x08
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_SET_ADDRESS_1:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x08, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08
	.db		0x08, 0x04, 0x04, 0x08, 0x04, 0x04, 0x08, 0x04
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_DATA_IN_0_0:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x04, 0x08, 0x04, 0x08
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_SETUP_TOKEN_1:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x08, 0x08, 0x04, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_SET_CONFIGURATION_1:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08
	.db		0x08, 0x04, 0x04, 0x08, 0x04, 0x04, 0x08, 0x04
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_DATA_IN_1_0:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_DATA_IN_1_1:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x08, 0x04, 0x08, 0x08, 0x08, 0x04, 0x04, 0x08
	.db		0x02, 0x02, 0x08, 0x08

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

MAIN:
	; **** Initialize Stack Pointer ****
	ldi		tmp1, LOW(RAMEND)	; Stack Pointer Setup
	out		SPL, tmp1			; Stack Pointer Low Byte	
	; **** Turn off Watchdog timer ****
	ldi		tmp1, 0x18			; 
	out		WDTCR, tmp1			; 
	ldi		tmp1, 0x10			; 
	out		WDTCR, tmp1			; 
	; **** Initialize Comparator ****
	ldi		tmp1, 0x80			; Disable comparator to save power
	out		ACSR, tmp1			; 
	; **** Initialize UART ****
	ldi		tmp1, 0x0C			; Baud rate 57600 Osc is 12 MHz
	out		UBRR, tmp1			; UART Baud rate generator
	ldi		tmp1, 0x18			; UART Interrupt Disables
	out		UCR, tmp1			; RX Enable, TX Enable, 9-Bit Disable
	ldi		tmp1, 0x00			; Dummy write
	out		UDR, tmp1
	; **** Initialize I/O Port ****
	ldi		tmp1, 0x1F			; Set PB0-4 as Output Mode
	out		DDRB, tmp1
	ldi		tmp1, 0x00			; LED All ON
	out		PORTB, tmp1
	ldi		tmp1, 0x00			; Set PD0-6 as Input Mode
	out		DDRD, tmp1
	ldi		tmp1, 0x00			; PD2-3 HI-Z
	out		PORTD, tmp1
	; **** Initialize Timer 0 ****
	ldi		tcount, 0x00			; 
	ldi		tmp1, 0x02			; Enable Timer0 Overflow Interrupt
	out		TIMSK, tmp1
	ldi		tmp1, 69			; 1ms Timer Count
	out		TCNT0, tmp1
	ldi		tmp1, 0x03			; CK/64, Timer Start
	out		TCCR0, tmp1
	sei							; Enable Global Interrupt
	; **** Initialize Register ****
	ldi		connect, 0			; Set State Disconnect
	ldi		tcount, 0
	ldi		icount, 0
	; **** Power On Wait ****
	ldi		arg1, 10			; 1sec wait
	rcall	DELAY_100MS
	ldi		tmp1, 0x1F			; LED All OFF
	out		PORTB, tmp1
	
	; **** Main Loop ****
MAIN_LOOP:
	ldi		arg1, 1				; 1ms wait
	rcall	DELAY_1MS
	cpi		connect, 0			; Check State
	breq	MAIN_DISCONNECT
	rjmp	MAIN_CONNECT

;------------------------------------------------------------------------------

MAIN_CONNECT:
	; **** Check Disconnection ****
	sbis	PIND, 3
	rjmp	MAIN_DISCONNECTING
	
	; **** Send EOP ****
	ldi		ZH, HIGH(DATA_EOP*2)
	ldi		ZL, LOW(DATA_EOP*2)
	ldi		arg1, 4
	rcall	USB_SND_ROM
	; **** Interval Count ****
	inc		icount
	cpi		icount, INTERVAL
	brne	MAIN_LOOP
	ldi		icount, 0
	
	; **** Interrupt Transfer ****
	ldi		ZH, HIGH(DATA_PKT_DATA_IN_1_1*2)
	ldi		ZL, LOW(DATA_PKT_DATA_IN_1_1*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	rcall	USB_RCV
	mov		tmp2, arg1
	ldi		ZH, HIGH(RAMSTART+8)	; Check DATA0/1 or NAK/STALL
	ldi		ZL, LOW(RAMSTART+8)
	ld		tmp1, Z
	sbrc	tmp1, 3
	rjmp	MAIN_LOOP
	ldi		ZH, HIGH(DATA_PKT_ACK*2)
	ldi		ZL, LOW(DATA_PKT_ACK*2)
	ldi		arg1, 20
	rcall	USB_SND_ROM
	
MAIN_PROCESS:
	; *** Processing Received Data ****
	mov		arg1, tmp2
	rcall	USB_CONV
	ldi		ZH, HIGH(RAMSTART+2)	; Z = RAMSTART+2
	ldi		ZL, LOW(RAMSTART+2)
	; *** for Mouse ****
	ld		arg1, Z
	com		arg1					; Invert for LED Out
	out		PORTB, arg1
	; *** for ASCII PAD USB mini ****
;	ldi		tmp1, 0x00
;	ld		arg1, Z+
;	ld		arg1, Z+
;	sbrs	arg1, 7					; Left ON  ( = 0x00 )
;	ori		tmp1, 0x04		
;	sbrc	arg1, 0					; Right ON ( = 0xFF )
;	ori		tmp1, 0x08		
;	ld		arg1, Z+
;	sbrs	arg1, 7					; Up ON    ( = 0x00 )
;	ori		tmp1, 0x01		
;	sbrc	arg1, 0					; Down ON  ( = 0xFF )
;	ori		tmp1, 0x02		
;	ld		arg1, Z
;	ldi		arg2, 0x00
;	cpse	arg1, arg2
;	ori		tmp1, 0x10
;	com		tmp1					; Invert for LED Out
;	out		PORTB, tmp1
	; *** for Check Received Data ****
;	rcall	CONSOLE_PUT_HEX2
;	ldi		arg1, 0x20
;	rcall	CONSOLE_PUT_CHAR
;	ld		arg1, Z+
;	rcall	CONSOLE_PUT_HEX2
;	ldi		arg1, 0x20
;	rcall	CONSOLE_PUT_CHAR
;	ld		arg1, Z+
;	rcall	CONSOLE_PUT_HEX2
;	ldi		arg1, 0x20
;	rcall	CONSOLE_PUT_CHAR
;	ld		arg1, Z+
;	rcall	CONSOLE_PUT_HEX2
;	ldi		arg1, 0x20
;	rcall	CONSOLE_PUT_CHAR
;	ld		arg1, Z+
;	rcall	CONSOLE_PUT_HEX2
;	ldi		arg1, 0x20
;	rcall	CONSOLE_PUT_CHAR
;	ld		arg1, Z+
;	rcall	CONSOLE_PUT_HEX2
;	ldi		arg1, 0x0D
;	rcall	CONSOLE_PUT_CHAR
;	ldi		arg1, 0x0A
;	rcall	CONSOLE_PUT_CHAR

	rjmp	MAIN_LOOP
	
;------------------------------------------------------------------------------

MAIN_DISCONNECTING:
	; **** 500ms Wait ****
	ldi		tmp1, 0x00			; LED All ON
	out		PORTB, tmp1
	ldi		arg1, 5				; 500ms wait
	rcall	DELAY_100MS
	ldi		tmp1, 0x1F			; LED All OFF
	out		PORTB, tmp1
	; **** Recheck Disconnection ****
	sbis	PIND, 3
	ldi		connect, 0			; Set State Disconnect
	rjmp	MAIN_LOOP

;------------------------------------------------------------------------------

MAIN_DISCONNECT:
	; **** Check Connection ****
	sbis	PIND, 3
	rjmp	MAIN_LOOP

;------------------------------------------------------------------------------

MAIN_CONNECTING:
	; **** 500ms Wait ****
	ldi		tmp1, 0x00			; LED All ON
	out		PORTB, tmp1
	ldi		arg1, 5				; 500ms wait
	rcall	DELAY_100MS
	ldi		tmp1, 0x1F			; LED All OFF
	out		PORTB, tmp1
	; **** Recheck Connection ****
	sbis	PIND, 3
	rjmp	MAIN_LOOP
	ldi		tmp1, 0x00			; LED All ON
	out		PORTB, tmp1
	
	; **** USB Reset ****
	ldi		arg1, 200			; 200ms wait
	rcall	DELAY_1MS
	ldi		tmp1, 0x0C			; Set PD2 and PD3 as output mode
	out		DDRD, tmp1
	ldi		tmp1, 0x02			; Set Bus Reset
	out		PORTD, tmp1
	ldi		arg1, 10			; 10ms wait
	rcall	DELAY_1MS
	ldi		tmp1, 0x00			; Set PD2 and PD3 as input mode
	out		DDRD, tmp1
	ldi		tmp1, 0x00			; PD2-3 HI-Z
	out		PORTD, tmp1
	
	; **** 40ms Loop ****
	ldi		tmp1, 40
MAIN_CONNECTING_AFTER_RESET:
	push	tmp1
	ldi		arg1, 1				;1ms Wait
	rcall	DELAY_1MS
	; **** Send EOP ****
	ldi		ZH, HIGH(DATA_EOP*2)
	ldi		ZL, LOW(DATA_EOP*2)
	ldi		arg1, 4
	rcall	USB_SND_ROM
	pop		tmp1
	dec		tmp1
	brne	MAIN_CONNECTING_AFTER_RESET
	
	; **** Set Address ****
	ldi		ZH, HIGH(DATA_PKT_SETUP_TOKEN_0*2)
	ldi		ZL, LOW(DATA_PKT_SETUP_TOKEN_0*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	ldi		ZH, HIGH(DATA_PKT_SET_ADDRESS_1*2)
	ldi		ZL, LOW(DATA_PKT_SET_ADDRESS_1*2)
	ldi		arg1, 100
	rcall	USB_SND_ROM
	rcall	USB_RCV
MAIN_CONNECTING_SET_ADDRESS:
	ldi		ZH, HIGH(DATA_PKT_DATA_IN_0_0*2)
	ldi		ZL, LOW(DATA_PKT_DATA_IN_0_0*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	rcall	USB_RCV
	ldi		ZH, HIGH(RAMSTART+8)	; Check DATA0/1 or NAK/STALL
	ldi		ZL, LOW(RAMSTART+8)
	ld		tmp1, Z
	sbrc	tmp1, 3
	rjmp	MAIN_CONNECTING_SET_ADDRESS
	ldi		ZH, HIGH(DATA_PKT_ACK*2)
	ldi		ZL, LOW(DATA_PKT_ACK*2)
	ldi		arg1, 20
	rcall	USB_SND_ROM

	; **** Send EOP ****
	ldi		arg1, 1
	rcall	DELAY_1MS
	ldi		ZH, HIGH(DATA_EOP*2)
	ldi		ZL, LOW(DATA_EOP*2)
	ldi		arg1, 4
	rcall	USB_SND_ROM

	; **** Set Configuration ****
	ldi		ZH, HIGH(DATA_PKT_SETUP_TOKEN_1*2)
	ldi		ZL, LOW(DATA_PKT_SETUP_TOKEN_1*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	ldi		ZH, HIGH(DATA_PKT_SET_CONFIGURATION_1*2)
	ldi		ZL, LOW(DATA_PKT_SET_CONFIGURATION_1*2)
	ldi		arg1, 100
	rcall	USB_SND_ROM
	rcall	USB_RCV
MAIN_CONNECTING_SET_CONFIG:
	ldi		ZH, HIGH(DATA_PKT_DATA_IN_1_0*2)
	ldi		ZL, LOW(DATA_PKT_DATA_IN_1_0*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	rcall	USB_RCV
	ldi		ZH, HIGH(RAMSTART+8)	; Check DATA0/1 or NAK/STALL
	ldi		ZL, LOW(RAMSTART+8)
	ld		tmp1, Z
	sbrc	tmp1, 3
	rjmp	MAIN_CONNECTING_SET_CONFIG
	ldi		ZH, HIGH(DATA_PKT_ACK*2)
	ldi		ZL, LOW(DATA_PKT_ACK*2)
	ldi		arg1, 20
	rcall	USB_SND_ROM
	
	; **** Finish Connecting ****
	ldi		tmp1, 0x1F			; LED All OFF
	out		PORTB, tmp1
	ldi		connect, 1			; Set State Connect

	rjmp	MAIN_LOOP

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

; parameter	ZH:ZL ... send data address
;           arg1  ... send data length
; return	none
; crash		arg1, tmp1, ZH, ZL, r0

USB_SND_ROM:
	ldi		tmp1, 0x08			; 
	out		PORTD, tmp1
	ldi		tmp1, 0x0C			; Set PD2 and PD3 as output mode
	out		DDRD, tmp1
USB_SND_ROM_LOOP:
	lpm							; r0 = (Z)
	inc		ZL
	out		PORTD, r0
	dec		arg1
	brne	USB_SND_ROM_LOOP
USB_SND_ROM_LOOPEND:
	ldi		tmp1, 0x00			; Set PD2 and PD3 as input mode
	out		DDRD, tmp1
	out		PORTD, tmp1			; Set PD2 and PD3 as HI-Z
	ret

;------------------------------------------------------------------------------

; parameter	none
; return    arg1  ... received data length
; crash		arg1, tmp1, ZH, ZL

USB_RCV:
	ldi		ZH, HIGH(RAMSTART)	; Z = RAMSTART
	ldi		ZL, LOW(RAMSTART)
	ldi		tmp1, 100
USB_RCV_WAITLOOP:
	sbic	PIND, 3				; Wait until PD3(D-) == 0
	rjmp	USB_RCV_WAITLOOP
USB_RCV_RCVLOOP:
	in		arg1, PIND
	st		Z+, arg1
	andi	arg1, 0x0C
	breq	USB_RCV_ENDLOOP
	dec		tmp1
	brne	USB_RCV_RCVLOOP
USB_RCV_ENDLOOP:
	sbis	PIND, 3				; Wait until PD3(D-) == 1
	rjmp	USB_RCV_ENDLOOP
	ldi		arg1, 100
	sub		arg1, tmp1	
	ret

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

; parameter	arg1  ... convert data length
; return	none
; crash		arg1, tmp1, tmp2. ZH, ZL

USB_CONV:
	rcall	USB_CONV_NRZI
	rcall	USB_CONV_BYTE
	ret

;------------------------------------------------------------------------------

; parameter	arg1  ... convert data length
; return	none
; crash		arg1, tmp1, tmp2, ZH, ZL

USB_CONV_NRZI:
	ldi		ZH, HIGH(RAMSTART)	; Z = RAMSTART
	ldi		ZL, LOW(RAMSTART)
	ldi		tmp1, 0x0B
USB_CONV_NRZI_LOOP:
	ld		tmp2, Z
	cp		tmp1, tmp2
	brne	USB_CONV_NRZI_NE
USB_CONV_NRZI_EQ:
	ldi		tmp2, 1
	rjmp	USB_CONV_NRZI_LOOPEND
USB_CONV_NRZI_NE:
	mov		tmp1, tmp2
	ldi		tmp2, 0
USB_CONV_NRZI_LOOPEND:
	st		Z+, tmp2
	dec		arg1
	brne	USB_CONV_NRZI_LOOP
	ldi		tmp1, 0xFF			; Set End Mark
	st		Z, tmp1
	ret

;------------------------------------------------------------------------------

; parameter	none
; return	none
; crash		arg1, arg2, tmp1, tmp2, YH, YL, ZH, ZL

USB_CONV_BYTE:
	ldi		YH, HIGH(RAMSTART)	; Y = RAMSTART
	ldi		YL, LOW(RAMSTART)
	ldi		ZH, HIGH(RAMSTART)	; Z = RAMSTART
	ldi		ZL, LOW(RAMSTART)
	ldi		tmp1, 0				; clear bit stuff count
USB_CONV_BYTE_LOOP1:
	ldi		tmp2, 0				; clear data
	ldi		arg1, 8
USB_CONV_BYTE_LOOP2:
	ld		arg2, Y+
	cpi		arg2, 0xFF
	breq	USB_CONV_BYTE_END
	ror		arg2
	ror		tmp2
	sbrs	tmp2, 7
	rjmp	USB_CONV_BYTE_0
USB_CONV_BYTE_1:
	inc		tmp1
	cpi		tmp1, 6
	brne	USB_CONV_BYTE_LOOPEND
	adiw	YL, 1
USB_CONV_BYTE_0:
	ldi		tmp1, 0
USB_CONV_BYTE_LOOPEND:
	dec		arg1
	brne	USB_CONV_BYTE_LOOP2
	st		Z+, tmp2
	rjmp	USB_CONV_BYTE_LOOP1
USB_CONV_BYTE_END:
	st		Z, arg2
	ret

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

; parameter	arg1 ... value to convert
; return	arg1 ... converted char
;			carry .. 0:valid(0-15)  1:invalid(16-255)
; crash		arg1, tmp1

HEX_TO_CHAR:
	cpi		arg1, 16
	brcc	HEX_TO_CHAR_INVALID
	cpi		arg1, 10
	brcc	HEX_TO_CHAR_AF
HEX_TO_CHAR_09:
	ldi		tmp1, '0'
	add		arg1, tmp1
	clc
	ret
HEX_TO_CHAR_AF:
	ldi		tmp1, 'A'-10
	add		arg1, tmp1
	clc
	ret
HEX_TO_CHAR_INVALID:
	sec
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... char to put
; return	none
; crash		none

CONSOLE_PUT_CHAR:
	sbis	USR, 5
	rjmp	CONSOLE_PUT_CHAR
	out		UDR, arg1
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... value to put
; return	none
; crash		none

CONSOLE_PUT_HEX1:
	rcall	HEX_TO_CHAR
	rcall	CONSOLE_PUT_CHAR
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... value to put
; return	none
; crash		arg1

CONSOLE_PUT_HEX2:
	push	arg1
	swap	arg1
	andi	arg1, 0x0F
	rcall	CONSOLE_PUT_HEX1
	pop		arg1
	andi	arg1, 0x0F
	rcall	CONSOLE_PUT_HEX1
	ret

;------------------------------------------------------------------------------

; parameter	ZH:ZL ... value to put
; return	none
; crash		arg1

CONSOLE_PUT_HEX4:
	mov		arg1, ZH
	rcall	CONSOLE_PUT_HEX2
	mov		arg1, ZL
	rcall	CONSOLE_PUT_HEX2
	ret

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
	
TIM0_OVF:
	inc		tcount
	ldi		tmp1, 69			; 1ms Timer Count
	out		TCNT0, tmp1
	reti

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

; parameter	arg1 ... delay time (ms)
; return	none
; crash		arg1, tmp1

DELAY_1MS:
	mov		tmp1, tcount
DELAY_1MS_LOOP:
	cp		tmp1, tcount
	breq	DELAY_1MS_LOOP
	dec		arg1
	brne	DELAY_1MS
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... delay time (100ms)
; return	none
; crash		arg1, tmp1, tmp2

DELAY_100MS:
	push	arg1
	ldi		arg1, 100
	rcall	DELAY_1MS
	pop		arg1
	dec		arg1
	brne	DELAY_100MS
	ret

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
Detected encoding: ASCII (7 bit)2