==== microdec1.asm ==== The program functionality is described at the beginning of the code below. Basically, this program initializes the codec, initializes a counter to interrupt for the 44.1kHz sample rate (externally driven by the codec), and defines jump locations for the various functions which can be loaded. To change what your MICrODEC does, simply drop in a different function file at the location of your choice. The current file can be downloaded here, [[attachment:microdec1.asm|microdec1.asm]], along with an AVRStudio project file, [[attachment:microdec1.aps|microdec1.aps]], if you're into that sort of thing. {{{#!highlight nasm .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" }}} [[MICrODEC]] [[MicrodecSoftware|Microdec Software]]