welcome: please sign in
location: MicrodecAsm

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 

MICrODEC

Microdec Software

MicrodecAsm (last edited 2010-08-21 01:47:08 by guest)