← Revision 1 as of 2010-08-13 19:17:42 →
Size: 126
Comment:
|
← Revision 6 as of 2010-08-21 02:06:09
Size: 12536
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
=== MICrODEC: Stock Functions === |
|
Line 3: | Line 5: |
This function implements a reverser, so all input sounds are played backwards. It takes mono data in on the left channel, and presents mono data out on both the left and right channels. The pot (MOD1) controls the buffer size. A reverser is created by playing all the samples in reverse order. Unfortunately, you end up hitting the beginning of your buffer at some point, and need to start over again. This creates an audible click in the sample playback. To eliminate this click, we use the fading method. This involves having two samples playing back simultaneously, each from a different point in the buffer (spaced a half-buffer's distance from each other). As one sample gets closer to the boundary, its volume is faded down, and the other is faded up. This continues as each sample moves forward in the buffer, with the volume of the sample being determined by its distance from the buffer boundary. This gives very smooth transitions across the buffer boundary, but also has a slight reverb effect, as multiple delayed signals are being mixed together. The pot (MOD1) varies the buffer size used for sample playback, from 6ms to 1.5s. Smaller buffer sizes give a more subtle effect, as you are playing through only very small samples at a time, but has the advantage of not having much of a delay. If the buffer is too small, you begin to hear the rate at which you are moving through the buffer, almost like a slight tremolo. For large buffer sizes, the samples sound more like reversed audio, but the delay becomes larger as well. |
|
Line 8: | Line 16: |
; 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,$21 ; 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 movw r13:r12,r27:r26 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 |
MICrODEC: Stock Functions
Reverser with Fading
This function implements a reverser, so all input sounds are played backwards. It takes mono data in on the left channel, and presents mono data out on both the left and right channels. The pot (MOD1) controls the buffer size.
A reverser is created by playing all the samples in reverse order. Unfortunately, you end up hitting the beginning of your buffer at some point, and need to start over again. This creates an audible click in the sample playback. To eliminate this click, we use the fading method. This involves having two samples playing back simultaneously, each from a different point in the buffer (spaced a half-buffer's distance from each other). As one sample gets closer to the boundary, its volume is faded down, and the other is faded up. This continues as each sample moves forward in the buffer, with the volume of the sample being determined by its distance from the buffer boundary. This gives very smooth transitions across the buffer boundary, but also has a slight reverb effect, as multiple delayed signals are being mixed together.
The pot (MOD1) varies the buffer size used for sample playback, from 6ms to 1.5s. Smaller buffer sizes give a more subtle effect, as you are playing through only very small samples at a time, but has the advantage of not having much of a delay. If the buffer is too small, you begin to hear the rate at which you are moving through the buffer, almost like a slight tremolo. For large buffer sizes, the samples sound more like reversed audio, but the delay becomes larger as well.
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