.include "m3250Pdef.inc" ; standard definitions include file

;microdec v1.0

;fuse settings
;
; start up time set to 258CK + 65ms
; set to 20MHz by external crystal
; BOD set at 4.3V
; RSTDISBL not set
; OCDEN not set
; JTAG enabled
; SPI enabled
; EESAVE not set
; CKOUT not set
; CKDIV8 not set
; WDT not set

;hardware connections
;
; portA0:7 = D0 - D7 for sram
; portB0:4 = SPI to codec and ISP
; portB5:6 = NC (XP3)
; portB7   = OE for sram
; portC0:7 = D8 - D15 for sram
; portD0:7 = A0 - A7 for sram
; portE0:1 = USART (CEREAL)
; portE2:3 = NC (XP1)
; portE4:5 = I2C to codec with external pullups (could be any pins as USI is pointless)
; portE6:7 = NC (XP2)
; portF0   = ADC0 for potentiometer input (MOD1)
; portF1:3 = NC (ADC1:3)
; portF4:7 = JTAG
; portG0:1 = A16 - A17 for sram
; portG2   = WE for sram
; portG3   = CE for sram
; portG4   = CLKin from codec to T0 for interrupt timing
; portG5   = RESET to JTAG/ISP
; portH0:7 = A8 - A15 for sram
; portJ0:1 = rotary encoder (b0,b1) with external pullups
; portJ2   = rotary encoder pushbutton
; portJ3:6 = rotary switch (b0 - b3)
; AREF     = externally connected to AVcc = +5V
; XTAL1:2  = 20MHz crystal
; VCC      = DVcc = +5V
; AVCC     = AVcc = +5V

;program structure overview
;
; Data is transferred to the codec via SPI, using the codec's DSP mode.
; The codec's master clock is divided by two within the codec, and then
; sent to the microcontroller where it is divided by 128 with T0.  This
; causes an interrupt at 44.1kHz for data transfers to the codec.  In
; order to eliminate audio glitches, this transfer must happen at the
; same time, every time.  For this reason, all code is run within this
; interrupt, and no other interrupts are used.  This way there can never
; be a delay in the transfer of data.  The exact piece of code that is
; run is determined by the rotary switch, which must be checked within
; the interrupt periodically to determine which code should be currently
; running.  The program executes the correct code by jumping to the
; program space defined by the rotary switch setting (ijmp command).
; This jump location has to be loaded into r31:r30 before returning from
; the interrupt, or the program may crash.  Because of the timing
; limitations, only 20MHz/44.1kHz = 453 clock cycles can occur per
; interrupt, of which approximatley 60 are taken up with SPI communication
; and interrupt handling.  A buffered data method could be used if
; the program does not perform the same operations each sample period,
; but the current method is used because of its simplicity.  If you want
; to change a function, merely swap out the code at that .org location.

;current programs and their memory locations
;
; code    switch        function
; -----   -----------   --------------------------------------------
; $0200 = position 07 = pitch_shifter-16b-tonal-fading.asm
; $0400 = position 06 = up_downsweep-18b-pot.asm
; $0600 = position 05 = reverser-18b-gated-delay.asm
; $0800 = position 04 = reverser-16b-pot-fading.asm
; $0a00 = position 03 = reverser-16b-pot-crossfade.asm
; $0c00 = position 02 = ping_pong-18b.asm
; $0e00 = position 01 = delay-18b-pot-mono.asm
; $1000 = position 00 = delay-16b-pot.asm
; $1200 = position 15 = reverb-16b.asm
; $1400 = position 14 = tremolo-stereo.asm
; $1600 = position 13 = chorus-16b-sine.asm
; $1800 = position 12 = flanger-16b-sine.asm
; $1a00 = position 11 = stereo_flanger-16b.asm
; $1c00 = position 10 = vco.asm
; $1e00 = position 09 = fullwave-delay-lowpass.asm
; $2000 = position 08 = sampler-18b-pot.asm

;interrupt vectors
;
.org 0 ; reset interrupt
rjmp start ; initialize microcontroller registers
.org OC0addr ; T0 compare interrupt - set to $80
ijmp ; send data to codec every 128 cycles of codec clock
.org OVF0addr ; T0 overflow interrupt
ijmp ; send data to codec every 128 cycles of codec clock

