welcome: please sign in
location: attachment:flanger_stereo_pan.asm of StereoFlangerPan

Attachment 'flanger_stereo_pan.asm'

Download

   1 ; program: stereo_flanger-16b.asm
   2 ; UID = 000053 - unique id to eliminate conflicts between variables
   3 ; 16b address space
   4 ; mono data in on left channel, stereo data out (opposite phasing)
   5 ; pot (MOD1) controls lfo frequency
   6 ; rotary encoder (MOD2) controls lfo depth
   7 
   8 ; program overview
   9 ;
  10 ; data is read in from the codec and stored to sram.  data is read out of
  11 ; sram at a variable delay set by an lfo.  the lfo is generated from a
  12 ; 16b/512s half sinewave lookup table.  this is incremented with a 24b
  13 ; number to get very low frequencies.  the lfo rate is set via the adc,
  14 ; which is oversampled 256 times and deadbanded to get rid of glitches.
  15 ; the lfo depth is created by multiplying the lfo signal with an 8b depth
  16 ; value, which is set via the rotary encoder.
  17 
  18 ; register usage - may be redefined in other sections
  19 ;
  20 ; r0  multiply result lsb
  21 ; r1  multiply result msb
  22 ; r2  accumulation lsb
  23 ; r3  accumulation mlb
  24 ; r4  left lsb out / accumulation mhb
  25 ; r5  left msb out / accumulation msb
  26 ; r6  right out lsb
  27 ; r7  right out msb
  28 ; r8  adc accumulator fractional byte
  29 ; r9  adc accumulator lsb
  30 ; r10 adc accumulator msb
  31 ; r11 rotary encoder counter
  32 ; r12 lfo rate lsb
  33 ; r13 lfo rate msb
  34 ; r14 null register
  35 ; r15 switch sample counter
  36 ; r16 temporary swap register
  37 ; r17 temporary swap register
  38 ; r18 sine wave buffer/multiply msb
  39 ; r19 sine wave buffer/multiply msb
  40 ; r20 multiply swap register
  41 ; r21 multiply swap register
  42 ; r22 sinetable lookup address lsb
  43 ; r23 sinetable lookup address mlb
  44 ; r24 write address lsb
  45 ; r25 write address msb
  46 ; r26 sinetable lookup address mhb
  47 ; r27 sinetable lookup address msb
  48 ; r28 temporary swap register
  49 ; r29 lfo depth
  50 ; r30 jump location for interrupt lsb
  51 ; r31 jump location for interrupt msb
  52 ; t   rotary encoder edge detect indicator
  53 
  54 ; program starts here first time
  55 ; intialize registers
  56 ldi r30,$04 ; increment z pointer to new jump location
  57 clr r14 ; clear null register
  58 ldi r29,$0d ; intiialize lfo depth
  59 reti ; finish with initialization and wait for next interrupt
  60 
  61 ; program starts here every time but first
  62 ; initiate data transfer to codec
  63 sbi portb,portb0 ; toggle slave select pin
  64 out spdr,r5 ; send out left channel msb
  65 cbi portb,portb0
  66 
  67 adiw r25:r24,$01 ; increment write address
  68 
  69 wait1_000053: ; check if byte has been sent
  70 
  71 in r17,spsr
  72 sbrs r17,spif
  73 rjmp wait1_000053
  74 in r19,spdr ; recieve in left channel msb
  75 out spdr,r4 ; send out left channel lsb
  76 
  77 wait2_000053: ; check if byte has been sent
  78 
  79 in r17,spsr
  80 sbrs r17,spif
  81 rjmp wait2_000053
  82 in r18,spdr ; recieve in left channel lsb
  83 out spdr,r7 ; send out right channel msb
  84 
  85 ;write left channel to sram
  86 out portd,r24 ; set address
  87 sts porth,r25
  88 out portg,r14 ; pull ce low,we low,and set high bits of address
  89 ldi r17,$ff
  90 out ddra,r17 ; set porta as output for data write
  91 out ddrc,r17 ; set portc as output for data write
  92 out porta,r18 ; set data
  93 out portc,r19
  94 sbi portg,portg2 ; pull we high to write
  95 out ddra,r14 ; set porta as input for data lines
  96 out ddrc,r14 ; set portc as input for data lines
  97 
  98 wait3_000053: ; check if byte has been sent
  99 
 100 in r17,spsr
 101 sbrs r17,spif
 102 rjmp wait3_000053
 103 in r17,spdr ; recieve in right channel msb
 104 out spdr,r6 ; send out right channel lsb
 105 
 106 wait4_000053: ; check if byte has been sent
 107 
 108 in r17,spsr
 109 sbrs r17,spif
 110 rjmp wait4_000053
 111 in r17,spdr ; recieve in right channel lsb
 112 
 113 ; vco generation
 114 movw r17:r16,r31:r30 ; store z register
 115 ;get sample 1
 116 add r22,r12 ; increment sinetable address
 117 adc r23,r13
 118 adc r26,r14 ; r14 is cleared above
 119 adc r27,r14
 120 movw r31:r30,r27:r26 ; move to z register for data fetch
 121 lsl r30 ; adjust pointer for 16b fetch
 122 rol r31
 123 andi r31,$03 ; limit value to 10b (512 samples x 2 bytes)
 124 ori r31,$48 ; set to memory address location where table is stored
 125 lpm r18,z+ ; get sine value lsb, increment z register
 126 lpm r19,z ; get sine value msb
 127 sbrc r27,$01 ; flip sign for half of the values
 128 rjmp interpolate_000053
 129 neg r18
 130 adc r19,r14 ; r14 is cleared above
 131 neg r19
 132 
 133 interpolate_000053: ; multiply sample 1 by distance
 134 
 135 movw r21:r20,r23:r22 ; get distance from sample 1
 136 com r20 ; invert distance
 137 com r21
 138 mulsu r19,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 139 movw r5:r4,r1:r0 ; store high bytes result for later
 140 mul	r18,r20	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 141 movw r3:r2,r1:r0 ; store low byets for later
 142 mulsu r19,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 143 sbc	r5,r14 ; r14 is cleared above - subtract sign bit
 144 add	r3,r0 ; accumulate result
 145 adc	r4,r1
 146 adc	r5,r14 ; r14 is cleared above
 147 mul r21,r18 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 148 add	r3,r0 ; accumulate result
 149 adc	r4,r1
 150 adc	r5,r14 ; r14 is cleared above
 151 
 152 ;get sample 2
 153 adiw r27:r26,$01 ; set to next sample
 154 movw r31:r30,r27:r26 ; move to z register for data fetch
 155 lsl r30 ; adjust pointer for 16b fetch
 156 rol r31
 157 andi r31,$03 ; limit value to 10b (512 samples x 2 bytes)
 158 ori r31,$48 ; set to memory address location where table is stored
 159 lpm r18,z+ ; get sine value lsb, increment z register
 160 lpm r19,z ; get sine value msb
 161 sbrc r27,$01 ; flip sign for half of the values
 162 rjmp interpolate1_000053
 163 neg r18
 164 adc r19,r14 ; r14 is cleared above
 165 neg r19
 166 
 167 interpolate1_000053: ; multiply sample 2 by distance
 168 
 169 sbiw r27:r26,$01 ; reset address
 170 movw r31:r30,r17:r16 ; restore z register
 171 mulsu r19,r23 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 172 add r4,r0 ; accumulate result
 173 adc r5,r1
 174 mul	r18,r22	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 175 add r2,r0 ; accumulate result
 176 adc r3,r1
 177 adc r4,r14 ; r14 is cleared above
 178 adc r5,r14
 179 mulsu r19,r22 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 180 sbc	r5,r14 ; r14 is cleared above - subtract sign bit
 181 add	r3,r0 ; accumulate result
 182 adc	r4,r1
 183 adc	r5,r14 ; r14 is cleared above
 184 mul r23,r18 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 185 add	r3,r0 ; accumulate result
 186 adc	r4,r1
 187 adc	r5,r14 ; r14 is cleared above
 188 
 189 ;set lfo depth - 8b value
 190 ldi r16,$80 ; convert lfo to unsigned number
 191 add r5,r16
 192 movw r19:r18,r5:r4 ; move lfo signal to multiply register
 193 mov r21,r29 ; move lfo depth to multiply register
 194 mul r19,r21 ; (unsigned)ah * (unsigned)b
 195 movw r5:r4,r1:r0
 196 mul r21,r18 ; (unsigned)b * (unsigned)al
 197 add	r4,r1
 198 adc	r5,r14 ; r14 is cleared above
 199 mov r28,r5 ; store lfo for later
 200 mov r21,r4
 201 
 202 ;right channel data preperation
 203 ;add lfo to delay
 204 movw r17:r16,r25:r24 ; move current location to read address
 205 sec ; set the carry bit so all values are reduced by 1 lsb for fractional byte
 206 sbc r16,r5 ; remove lfo time
 207 sbc r17,r14 ; r14 is cleared above
 208 
 209 ;get right channel sample 1 from sram
 210 out portd,r16 ; set address
 211 sts porth,r17
 212 nop ; wait setup period of two cycles
 213 nop
 214 in r18,pina ; get data
 215 in r19,pinc ; get data
 216 
 217 ;multiply sample 1 by distance
 218 mov r20,r4 ; get distance from sample 1
 219 mulsu r19,r20 ; (signed)ah * b
 220 movw r5:r4,r1:r0
 221 mul r18,r20 ; al * b
 222 add r4,r1
 223 adc r5,r14 ; r14 is cleared above
 224 mov r3,r0
 225 
 226 ;get right channel sample 2 from sram
 227 subi r16,$ff ; set to next sample
 228 sbci r17,$ff ; done this way because there is no addi or adci
 229 out portd,r16 ; set address
 230 sts porth,r17
 231 nop ; wait setup period of two cycles
 232 nop
 233 in r18,pina ; get data
 234 in r19,pinc ; get data
 235 
 236 ;multiply sample 2 by distance
 237 com r20 ; get distance to sample 2
 238 mulsu r19,r20 ; (signed)ah * b
 239 add r4,r0 ; accumulate result
 240 adc r5,r1
 241 mul r18,r20 ; al * b
 242 add r3,r0 ; accumulate result
 243 add r4,r1
 244 adc r5,r14 ; r14 is cleared above
 245 movw r7:r6,r5:r4 ; move right channel to output register
 246 
 247 ;left channel data preperation
 248 ;add lfo to delay
 249 clr r4 ; get max depth value
 250 mov r5,r29
 251 sub r4,r21 ; subtract lfo to make inverse
 252 sbc r5,r28
 253 movw r17:r16,r25:r24 ; move current location to read address
 254 sec ; set the carry bit so all values are reduced by 1 lsb for fractional byte
 255 sbc r16,r5 ; remove lfo time
 256 sbc r17,r14 ; r14 is cleared above
 257 
 258 ;get left channel sample 1 from sram
 259 out portd,r16 ; set address
 260 sts porth,r17
 261 nop ; wait setup period of two cycles
 262 nop
 263 in r18,pina ; get data
 264 in r19,pinc ; get data
 265 
 266 ;multiply sample 1 by distance
 267 mov r20,r4 ; get distance from sample 1
 268 mulsu r19,r20 ; (signed)ah * b
 269 movw r5:r4,r1:r0
 270 mul r18,r20 ; al * b
 271 add r4,r1
 272 adc r5,r14 ; r14 is cleared above
 273 mov r3,r0
 274 
 275 ;get left channel sample 2 from sram
 276 subi r16,$ff ; set to next sample
 277 sbci r17,$ff ; done this way because there is no addi or adci
 278 out portd,r16 ; set address
 279 sts porth,r17
 280 nop ; wait setup period of two cycles
 281 nop
 282 in r18,pina ; get data
 283 in r19,pinc ; get data
 284 
 285 ;multiply sample 2 by distance
 286 com r20 ; get distance to sample 2
 287 mulsu r19,r20 ; (signed)ah * b
 288 add r4,r0 ; accumulate result
 289 adc r5,r1
 290 mul r18,r20 ; al * b
 291 add r3,r0 ; accumulate result
 292 add r4,r1
 293 adc r5,r14 ; r14 is cleared above
 294 
 295 ;check rotary encoder and adjust lfo depth
 296 ; although rotary encoder is externally debounced, it is done here again.
 297 ; pin1 is sampled on a transition from high to low on pin0.  if pin1 is
 298 ; high, a left turn occured, if pin1 is low, a right turn occured.
 299 dec r11 ; count down sample clock
 300 brne adcsample_000053 ; continue if not
 301 ldi r17,$40 ; adjust sample frequency to catch all rising edges (1.5ms)
 302 mov r11,r17 ; reload sample clock
 303 lds r17,pinj ; get switch data
 304 sbrs r17,$00 ; check if pin0 is low
 305 rjmp edge_000053 ; check if pin0 was low on previous sample
 306 clt ;  clear state register if back high
 307 rjmp adcsample_000053 ; finish off
 308 
 309 edge_000053: ; check for falling edge
 310 
 311 brts adcsample_000053 ; do nothing if edge was already detected
 312 set ; set t register to indicate edge detected
 313 ldi r21,$01 ; prepare for addition or subtraction
 314 sbrs r17,$01 ; check if pin1 is high
 315 rjmp increment_000053 ; increment desired delay if right rotation
 316 sub r29,r21 ; decrement lfo depth register else
 317 brcc adcsample_000053 ; check if underflow
 318 clr r29 ; set depth to min
 319 rjmp adcsample_000053 ; finish off
 320 
 321 increment_000053: ; increment desired delay register
 322 
 323 add r29,r21 ; increment lfo depth register
 324 brcc adcsample_000053 ; check if overflow occured
 325 ser r29 ; set depth to max
 326 
 327 adcsample_000053: ; sample adc for lfo rate
 328 
 329 lds r17,adcsra ; get adc control register
 330 sbrs r17,adif ; check if adc conversion is complete
 331 rjmp done_000053 ; skip adc sampling
 332 lds r16,adcl ; get low byte adc value
 333 lds r17,adch ; get high byte adc value
 334 add r8,r16 ; accumulate adc samples
 335 adc r9,r17
 336 adc r10,r14 ; r14 is cleared above
 337 ldi r17,$f7
 338 sts adcsra,r17 ; clear interrupt flag
 339 dec r15 ; countdown adc sample clock
 340 brne done_000053 ; get delay time if its been long enough
 341 
 342 deadband_000053: ; set the low value of the delay
 343 
 344 lsr r10 ; divide adc value by 16
 345 ror r9
 346 ror r8
 347 lsr r10
 348 ror r9
 349 ror r8
 350 lsr r9 ; r10 now empty
 351 ror r8
 352 lsr r9
 353 ror r8
 354 movw r17:r16,r9:r8 ; move adc sample to temporary register
 355 ldi r21,$80 ; add in offset of min lfo rate ($0080)
 356 add r16,r21
 357 adc r17,r14 ; r14 is cleared above
 358 sub r16,r12 ; find difference between adc sample and current lfo rate
 359 sbc r17,r13
 360 brsh check_000053 ; check for deadband if positive
 361 neg r16 ; invert if negative
 362 adc r17,r14 ; r14 is cleared above
 363 neg r17
 364 
 365 check_000053: ; check if difference is greater than deadband
 366 
 367 cpi r16,$10 ; check if difference is less than 1 adc lsb
 368 cpc r17,r14 ; r14 cleared above
 369 brlo empty_000053 ; do nothing if less than 1 adc lsb
 370 movw r13:r12,r9:r8 ; move adc sample to lfo rate register
 371 add r12,r21 ; add in offset of min lfo rate ($0080)
 372 adc r13,r14 ; r14 is cleared above
 373 
 374 empty_000053: ; empty accumulation registers and finish off
 375 
 376 clr r8 ; empty accumulation registers
 377 clr r9
 378 clr r10
 379 
 380 switchsample_000053: ; check rotary switch
 381 
 382 lds r16,pinj ; get switch data
 383 andi r16,$78 ; mask off rotary switch
 384 lsr r16 ; adjust switch position to program memory location
 385 lsr r16
 386 ldi r17,$02
 387 add r16,r17
 388 cpse r16,r31 ; check if location has changed
 389 clr r30 ; reset jump register to intial state
 390 mov r31,r16
 391 
 392 done_000053:
 393 
 394 reti ; return to waiting
 395 

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.