← Revision 1 as of 2010-08-13 19:19:41
Size: 113
Comment:
|
← Revision 2 as of 2010-08-14 01:38:06 →
Size: 10561
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 3: | Line 3: |
This function implements an up-down sweep. This means it plays forward at double speed until it hits the top of the buffer, and then plays in reverse until it hits the bottom. It takes in stereo data, and outputs stereo data. The pot (MOD1) varies the buffer size, within which the function reads back and forth. Since the function just bounces back and forth inside the buffer, there is no buffer boundary problems, although the change in direction at the buffer ends can add a slight high frequency element. The buffer size is settable between and 3ms and 1.5s. |
|
Line 8: | Line 12: |
; program: up_downsweep-18b-pot.asm ; UID = 000035 - unique id to eliminate conflicts between variables ; 18b address space (1.5s sample time) ; stereo data ; pot (MOD1) controlled buffer size (3ms - 1.5s) ; program overview ; ; data is read in from memory and written out to the codec at the same time ; new data is written to the memory from the codec. the write address ; increments until it reaches the top of the buffer and then starts at ; zero. the read address increases at twice the rate until it reaches the ; write address, and then decreases until it reaches the write address. ; it continues this back and forth sample playback. ADC0 (MOD1) is read ; and averaged over 256 samples to reduce jitter. this value is subtracted ; from the write address to create the desired read address. if the actual ; read address doesnt match the desired read address, it is either ; incremented or decremented by one sample each sample period until it ; matches. this reduces noise during delay time transitions. ; register usage - may be redefined in other sections ; ; r0 desired buffer size fractional byte ; r1 ; r2 left lsb out ; r3 left msb out ; r4 right lsb out ; r5 right msb out ; r6 left lsb in ; r7 left msb in ; r8 right lsb in ; r9 right msb in ; r10 adc accumulation lsb ; r11 adc accumulation msb ; r12 read address offset lsb ; r13 read address offset msb ; r14 adc/switch sample counter ; r15 ; r16 temporary swap register ; r17 temporary swap register ; r18 null register ; r19 adc accumulation fractional byte ; r20 temporary swap regiser ; r21 read address offset high byte ; r22 write address high byte ; r23 read address high byte ; r24 write address lsb ; r25 write address msb ; r26 desired buffer size lsb ; r27 desired buffer size msb ; r28 read address lsb ; r29 read address msb ; r30 jump location for interrupt lsb ; r31 jump location for interrupt msb ; t forward/reverse indicator ; program starts here first time ; initialze z pointer for correct jump ; this assumes a less than 256 word jump ldi r30,$29 ; 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_000035: ; 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,$04 ; check if full memory space has been cleared breq cleardone_000035 ; 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_000035 ; continue clearing cleardone_000035: ; 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,$fe ldi r23,$07 ; setup read address high byte clr r0 ; set buffer size to minimum ldi r26,$01 clr r27 clr r12 ; set read address offset to minimum buffer size ldi r16,$01 mov r13,r16 clr r21 clr r2 ; initialize data output registers clr r3 clr r4 clr r5 clt ; clear t register to start with forward play reti ; finish with initialization and wait for next interrupt ; program starts here all but first time ; this is the point the z-pointer is incremented to ; initiate data transfer to codec sbi portb,portb0 ; toggle slave select pin out spdr,r3 ; send out left channel msb cbi portb,portb0 wait1_000035: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait1_000035 in r7,spdr ; recieve in left channel msb out spdr,r2 ; send out left channel lsb ;get left channel data from sram out portg,r23 ; pull ce low, we high, and set high bits of register out portd,r28 ; set address sts porth,r29 adiw r29:r28,$01 ; increment read address adc r23,r18 ; placed here for efficient use of setup time andi r23,$03 ; mask off unsed bits ori r23,$04 ; set we/ bit in high byte register in r2,pina ; get data in r3,pinc ; get data wait2_000035: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait2_000035 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,r18 ; set porta as input for data lines out ddrc,r18 ; set portc as input for data lines wait3_000035: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait3_000035 in r9,spdr ; recieve in right channel msb out spdr,r4 ; send out right channel lsb ;get right channel data from sram out portg,r23 ; pull ce low, we high, and set high bits of register out portd,r28 ; set address sts porth,r29 adiw r25:r24,$01 ; increment write address adc r22,r18 ; placed here to use setup time efficiently andi r22,$03 ; mask off unsed bits in r4,pina ; get data in r5,pinc ; get data wait4_000035: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait4_000035 in r8,spdr ; recieve in left channel lsb ;write right 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,r8 ; set data out portc,r9 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 ;increment write address to next sample position adiw r25:r24,$01 ; increment write address adc r22,r18 ; increment write third byte andi r22,$03 ; mask off unsed bits movw r29:r28,r25:r24 ; move write address to read address mov r23,r22 ;calculate read offset brtc increment_000035 ; move read address forward if in foward mode ldi r16,$04 ; else move read address backwards by 2 add r12,r16 ; this requires incrementing the read offset by 4 adc r13,r18 ; r18 is cleared above adc r21,r18 cp r12,r0 ; check if at bottom of buffer cpc r13,r26 cpc r21,r27 brlo readadd_000035 ; load read address if not at bottom of buffer sub r12,r16 ; halt playback for one sample sbc r13,r18 ; reduces spike at transition sbc r21,r18 ; r18 is cleared above clt ; else clear t register to indicate forward motion after next sample increment_000035: ; move read address forward by 4 ; moving read address forward requires reducing the read offset by 2 ldi r16,$02 ; subtract 2 from read offset sub r12,r16 sbc r13,r18 ; r18 is cleared above sbc r21,r18 brne readadd_000035 ; load read address if not at top of buffer mov r12,r16 ; set offset to min and halt playback for one sample set ; else set t register to start reversing on next sample readadd_000035: ; add in read offset sub r28,r12 ; subtract offset from read address sbc r29,r13 sbc r23,r21 andi r23,$03 ; mask off unused bits ori r23,$04 ; set we/ bit for reading adcsample_000035: ; get buffer size from adc lds r17,adcsra ; get adc control register sbrs r17,adif ; check if adc conversion is complete rjmp done_000035 ; skip adc sampling if not lds r16,adcl ; get low byte adc value lds r17,adch ; get high byte adc value add r19,r16 ; accumulate adc samples adc r10,r17 adc r11,r18 ; r18 is cleared above ldi r17,$f7 sts adcsra,r17 ; clear interrupt flag dec r14 ; countdown adc sample clock brne done_000035 ; dont get buffer size till its been long enough lsr r11 ; divide adc sample by 2 ror r10 ; as the max buffer size is only $020000 ror r19 ; as the buffer is read backwards half of the time ldi r17,$01 ; check if adc value is less than $000100 cp r19,r18 ; r18 is cleared above cpc r10,r17 cpc r11,r18 brsh deadband_000035 ; check if adc value changed enough to update delay inc r10 ; set minimum delay to $000100 = 3ms clr r19 deadband_000035: ; check for change in adc value movw r17:r16,r11:r10 ; move adc sample to temporary register mov r20,r19 sub r20,r0 ; find difference between adc sample and desired buffer size sbc r16,r26 sbc r17,r27 brsh check_000035 ; check for deadband if positive com r20 ; invert if negative com r16 ; using ones complement as it is faster, and only has 1 bit error com r17 check_000035: ; check if difference is greater than deadband cpi r16,$01 ; check if difference is less than 1 lsb cpc r17,r18 ; r18 cleared above brlo empty_000035 ; do nothing if less than 1 lsb movw r27:r26,r11:r10 ; move adc sample to delay time if large enough change andi r19,$fc ; make sure buffer size is a multiple of 4 mov r0,r19 empty_000035: ; empty accumulation registers and finish off clr r10 ; empty accumulation registers clr r11 clr r19 switchsample_000035: ; check if at same function 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 ; move to jump register cp r16,r31 ; check if location has changed breq done_000035 ; finish off if no change clr r30 ; reset jump register to new function mov r31,r16 done_000035: reti ; return to waiting |
Up-Down Sweep
This function implements an up-down sweep. This means it plays forward at double speed until it hits the top of the buffer, and then plays in reverse until it hits the bottom. It takes in stereo data, and outputs stereo data. The pot (MOD1) varies the buffer size, within which the function reads back and forth.
Since the function just bounces back and forth inside the buffer, there is no buffer boundary problems, although the change in direction at the buffer ends can add a slight high frequency element. The buffer size is settable between and 3ms and 1.5s.
1 ; program: up_downsweep-18b-pot.asm
2 ; UID = 000035 - unique id to eliminate conflicts between variables
3 ; 18b address space (1.5s sample time)
4 ; stereo data
5 ; pot (MOD1) controlled buffer size (3ms - 1.5s)
6
7 ; program overview
8 ;
9 ; data is read in from memory and written out to the codec at the same time
10 ; new data is written to the memory from the codec. the write address
11 ; increments until it reaches the top of the buffer and then starts at
12 ; zero. the read address increases at twice the rate until it reaches the
13 ; write address, and then decreases until it reaches the write address.
14 ; it continues this back and forth sample playback. ADC0 (MOD1) is read
15 ; and averaged over 256 samples to reduce jitter. this value is subtracted
16 ; from the write address to create the desired read address. if the actual
17 ; read address doesnt match the desired read address, it is either
18 ; incremented or decremented by one sample each sample period until it
19 ; matches. this reduces noise during delay time transitions.
20
21 ; register usage - may be redefined in other sections
22 ;
23 ; r0 desired buffer size fractional byte
24 ; r1
25 ; r2 left lsb out
26 ; r3 left msb out
27 ; r4 right lsb out
28 ; r5 right msb out
29 ; r6 left lsb in
30 ; r7 left msb in
31 ; r8 right lsb in
32 ; r9 right msb in
33 ; r10 adc accumulation lsb
34 ; r11 adc accumulation msb
35 ; r12 read address offset lsb
36 ; r13 read address offset msb
37 ; r14 adc/switch sample counter
38 ; r15
39 ; r16 temporary swap register
40 ; r17 temporary swap register
41 ; r18 null register
42 ; r19 adc accumulation fractional byte
43 ; r20 temporary swap regiser
44 ; r21 read address offset high byte
45 ; r22 write address high byte
46 ; r23 read address high byte
47 ; r24 write address lsb
48 ; r25 write address msb
49 ; r26 desired buffer size lsb
50 ; r27 desired buffer size msb
51 ; r28 read address lsb
52 ; r29 read address msb
53 ; r30 jump location for interrupt lsb
54 ; r31 jump location for interrupt msb
55 ; t forward/reverse indicator
56
57 ; program starts here first time
58 ; initialze z pointer for correct jump
59 ; this assumes a less than 256 word jump
60 ldi r30,$29 ; set jump location to program start
61 clr r24 ; clear write register
62 clr r25
63 ldi r22,$00 ; setup write address high byte
64 clr r18 ; setup r18 as null register for carry addition and ddr setting
65 ldi r17,$ff ; setup r17 for ddr setting
66
67 clear_000035: ; clear delay buffer
68 ; eliminates static when first switching to the delay setting
69
70 adiw r25:r24,$01 ; increment write register
71 adc r22,r18 ; increment write third byte
72 cpi r22,$04 ; check if full memory space has been cleared
73 breq cleardone_000035 ; continue until end of buffer reached
74 out portd,r24 ; set address
75 sts porth,r25
76 out portg,r22 ; pull ce low,we low,and set high bits of address
77 out ddra,r17 ; set porta as output for data write
78 out ddrc,r17 ; set portc as output for data write
79 out porta,r18 ; set data
80 out portc,r18 ; r18 is cleared above
81 sbi portg,portg2 ; pull we high to write
82 out ddra,r18 ; set porta as input for data lines
83 out ddrc,r18 ; set portc as input for data lines
84 rjmp clear_000035 ; continue clearing
85
86 cleardone_000035: ; reset registers
87
88 ldi r24,$00 ; initialize write register
89 ldi r25,$00
90 ldi r22,$00 ; setup write address high byte
91 ldi r28,$00 ; set read address to minimum delay
92 ldi r29,$fe
93 ldi r23,$07 ; setup read address high byte
94 clr r0 ; set buffer size to minimum
95 ldi r26,$01
96 clr r27
97 clr r12 ; set read address offset to minimum buffer size
98 ldi r16,$01
99 mov r13,r16
100 clr r21
101 clr r2 ; initialize data output registers
102 clr r3
103 clr r4
104 clr r5
105 clt ; clear t register to start with forward play
106 reti ; finish with initialization and wait for next interrupt
107
108 ; program starts here all but first time
109 ; this is the point the z-pointer is incremented to
110 ; initiate data transfer to codec
111 sbi portb,portb0 ; toggle slave select pin
112 out spdr,r3 ; send out left channel msb
113 cbi portb,portb0
114
115 wait1_000035: ; check if byte has been sent
116
117 in r17,spsr
118 sbrs r17,spif
119 rjmp wait1_000035
120 in r7,spdr ; recieve in left channel msb
121 out spdr,r2 ; send out left channel lsb
122
123 ;get left channel data from sram
124 out portg,r23 ; pull ce low, we high, and set high bits of register
125 out portd,r28 ; set address
126 sts porth,r29
127 adiw r29:r28,$01 ; increment read address
128 adc r23,r18 ; placed here for efficient use of setup time
129 andi r23,$03 ; mask off unsed bits
130 ori r23,$04 ; set we/ bit in high byte register
131 in r2,pina ; get data
132 in r3,pinc ; get data
133
134 wait2_000035: ; check if byte has been sent
135
136 in r17,spsr
137 sbrs r17,spif
138 rjmp wait2_000035
139 in r6,spdr ; recieve in left channel lsb
140 out spdr,r5 ; send out right channel msb
141
142 ;write left channel data to sram
143 out portd,r24 ; set address
144 sts porth,r25
145 out portg,r22 ; pull ce low,we low,and set high bits of address
146 ldi r17,$ff
147 out ddra,r17 ; set porta as output for data write
148 out ddrc,r17 ; set portc as output for data write
149 out porta,r6 ; set data
150 out portc,r7
151 sbi portg,portg2 ; pull we high to write
152 out ddra,r18 ; set porta as input for data lines
153 out ddrc,r18 ; set portc as input for data lines
154
155 wait3_000035: ; check if byte has been sent
156
157 in r17,spsr
158 sbrs r17,spif
159 rjmp wait3_000035
160 in r9,spdr ; recieve in right channel msb
161 out spdr,r4 ; send out right channel lsb
162
163 ;get right channel data from sram
164 out portg,r23 ; pull ce low, we high, and set high bits of register
165 out portd,r28 ; set address
166 sts porth,r29
167 adiw r25:r24,$01 ; increment write address
168 adc r22,r18 ; placed here to use setup time efficiently
169 andi r22,$03 ; mask off unsed bits
170 in r4,pina ; get data
171 in r5,pinc ; get data
172
173 wait4_000035: ; check if byte has been sent
174
175 in r17,spsr
176 sbrs r17,spif
177 rjmp wait4_000035
178 in r8,spdr ; recieve in left channel lsb
179
180 ;write right channel data to sram
181 out portd,r24 ; set address
182 sts porth,r25
183 out portg,r22 ; pull ce low,we low,and set high bits of address
184 ldi r17,$ff
185 out ddra,r17 ; set porta as output for data write
186 out ddrc,r17 ; set portc as output for data write
187 out porta,r8 ; set data
188 out portc,r9
189 sbi portg,portg2 ; pull we high to write
190 out ddra,r18 ; set porta as input for data lines
191 out ddrc,r18 ; set portc as input for data lines
192
193 ;increment write address to next sample position
194 adiw r25:r24,$01 ; increment write address
195 adc r22,r18 ; increment write third byte
196 andi r22,$03 ; mask off unsed bits
197 movw r29:r28,r25:r24 ; move write address to read address
198 mov r23,r22
199
200 ;calculate read offset
201 brtc increment_000035 ; move read address forward if in foward mode
202 ldi r16,$04 ; else move read address backwards by 2
203 add r12,r16 ; this requires incrementing the read offset by 4
204 adc r13,r18 ; r18 is cleared above
205 adc r21,r18
206 cp r12,r0 ; check if at bottom of buffer
207 cpc r13,r26
208 cpc r21,r27
209 brlo readadd_000035 ; load read address if not at bottom of buffer
210 sub r12,r16 ; halt playback for one sample
211 sbc r13,r18 ; reduces spike at transition
212 sbc r21,r18 ; r18 is cleared above
213 clt ; else clear t register to indicate forward motion after next sample
214
215 increment_000035: ; move read address forward by 4
216 ; moving read address forward requires reducing the read offset by 2
217 ldi r16,$02 ; subtract 2 from read offset
218 sub r12,r16
219 sbc r13,r18 ; r18 is cleared above
220 sbc r21,r18
221 brne readadd_000035 ; load read address if not at top of buffer
222 mov r12,r16 ; set offset to min and halt playback for one sample
223 set ; else set t register to start reversing on next sample
224
225 readadd_000035: ; add in read offset
226
227 sub r28,r12 ; subtract offset from read address
228 sbc r29,r13
229 sbc r23,r21
230 andi r23,$03 ; mask off unused bits
231 ori r23,$04 ; set we/ bit for reading
232
233 adcsample_000035: ; get buffer size from adc
234
235 lds r17,adcsra ; get adc control register
236 sbrs r17,adif ; check if adc conversion is complete
237 rjmp done_000035 ; skip adc sampling if not
238 lds r16,adcl ; get low byte adc value
239 lds r17,adch ; get high byte adc value
240 add r19,r16 ; accumulate adc samples
241 adc r10,r17
242 adc r11,r18 ; r18 is cleared above
243 ldi r17,$f7
244 sts adcsra,r17 ; clear interrupt flag
245 dec r14 ; countdown adc sample clock
246 brne done_000035 ; dont get buffer size till its been long enough
247 lsr r11 ; divide adc sample by 2
248 ror r10 ; as the max buffer size is only $020000
249 ror r19 ; as the buffer is read backwards half of the time
250 ldi r17,$01 ; check if adc value is less than $000100
251 cp r19,r18 ; r18 is cleared above
252 cpc r10,r17
253 cpc r11,r18
254 brsh deadband_000035 ; check if adc value changed enough to update delay
255 inc r10 ; set minimum delay to $000100 = 3ms
256 clr r19
257
258 deadband_000035: ; check for change in adc value
259
260 movw r17:r16,r11:r10 ; move adc sample to temporary register
261 mov r20,r19
262 sub r20,r0 ; find difference between adc sample and desired buffer size
263 sbc r16,r26
264 sbc r17,r27
265 brsh check_000035 ; check for deadband if positive
266 com r20 ; invert if negative
267 com r16 ; using ones complement as it is faster, and only has 1 bit error
268 com r17
269
270 check_000035: ; check if difference is greater than deadband
271
272 cpi r16,$01 ; check if difference is less than 1 lsb
273 cpc r17,r18 ; r18 cleared above
274 brlo empty_000035 ; do nothing if less than 1 lsb
275 movw r27:r26,r11:r10 ; move adc sample to delay time if large enough change
276 andi r19,$fc ; make sure buffer size is a multiple of 4
277 mov r0,r19
278
279 empty_000035: ; empty accumulation registers and finish off
280
281 clr r10 ; empty accumulation registers
282 clr r11
283 clr r19
284
285 switchsample_000035: ; check if at same function
286
287 lds r16,pinj ; get switch data
288 andi r16,$78 ; mask off rotary switch
289 lsr r16 ; adjust switch position to program memory location
290 lsr r16
291 ldi r17,$02
292 add r16,r17 ; move to jump register
293 cp r16,r31 ; check if location has changed
294 breq done_000035 ; finish off if no change
295 clr r30 ; reset jump register to new function
296 mov r31,r16
297
298 done_000035:
299
300 reti ; return to waiting
301