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