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