;register usage - may be redefined in other sections
; for conistency between programs, these registers(*) are normally used
; as shown
;
; r0  multiply result lsb(*)
; r1  multiply result msb(*)
; r2  left data out lsb(*)
; r3  left data out msb(*)
; r4  right data out lsb(*)
; r5  right data out msb(*)
; r6  left data in lsb(*)
; r7  left data in msb(*)
; r8  right data in lsb(*)
; r9  right data in msb(*)
; r10 
; r11 
; r12 
; r13 
; r14 
; r15 
; r16 temporary swap register(*)
; r17 temporary swap register(*)
; r18 twi (i2c) counter register
; r19 
; r20 
; r21 
; r22 write address third byte(*)
; r23 read address third byte(*)
; r24 write address lsb(*)
; r25 write address msb(*)
; r26 
; r27 
; r28 read address lsb(*)
; r29 read address msb(*)
; r30 jump location for interrupts lsb(*)
; r31 jump location for interrupts msb(*)

start: ; configure microcontroller registers

;set stack pointer to top of SRAM
ldi r16,high(RAMEND)
out SPH,r16
ldi r16,low(RAMEND)
out SPL,r16

;setup sram io lines
ldi r16,$ff
out ddrd,r16 ; set portd as output for address lines
sts ddrh,r16 ; set porth as output for address lines
out porta,r16 ; turn on pullups on porta for data lines
out portc,r16 ; turn on pullups on portc for data lines
ldi r16,$00
out ddra,r16 ; set porta as input for data lines
out ddrc,r16 ; set portc as input for data lines
ldi r16,$0f
out ddrg,r16 ; set portg sram control pins to output
sbi ddrb,ddb7 ; set oe control pin to output
cbi portb,portb7 ; set oe to low - defined again in the spi setup

;setup spi for codec data io
ldi r16,$87
out ddrb,r16 ; set ss,sck,mosi as output,and pb7 as output for oe on sram
ldi r16,$50 ; set spi to master,mode 0
out spcr,r16
ldi r16,$01 ; set spi to 2x (10MHz)
out spsr,r16

;initialize ijmp address for reset vectors
ldi r30,$00
ldi r31,$02

;setup adc
ldi r16,$01
sts didr0,r16 ; turn off input stage for pf0(adc0)
ldi r16,$00
sts admux,r16 ; set adc to sample adc0,external vcc ref,10b result
ldi r16,$e7
sts adcsra,r16 ;  enable adc,start conversion,free running mode,interrupt disabled,ck/128(156khz@20mhz cpu)

;initialize sram address buffers
ldi r25,$00 ; initialize sram write address registers
ldi r24,$00
ldi r29,$00 ; initialize sram read address registers
ldi r28,$80
ldi r23,$04 ; initialize high byte read address register (/we bit set)
ldi r22,$00 ; initialize high byte write address register (/we bit cleared)

;setup switch lines
ldi r16,$7c
sts portj,r16 ; turn on pullups for rotary switch and pushbutton

;codec initialization routines
;check wm8731 datasheet for other settings
;
;setup codec - power and clock registers
ldi r17,$34 ; send address
rcall twisend
ldi r17,$0c ; power down command register
rcall clock_data
ldi r17,$02 ; adc on,line in on,adc on,osc on,power on,clock out,mic off
rcall clock_data

;setup codec - digital interface
ldi r17,$34 ; send address
rcall twisend
ldi r17,$0e ; digital interface command register
rcall clock_data
ldi r17,$03 ; dsp mode,16bit,slave mode,bclk invert disabled,lrswap disabled,data on first edge
rcall clock_data

;setup codec - left analog input
ldi r17,$34 ; send address
rcall twisend
ldi r17,$00 ; left analog interface command register
rcall clock_data
ldi r17,$17 ; mute off, +0db gain, lr load off
rcall clock_data

;setup codec - right analog input
ldi r17,$34 ; send address
rcall twisend
ldi r17,$02 ; right analog interface command register
rcall clock_data
ldi r17,$17 ; mute off, +0db gain, lr load off
rcall clock_data

