
;; dac_player - Copyright 2009 by Michael Kohn
;; Email: mike at mikekohn.net
;;   Web: http://www.mikekohn.net/
;;
;; Play 8 bit digital sound recording through from an i2c eeprom chip
;; to a TI TLC7524 DAC

;; sox /tmp/rotate.wav -b 8 -c 1 -r 8000 out.wav

.include "tn2313def.inc"
;;.device ATtiny2313

.macro PAUSE
  nop
  nop
  nop
  nop
  nop
  nop
  nop
.endm

.macro SHIFT_BIT
  out USICR, r6
  PAUSE
  out USICR, r7
  PAUSE
.endm

;  cycles  sample rate   @1MHz:
;    125   8000

; Outputs
; PB0 - PB7: 8 voices of sound

; r0  = 0
; r1  = 1
; r15 = 255
; r14 = temp
; r17 = temp
; r24 = if not 0, don't play sound
; r25 = 15 bit counter LSB
; r26 = 15 bit counter MSB
;

; Commands are 3 bytes, velocity is ignored:
; 0x9x [note 0 to 127] [velocity 0 to 127] (on)
; 0x8x [note 0 to 127] [velocity 0 to 127] (off)

; note: CLKSEL 0100

.cseg

.org 0x000
  rjmp start
.org 0x008
  rjmp service_interrupt
.org 0x00a
  reti
  ;rjmp service_voices

;; FIXME - erase this padding.. it's dumb
.org 0x020

start:
  ;; I'm busy.  Don't interrupt me!
  cli

  ;; Set up stack ptr
  ;ldi r17, RAMEND>>8
  ;out SPH, r17
  ldi r17, RAMEND&255
  out SPL, r17

  ;; r0 = 0, r1 = 1, r15 = 255
  eor r0, r0
  eor r1, r1
  inc r1
  eor r15, r15
  dec r15

  ;; Set up PORTB, PORTC, PORTD
  out DDRB, r15             ; entire port B is output
  out PORTB, r0             ; turn off all of port B for fun
  out DDRD, r15             ; entire port D is output
  out PORTD, r15            ; turn on all of port D for fun


  ;; Set up TIMER1
  ;lds r17, PRR
  ;andi r17, 255 ^ (1<<PRTIM1)
  ;sts PRR, r17                   ; turn of power management bit on TIM1

  ldi r17, (1000>>8)
  out OCR1AH, r17
  ldi r17, (1000&0xff)            ; compare to 64 clocks
  out OCR1AL, r17

  ldi r17, (1<<OCIE1A)
  out TIMSK, r17                 ; enable interrupt compare A 
  out TCCR1C, r0
  out TCCR1A, r0                 ; normal counting (0xffff is top, count up)
  ldi r17, (1<<CS10)|(1<<WGM12)  ; CTC OCR1A  Clear Timer on Compare
  out TCCR1B, r17                ; prescale = 1 from clock source

  clr r24
  clr r25
  ldi r26, 0x80

  ;clr r21
  ;ldi r21, 0xff

  ;; Set up 2-wire
  ldi r28, (1<<USIWM1)|(1<<USITC)
  mov r6, r28
  ldi r29, (1<<USIWM1)|(1<<USICLK)|(1<<USITC)
  mov r7, r29
  ldi r17, (1<<USIOIF)|(1<<USIPF)|(1<<USISIF)
  mov r3, r17
  ldi r17, 0xa1
  mov r4, r17

  ;; SDA and SCL should be on..
  sbi PORTB, PB5
  sbi PORTB, PB7

  ; Fine, I can be interrupted now
  sei

  ;;out USIDR, r15
  ;;out USISR, r3
  ;;out USICR, r6
  ;;nop
  ;;out USICR, r28

main:
  rjmp main               ; if no data, loop around

;; The Great Interrupt Routine!
service_interrupt:
  inc r25
  brne not_yet
  inc r26
  brne not_yet
  inc r24

;;;; debug
  ;;cpi r24, 10
  ;;brne not_10
  ;;clr r24
;;not_10:
;;;;
  ldi r26, 0x80

not_yet:
  tst r24
  breq okay_to_play
  reti

okay_to_play:
  cbi PORTB, PB5     ;; start condition. SCL, SDA should be high already
  PAUSE
  cbi PORTB, PB7
  PAUSE

  out USISR, r3      ;; Clear the flags in i2c

  out USIDR, r4
  sbi PORTB, PB5     ;; SDA must be high for data to go out

  ;; Write to i2c
  SHIFT_BIT      ;; 7
  SHIFT_BIT      ;; 6
  SHIFT_BIT      ;; 5
  SHIFT_BIT      ;; 4
  SHIFT_BIT      ;; 3
  SHIFT_BIT      ;; 2
  SHIFT_BIT      ;; 1
  SHIFT_BIT      ;; 0

  ;; Read from i2c
  cbi DDRB, PB5     ;; We are input now
  cbi PORTB, PB5    ;; No more internal pullup
  out USICR, r6     ;; Shift this ack bit out
  PAUSE
  out USICR, r7     ;; ACK!!!!
  PAUSE

  out USISR, r3

  SHIFT_BIT      ;; 7
  SHIFT_BIT      ;; 6
  SHIFT_BIT      ;; 5
  SHIFT_BIT      ;; 4
  SHIFT_BIT      ;; 3
  SHIFT_BIT      ;; 2
  SHIFT_BIT      ;; 1
  SHIFT_BIT      ;; 0

  in r21, USIDR        ;; input from i2c EEPROM
  mov r22, r21
  mov r23, r21

  sbi PORTB, PB7       ;; Set SCL high
  PAUSE
  sbi PORTB, PB5       ;; Set SDA high
  sbi DDRB, PB5        ;; STOP!!!!!

  andi r22, 0x1f       ;; first 5 bits is sound data
  ori r22, (1<<PB5)|(1<<PB7)  ;; SCL high, and SDA high
  lsr r23
  lsr r23
  lsr r23
  lsr r23
  lsr r23
  andi r23, 0x07       ;; probably don't need this
  out PORTB, r22
  out PORTD, r23

  ;; sbi PORTD, PD3    <-- let's do this instead
  ori r23, 0x08
  out PORTD, r23

  reti

signature:
.db "DAC Sound Player - Copyright 2009 - Michael Kohn - Version 0.02",0



