
;
; CS8416 with AVR ATtiny26L
;
; ver 1.0 
; by UENO Tomohiro    2006/10/15

.include "tn26def.inc"

.def	tmp		= R16
.def	tmp2		= R17
.def	tmp3		= R18
.def	counter		= R19
.def	reg_address	= R20
.def	reg_data	= R21
.def	tmp4		= R22
.def	btn1		= R23
.def	ch		= R0
.def	current_btn	= R1
.def	current_freq	= R2
.def	current_ch	= R3

.equ	dai_reset	= 7	; portA
.equ	sel		= 6	; portA
.equ	lcd_e		= 5	; portA
.equ	lcd_rs		= 4	; portA
.equ	lcd_d7		= 3	; portA
.equ	lcd_d6		= 2	; portA
.equ	lcd_d5		= 1	; portA
.equ	lcd_d4		= 0	; portA

.equ	cdout		= 6	; portB
.equ	cclk		= 5	; portB
.equ	cdin		= 4	; portB
.equ	dai_cs		= 3	; portB
.equ	button2		= 2	; portB
.equ	button1		= 1	; portB
.equ	button0		= 0	; portB

.equ	freq_44_1	= 0
.equ	freq_48_0	= 1
.equ	freq_88_2	= 2
.equ	freq_96_0	= 3
.equ	freq_d_c	= 4
.equ	freq_32_0	= 5
.equ	freq_no_signal	= 0xff

.equ	ch_status_table	= 0x60

.macro LCD_STR
	ldi	ZL,low(@0)
	ldi	ZH,high(@0)
	rcall	lcd_put_str
.endmacro


	rjmp	reset	; $000 reset vector
	reti		; $001 EXT_INT0 
	reti		; $002 PIN_CHG 
	reti		; $003 TIMER1 COMPA 
	reti		; $004 TIMER1 COMPB
	reti		; $005 TIMER1 OVF1 
	reti		; $006 TIMER1 OVF0 
	reti		; $007 USI_STRT
	reti		; $008 USI_OVF
	reti		; $009 EE_RDY
	reti		; $00A ANA_COMP
	reti		; $00B ADC

reset:	
	ldi	tmp,LOW(RAMEND)
	out	SP,tmp

	rcall	wait_1ms

	; portA initialize
	ldi	tmp,0b10111111
	out	DDRA,tmp
	ldi	tmp,0b11111111	
	out	PORTA,tmp

	; portB initialize
	ldi	tmp,0b00111000
	out	DDRB,tmp
	ldi	tmp,0b11111111
	out	PORTB,tmp

	rcall	lcd_init
	rcall	lcd_clear

	; A/D converter initialize
	ldi	tmp,0b11000111	; ADEN=1,ADSC=1,ADFR=0(not continue),ADIF=0,ADIE=0,ASPS<2-0>=111
	out	ADCSR,tmp

;	rcall	eeprom_read

	ldi	tmp,0x00+0
	rcall	lcd_pos
	LCD_STR(initial_str1)
	ldi	tmp,0x40+0
	rcall	lcd_pos
	LCD_STR(initial_str2)
	
	ldi	tmp,0xfe
	mov	current_freq,tmp

reset_loop:

	; CS8416 reset
	sbi	PORTA,dai_reset
	cbi	PORTA,dai_reset
	rcall	wait_1ms
	sbi	PORTA,dai_reset
	
	ldi	reg_address,0x04
	ldi	reg_data,0x80
	rcall	dai_write

	ldi	reg_address,0x05
	ldi	reg_data,0x88
	rcall	dai_write

;	ldi	reg_address,0x01
;	ldi	reg_data,0x04
;	rcall	dai_write

	ldi	reg_address,0x7f
	rcall	dai_read
	mov	tmp,reg_data

	cbr	tmp,0b00001111
	cpi	tmp,0x20
	brne	reset_loop	
	ldi	tmp,'?'
	cpi	reg_data,0x21
	brne	PC+3
	ldi	tmp,'A'
	rjmp	PC+16
	cpi	reg_data,0x22
	brne	PC+3
	ldi	tmp,'B'
	rjmp	PC+12
	cpi	reg_data,0x23
	brne	PC+3
	ldi	tmp,'C'
	rjmp	PC+8
	cpi	reg_data,0x27
	brne	PC+3
	ldi	tmp,'D'
	rjmp	PC+4
	cpi	reg_data,0x2f
	brne	PC+2
	ldi	tmp,'E'
	rcall	lcd_put


