MICrODEC
Main File
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, microdec1.asm, along with an AVRStudio project file, microdec1.aps, if you're into that sort of thing.
1 .include "m3250Pdef.inc" ; standard definitions include file
2
3 ;microdec v1.0
4
5 ;fuse settings
6 ;
7 ; start up time set to 258CK + 65ms
8 ; set to 20MHz by external crystal
9 ; BOD set at 4.3V
10 ; RSTDISBL not set
11 ; OCDEN not set
12 ; JTAG enabled
13 ; SPI enabled
14 ; EESAVE not set
15 ; CKOUT not set
16 ; CKDIV8 not set
17 ; WDT not set
18
19 ;hardware connections
20 ;
21 ; portA0:7 = D0 - D7 for sram
22 ; portB0:4 = SPI to codec and ISP
23 ; portB5:6 = NC (XP3)
24 ; portB7 = OE for sram
25 ; portC0:7 = D8 - D15 for sram
26 ; portD0:7 = A0 - A7 for sram
27 ; portE0:1 = USART (CEREAL)
28 ; portE2:3 = NC (XP1)
29 ; portE4:5 = I2C to codec with external pullups
30 ; (could be any pins as USI is pointless)
31 ; portE6:7 = NC (XP2)
32 ; portF0 = ADC0 for potentiometer input (MOD1)
33 ; portF1:3 = NC (ADC1:3)
34 ; portF4:7 = JTAG
35 ; portG0:1 = A16 - A17 for sram
36 ; portG2 = WE for sram
37 ; portG3 = CE for sram
38 ; portG4 = CLKin from codec to T0 for interrupt timing
39 ; portG5 = RESET to JTAG/ISP
40 ; portH0:7 = A8 - A15 for sram
41 ; portJ0:1 = rotary encoder (b0,b1) with external pullups
42 ; portJ2 = rotary encoder pushbutton
43 ; portJ3:6 = rotary switch (b0 - b3)
44 ; AREF = externally connected to AVcc = +5V
45 ; XTAL1:2 = 20MHz crystal
46 ; VCC = DVcc = +5V
47 ; AVCC = AVcc = +5V
48
49 ;program structure overview
50 ;
51 ; Data is transferred to the codec via SPI, using the codec's DSP mode.
52 ; The codec's master clock is divided by two within the codec, and then
53 ; sent to the microcontroller where it is divided by 128 with T0. This
54 ; causes an interrupt at 44.1kHz for data transfers to the codec. In
55 ; order to eliminate audio glitches, this transfer must happen at the
56 ; same time, every time. For this reason, all code is run within this
57 ; interrupt, and no other interrupts are used. This way there can never
58 ; be a delay in the transfer of data. The exact piece of code that is
59 ; run is determined by the rotary switch, which must be checked within
60 ; the interrupt periodically to determine which code should be currently
61 ; running. The program executes the correct code by jumping to the
62 ; program space defined by the rotary switch setting (ijmp command).
63 ; This jump location has to be loaded into r31:r30 before returning from
64 ; the interrupt, or the program may crash. Because of the timing
65 ; limitations, only 20MHz/44.1kHz = 453 clock cycles can occur per
66 ; interrupt, of which approximatley 60 are taken up with SPI communication
67 ; and interrupt handling. A buffered data method could be used if
68 ; the program does not perform the same operations each sample period,
69 ; but the current method is used because of its simplicity. If you want
70 ; to change a function, merely swap out the code at that .org location.
71
72 ;current programs and their memory locations
73 ;
74 ; code switch function
75 ; ----- ----------- --------------------------------------------
76 ; $0200 = position 07 = pitch_shifter-16b-tonal-fading.asm
77 ; $0400 = position 06 = up_downsweep-18b-pot.asm
78 ; $0600 = position 05 = reverser-18b-gated-delay.asm
79 ; $0800 = position 04 = reverser-16b-pot-fading.asm
80 ; $0a00 = position 03 = reverser-16b-pot-crossfade.asm
81 ; $0c00 = position 02 = ping_pong-18b.asm
82 ; $0e00 = position 01 = delay-18b-pot-mono.asm
83 ; $1000 = position 00 = delay-16b-pot.asm
84 ; $1200 = position 15 = reverb-16b.asm
85 ; $1400 = position 14 = tremolo-stereo.asm
86 ; $1600 = position 13 = chorus-16b-sine.asm
87 ; $1800 = position 12 = flanger-16b-sine.asm
88 ; $1a00 = position 11 = stereo_flanger-16b.asm
89 ; $1c00 = position 10 = vco.asm
90 ; $1e00 = position 09 = fullwave-delay-lowpass.asm
91 ; $2000 = position 08 = sampler-18b-pot.asm
92
93 ;interrupt vectors
94 ;
95 .org 0 ; reset interrupt
96 rjmp start ; initialize microcontroller registers
97 .org OC0addr ; T0 compare interrupt - set to $80
98 ijmp ; send data to codec every 128 cycles of codec clock
99 .org OVF0addr ; T0 overflow interrupt
100 ijmp ; send data to codec every 128 cycles of codec clock
101
102 ;register usage - may be redefined in other sections
103 ; for conistency between programs, these registers(*) are normally used
104 ; as shown
105 ;
106 ; r0 multiply result lsb(*)
107 ; r1 multiply result msb(*)
108 ; r2 left data out lsb(*)
109 ; r3 left data out msb(*)
110 ; r4 right data out lsb(*)
111 ; r5 right data out msb(*)
112 ; r6 left data in lsb(*)
113 ; r7 left data in msb(*)
114 ; r8 right data in lsb(*)
115 ; r9 right data in msb(*)
116 ; r10
117 ; r11
118 ; r12
119 ; r13
120 ; r14
121 ; r15
122 ; r16 temporary swap register(*)
123 ; r17 temporary swap register(*)
124 ; r18 twi (i2c) counter register
125 ; r19
126 ; r20
127 ; r21
128 ; r22 write address third byte(*)
129 ; r23 read address third byte(*)
130 ; r24 write address lsb(*)
131 ; r25 write address msb(*)
132 ; r26
133 ; r27
134 ; r28 read address lsb(*)
135 ; r29 read address msb(*)
136 ; r30 jump location for interrupts lsb(*)
137 ; r31 jump location for interrupts msb(*)
138
139 start: ; configure microcontroller registers
140
141 ;set stack pointer to top of SRAM
142 ldi r16,high(RAMEND)
143 out SPH,r16
144 ldi r16,low(RAMEND)
145 out SPL,r16
146
147 ;setup sram io lines
148 ldi r16,$ff
149 out ddrd,r16 ; set portd as output for address lines
150 sts ddrh,r16 ; set porth as output for address lines
151 out porta,r16 ; turn on pullups on porta for data lines
152 out portc,r16 ; turn on pullups on portc for data lines
153 ldi r16,$00
154 out ddra,r16 ; set porta as input for data lines
155 out ddrc,r16 ; set portc as input for data lines
156 ldi r16,$0f
157 out ddrg,r16 ; set portg sram control pins to output
158 sbi ddrb,ddb7 ; set oe control pin to output
159 cbi portb,portb7 ; set oe to low - defined again in the spi setup
160
161 ;setup spi for codec data io
162 ldi r16,$87
163 out ddrb,r16 ; set ss,sck,mosi as output,and pb7 as output for oe on sram
164 ldi r16,$50 ; set spi to master,mode 0
165 out spcr,r16
166 ldi r16,$01 ; set spi to 2x (10MHz)
167 out spsr,r16
168
169 ;initialize ijmp address for reset vectors
170 ldi r30,$00
171 ldi r31,$02
172
173 ;setup adc
174 ldi r16,$01
175 sts didr0,r16 ; turn off input stage for pf0(adc0)
176 ldi r16,$00
177 sts admux,r16 ; set adc to sample adc0,external vcc ref,10b result
178 ldi r16,$e7
179 sts adcsra,r16 ; enable adc,start conversion,free running mode,
180 ; interrupt disabled,ck/128(156khz@20mhz cpu)
181
182 ;initialize sram address buffers
183 ldi r25,$00 ; initialize sram write address registers
184 ldi r24,$00
185 ldi r29,$00 ; initialize sram read address registers
186 ldi r28,$80
187 ldi r23,$04 ; initialize high byte read address register (/we bit set)
188 ldi r22,$00 ; initialize high byte write address register (/we bit cleared)
189
190 ;setup switch lines
191 ldi r16,$7c
192 sts portj,r16 ; turn on pullups for rotary switch and pushbutton
193
194 ;codec initialization routines
195 ;check wm8731 datasheet for other settings
196 ;
197 ;setup codec - power and clock registers
198 ldi r17,$34 ; send address
199 rcall twisend
200 ldi r17,$0c ; power down command register
201 rcall clock_data
202 ldi r17,$02 ; adc on,line in on,adc on,osc on,power on,clock out,mic off
203 rcall clock_data
204
205 ;setup codec - digital interface
206 ldi r17,$34 ; send address
207 rcall twisend
208 ldi r17,$0e ; digital interface command register
209 rcall clock_data
210 ldi r17,$03 ; dsp mode,16bit,slave mode,bclk invert disabled,
211 ; lrswap disabled,data on first edge
212 rcall clock_data
213
214 ;setup codec - left analog input
215 ldi r17,$34 ; send address
216 rcall twisend
217 ldi r17,$00 ; left analog interface command register
218 rcall clock_data
219 ldi r17,$17 ; mute off, +0db gain, lr load off
220 rcall clock_data
221
222 ;setup codec - right analog input
223 ldi r17,$34 ; send address
224 rcall twisend
225 ldi r17,$02 ; right analog interface command register
226 rcall clock_data
227 ldi r17,$17 ; mute off, +0db gain, lr load off
228 rcall clock_data
229
230 ;setup codec - left headphone output
231 ldi r17,$34 ; send address
232 rcall twisend
233 ldi r17,$04 ; left headphone otput command register
234 rcall clock_data
235 ldi r17,$79 ; zero-cross disable, +0db gain, lr load off
236 rcall clock_data
237
238 ;setup codec - right headphone output
239 ldi r17,$34 ; send address
240 rcall twisend
241 ldi r17,$06 ; right headphone output command register
242 rcall clock_data
243 ldi r17,$79 ; zero-cross disable, +0db gain, lr load off
244 rcall clock_data
245
246 ;setup codec - digital audio path
247 ldi r17,$34 ; send address
248 rcall twisend
249 ldi r17,$0a ; digital audio path command register
250 rcall clock_data
251 ldi r17,$00 ; highpass filter enabled,de-emphasis disabled,
252 ; mute disabled,dc offset storage disabled
253 rcall clock_data
254
255 ;setup codec - analog audio path
256 ldi r17,$34 ; send address
257 rcall twisend
258 ldi r17,$08 ; analog audio path command register
259 rcall clock_data
260 ldi r17,$12 ; disable mic boost,mute mic,line in to adc,
261 ; disable bypass,select dac,disable sidetone
262 rcall clock_data
263
264 ;setup codec - sampling control
265 ldi r17,$34 ; send address
266 rcall twisend
267 ldi r17,$10 ; sampling control command register
268 rcall clock_data
269 ldi r17,$a0 ; normal mode,256fs,clk/2 disable,clk/2 out enable
270 rcall clock_data
271
272 ;setup codec - activate codec
273 ldi r17,$34 ; send address
274 rcall twisend
275 ldi r17,$12 ; active command register
276 rcall clock_data
277 ldi r17,$01 ; active
278 rcall clock_data
279
280 ;setup timer0 for interrupt on dataclock
281 ldi r17,$07
282 out tccr0a,r17 ; set timer0 to external clock source, normal mode
283 ldi r17,$00
284 out tcnt0,r17 ; clear counter
285 ldi r17,$80
286 out ocr0a,r17 ; set counter top to 128
287 ldi r17,$03
288 sts timsk0,r17 ; set timer to interrupt on compare match and overflow
289
290 sei ; turn on interrupts
291
292 repeat: ; idle while outside of interrupt
293
294 nop
295 nop
296 nop
297 nop
298 nop
299 nop
300 rjmp repeat ; continue to idle
301
302 twisend: ; send data over twi (r17=data)
303 ; this is being bit banged as the USI peripheral essentially needs to be
304 ; bit banged anyways. the stop bit is not sent, as it doesn't seem to be
305 ; neccesary.
306 ;
307 ;setup timer0 for twi operation
308 ldi r16,$00
309 out tcnt0,r16 ; clear counter
310 ldi r16,$20
311 out ocr0a,r16 ; set counter top to 32 (167kHz data clock frequency)
312 ldi r16,$01
313 out tccr0a,r16 ; set timer0 to internal clock (cpu/1 = 20MHz), normal mode
314 ; make sure pullups are off
315 cbi porte,porte4 ; clock
316 cbi porte,porte5 ; data
317 cbi ddre,dde4 ; pull clock high
318 cbi ddre,dde5 ; pull data high
319
320 ;initiate start condition
321 ;
322 wait_start1: ; wait one clock cycle
323
324 sbis tifr0,ocf0a
325 rjmp wait_start1
326 ldi r16,$00
327 out tcnt0,r16 ; clear counter
328 sbi tifr0,ocf0a ; clear interrupt flag
329 sbi ddre,dde5 ; pull data low
330
331 wait_start2: ; wait one clock cycle
332
333 sbis tifr0,ocf0a
334 rjmp wait_start2
335 sbi ddre,dde4 ; pull clock low
336 ldi r16,$00
337 out tcnt0,r16 ; clear counter
338 sbi tifr0,ocf0a ; clear interrupt flag
339
340 wait_start3: ; wait one clock cycle
341
342 sbis tifr0,ocf0a
343 rjmp wait_start3
344 sbi tifr0,ocf0a ; clear interrupt flag
345
346 clock_data: ; clock out data
347
348 ldi r18,$08 ; setup data counter for 8 data bits
349 ldi r16,$00 ; reinitialize counter as data sends start from here
350 out tcnt0,r16 ; clear counter
351 ldi r16,$20
352 out ocr0a,r16 ; set counter top to 32 (167kHz data clock frequency)
353 ldi r16,$01
354 out tccr0a,r16 ; set timer0 to internal clock (cpu/1 = 20MHz), normal mode
355
356 clock_data1: ; continue clocking bits
357
358 lsl r17 ; move bit to be sent to carry register
359 brcs setbit_data ; check if bit is set
360 sbi ddre,dde5 ; clear data at output if not
361 rjmp wait_data1 ; continue with clocking
362
363 setbit_data: ; set data at output
364
365 cbi ddre,dde5 ; output data if bit is set
366
367 wait_data1: ; wait one clock cycle
368
369 sbis tifr0,ocf0a
370 rjmp wait_data1
371 cbi ddre,dde4 ; pull clock high
372 ldi r16,$00
373 out tcnt0,r16 ; clear counter
374 sbi tifr0,ocf0a ; clear interrupt flag
375
376 wait_data2: ; wait one clock cycle
377
378 sbis tifr0,ocf0a
379 rjmp wait_data2
380 sbi ddre,dde4 ; pull clock low
381 ldi r16,$00
382 out tcnt0,r16 ; clear counter
383 sbi tifr0,ocf0a ; clear interrupt flag
384
385 wait_data3: ; wait one clock cycle
386
387 sbis tifr0,ocf0a
388 rjmp wait_data3
389 ldi r16,$00
390 out tcnt0,r16 ; clear counter
391 sbi tifr0,ocf0a ; clear interrupt flag
392 dec r18 ; check if all bits have been clocked out
393 brne clock_data1 ; continue if not done
394 cbi ddre,dde5 ; release data line for ack
395
396 ;check for ack from codec
397 ;
398 wait_ack1: ; check for ack
399
400 sbic tifr0,ocf0a ; check if timer has expired
401 rjmp start ; reset micro if no ack within timeout (1.3us)
402 sbic pine,pine5 ; check for codec pulling the data line low
403 rjmp wait_ack1
404
405 wait_ack2: ; wait remainder of clock cycle
406
407 sbis tifr0,ocf0a
408 rjmp wait_ack2
409 cbi ddre,dde4 ; pull clock high
410 ldi r16,$00
411 out tcnt0,r16 ; clear counter
412 sbi tifr0,ocf0a ; clear interrupt flag
413
414 wait_ack3: ; wait one clock cycle
415
416 sbis tifr0,ocf0a
417 rjmp wait_ack3
418 sbi ddre,dde4 ; pull clock low
419 ldi r16,$00
420 out tcnt0,r16 ; clear counter
421 sbi tifr0,ocf0a ; clear interrupt flag
422
423 wait_ack4: ; wait one clock cycle
424
425 sbis tifr0,ocf0a
426 rjmp wait_ack4
427 ldi r16,$00
428 out tcnt0,r16 ; clear counter
429 sbi tifr0,ocf0a ; clear interrupt flag
430 ldi r16,$80
431 out ocr0a,r16 ; set counter top to 128 for ack timeout (6.4us time out)
432
433 wait_ack5: ; check for ack complete
434
435 sbic tifr0,ocf0a ; check if timer has expired
436 rjmp start ; reset micro if no ack within timeout (6.4us)
437 sbis pine,pine5 ; check for codec releasing the data line
438 rjmp wait_ack5
439 ldi r16,$00
440 out tccr0a,r16 ; turn counter0 off
441 ret
442
443 .org $0200 ; program space for switch position 7
444
445 .include "pitch_shifter-16b-tonal-fading.asm"
446
447
448 .org $0400 ; program space for switch position 6
449
450 .include "up_downsweep-18b-pot.asm"
451
452
453 .org $0600 ; program space for switch position 5
454
455 .include "reverser-18b-gated-delay.asm"
456
457
458 .org $0800 ; program space for switch position 4
459
460 .include "reverser-16b-pot-fading.asm"
461
462
463 .org $0a00 ; program space for switch position 3
464
465 .include "reverser-16b-pot-crossfade.asm"
466
467
468 .org $0c00 ; program space for switch position 2
469
470 .include "ping_pong-18b.asm"
471
472
473 .org $0e00 ; program space for switch position 1
474
475 .include "delay-18b-pot-mono.asm"
476
477
478 .org $1000 ; program space for switch position 0
479
480 .include "delay-16b-pot.asm"
481
482
483 .org $1200 ; program space for switch position 15
484
485 .include "reverb-16b.asm"
486
487
488 .org $1400 ; program space for switch position 14
489
490 .include "tremolo-stereo.asm"
491
492
493 .org $1600 ; program space for switch position 13
494
495 .include "chorus-16b-sine.asm"
496
497
498 .org $1800 ; program space for switch position 12
499
500 .include "flanger-16b-sine.asm"
501
502
503 .org $1a00 ; program space for switch position 11
504
505 .include "stereo_flanger-16b.asm"
506
507
508 .org $1c00 ; program space for switch position 10
509
510 .include "vco.asm"
511
512
513 .org $1e00 ; program space for switch position 9
514
515 .include "fullwave-delay-lowpass.asm"
516
517
518 .org $2000 ; program space for switch position 8
519
520 .include "sampler-18b-pot.asm"
521
522
523 .org $2400 ; program space for sinewave lookup table
524 ; 512 samples at 16b resolution, halfwave table, signed positive values
525 ; only [$0000 - $7fff].
526 .include "sinewave-16b-512s.asm"
527
528 .org $2600 ; program space for tone lookup table
529 ; tone lookup table for pitch shifter program - up and down one octave
530 ; includes each half step in 12 tone system
531 .include "tone_chart-16b.asm"
532