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