;	rcall	wait_1s
;	rcall	wait_1s
	rcall	wait_1s
	rcall	lcd_clear

	ldi	tmp,0xff
	mov	current_ch,tmp
	ldi	btn1,0

	ldi	tmp,0x00+0
	rcall	lcd_pos
	LCD_STR(str_input_ch)
	ldi	tmp,0x40+0
	rcall	lcd_pos
	LCD_STR(str_receive)

;	ldi	reg_address,0x04
;	ldi	reg_data,0x80
;	rcall	dai_write

main_loop:
	rcall	wait_1ms

mainloop_check_ch:
	rcall	check_ch
	cp	tmp,current_ch
	breq	mainloop_check_ch_end
	mov	current_ch,tmp
	lsl	tmp
	lsl	tmp
	lsl	tmp
	or	tmp,current_ch
	ori	tmp,0x80
	ldi	reg_address,0x04
	mov	reg_data,tmp
	rcall	dai_write
	ldi	tmp,0x00+4
	rcall	lcd_pos
	mov	tmp,current_ch
	inc	tmp
	rcall	lcd_put_hex
mainloop_check_ch_end:

	ldi	tmp,12
	rcall	lcd_pos
	ldi	reg_address,0x04
	rcall	dai_read
	mov	tmp,reg_data
	rcall	lcd_put_hex

mainloop_check_freq:
	rcall	detect_rx_freq	
	cp	current_freq,tmp
	breq	mainloop_check_freq_end
	mov	current_freq,tmp
	ldi	tmp,0x40+8
	rcall	lcd_pos
	mov	tmp,current_freq
	rcall	put_freq
mainloop_check_freq_end:

	rjmp	main_loop	
                                                                                                                                                                                                                                                                                                                                                         
initial_str1:
.db	"Software v1.0",0
initial_str2:
.db	"CS8416 rev.",0

str_input_ch:
.db	"Ch.",0
str_receive:
.db	"Receive",0

put_selector:
	push	tmp
	subi	tmp,-9
	rcall	lcd_pos
	ldi	tmp,' '
	cpi	tmp2,0
	breq	PC+2
	ldi	tmp,'['
	rcall	lcd_put
	pop	tmp
	subi	tmp,-19
	rcall	lcd_pos
	ldi	tmp,' '
	cpi	tmp2,0
	breq	PC+2
	ldi	tmp,']'
	rcall	lcd_put
	ret

detect_rx_freq:
	ldi	reg_address,0x18
	rcall	dai_read

	rcall	detect_rx_freq_sub
	cpi	tmp,freq_no_signal
	breq	PC+2
	ret
	dec	reg_data
	rcall	detect_rx_freq_sub
	cpi	tmp,freq_no_signal
	breq	PC+2
	ret
	inc	reg_data
	inc	reg_data
	rcall	detect_rx_freq_sub
	ret
	
detect_rx_freq_sub:
	ldi	tmp,freq_no_signal
	cpi	reg_data,92
	brne	PC+2
	ldi	tmp,freq_32_0
	cpi	reg_data,67
	brne	PC+2
	ldi	tmp,freq_44_1
	cpi	reg_data,61
	brne	PC+2
	ldi	tmp,freq_48_0
	cpi	reg_data,33
	brne	PC+2
	ldi	tmp,freq_88_2
	cpi	reg_data,31
	brne	PC+2
	ldi	tmp,freq_96_0
	ret	

set_cpld_status:
	ldi	reg_address,0x04
	ldi	reg_data,0b11000000
	rcall	dai_write

	mov	tmp,current_ch
	ldi	tmp2,4
	cp	current_ch,tmp2
	brsh	PC+3
	ldi	tmp,3
	sub	tmp,current_ch
	lsl	tmp
	lsl	tmp
	lsl	tmp
	sbr	tmp,0b10000000
	ldi	reg_address,0x04
	mov	reg_data,tmp
	rcall	dai_write

	ldi	reg_address,0x7f
	rcall	dai_read
	cpi	reg_data,0x27
	brne	PC-7

	ldi	tmp3,50
	rcall	wait_10ms
	dec	tmp3
	brne	PC-2

;	ldi	reg_address,0b00001010
;	ldi	reg_data,0b00000011
;	rcall	cpld_write

	ret

set_input:
;  tmp2; value (000/100 = coaxica/optical)
	push	tmp2
	ldi	YH,high(ch_status_table)
	ldi	YL,low(ch_status_table)
	add	YL,current_ch
	ld	tmp2,Y
	cbr	tmp2,0b00000100
	or	tmp2,tmp
	st	Y,tmp2
	pop	tmp2
	ret

