.include "tn13def.inc"
.cseg
.org 0
.def temp1 = r16
.def temp2 = r17
.def temp3 = r18
.def temp4 = r19
.def ar0 = r20
.def status = r21
.def i2cdelay= r24 ; Delay loop variable
.def i2cdata = r25 ; I2C data transfer register
.def i2cadr = r26 ; I2C address and direction register
.def i2cstat = r27 ; I2C bus status register
.def speca = r28
.def specb = r28
.equ SCLP = 2 ; SCL für PCD3312C
.equ DENA = 0 ; Taster für zweiten Song
.equ SDAP = 1 ; SDA für PCD3312C
.equ b_dir = 0 ; transfer direction bit in i2cadr
.equ i2crd = 1
.equ i2cwr = 0
ldi temp1, RAMEND
out SPL, temp1
clr temp1
INIT:
cbi DDRB, DENA ; DENA im Ruhezustand immer auf 1.
cbi DDRB, SDAP ; SCL im Ruhezustand immer auf 1.
cbi DDRB, SCLP ; SDA im Ruhezustand immer auf 1.
; ADC initialisieren: ADC0, REF als Referenz, Single Conversion, Vorteiler 128
ldi temp1, (1<<REFS0) | (1<<MUX1) ; Kanal 2, interne Referenzspannung 2,5V
out ADMUX, temp1
ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
out ADCSRA, temp1
ldi i2cadr,132 ; TDA6610
rcall i2c_start
rcall TDA_PAUSE
ldi i2cdata,$01
rcall i2c_do_transfer
rcall TDA_PAUSE
ldi i2cdata,55
rcall i2c_do_transfer
rcall i2c_stop
rcall TDA_PAUSE
ldi i2cadr,132 ; TDA6610
rcall i2c_start
rcall TDA_PAUSE
ldi i2cdata,$02
rcall i2c_do_transfer
rcall TDA_PAUSE
ldi i2cdata,55
rcall i2c_do_transfer
rcall i2c_stop
rcall TDA_PAUSE
ldi i2cadr,132 ; TDA6610
rcall i2c_start
rcall TDA_PAUSE
ldi i2cdata,$03
rcall i2c_do_transfer
rcall TDA_PAUSE
ldi i2cdata,31
rcall i2c_do_transfer
rcall i2c_stop
rcall TDA_PAUSE
ldi i2cadr,132 ; TDA6610
rcall i2c_start
rcall TDA_PAUSE
ldi i2cdata,$07
rcall i2c_do_transfer
rcall TDA_PAUSE
ldi i2cdata,196
rcall i2c_do_transfer
rcall i2c_stop
rcall TDA_PAUSE
ldi i2cadr,132 ; TDA6610
rcall i2c_start
rcall TDA_PAUSE
ldi i2cdata,$00
rcall i2c_do_transfer
rcall TDA_PAUSE
ldi i2cdata,194
rcall i2c_do_transfer
rcall i2c_stop
rcall TDA_PAUSE
rjmp RETOUR
RETOUR:
rcall sample_adc
ldi i2cadr,132 ; TDA6610
rcall i2c_start
rcall WARTE
ldi i2cdata,$05
rcall i2c_do_transfer
rcall WARTE
mov i2cdata,speca
rcall i2c_do_transfer
rcall i2c_stop
rcall SEKUNDE
rjmp RETOUR
sample_adc:
sbi ADCSRA, ADSC ; den ADC starten
wait_adc:
sbic ADCSRA, ADSC ; wenn der ADC fertig ist, wird dieses Bit gelöscht
rjmp wait_adc
; ADC einlesen:
in speca, ADCL ; immer zuerst LOW Byte lesen
in specb, ADCH ; danach das mittlerweile gesperrte High Byte
com speca
ldi temp1, 128
add speca, temp1
ret
SEKUNDE:
; =============================
; Warteschleifen-Generator
; 800000 Zyklen:
; -----------------------------
; warte 799995 Zyklen:
ldi temp1, $5F
MSP0a: ldi temp2, $17
MSP1a: ldi temp3, $79
MSP2a: dec temp3
brne MSP2a
dec temp2
brne MSP1a
dec temp1
brne MSP0a
; -----------------------------
; warte 3 Zyklen:
ldi temp1, $01
MSP3a: dec temp1
brne MSP3a
; -----------------------------
; warte 2 Zyklen:
nop
nop
ret
; =============================
TDA_PAUSE:
; =============================
; Warteschleifen-Generator
; 40000 Zyklen:
; -----------------------------
; warte 39999 Zyklen:
ldi temp1, $43
MP0: ldi temp2, $C6
MP1: dec temp2
brne MP1
dec temp1
brne MP0
; -----------------------------
; warte 1 Zyklus:
nop
ret
WARTE:
ldi R20, $63
WGLOOP0: ldi R21, $C9
WGLOOP1: dec R21
brne WGLOOP1
dec R20
brne WGLOOP0
ldi R20, $02
WGLOOP2: dec R20
brne WGLOOP2
ret
; Warteschleifenende
i2c_hp_delay:
ldi i2cdelay,5 ;2
i2c_hp_delay_loop:
dec i2cdelay
brne i2c_hp_delay_loop
ret
i2c_qp_delay:
ldi i2cdelay,1
i2c_qp_delay_loop:
dec i2cdelay
brne i2c_qp_delay_loop
ret
i2c_rep_start:
sbi DDRB,SCLP ; force SCL low
cbi DDRB,SDAP ; release SDA
rcall i2c_hp_delay ; half period delay
cbi DDRB,SCLP ; release SCL
rcall i2c_qp_delay ; quarter period delay
i2c_start:
mov i2cdata,i2cadr ; copy address to transmitt register
sbi DDRB,SDAP ; force SDA low
rcall i2c_qp_delay ; quarter period delay
i2c_write:
sec ; set carry flag
rol i2cdata ; shift in carry and out bit one
rjmp i2c_write_first
i2c_write_bit:
lsl i2cdata ; if transmit register empty
i2c_write_first:
breq i2c_get_ack ; goto get acknowledge
sbi DDRB,SCLP ; force SCL low
brcc i2c_write_low ; if bit high
nop ; (equalize number of cycles)
cbi DDRB,SDAP ; release SDA
rjmp i2c_write_high
i2c_write_low: ; else
sbi DDRB,SDAP ; force SDA low
rjmp i2c_write_high ; (equalize number of cycles)
i2c_write_high:
rcall i2c_hp_delay ; half period delay
cbi DDRB,SCLP ; release SCL
rcall i2c_hp_delay ; half period delay
rjmp i2c_write_bit
i2c_get_ack:
sbi DDRB,SCLP ; force SCL low
cbi DDRB,SDAP ; release SDA
rcall i2c_hp_delay ; half period delay
cbi DDRB,SCLP ; release SCL
i2c_get_ack_wait:
sbis PINB,SCLP ; wait SCL high
;(In case wait states are inserted)
rjmp i2c_get_ack_wait
clc ; clear carry flag
sbic PINB,SDAP ; if SDA is high
sec ; set carry flag
rcall i2c_hp_delay ; half period delay
ret
i2c_do_transfer:
sbrs i2cadr,b_dir ; if dir = write
rjmp i2c_write ; goto write data
i2c_read:
rol i2cstat ; store acknowledge
; (used by i2c_put_ack)
ldi i2cdata,0x01 ; data = 0x01
i2c_read_bit: ; do
sbi DDRB,SCLP ; force SCL low
rcall i2c_hp_delay ; half period delay
cbi DDRB,SCLP ; release SCL
rcall i2c_hp_delay ; half period delay
clc ; clear carry flag
sbic PINB,SDAP ; if SDA is high
sec ; set carry flag
rol i2cdata ; store data bit
brcc i2c_read_bit ; while receive register not full
i2c_put_ack:
sbi DDRB,SCLP ; force SCL low
ror i2cstat ; get status bit
brcc i2c_put_ack_low ; if bit low goto assert low
cbi DDRB,SDAP ; release SDA
rjmp i2c_put_ack_high
i2c_put_ack_low: ; else
sbi DDRB,SDAP ; force SDA low
i2c_put_ack_high:
rcall i2c_hp_delay ; half period delay
cbi DDRB,SCLP ; release SCL
i2c_put_ack_wait:
sbis PINB,SCLP ; wait SCL high
rjmp i2c_put_ack_wait
rcall i2c_hp_delay ; half period delay
ret
i2c_stop:
sbi DDRB,SCLP ; force SCL low
sbi DDRB,SDAP ; force SDA low
rcall i2c_hp_delay ; half period delay
cbi DDRB,SCLP ; release SCL
rcall i2c_qp_delay ; quarter period delay
cbi DDRB,SDAP ; release SDA
rcall i2c_hp_delay ; half period delay
ret
i2c_init:
clr i2cstat ; clear I2C status register (used
; as a temporary register)
out PORTB,i2cstat ; set I2C pins to open colector
out DDRB,i2cstat
ret