;setup codec - left headphone output
ldi r17,$34 ; send address
rcall twisend
ldi r17,$04 ; left headphone otput command register
rcall clock_data
ldi r17,$79 ; zero-cross disable, +0db gain, lr load off
rcall clock_data

;setup codec - right headphone output
ldi r17,$34 ; send address
rcall twisend
ldi r17,$06 ; right headphone output command register
rcall clock_data
ldi r17,$79 ; zero-cross disable, +0db gain, lr load off
rcall clock_data

;setup codec - digital audio path
ldi r17,$34 ; send address
rcall twisend
ldi r17,$0a ; digital audio path command register
rcall clock_data
ldi r17,$00 ; highpass filter enabled,de-emphasis disabled,mute disabled,dc offset storage disabled
rcall clock_data

;setup codec - analog audio path
ldi r17,$34 ; send address
rcall twisend
ldi r17,$08 ; analog audio path command register
rcall clock_data
ldi r17,$12 ; disable mic boost,mute mic,line in to adc,disable bypass,select dac,disable sidetone
rcall clock_data

;setup codec - sampling control
ldi r17,$34 ; send address
rcall twisend
ldi r17,$10 ; sampling control command register
rcall clock_data
ldi r17,$a0 ; normal mode,256fs,clk/2 disable,clk/2 out enable
rcall clock_data

;setup codec - activate codec
ldi r17,$34 ; send address
rcall twisend
ldi r17,$12 ; active command register
rcall clock_data
ldi r17,$01 ; active
rcall clock_data

;setup timer0 for interrupt on dataclock
ldi r17,$07
out tccr0a,r17 ; set timer0 to external clock source, normal mode
ldi r17,$00
out tcnt0,r17 ; clear counter
ldi r17,$80
out ocr0a,r17 ; set counter top to 128
ldi r17,$03
sts timsk0,r17 ; set timer to interrupt on compare match and overflow

sei ; turn on interrupts

repeat: ; idle while outside of interrupt

nop
nop
nop
nop
nop
nop
rjmp repeat ; continue to idle

twisend: ; send data over twi (r17=data)
; this is being bit banged as the USI peripheral essentially needs to be
; bit banged anyways.  the stop bit is not sent, as it doesn't seem to be
; neccesary.
;
;setup timer0 for twi operation
ldi r16,$00
out tcnt0,r16 ; clear counter
ldi r16,$20
out ocr0a,r16 ; set counter top to 32 (167kHz data clock frequency)
ldi r16,$01
out tccr0a,r16 ; set timer0 to internal clock (cpu/1 = 20MHz), normal mode
; make sure pullups are off
cbi porte,porte4 ; clock
cbi porte,porte5 ; data
cbi ddre,dde4 ; pull clock high
cbi ddre,dde5 ; pull data high

;initiate start condition
;
wait_start1: ; wait one clock cycle

sbis tifr0,ocf0a
rjmp wait_start1
ldi r16,$00
out tcnt0,r16 ; clear counter
sbi tifr0,ocf0a ; clear interrupt flag
sbi ddre,dde5 ; pull data low

wait_start2: ; wait one clock cycle

sbis tifr0,ocf0a
rjmp wait_start2
sbi ddre,dde4 ; pull clock low
ldi r16,$00
out tcnt0,r16 ; clear counter
sbi tifr0,ocf0a ; clear interrupt flag

wait_start3: ; wait one clock cycle

sbis tifr0,ocf0a
rjmp wait_start3
sbi tifr0,ocf0a ; clear interrupt flag

clock_data: ; clock out data

ldi r18,$08 ; setup data counter for 8 data bits
ldi r16,$00 ; reinitialize counter as data sends start from here
out tcnt0,r16 ; clear counter
ldi r16,$20
out ocr0a,r16 ; set counter top to 32 (167kHz data clock frequency)
ldi r16,$01
out tccr0a,r16 ; set timer0 to internal clock (cpu/1 = 20MHz), normal mode

clock_data1: ; continue clocking bits

lsl r17 ; move bit to be sent to carry register
brcs setbit_data ; check if bit is set
sbi ddre,dde5 ; clear data at output if not
rjmp wait_data1 ; continue with clocking

setbit_data: ; set data at output

cbi ddre,dde5 ; output data if bit is set

wait_data1: ; wait one clock cycle