set_fifo_out:
;  tmp: value (0000/0001/0010/0011/0100 = 44.1/48/88.2/96/free)
	push	tmp2
	ldi	YH,high(ch_status_table)
	ldi	YL,low(ch_status_table)
	add	YL,current_ch
	ld	tmp2,Y
	cbr	tmp2,0b01110000
	swap	tmp
	cbr	tmp,0b10001111
	or	tmp2,tmp
	st	Y,tmp2
	pop	tmp2
	ret

set_wordsync:
;  tmp2; value (00/01/10/11 = 44.1/48.0/88.2/96.0)
	push	tmp2
	ldi	YH,high(ch_status_table)
	ldi	YL,low(ch_status_table)
	add	YL,current_ch
	ld	tmp2,Y
	cbr	tmp2,0b00000011
	or	tmp2,tmp
	st	Y,tmp2
	pop	tmp2
	ret

put_input:
	ldi	tmp,0x00+11
	rcall	lcd_pos
	ldi	YH,high(ch_status_table)
	ldi	YL,low(ch_status_table)
	add	YL,current_ch
	ld	tmp,Y
	cbr	tmp,0b11111011
	cpi	tmp,0
	brne	put_input_optical
put_input_coaxial:
	LCD_STR(str_coaxial)
	ret
put_input_optical:
	LCD_STR(str_optical)
	ret
str_coaxial:
.db	"Coaxial",0
str_optical:
.db	"Optical",0

put_fifo_out:
	ldi	tmp,0x14+11
	rcall	lcd_pos
	ldi	YH,high(ch_status_table)
	ldi	YL,low(ch_status_table)
	add	YL,current_ch
	ld	tmp,Y
	swap	tmp
	cbr	tmp,0b11111000
	cpi	tmp,0
	brne	put_fifo_out_48_0
put_fifo_out_44_1:
	LCD_STR(str_freq_44_1)
	ret
put_fifo_out_48_0:
	cpi	tmp,1
	brne	put_fifo_out_88_2
	LCD_STR(str_freq_48_0)
	ret
put_fifo_out_88_2:
	cpi	tmp,2
	brne	put_fifo_out_96_0
	LCD_STR(str_freq_88_2)
	ret
put_fifo_out_96_0:
	cpi	tmp,3
	brne	put_fifo_out_d_c
	LCD_STR(str_freq_96_0)
	ret
put_fifo_out_d_c:
	LCD_STR(str_freq_d_c)
	ret

put_wordsync:
	ldi	tmp,0x54+11
	rcall	lcd_pos
	ldi	YH,high(ch_status_table)
	ldi	YL,low(ch_status_table)
	add	YL,current_ch
	ld	tmp,Y
	cbr	tmp,0b11111100
	cpi	tmp,0
	brne	put_wordsync_48_0
put_wordsync_44_1:
	LCD_STR(str_freq_44_1)
	ret
put_wordsync_48_0:
	cpi	tmp,1
	brne	put_wordsync_88_2
	LCD_STR(str_freq_48_0)
	ret
put_wordsync_88_2:
	cpi	tmp,2
	brne	put_wordsync_96_0
	LCD_STR(str_freq_88_2)
	ret
put_wordsync_96_0:
	LCD_STR(str_freq_96_0)
	ret

;
; dai register write
;
;   tmp  : address (bit7-0)
;   tmp2 : data    (bit7-0)
;
dai_write:
	cbi	PORTB,dai_cs
	ldi	tmp,0b00100000
	rcall	write_sub
	mov	tmp,reg_address
	rcall	write_sub
	mov	tmp,reg_data
	rcall	write_sub
	sbi	PORTB,dai_cs
	ret

;
; dai register read
;
;   tmp  : address (bit7-0)
;   tmp2 : data    (bit7-0)
;
dai_read:
	cbi	PORTB,dai_cs
	ldi	tmp,0b00100000
	rcall	write_sub
	mov	tmp,reg_address
	rcall	write_sub
	sbi	PORTB,dai_cs
	nop
	nop
	cbi	PORTB,dai_cs
	ldi	tmp,0b00100001
	rcall	write_sub
	ldi	tmp2,8
dai_read_loop:
	lsl	reg_data		
	cbr	reg_data,0x01
	sbic	PINB,cdout
	sbr	reg_data,0x01
	sbi	PORTB,cclk
	cbi	PORTB,cclk
	dec	tmp2
	brne	dai_read_loop
	sbi	PORTB,dai_cs
	rcall	wait_1ms
	ret

write_sub:
	ldi	tmp2,8
