.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
.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.
sbic PINB,DENA
rjmp SONGA
rjmp SONGB
SONGA:
rcall SEKUNDE
ldi i2cadr,72 ; PCD3312C
rcall i2c_start
rcall PCD_PAUSE
ldi i2cdata,$38
rcall i2c_do_transfer
rcall i2c_stop
rcall PCD_PAUSE
rcall SEKUNDE
ldi i2cadr,72 ; PCD3312C
rcall i2c_start
rcall PCD_PAUSE
ldi i2cdata,$30 ;
rcall i2c_do_transfer
rcall i2c_stop
rcall PCD_PAUSE
rcall SEKUNDE
rjmp SOUNDOUT
SOUNDOUT:
ldi zh, high(SONG1*2)
ldi zl, low(SONG1*2)
rjmp spkout
spkout:
lpm
mov ar0, r0 ;get lentgh
_ldo1:
adiw ZH:ZL, 1
lpm ;get pattern
ldi i2cadr,72 ; PCD3312C
rcall i2c_start
rcall PCD_PAUSE
mov i2cdata, r0 ;
rcall i2c_do_transfer
rcall i2c_stop
rcall PCD_PAUSE
rcall SEKUNDE
dec ar0 ;count down
brne _ldo1
rjmp SOUNDOUT
SONGB:
ldi zh, high(SONG2*2)
ldi zl, low(SONG2*2)
rjmp spksong
spksong:
lpm
mov ar0, r0 ;get lentgh
_ldo2:
adiw ZH:ZL, 1
lpm ;get pattern
ldi i2cadr,72 ; PCD3312C
rcall i2c_start
rcall PCD_PAUSE
mov i2cdata, r0 ;
rcall i2c_do_transfer
rcall i2c_stop
rcall PCD_PAUSE
rcall SEKUNDE
dec ar0 ;count down
brne _ldo2
rjmp SONGB
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
; =============================
PCD_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
; 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
SONG1:
.db 37, $35
.db $35, $35
.db $35, $35
.db $35, $35
.db $36, $00
.db $00, $35
.db $35, $35
.db $31, $35
.db $35, $35
.db $36, $00
.db $31, $36
.db $36, $36
.db $31, $36
.db $37, $37
.db $38, $00
.db $38, $38
.db $38, $38
.db $39, $39
.db $00, $00
SONG2:
.db 37, $00
.db $30, $31
.db $32, $33
.db $34, $35
.db $34, $34
.db $34, $34
.db $35, $00
.db $34, $34
.db $34, $34
.db $35, $00
.db $34, $34
.db $34, $34
.db $35, $00
.db $32, $32
.db $32, $32
.db $32, $33
.db $30, $30
.db $30, $30
.db $30, $31