sbis tifr0,ocf0a
rjmp wait_data1
cbi ddre,dde4 ; pull clock high
ldi r16,$00
out tcnt0,r16 ; clear counter
sbi tifr0,ocf0a ; clear interrupt flag

wait_data2: ; wait one clock cycle

sbis tifr0,ocf0a
rjmp wait_data2
sbi ddre,dde4 ; pull clock low
ldi r16,$00
out tcnt0,r16 ; clear counter
sbi tifr0,ocf0a ; clear interrupt flag

wait_data3: ; wait one clock cycle

sbis tifr0,ocf0a
rjmp wait_data3
ldi r16,$00
out tcnt0,r16 ; clear counter
sbi tifr0,ocf0a ; clear interrupt flag
dec r18 ; check if all bits have been clocked out
brne clock_data1 ; continue if not done
cbi ddre,dde5 ; release data line for ack

;check for ack from codec
;
wait_ack1: ; check for ack

sbic tifr0,ocf0a ; check if timer has expired
rjmp start ; reset micro if no ack within timeout (1.3us)
sbic pine,pine5 ; check for codec pulling the data line low
rjmp wait_ack1

wait_ack2: ; wait remainder of clock cycle

sbis tifr0,ocf0a
rjmp wait_ack2
cbi ddre,dde4 ; pull clock high
ldi r16,$00
out tcnt0,r16 ; clear counter
sbi tifr0,ocf0a ; clear interrupt flag

wait_ack3: ; wait one clock cycle

sbis tifr0,ocf0a
rjmp wait_ack3
sbi ddre,dde4 ; pull clock low
ldi r16,$00
out tcnt0,r16 ; clear counter
sbi tifr0,ocf0a ; clear interrupt flag

wait_ack4: ; wait one clock cycle

sbis tifr0,ocf0a
rjmp wait_ack4
ldi r16,$00
out tcnt0,r16 ; clear counter
sbi tifr0,ocf0a ; clear interrupt flag
ldi r16,$80
out ocr0a,r16 ; set counter top to 128 for ack timeout (6.4us time out)

wait_ack5: ; check for ack complete

sbic tifr0,ocf0a ; check if timer has expired
rjmp start ; reset micro if no ack within timeout (6.4us)
sbis pine,pine5 ; check for codec releasing the data line
rjmp wait_ack5
ldi r16,$00
out tccr0a,r16 ; turn counter0 off
ret

.org $0200 ; program space for switch position 7

.include "pitch_shifter-16b-tonal-fading.asm"


.org $0400 ; program space for switch position 6

.include "up_downsweep-18b-pot.asm"


.org $0600 ; program space for switch position 5

.include "reverser-18b-gated-delay.asm"


.org $0800 ; program space for switch position 4

.include "reverser-16b-pot-fading.asm"


.org $0a00 ; program space for switch position 3

.include "reverser-16b-pot-crossfade.asm"


.org $0c00 ; program space for switch position 2

.include "ping_pong-18b.asm"


.org $0e00 ; program space for switch position 1

.include "delay-18b-pot-mono.asm"


.org $1000 ; program space for switch position 0

.include "delay-16b-pot.asm"


.org $1200 ; program space for switch position 15

.include "reverb-16b.asm"


.org $1400 ; program space for switch position 14

.include "tremolo-stereo.asm"


.org $1600 ; program space for switch position 13

.include "chorus-16b-sine.asm"


.org $1800 ; program space for switch position 12

.include "flanger-16b-sine.asm"


.org $1a00 ; program space for switch position 11

.include "stereo_flanger-16b.asm"


.org $1c00 ; program space for switch position 10

.include "vco.asm"


.org $1e00 ; program space for switch position 9

.include "fullwave-delay-lowpass.asm"


.org $2000 ; program space for switch position 8

.include "sampler-18b-pot.asm"


.org $2400 ; program space for sinewave lookup table
; 512 samples at 16b resolution, halfwave table, signed positive values
; only [$0000 - $7fff].
.include "sinewave-16b-512s.asm"

.org $2600 ; program space for tone lookup table
; tone lookup table for pitch shifter program - up and down one octave
; includes each half step in 12 tone system
.include "tone_chart-16b.asm"