write_sub_loop:	
	sbi	PORTB,cdin	
	rol	tmp
	brcs	PC+2
	cbi	PORTB,cdin
	sbi	PORTB,cclk
	cbi	PORTB,cclk
	dec	tmp2
	brne	write_sub_loop
	ret

eeprom_write:
	ldi	tmp2,0
	ldi	YH,high(ch_status_table)
	ldi	YL,low(ch_status_table)
eeprom_write_loop:	
	sbic	EECR,EEWE
	rjmp	PC-1
	out	EEAR,tmp2
	ld	tmp,Y+
	out	EEDR,tmp
	sbi	EECR,EEMWE
	sbi	EECR,EEWE
	rcall	wait_1ms
	inc	tmp2
	cpi	tmp2,8
	brne	eeprom_write_loop
	ret

eeprom_read:
	ldi	tmp2,0
	ldi	YH,high(ch_status_table)
	ldi	YL,low(ch_status_table)
eeprom_read_loop:	
	sbic	EECR,EEWE
	rjmp	PC-1
	out	EEAR,tmp2
	sbi	EECR,EERE
	in	tmp,EEDR
	st	Y+,tmp
	rcall	wait_1ms
	inc	tmp2
	cpi	tmp2,8
	brne	eeprom_read_loop

	ldi	YH,high(ch_status_table)
	ldi	YL,low(ch_status_table)
	ld	tmp,Y
	cpi	tmp,0xff
	breq	PC+2
	ret
	ldi	tmp,0b01000000
	st	Y+,tmp	
	st	Y+,tmp	
	st	Y+,tmp	
	st	Y+,tmp	
	st	Y+,tmp	
	st	Y+,tmp	
	st	Y+,tmp	
	st	Y+,tmp	
	rcall	eeprom_write
	ret

check_btn:
	ldi	tmp,0b00100101 	; REFS1=0,REFS0=0(AVCC),ADLAR=1(left adjust),convert=ADC5
	out	ADMUX,tmp
	sbi	ADCSR,ADSC
	sbic	ADCSR,ADSC
	rjmp	PC-1
	in	tmp2,ADCH
	ldi	tmp,12
	cpi	tmp2,0x90
	brlo	PC+2
	ret
	ldi	tmp,1
	cpi	tmp2,0x60
	brlo	PC+2
	ret
	ldi	tmp,2
	ret
	
check_ch:
	ldi	tmp,0b00100101 	; REFS1=0,REFS0=0(AVCC),ADLAR=1(left adjust),convert=ADC5
	out	ADMUX,tmp
	sbi	ADCSR,ADSC
	sbic	ADCSR,ADSC
	rjmp	PC-1

	in	tmp2,ADCH
	ldi	tmp,0
	cpi	tmp2,18
	brsh	PC+2
	ret
	ldi	tmp,1
	cpi	tmp2,54
	brsh	PC+2
	ret
	ldi	tmp,2
	cpi	tmp2,90
	brsh	PC+2
	ret
	ldi	tmp,3
	cpi	tmp2,128
	brsh	PC+2
	ret
	ldi	tmp,4
	cpi	tmp2,164
	brsh	PC+2
	ret
	ldi	tmp,5
	cpi	tmp2,200
	brsh	PC+2
	ret
	ldi	tmp,6
	cpi	tmp2,238
	brsh	PC+2
	ret
	ldi	tmp,7
	ret

	
put_freq:
	cpi	tmp,freq_32_0
	brne	put_freq_44_1
	LCD_STR(str_freq_32_0)
	ret
put_freq_44_1:
	cpi	tmp,freq_44_1
	brne	put_freq_48_0
	LCD_STR(str_freq_44_1)
	ret
put_freq_48_0:
	cpi	tmp,freq_48_0
	brne	put_freq_88_2
	LCD_STR(str_freq_48_0)
	ret
put_freq_88_2:
	cpi	tmp,freq_88_2
	brne	put_freq_96_0
	LCD_STR(str_freq_88_2)
	ret
put_freq_96_0:
	cpi	tmp,freq_96_0
	brne	put_freq_no_signal
	LCD_STR(str_freq_96_0)
	ret
put_freq_no_signal:
	LCD_STR(str_freq_no_signal)
	ret

