Audioint4.asm
[Discussion of code elements, needed revision etc, can go here]
.include "m3250Pdef.inc" ; standard definitions include file
; microdec v1.0 - /ss = pb0
; 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 memory address/data bits/channels - function
; ----- ----------- --------------------------------------------
; $0200 = position 07 = 18b/16b/stereo - delay - pot controlled (3ms - 3s)
; $0400 = position 06 = 16b/16b/stereo - delay - pot controlled (0s - .7s)
; $0600 = position 05 = 16b/16b/mono - vco with vca
; $0800 = position 04 = 16b/16b/stereo - upsweep - pot controlled
; $0a00 = position 03 = 16b/16b/stereo - reverser
; $0c00 = position 02 = 16b/16b/stereo - up/down sweep
; $0e00 = position 01 = 16b/16b/stereo - delay - rotary encoder controlled
; $1000 = position 00 = 16b/16b/mono - reverb
; $1200 = position 15 = 16b/16b/mono - fullwave rectifier
; $1400 = position 14 = 16b/16b/mono - gated reverser
; $1600 = position 13 = 16b/16b/mono - envelope stripper as vca on rampwave
; $1800 = position 12 = 16b/16b/mono - ring modulator
; $1a00 = position 11 = 16b/16b/mono - sampler - pot controlled playback speed
; $1c00 = position 10 = 16b/16b/mono - 16 voice chorus
; $1e00 = position 09 = 16b/16b/mono - flanger
; $2000 = position 08 = 16b/16b/mono - sampler - rotary encoder controlled playback speed
; 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,low(RAMEND)
out SPH,r16
ldi r16,high(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 position 7 on rotary encoder
;.include "flanger-16b-variable.asm"
;.include "delay-16b-midi.asm"
.include "pitch_shifter-16b-variable-fading.asm"
;.include "delay-18b-pot.asm" ; place delay program here
.org $0400 ; program space for switch position 6
;.include "delay-16b-pot.asm" ; place delay program here
.include "pitch_shifter-16b-variable-ducking.asm"
.org $0600 ; program space for switch position 5
;.include "pitch_shifter-16b-rotary.asm"
.include "pll-16b.asm" ; place pll program here
.org $0800 ; program space for switch position 4
;.include "pitch_shifter-16b-variable.asm"
.include "upsweep-16b-pot.asm" ; place upsweep program here
.org $0a00 ; program space for switch position 3
.include "downsweep-16b.asm" ; place downsweep program here
.org $0c00 ; program space for switch position 2
.include "up_downsweep-16b.asm" ; place up_downsweep program here
.org $0e00 ; program space for switch position 1
.include "delay-16b-rotary.asm" ; place delay program here
.org $1000 ; program space for switch position 0
.include "reverb-16b.asm" ; place reverb program here
.org $1200 ; program space for switch position 15
.include "pseudo_convolver-16b.asm"
;.include "fullwave.asm" ; place fullwave rectifier program here
.org $1400 ; program space for switch position 14
.include "gated_reverser-16b.asm" ; place gated reverser program here
.org $1600 ; program space for switch position 13
.include "envelope_stripper.asm" ; place envelope stripper program here
.org $1800 ; program space for switch position 12
.include "ring_modulator.asm" ; place ring modulator program here
.org $1a00 ; program space for switch position 11
.include "sampler-pot.asm" ; place sampler program here
.org $1c00 ; program space for switch position 10
.include "chorus-16b.asm" ; place chorus program here
.org $1e00 ; program space for switch position 9
.include "flanger-16b.asm" ; place flanger program here
.org $2000 ; program space for switch position 8
.include "sampler-rotary.asm" ; place sampler program here
.org $2200 ; program space for sinewave table
; 256 sample, 8b, half sine table, only positive values [$00 - $7f]
; should update to 16b table, as this sounds pretty bad
.include "sinewave-8b-256s.asm"
.org $2400 ; program space for sinewave lookup table
; 256 samples at 16b resolution, halfwave table, signed positive values
; only [$0000 - $7fff].
.include "sinewave-16b-256s.asm"
Last edited 2010-06-17 by DanielMcAnulty · 12 revisions