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.