str_freq_32_0:
.db	"32.0kHz ",0
str_freq_44_1:
.db	"44.1kHz ",0
str_freq_48_0:
.db	"48.0kHz ",0
str_freq_88_2:
.db	"88.2kHz ",0
str_freq_96_0:
.db	"96.0kHz ",0
str_freq_no_signal:
.db	"NoSignal",0
str_freq_d_c:
.db	"------- ",0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;
; LCD (SUNLIKE SC1602BS-B) initialize
;
lcd_init:
	ldi	counter,10
	rcall	wait_1ms
	dec	counter
	brne	PC-2
	ldi	tmp,0x03
	rcall	lcd_control_out
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	ldi	tmp,0x03
	rcall	lcd_control_out
	rcall	wait_1ms
	ldi	tmp,0x03
	rcall	lcd_control_out
	rcall	wait_1ms
	ldi	tmp,0x02
	rcall	lcd_control_out
	ldi	tmp,0x28
	rcall	lcd_control
	ldi	tmp,0x0c
	rcall	lcd_control
	ldi	tmp,0x06
	rcall	lcd_control
	ldi	tmp,0x01
	ret

;
; LCD screen clear and move position (0,0)
;
lcd_clear:
	ldi	tmp,0x01
	rcall	lcd_control
	ret
	
;
; LCD move position  :  (0,0)=0x00, (0,1)=0x01, (1,0)=0x40
;
lcd_pos:
	sbr	tmp,0x80
	rcall	lcd_control
	ret

;
; LCD put character
;
lcd_put:
	push	tmp
	swap	tmp	
	rcall	lcd_data_out
	pop	tmp
	rcall	lcd_data_out
	ret

;
; LCD put number in hex
;
lcd_put_hex:
	ldi	tmp2,7
	push	tmp
	swap	tmp
	cbr	tmp,0xf0
	sbr	tmp,0x30
	cpi	tmp,0x3a
	brcs	PC+2
	add	tmp,tmp2
	rcall	lcd_put
	pop	tmp
	cbr	tmp,0xf0
	sbr	tmp,0x30
	cpi	tmp,0x3a
	brcs	PC+2
	add	tmp,tmp2
	rcall	lcd_put
	ret

;
; LCD put number in decimal
;
lcd_put_decimal:
	mov	tmp2,tmp
	ldi	tmp,0
lcd_put_decimal_loop:
	cpi	tmp2,10
	brlo	lcd_put_decimal_skip
	subi	tmp2,10
	inc	tmp
	rjmp	lcd_put_decimal_loop
lcd_put_decimal_skip:
	sbr	tmp,0x30
	rcall	lcd_put
	mov	tmp,tmp2
	sbr	tmp,0x30
	rcall	lcd_put
	ret

lcd_put_str:
;	ldi	ZL,LOW(vol_data_2)
;	ldi	ZH,HIGH(vol_data_2)
	lsl	ZL
	rol	ZH	
lcd_put_str_loop:
	lpm	tmp,Z
	cpi	tmp,0
	brne	PC+2
	ret
	rcall	lcd_put
	adiw	ZL,1
	rjmp	lcd_put_str_loop

lcd_control:
	push	tmp
	swap	tmp	
	rcall	lcd_control_out
	pop	tmp
	rcall	lcd_control_out
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	ret

lcd_control_out:
	cbr	tmp,0x10	;rs
	sbr	tmp,0xe0	;e
	out	PORTA,tmp
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	cbi	PORTA,lcd_e
	sbi	PORTA,lcd_e
	rcall	wait_1ms
	ret

lcd_data_out:
	sbr	tmp,0xf0	;rs,e
	out	PORTA,tmp
	rcall	wait_1ms
	cbi	PORTA,lcd_e
	sbi	PORTA,lcd_e
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;
; wait 1 second
;
wait_1s:
	push	tmp

	ldi	tmp,250
wait_1s_a:
	rcall	wait_1ms
	dec	tmp
	brne	wait_1s_a

	ldi	tmp,250
wait_1s_b:
	rcall	wait_1ms
	dec	tmp
	brne	wait_1s_b

	ldi	tmp,250
wait_1s_c:
	rcall	wait_1ms
	dec	tmp
	brne	wait_1s_c

	ldi	tmp,250
wait_1s_d:
	rcall	wait_1ms
	dec	tmp
	brne	wait_1s_d

	pop	tmp	
	ret
	
;
; wait 1 ms
;
wait_1ms:
	push	tmp
	ldi	tmp,255
wait_1ms_loop:
	nop
	nop
	dec	tmp
	brne	wait_1ms_loop
	pop	tmp
	ret
	

;
; wait 10 us
;
wait_10us:
	push	tmp
	ldi	tmp,10
	nop
	dec	tmp
	brne	PC-2
	pop	tmp
	ret
	
;
; wait 10 ms
;
wait_10ms:
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	ret
