← Revision 1 as of 2010-08-13 19:16:00 →
134
Comment:
|
13162
|
Deletions are marked like this. | Additions are marked like this. |
Line 3: | Line 3: |
This function implements a flanger which varies the delay between the left and right outputs. It takes in mono audio on the left channel, and outputs a stereo signal on both left and right channels. the pot (MOD1) adjusts the LFO frequency, and the rotary encoder (MOD2) adjusts the LFO depth. Flanging is based on analog tape and reel recording techniques, where slight pressure is applied to the flange of the reel, slowing down the playback. This creates a time-varying delayed signal, which, when mixed with the original signal, has a swept filter effect. Any time-varying signal can be used, but in this case, we are using a sinusoidal signal, as it introduces the least amount of added frequency content (ramp waves are also common). This sinusoid is created by taking values from a look-up table stored in program memory. The frequency of the sinusoid is set by the pot (MOD1), and is variable from .084Hz to 10.84Hz. |
|
Line 8: | Line 15: |
; program: stereo_flanger-16b.asm ; UID = 000053 - unique id to eliminate conflicts between variables ; 16b address space ; mono data in on left channel, stereo data out (opposite phasing) ; pot (MOD1) controls lfo frequency ; rotary encoder (MOD2) controls lfo depth ; program overview ; ; data is read in from the codec and stored to sram. data is read out of ; sram at a variable delay set by an lfo. the lfo is generated from a ; 16b/512s half sinewave lookup table. this is incremented with a 24b ; number to get very low frequencies. the lfo rate is set via the adc, ; which is oversampled 256 times and deadbanded to get rid of glitches. ; the lfo depth is created by multiplying the lfo signal with an 8b depth ; value, which is set via the rotary encoder. ; register usage - may be redefined in other sections ; ; r0 multiply result lsb ; r1 multiply result msb ; r2 accumulation lsb ; r3 accumulation mlb ; r4 left lsb out / accumulation mhb ; r5 left msb out / accumulation msb ; r6 right out lsb ; r7 right out msb ; r8 adc accumulator fractional byte ; r9 adc accumulator lsb ; r10 adc accumulator msb ; r11 rotary encoder counter ; r12 lfo rate lsb ; r13 lfo rate msb ; r14 null register ; r15 switch sample counter ; r16 temporary swap register ; r17 temporary swap register ; r18 sine wave buffer/multiply msb ; r19 sine wave buffer/multiply msb ; r20 multiply swap register ; r21 multiply swap register ; r22 sinetable lookup address lsb ; r23 sinetable lookup address mlb ; r24 write address lsb ; r25 write address msb ; r26 sinetable lookup address mhb ; r27 sinetable lookup address msb ; r28 temporary swap register ; r29 lfo depth ; r30 jump location for interrupt lsb ; r31 jump location for interrupt msb ; t rotary encoder edge detect indicator ; program starts here first time ; intialize registers ldi r30,$04 ; increment z pointer to new jump location clr r14 ; clear null register ldi r29,$0d ; intiialize lfo depth reti ; finish with initialization and wait for next interrupt ; program starts here every time but first ; initiate data transfer to codec sbi portb,portb0 ; toggle slave select pin out spdr,r5 ; send out left channel msb cbi portb,portb0 adiw r25:r24,$01 ; increment write address wait1_000053: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait1_000053 in r19,spdr ; recieve in left channel msb out spdr,r4 ; send out left channel lsb wait2_000053: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait2_000053 in r18,spdr ; recieve in left channel lsb out spdr,r7 ; send out right channel msb ;write left channel to sram out portd,r24 ; set address sts porth,r25 out portg,r14 ; 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,r18 ; set data out portc,r19 sbi portg,portg2 ; pull we high to write out ddra,r14 ; set porta as input for data lines out ddrc,r14 ; set portc as input for data lines wait3_000053: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait3_000053 in r17,spdr ; recieve in right channel msb out spdr,r6 ; send out right channel lsb wait4_000053: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait4_000053 in r17,spdr ; recieve in right channel lsb ; vco generation movw r17:r16,r31:r30 ; store z register ;get sample 1 add r22,r12 ; increment sinetable address adc r23,r13 adc r26,r14 ; r14 is cleared above adc r27,r14 movw r31:r30,r27:r26 ; move to z register for data fetch lsl r30 ; adjust pointer for 16b fetch rol r31 andi r31,$03 ; limit value to 10b (512 samples x 2 bytes) ori r31,$48 ; set to memory address location where table is stored lpm r18,z+ ; get sine value lsb, increment z register lpm r19,z ; get sine value msb sbrc r27,$01 ; flip sign for half of the values rjmp interpolate_000053 neg r18 adc r19,r14 ; r14 is cleared above neg r19 interpolate_000053: ; multiply sample 1 by distance movw r21:r20,r23:r22 ; get distance from sample 1 com r20 ; invert distance com r21 mulsu r19,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes movw r5:r4,r1:r0 ; store high bytes result for later mul r18,r20 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes movw r3:r2,r1:r0 ; store low byets for later mulsu r19,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes sbc r5,r14 ; r14 is cleared above - subtract sign bit add r3,r0 ; accumulate result adc r4,r1 adc r5,r14 ; r14 is cleared above mul r21,r18 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes add r3,r0 ; accumulate result adc r4,r1 adc r5,r14 ; r14 is cleared above ;get sample 2 adiw r27:r26,$01 ; set to next sample movw r31:r30,r27:r26 ; move to z register for data fetch lsl r30 ; adjust pointer for 16b fetch rol r31 andi r31,$03 ; limit value to 10b (512 samples x 2 bytes) ori r31,$48 ; set to memory address location where table is stored lpm r18,z+ ; get sine value lsb, increment z register lpm r19,z ; get sine value msb sbrc r27,$01 ; flip sign for half of the values rjmp interpolate1_000053 neg r18 adc r19,r14 ; r14 is cleared above neg r19 interpolate1_000053: ; multiply sample 2 by distance sbiw r27:r26,$01 ; reset address movw r31:r30,r17:r16 ; restore z register mulsu r19,r23 ; (signed)Ah * (unsigned)Bh - multiply high bytes add r4,r0 ; accumulate result adc r5,r1 mul r18,r22 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes add r2,r0 ; accumulate result adc r3,r1 adc r4,r14 ; r14 is cleared above adc r5,r14 mulsu r19,r22 ; (signed)Ah * (unsigned)Bl - multiply middle bytes sbc r5,r14 ; r14 is cleared above - subtract sign bit add r3,r0 ; accumulate result adc r4,r1 adc r5,r14 ; r14 is cleared above mul r23,r18 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes add r3,r0 ; accumulate result adc r4,r1 adc r5,r14 ; r14 is cleared above ;set lfo depth - 8b value ldi r16,$80 ; convert lfo to unsigned number add r5,r16 movw r19:r18,r5:r4 ; move lfo signal to multiply register mov r21,r29 ; move lfo depth to multiply register mul r19,r21 ; (unsigned)ah * (unsigned)b movw r5:r4,r1:r0 mul r21,r18 ; (unsigned)b * (unsigned)al add r4,r1 adc r5,r14 ; r14 is cleared above mov r28,r5 ; store lfo for later mov r21,r4 ;right channel data preperation ;add lfo to delay movw r17:r16,r25:r24 ; move current location to read address sec ; set the carry bit so all values are reduced by 1 lsb for fractional byte sbc r16,r5 ; remove lfo time sbc r17,r14 ; r14 is cleared above ;get right channel sample 1 from sram out portd,r16 ; set address sts porth,r17 nop ; wait setup period of two cycles nop in r18,pina ; get data in r19,pinc ; get data ;multiply sample 1 by distance mov r20,r4 ; get distance from sample 1 mulsu r19,r20 ; (signed)ah * b movw r5:r4,r1:r0 mul r18,r20 ; al * b add r4,r1 adc r5,r14 ; r14 is cleared above mov r3,r0 ;get right channel sample 2 from sram subi r16,$ff ; set to next sample sbci r17,$ff ; done this way because there is no addi or adci out portd,r16 ; set address sts porth,r17 nop ; wait setup period of two cycles nop in r18,pina ; get data in r19,pinc ; get data ;multiply sample 2 by distance com r20 ; get distance to sample 2 mulsu r19,r20 ; (signed)ah * b add r4,r0 ; accumulate result adc r5,r1 mul r18,r20 ; al * b add r3,r0 ; accumulate result add r4,r1 adc r5,r14 ; r14 is cleared above movw r7:r6,r5:r4 ; move right channel to output register ;left channel data preperation ;add lfo to delay clr r4 ; get max depth value mov r5,r29 sub r4,r21 ; subtract lfo to make inverse sbc r5,r28 movw r17:r16,r25:r24 ; move current location to read address sec ; set the carry bit so all values are reduced by 1 lsb for fractional byte sbc r16,r5 ; remove lfo time sbc r17,r14 ; r14 is cleared above ;get left channel sample 1 from sram out portd,r16 ; set address sts porth,r17 nop ; wait setup period of two cycles nop in r18,pina ; get data in r19,pinc ; get data ;multiply sample 1 by distance mov r20,r4 ; get distance from sample 1 mulsu r19,r20 ; (signed)ah * b movw r5:r4,r1:r0 mul r18,r20 ; al * b add r4,r1 adc r5,r14 ; r14 is cleared above mov r3,r0 ;get left channel sample 2 from sram subi r16,$ff ; set to next sample sbci r17,$ff ; done this way because there is no addi or adci out portd,r16 ; set address sts porth,r17 nop ; wait setup period of two cycles nop in r18,pina ; get data in r19,pinc ; get data ;multiply sample 2 by distance com r20 ; get distance to sample 2 mulsu r19,r20 ; (signed)ah * b add r4,r0 ; accumulate result adc r5,r1 mul r18,r20 ; al * b add r3,r0 ; accumulate result add r4,r1 adc r5,r14 ; r14 is cleared above ;check rotary encoder and adjust lfo depth ; although rotary encoder is externally debounced, it is done here again. ; pin1 is sampled on a transition from high to low on pin0. if pin1 is ; high, a left turn occured, if pin1 is low, a right turn occured. dec r11 ; count down sample clock brne adcsample_000053 ; continue if not ldi r17,$40 ; adjust sample frequency to catch all rising edges (1.5ms) mov r11,r17 ; reload sample clock lds r17,pinj ; get switch data sbrs r17,$00 ; check if pin0 is low rjmp edge_000053 ; check if pin0 was low on previous sample clt ; clear state register if back high rjmp adcsample_000053 ; finish off edge_000053: ; check for falling edge brts adcsample_000053 ; do nothing if edge was already detected set ; set t register to indicate edge detected ldi r21,$01 ; prepare for addition or subtraction sbrs r17,$01 ; check if pin1 is high rjmp increment_000053 ; increment desired delay if right rotation sub r29,r21 ; decrement lfo depth register else brcc adcsample_000053 ; check if underflow clr r29 ; set depth to min rjmp adcsample_000053 ; finish off increment_000053: ; increment desired delay register add r29,r21 ; increment lfo depth register brcc adcsample_000053 ; check if overflow occured ser r29 ; set depth to max adcsample_000053: ; sample adc for lfo rate lds r17,adcsra ; get adc control register sbrs r17,adif ; check if adc conversion is complete rjmp done_000053 ; skip adc sampling lds r16,adcl ; get low byte adc value lds r17,adch ; get high byte adc value add r8,r16 ; accumulate adc samples adc r9,r17 adc r10,r14 ; r14 is cleared above ldi r17,$f7 sts adcsra,r17 ; clear interrupt flag dec r15 ; countdown adc sample clock brne done_000053 ; get delay time if its been long enough deadband_000053: ; set the low value of the delay lsr r10 ; divide adc value by 16 ror r9 ror r8 lsr r10 ror r9 ror r8 lsr r9 ; r10 now empty ror r8 lsr r9 ror r8 movw r17:r16,r9:r8 ; move adc sample to temporary register ldi r21,$80 ; add in offset of min lfo rate ($0080) add r16,r21 adc r17,r14 ; r14 is cleared above sub r16,r12 ; find difference between adc sample and current lfo rate sbc r17,r13 brsh check_000053 ; check for deadband if positive neg r16 ; invert if negative adc r17,r14 ; r14 is cleared above neg r17 check_000053: ; check if difference is greater than deadband cpi r16,$10 ; check if difference is less than 1 adc lsb cpc r17,r14 ; r14 cleared above brlo empty_000053 ; do nothing if less than 1 adc lsb movw r13:r12,r9:r8 ; move adc sample to lfo rate register add r12,r21 ; add in offset of min lfo rate ($0080) adc r13,r14 ; r14 is cleared above empty_000053: ; empty accumulation registers and finish off clr r8 ; empty accumulation registers clr r9 clr r10 switchsample_000053: ; check rotary switch 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_000053: reti ; return to waiting |
Stereo Panning Flanger
This function implements a flanger which varies the delay between the left and right outputs. It takes in mono audio on the left channel, and outputs a stereo signal on both left and right channels. the pot (MOD1) adjusts the LFO frequency, and the rotary encoder (MOD2) adjusts the LFO depth.
Flanging is based on analog tape and reel recording techniques, where slight pressure is applied to the flange of the reel, slowing down the playback. This creates a time-varying delayed signal, which, when mixed with the original signal, has a swept filter effect. Any time-varying signal can be used, but in this case, we are using a sinusoidal signal, as it introduces the least amount of added frequency content (ramp waves are also common). This sinusoid is created by taking values from a look-up table stored in program memory. The frequency of the sinusoid is set by the pot (MOD1), and is variable from .084Hz to 10.84Hz.
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