← Revision 2 as of 2010-08-13 07:56:01
Revision 3 as of 2010-08-21 02:05:32
|Deletions are marked like this.||Additions are marked like this.|
|Line 1:||Line 1:|
=== MICrODEC: Stock Functions ===
MICrODEC: Stock Functions
3s Stereo Ping-Pong Delay
This program performs a ping-pong delay routine. It stores the incoming data from the codec, and plays back a delayed sample, but reverses the orientation of the channels on playback. In this way, the audio coming in on the left channel comes out on the right after a delay. With a bit of feedback, the signals chase each other from left to right. The input data is stereo, and is taken from the left and right channels. The output is also stereo, and is presented on both the left and right channels.
The pot (MOD1) controls the delay time. It goes from 3ms to 3s. MOD2 does nothing for this program. Most analog delay pedals change the rate at which data is being clocked in and out, to change the delay time. This gives a smooth change in audio when the delay is varied, although it also changes the frequency resolution of the signal. To change the delay time in the MICrODEC, the easiest way is to just jump to the new delay time, although this gives an audible pop as the data abruptly switches. In this program, we increment the delay time (or decrement it) at a rate of one sample per sample, until it matches what you want it to be. This gives the effect of frequency doubling (or reversing) during delay transitions, which can be interesting sonically.
1 ; program: ping_pong-18b-pot.asm 2 ; UID = 000030 - unique id to eliminate conflicts between variables 3 ; 18b address space (3s delay time) 4 ; stereo data - left and right swap to create ping-pong effect 5 ; pot (MOD1) controlled delay time (3ms - 3s) 6 7 ; program overview 8 ; 9 ; data is read in from memory and written out the codec at the same time 10 ; new data is written to the memory from the codec. ADC0 (MOD1) is read 11 ; and averaged over 256 samples to reduce jitter. this value is subtracted 12 ; from the write address to create the desired read address. if the actual 13 ; read address doesnt match the desired read address, it is either 14 ; incremented or decremented by one sample each sample period until it 15 ; matches. this reduces noise during delay time transitions. the left 16 ; channel input is recorded to the right channel output buffer (and vice 17 ; versa), so the sound bounces back and forth between the two channels. 18 19 ; register usage - may be redefined in other sections 20 ; 21 ; r0 deisred delay time fractional byte 22 ; r1 23 ; r2 left lsb out 24 ; r3 left msb out 25 ; r4 right lsb out 26 ; r5 right msb out 27 ; r6 left lsb in 28 ; r7 left msb in 29 ; r8 right lsb in 30 ; r9 right msb in 31 ; r10 adc accumulator lsb 32 ; r11 adc accumulator msb 33 ; r12 actual delay lsb 34 ; r13 actual delay msb 35 ; r14 adc sample counter 36 ; r15 switch sample counter 37 ; r16 temporary swap register 38 ; r17 temporary swap register 39 ; r18 null register 40 ; r19 adc accumulator fractional byte 41 ; r20 temporary swap register 42 ; r21 actual delay fractional byte 43 ; r22 write address third byte 44 ; r23 read address third byte 45 ; r24 write address lsb 46 ; r25 write address msb 47 ; r26 desired delay lsb 48 ; r27 desired delay msb 49 ; r28 read address lsb 50 ; r29 read address msb 51 ; r30 jump location for interrupt lsb 52 ; r31 jump location for interrupt msb 53 ; t 54 55 ;program starts here first time 56 ldi r30,$25 ; set jump location to program start 57 clr r24 ; clear write register 58 clr r25 59 ldi r22,$00 ; setup write address high byte 60 clr r18 ; setup r18 as null register for carry addition and ddr setting 61 ldi r17,$ff ; setup r17 for ddr setting 62 63 clear_000030: ; clear delay buffer 64 ; eliminates static when first switching to the delay setting 65 66 adiw r25:r24,$01 ; increment write register 67 adc r22,r18 ; increment write third byte 68 cpi r22,$04 ; check if full memory space has been cleared 69 breq cleardone_000030 ; continue until end of buffer reached 70 out portd,r24 ; set address 71 sts porth,r25 72 out portg,r22 ; pull ce low,we low,and set high bits of address 73 out ddra,r17 ; set porta as output for data write 74 out ddrc,r17 ; set portc as output for data write 75 out porta,r18 ; set data 76 out portc,r18 ; r18 is cleared above 77 sbi portg,portg2 ; pull we high to write 78 out ddra,r18 ; set porta as input for data lines 79 out ddrc,r18 ; set portc as input for data lines 80 rjmp clear_000030 ; continue clearing 81 82 cleardone_000030: ; reset registers 83 84 clr r24 ; clear write register 85 clr r25 86 ldi r22,$00 ; setup write address high byte 87 clr r28 ; set read address to minimum delay 88 ldi r29,$ff 89 ldi r23,$07 ; setup read address high byte 90 clr r21 ; set actual delay time to minimum delay 91 ldi r16,$01 92 mov r12,r16 93 clr r13 94 clr r2 ; initialize data output registers 95 clr r3 96 clr r4 97 clr r5 98 reti ; finish with initialization and wait for next interrupt 99 100 ; program starts here every time but first 101 ; initiate data transfer to codec 102 sbi portb,portb0 ; toggle slave select pin 103 out spdr,r3 ; send out left channel msb 104 cbi portb,portb0 105 106 ;increment sram addresses 107 adiw r25:r24,$01 ; increment write address 108 adc r22,r18 ; increment write third byte 109 andi r22,$03 ; mask off unsed bits 110 adiw r29:r28,$01 ; increment read address 111 adc r23,r18 ; increment read third byte 112 andi r23,$03 ; mask off unsed bits 113 ori r23,$04 ; set we bit for reading 114 115 wait1_000030: ; check if byte has been sent 116 117 in r17,spsr 118 sbrs r17,spif 119 rjmp wait1_000030 120 in r7,spdr ; recieve in left channel msb 121 out spdr,r2 ; send out left channel lsb 122 123 ;get left channel data from sram 124 out portg,r23 ; pull ce low, we high, and set high bits of register 125 out portd,r28 ; set address 126 sts porth,r29 127 adiw r29:r28,$01 ; increment read address 128 adc r23,r18 ; placed here to use setup time efficiently 129 andi r23,$03 ; mask off unsed bits 130 ori r23,$04 ; set we bit for reading 131 in r2,pina ; get data 132 in r3,pinc ; get data 133 134 wait2_000030: ; check if byte has been sent 135 136 in r17,spsr 137 sbrs r17,spif 138 rjmp wait2_000030 139 in r6,spdr ; recieve in left channel lsb 140 out spdr,r5 ; send out right channel msb 141 142 ;write left channel data to sram 143 out portd,r24 ; set address 144 sts porth,r25 145 out portg,r22 ; pull ce low,we low,and set high bits of address 146 ldi r17,$ff 147 out ddra,r17 ; set porta as output for data write 148 out ddrc,r17 ; set portc as output for data write 149 out porta,r6 ; set data 150 out portc,r7 151 sbi portg,portg2 ; pull we high to write 152 out ddra,r18 ; set porta as input for data lines 153 out ddrc,r18 ; set portc as input for data lines 154 155 wait3_000030: ; check if byte has been sent 156 157 in r17,spsr 158 sbrs r17,spif 159 rjmp wait3_000030 160 in r9,spdr ; recieve in right channel msb 161 out spdr,r4 ; send out right channel lsb 162 163 ;get right channel data from sram 164 out portg,r23 ; pull ce low,we high,oe low, and set high bits of address 165 out portd,r28 ; set address 166 sts porth,r29 167 adiw r25:r24,$01 ; increment write address 168 adc r22,r18 ; placed here for efficient use of setup time 169 andi r22,$03 ; mask off unsed bits 170 in r4,pina ; get data 171 in r5,pinc ; get data 172 173 wait4_000030: ; check if byte has been sent 174 175 in r17,spsr 176 sbrs r17,spif 177 rjmp wait4_000030 178 in r8,spdr ; recieve in left channel lsb 179 180 ;write right channel data to sram 181 out portd,r24 ; set address 182 sts porth,r25 183 out portg,r22 ; pull ce low,we low,and set high bits of address 184 ldi r17,$ff 185 out ddra,r17 ; set porta as output for data write 186 out ddrc,r17 ; set portc as output for data write 187 out porta,r8 ; set data 188 out portc,r9 189 sbi portg,portg2 ; pull we high to write 190 out ddra,r18 ; set porta as input for data lines 191 out ddrc,r18 ; set portc as input for data lines 192 193 ; get delay settings 194 lds r17,adcsra ; get adc control register 195 sbrs r17,adif ; check if adc conversion is complete 196 rjmp shift_000030 ; skip adc sampling 197 lds r16,adcl ; get low byte adc value 198 lds r17,adch ; get high byte adc value 199 add r19,r16 ; accumulate adc samples 200 adc r10,r17 201 adc r11,r18 ; r18 is cleared above 202 ldi r17,$f7 203 sts adcsra,r17 ; clear interrupt flag 204 dec r14 ; countdown adc sample clock 205 brne shift_000030 ; get delay time if its been long enough 206 ldi r17,$01 ; check if adc value is less than $000100 207 cp r19,r18 ; r18 is cleared above 208 cpc r10,r17 209 cpc r11,r18 210 brsh deadband_000030 ; check if adc value changed enough to update delay 211 inc r10 ; set minimum delay to $000100 = 3ms 212 clr r19 213 214 deadband_000030: ; check for change in adc value 215 216 movw r17:r16,r11:r10 ; move adc sample to temporary register 217 mov r20,r19 218 sub r20,r0 ; find difference between adc sample and desired delay time 219 sbc r16,r26 220 sbc r17,r27 221 brsh check_000030 ; check for deadband if positive 222 com r20 ; invert if negative 223 com r16 ; using ones complement as it is faster, and only has 1 bit error 224 com r17 225 226 check_000030: ; check if difference is greater than deadband 227 228 cpi r16,$01 ; check if difference is less than 1 lsb 229 cpc r17,r18 ; r18 cleared above 230 brlo empty_000030 ; do nothing if less than 1 lsb 231 movw r27:r26,r11:r10 ; move adc sample to delay time if large enough change 232 andi r19,$fc ; make sure delay time is a multiple of 4 233 mov r0,r19 234 235 empty_000030: ; empty accumulation registers and finish off 236 237 clr r10 ; empty accumulation registers 238 clr r11 239 clr r19 240 241 shift_000030: ; check if delay time is correct 242 243 cp r0,r21 ; compare desired delay to actual delay 244 cpc r26,r12 245 cpc r27,r13 246 breq switchsample_000030 ; do nothing if the same 247 brlo indexdown_000030 248 ldi r17,$04 ; increment delay register 249 add r21,r17 250 adc r12,r18 ; r18 is cleared above 251 adc r13,r18 252 ldi r17,$03 253 and r13,r17 ; mask off unused bits 254 rjmp switchsample_000030 255 256 indexdown_000030: 257 258 subi r21,$02 ; decrement delay register 259 sbc r12,r18 ; r18 is cleared above 260 sbc r13,r18 261 ldi r17,$03 262 and r13,r17 ; mask off unused bits 263 264 switchsample_000030: ; check state of rotary switch 265 266 dec r15 267 brne done_000030 268 lds r16,pinj ; get switch data 269 andi r16,$78 ; mask off rotary switch 270 lsr r16 ; adjust switch position to program memory location 271 lsr r16 272 ldi r17,$02 273 add r16,r17 ; move to jump register 274 cp r16,r31 ; check if location has changed 275 breq done_000030 ; finish off if no change 276 clr r30 ; reset jump register to intial state 277 mov r31,r16 278 279 done_000030: 280 281 movw r29:r28,r25:r24 ; move write address to read destination register 282 mov r23,r22 ; move write third byte to read third byte 283 sub r28,r21 ; subtract delay time 284 sbc r29,r12 285 sbc r23,r13 286 andi r23,$03 ; mask off unsed bits 287 ori r23,$04 ; set we bit for reading 288 movw r17:r16,r3:r2 ; swap left and right channels 289 movw r3:r2,r5:r4 290 movw r5:r4,r17:r16 291 reti 292