welcome: please sign in
location: attachment:flanger_sine.asm of Flanger

Attachment 'flanger_sine.asm'

Download

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

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.