welcome: please sign in
location: attachment:reverser_fading.asm of ReverserFading

Attachment 'reverser_fading.asm'

Download

   1 ; program: reverser-16b-pot-fading.asm
   2 ; UID = 000036 - this is a unique id so variables dont conflict
   3 ; 16b address space (1.5s sample time)
   4 ; mono data in on left channel, mono data out on left and right
   5 ; pot (MOD1) controlled buffer size
   6 
   7 ; program overview
   8 ;
   9 ; data is sent out and taken in from the codec.  data is taken in on the
  10 ; left channel, and played out on both left and right.  a buffer of the
  11 ; past n seconds is kept and the output is the result of sampling this
  12 ; buffer in reverse.  this buffer size is determined by the pot (MOD1) value,
  13 ; which is multiplied up to a 16b value.  the buffer size is adjusted at a
  14 ; rate of 2 lsb per sample period, until it matches to what the pot says
  15 ; it should be. two samples are taken and averaged together by the
  16 ; ratio of their distances to the buffer boundary.  they are 180 degrees
  17 ; out of phase, so as one sample is crossing the buffer boundary, it is
  18 ; silent, and the other plays full volume.  this helps reduce the clicks
  19 ; at buffer boundary transitions.  it also creates a reverb sound.
  20 
  21 ; constant definitions
  22 ;
  23 .equ buffer_min_000036 = $0200 ; minimum sample buffer size
  24 
  25 ; register usage - may be redefined in other sections
  26 ;
  27 ; r0  multiply result lsb
  28 ; r1  multiply result msb
  29 ; r2  sample 2 lsb
  30 ; r3  sample 2 msb
  31 ; r4  left/right lsb out / sample 1 lsb
  32 ; r5  left/right msb out / sample 1 msb
  33 ; r6  left lsb in
  34 ; r7  left msb in
  35 ; r8  
  36 ; r9  adc msb accumulator
  37 ; r10 adc fractional byte accumulator
  38 ; r11 adc lsb accumulator
  39 ; r12 desired buffer size lsb
  40 ; r13 desired buffer size msb
  41 ; r14 
  42 ; r15 switch/adc counter
  43 ; r16 temporary swap register
  44 ; r17 temporary swap register
  45 ; r18 multiplicand lsb
  46 ; r19 multiplicand msb
  47 ; r20 multiplicand lsb
  48 ; r21 multiplicand msb
  49 ; r22 null register
  50 ; r23 
  51 ; r24 write address lsb
  52 ; r25 write address msb
  53 ; r26 buffer length lsb
  54 ; r27 buffer length msb
  55 ; r28 read address lsb
  56 ; r29 read address msb
  57 ; r30 jump location for interrupt lsb
  58 ; r31 jump location for interrupt msb
  59 ; t
  60 
  61 ; program starts here first time
  62 ; initialze z pointer for correct jump
  63 ; this assumes a less than 256 word jump
  64 ldi r30,$21 ; set jump location to program start
  65 clr r24 ; clear write register
  66 clr r25
  67 ldi r22,$00 ; setup write address high byte
  68 clr r18 ; setup r18 as null register for carry addition and ddr setting
  69 ldi r17,$ff ; setup r17 for ddr setting
  70 
  71 clear_000036: ; clear delay buffer
  72 ; eliminates static when first switching to the delay setting
  73 
  74 adiw r25:r24,$01 ; increment write register
  75 adc r22,r18 ; increment write third byte
  76 cpi r22,$01 ; check if 16b memory space has been cleared
  77 breq cleardone_000036 ; continue until end of buffer reached
  78 out portd,r24 ; set address
  79 sts porth,r25
  80 out portg,r22 ; pull ce low,we low,and set high bits of address
  81 out ddra,r17 ; set porta as output for data write
  82 out ddrc,r17 ; set portc as output for data write
  83 out porta,r18 ; set data
  84 out portc,r18 ; r18 is cleared above
  85 sbi portg,portg2 ; pull we high to write
  86 out ddra,r18 ; set porta as input for data lines
  87 out ddrc,r18 ; set portc as input for data lines
  88 rjmp clear_000036 ; continue clearing
  89 
  90 cleardone_000036: ; reset registers
  91 
  92 ldi r24,$00 ; initialize write register
  93 ldi r25,$00
  94 ldi r22,$00 ; setup write address high byte
  95 ldi r28,$00 ; set read address to minimum delay
  96 ldi r29,$fd
  97 clr r4 ; initialize data output registers
  98 clr r5
  99 ldi r26,$00 ; initialize buffer size
 100 ldi r27,$06
 101 movw r13:r12,r27:r26
 102 reti ; finish with initialization and wait for next interrupt
 103 
 104 ; program begins here
 105 ; initiate data transfer to codec
 106 sbi portb,portb0 ; toggle slave select pin
 107 out spdr,r5 ; send out left channel msb
 108 cbi portb,portb0
 109 
 110 ;increment write address
 111 adiw r25:r24,$01 ; increment write address
 112 cp r24,r26 ; check if at end of buffer
 113 cpc r25,r27
 114 brlo wait1_000036 ; do nothing if not at end of buffer
 115 clr r24 ; reset buffer to bottom
 116 clr r25
 117 
 118 wait1_000036: ; check if byte has been sent
 119 
 120 in r17,spsr
 121 sbrs r17,spif
 122 rjmp wait1_000036
 123 in r7,spdr ; recieve in left channel msb
 124 out spdr,r4 ; send out left channel lsb
 125 
 126 ;decrement read address (for going in reverse)
 127 sbiw r29:r28,$01
 128 brcc wait2_000036 ; do nothing if not at end of buffer
 129 movw r29:r28,r27:r26 ; reset to top of buffer
 130 sbiw r29:r28,$01 ; reset to top of buffer
 131 
 132 wait2_000036: ; check if byte has been sent
 133 
 134 in r17,spsr
 135 sbrs r17,spif
 136 rjmp wait2_000036
 137 in r6,spdr ; recieve in left channel lsb
 138 out spdr,r5 ; send out right channel msb
 139 
 140 ;write left channel data to sram
 141 out portd,r24 ; set address
 142 sts porth,r25
 143 out portg,r22 ; pull ce low,we low,and set high bits of address
 144 ldi r17,$ff
 145 out ddra,r17 ; set porta as output for data write
 146 out ddrc,r17 ; set portc as output for data write
 147 out porta,r6 ; set data
 148 out portc,r7
 149 sbi portg,portg2 ; pull we high to write
 150 out ddra,r22 ; set porta as input for data lines
 151 out ddrc,r22 ; set portc as input for data lines
 152 
 153 wait3_000036: ; check if byte has been sent
 154 
 155 in r17,spsr
 156 sbrs r17,spif
 157 rjmp wait3_000036
 158 in r17,spdr ; recieve in right channel msb
 159 out spdr,r4 ; send out right channel lsb
 160 
 161 ;get sample 1 from sram
 162 out portd,r28 ; set address
 163 sts porth,r29
 164 nop ; wait required 2 cycle setup time
 165 nop
 166 in r4,pina ; get data
 167 in r5,pinc ; get data
 168 
 169 wait4_000036: ; check if byte has been sent
 170 
 171 in r17,spsr
 172 sbrs r17,spif
 173 rjmp wait4_000036
 174 in r17,spdr ; recieve in right channel lsb
 175 
 176 ;get sample 2 from other side of buffer
 177 movw r17:r16,r29:r28 ; move current position to temporary register
 178 movw r7:r6,r27:r26 ; move buffer size to temporary register
 179 lsr r7 ; divide buffer size by 2
 180 ror r6
 181 cp r16,r6 ; check if in lower or upper half of buffer
 182 cpc r17,r7
 183 brsh buffer_flip_000036 ; subtract half buffer if in upper half
 184 add r16,r6 ; add half buffer size if in lower half
 185 adc r17,r7
 186 rjmp getsample2_000036 ; continue
 187 
 188 buffer_flip_000036: ; adjust to opposite side of memory
 189 
 190 sub r16,r6 ; subtract half buffer size if in upper half
 191 sbc r17,r7
 192 
 193 getsample2_000036: ;get left channel sample 3 data from sram
 194 
 195 out portd,r16 ; set address
 196 sts porth,r17
 197 nop ; wait 2 cycle setup time
 198 nop
 199 in r2,pina ; get data
 200 in r3,pinc ; get data
 201 
 202 ;get distance to boundary
 203 movw r17:r16,r29:r28 ; move read address to temporary register
 204 sub r16,r24 ; find distance to loop boundary
 205 sbc r17,r25
 206 brcc half_000036 ; check if result is negative
 207 neg r16 ; invert distance if negative
 208 adc r17,r22 ; r22 is cleared above
 209 neg r17
 210 
 211 half_000036: ; check if result is greater than half the buffer size
 212 
 213 movw r7:r6,r27:r26 ; move buffer size to temporary register
 214 lsr r7 ; divide buffer size by 2
 215 ror r6
 216 cp r16,r6 ; check if result is greater than half the buffer size
 217 cpc r17,r7
 218 brlo scale_000036 ; skip flip if not
 219 sub r16,r26 ; flip result around boundary
 220 sbc r17,r27
 221 neg r16 ; invert distance
 222 adc r17,r22 ; r22 is cleared above
 223 neg r17
 224 
 225 scale_000036: ; scale distance to match buffer size - 50% accurate
 226 
 227 movw r7:r6,r27:r26 ; move buffer size to temporary register
 228 sbrc r7,$07 ; check if msb of buffer size is set
 229 rjmp attenuate_000036 ; attenuate signal if 16b value
 230 
 231 shift_000036: ; shift buffer size till it occupies full 16b
 232 
 233 lsl r6 ; multiply buffer size by 2
 234 rol r7
 235 lsl r16 ; multiply distance by 2
 236 rol r17
 237 sbrs r7,$07 ; check if msb of buffer size is set
 238 rjmp shift_000036 ; keep checking if not set
 239 
 240 attenuate_000036: ; multiply sample 1 by distance
 241 
 242 lsl r16 ; multiply distance by 2 since max value is 1/2 buffer size
 243 rol r17
 244 sub r6,r16 ; find complementary distance of sample 2
 245 sbc r7,r17
 246 movw r21:r20,r7:r6 ; move distance to signed multiply register
 247 movw r19:r18,r5:r4 ; move value to signed multiply register
 248 mulsu r19,r17 ; (signed)ah * bh
 249 movw r5:r4,r1:r0
 250 mul	r18,r16	; al * bl
 251 movw r7:r6,r1:r0
 252 mulsu r19,r16 ; (signed)ah * bl
 253 sbc	r5,r22 ; r22 is cleared above
 254 add	r7,r0
 255 adc	r4,r1
 256 adc	r5,r22
 257 mul r17,r18 ; bh * al
 258 add	r7,r0
 259 adc	r4,r1
 260 adc	r5,r22
 261 
 262 ;multiply and accumulate opposing sample with result from above
 263 movw r19:r18,r3:r2 ; move value to signed multiply register
 264 mulsu r19,r21 ; (signed)ah * bh
 265 add	r4,r0
 266 adc	r5,r1
 267 mul	r18,r20 ; al * bl
 268 add	r6,r0
 269 adc	r7,r1
 270 adc	r4,r22
 271 adc	r5,r22
 272 mulsu r19,r20 ; (signed)ah * bl
 273 sbc	r5,r22
 274 add	r7,r0
 275 adc	r4,r1
 276 adc	r5,r22
 277 mul r21,r18 ; bh * al
 278 add	r7,r0
 279 adc	r4,r1
 280 adc	r5,r22
 281 
 282 ;check if buffer size is correct
 283 cp r26,r12 ; compare current delay to desired delay
 284 cpc r27,r13
 285 brlo upcount_000036 ; increment if smaller than
 286 breq adcsample_000036 ; do nothing if they are same size
 287 sbiw r27:r26,$02 ; decrement buffer size
 288 rjmp adcsample_000036 ; finish off
 289 
 290 upcount_000036: ; increment buffer size register
 291 
 292 adiw r27:r26,$02 ; increment buffer size
 293 
 294 adcsample_000036: ; get loop setting
 295 
 296 lds r17,adcsra ; get adc control register
 297 sbrs r17,adif ; check if adc conversion is complete
 298 rjmp done_000036 ; skip adc sampling
 299 lds r16,adcl ; get low byte adc value
 300 lds r17,adch ; get high byte adc value
 301 add r10,r16
 302 adc r11,r17 ; accumulate adc samples
 303 adc r9,r22 ; accumulate adc samples - r22 is cleared above
 304 ldi r17,$f7
 305 sts adcsra,r17 ; clear interrupt flag
 306 dec r15 ; countdown adc sample clock
 307 brne done_000036 ; move adc value to loop setting after 256 samples
 308 lsr r9 ; divide accumulated value by 4
 309 ror r11
 310 ror r10
 311 lsr r9
 312 ror r11
 313 ror r10
 314 ldi r16,low(buffer_min_000036) ; load minimum buffer size
 315 ldi r17,high(buffer_min_000036)
 316 cp r10,r16 ; check if less than minimum
 317 cpc r11,r17
 318 brsh compare_000036 ; compare to previous value if above min
 319 movw r11:r10,r17:r16 ; set buffer size to minimum
 320 
 321 compare_000036: ; compare to previous value
 322 
 323 movw r17:r16,r13:r12 ; make a copy of current loop time for comparison
 324 sub r16,r10 ; find difference between current loop time and last loop time
 325 sbc r17,r11
 326 brcc deadband_000036 ; see if difference is large enough to indicate a change
 327 neg r16 ; invert difference if negative
 328 adc r17,r22 ; r22 is cleared above
 329 neg r17
 330 
 331 deadband_000036: ; see if pot has moved or if its just noise
 332 
 333 cpi r16,$40 ; see if difference is greater than 1 lsb
 334 cpc r17,r22 ; r22 is cleared above
 335 brlo nochange_000036 ; dont update loop time if difference is not large enough
 336 ldi r16,$fe ; make sure buffer size is even
 337 and r10,r16
 338 movw r13:r12,r11:r10 ; move adc value to loop time register
 339 
 340 nochange_000036: ; clear accumulation registers
 341 
 342 clr r10 ; empty accumulation registers
 343 clr r11
 344 clr r9
 345 
 346 ;check rotary switch state
 347 lds r16,pinj ; get switch data
 348 andi r16,$78 ; mask off rotary switch
 349 lsr r16 ; adjust switch position to program memory location
 350 lsr r16
 351 ldi r17,$02
 352 add r16,r17
 353 cpse r16,r31 ; check if location has changed
 354 clr r30 ; reset jump register to intial state
 355 mov r31,r16
 356 
 357 done_000036:
 358 
 359 reti ; return to waiting
 360 

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.