welcome: please sign in
location: attachment:chorus_sine.asm of Chorus

Attachment 'chorus_sine.asm'

Download

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

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.