microdec1.asm [Discussion of code elements, needed revision etc, can go here] {{{#!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]]