MICrODEC: Stock Functions
700ms Stereo Delay
This program performs a simple delay routine. It stores the incoming data from the codec, and plays back a delayed sample. The input data is stereo, and is taken from both the left and right channels. The output is also stereo, and is presented on both the left and right channels. This program only uses the first 16b of the SRAM address space. This reduces the total possible delay time, but also makes the math and data fetches much, much easier. Unless the full 6s (3s stereo) sample time is required, its best to only use the 16b address space.
The pot (MOD1) controls the delay time. It goes from 3ms to 700ms. MOD2 does nothing for this program. Most analog delay pedals change the rate at which data is being clocked in and out, to change the delay time. This gives a smooth change in audio when the delay is varied, although it also changes the frequency resolution of the signal. To change the delay time in the MICrODEC, the easiest way is to just jump to the new delay time, although this gives an audible pop as the data abruptly switches. In this program, we increment the delay time (or decrement it) at a rate of one sample per sample, until it matches what you want it to be. This gives the effect of frequency doubling (or reversing) during delay transitions, which can be interesting sonically.
1 ; program: delay-16b-pot.asm
2 ; UID = 000003 - unique id to eliminate conflicts between variables
3 ; 16b address space (.7s delay time)
4 ; stereo data
5 ; pot (MOD1) controlled delay time (3ms - 700ms)
6
7 ; program overview
8 ;
9 ; data is read in from memory and written out the codec at the same time
10 ; new data is written to the memory from the codec. ADC0 (MOD1) is read
11 ; and averaged over 256 samples to reduce jitter. this value is subtracted
12 ; from the write address to create the desired read address. if the actual
13 ; read address doesnt match the desired read address, it is either
14 ; incremented or decremented by one sample each sample period until it
15 ; matches. this reduces noise during delay time transitions.
16
17 ; register usage - may be redefined in other sections
18 ;
19 ; r0
20 ; r1
21 ; r2 left lsb out
22 ; r3 left msb out
23 ; r4 right lsb out
24 ; r5 right msb out
25 ; r6 left lsb in
26 ; r7 left msb in
27 ; r8 right lsb in
28 ; r9 right msb in
29 ; r10 adc accumulator fractional byte
30 ; r11 adc accumulator lsb
31 ; r12 actual delay lsb
32 ; r13 actual delay msb
33 ; r14 adc sample counter
34 ; r15 switch sample counter
35 ; r16 temporary swap register
36 ; r17 temporary swap register
37 ; r18
38 ; r19 adc accumulator msb
39 ; r20
40 ; r21
41 ; r22 null register
42 ; r23 read address third byte
43 ; r24 write address lsb
44 ; r25 write address msb
45 ; r26 desired delay lsb
46 ; r27 desired delay msb
47 ; r28 read address lsb
48 ; r29 read address msb
49 ; r30 jump location for interrupt lsb
50 ; r31 jump location for interrupt msb
51 ; t
52
53 ;program starts here first time
54 ldi r30,$25 ; set jump location to program start
55 clr r24 ; clear write register
56 clr r25
57 ldi r22,$00 ; setup write address high byte
58 clr r18 ; setup r18 as null register for carry addition and ddr setting
59 ldi r17,$ff ; setup r17 for ddr setting
60
61 clear_000003: ; clear delay buffer
62 ; eliminates static when first switching to the delay setting
63
64 adiw r25:r24,$01 ; increment write register
65 adc r22,r18 ; increment write third byte
66 cpi r22,$01 ; check if 16b memory space has been cleared
67 breq cleardone_000003 ; continue until end of buffer reached
68 out portd,r24 ; set address
69 sts porth,r25
70 out portg,r22 ; pull ce low,we low,and set high bits of address
71 out ddra,r17 ; set porta as output for data write
72 out ddrc,r17 ; set portc as output for data write
73 out porta,r18 ; set data
74 out portc,r18 ; r18 is cleared above
75 sbi portg,portg2 ; pull we high to write
76 out ddra,r18 ; set porta as input for data lines
77 out ddrc,r18 ; set portc as input for data lines
78 rjmp clear_000003 ; continue clearing
79
80 cleardone_000003: ; reset registers
81
82 clr r24 ; clear write register
83 clr r25
84 ldi r22,$00 ; setup null register
85 clr r28 ; set read address to minimum delay
86 ldi r29,$ff
87 ldi r23,$04 ; setup read address high byte
88 clr r21 ; set actual delay time to minimum delay
89 ldi r16,$01
90 mov r13,r16
91 clr r12
92 clr r2 ; initialize data output registers
93 clr r3
94 clr r4
95 clr r5
96 reti ; finish with initialization and wait for next interrupt
97
98 ;program starts here every time but first
99 ;initiate data transfer to codec
100 sbi portb,portb0 ; toggle slave select pin
101 out spdr,r3 ; send out left channel msb
102 cbi portb,portb0
103
104 ;increment sram address
105 adiw r25:r24,$01 ; increment write address
106 adiw r29:r28,$01 ; increment read address
107
108 wait1_000003: ; check if byte has been sent
109
110 in r17,spsr
111 sbrs r17,spif
112 rjmp wait1_000003
113 in r7,spdr ; recieve in left channel msb
114 out spdr,r2 ; send out left channel lsb
115
116 ;get left channel data from sram
117 out portd,r28 ; set address
118 sts porth,r29
119 nop ; wait input latch time of 2 clock cycles
120 nop ; wait input latch time of 2 clock cycles
121 in r2,pina ; get data
122 in r3,pinc ; get data
123 adiw r29:r28,$01 ; increment read address
124
125 wait2_000003: ; check if byte has been sent
126
127 in r17,spsr
128 sbrs r17,spif
129 rjmp wait2_000003
130 in r6,spdr ; recieve in left channel lsb
131 out spdr,r5 ; send out right channel msb
132
133 ;write left channel data to sram
134 out portd,r24 ; set address
135 sts porth,r25
136 out portg,r22 ; pull ce low,we low,and set high bits of address
137 ldi r17,$ff
138 out ddra,r17 ; set porta as output for data write
139 out ddrc,r17 ; set portc as output for data write
140 out porta,r6 ; set data
141 out portc,r7
142 sbi portg,portg2 ; pull we high to write
143 out ddra,r22 ; set porta as input for data lines
144 out ddrc,r22 ; set portc as input for data lines
145
146 wait3_000003: ; check if byte has been sent
147
148 in r17,spsr
149 sbrs r17,spif
150 rjmp wait3_000003
151 in r9,spdr ; recieve in right channel msb
152 out spdr,r4 ; send out right channel lsb
153
154 ;get right channel data from sram
155 out portd,r28 ; set address
156 sts porth,r29
157 nop ; wait input latch time of 2 clock cycles
158 nop ; wait input latch time of 2 clock cycles
159 in r4,pina ; get data
160 in r5,pinc ; get data
161 adiw r25:r24,$01 ; increment write address
162
163 wait4_000003: ; check if byte has been sent
164
165 in r17,spsr
166 sbrs r17,spif
167 rjmp wait4_000003
168 in r8,spdr ; recieve in left channel lsb
169
170 ;write right channel data to sram
171 out portd,r24 ; set address
172 sts porth,r25
173 out portg,r22 ; pull ce low,we low,and set high bits of address
174 ldi r17,$ff
175 out ddra,r17 ; set porta as output for data write
176 out ddrc,r17 ; set portc as output for data write
177 out porta,r8 ; set data
178 out portc,r9
179 sbi portg,portg2 ; pull we high to write
180 out ddra,r22 ; set porta as input for data lines
181 out ddrc,r22 ; set portc as input for data lines
182
183 ;get delay settings
184 lds r17,adcsra ; get adc control register
185 sbrs r17,adif ; check if adc conversion is complete
186 rjmp shift_000003 ; skip adc sampling
187 lds r16,adcl ; get low byte adc value
188 lds r17,adch ; get high byte adc value
189 add r10,r16 ; accumulate adc samples
190 adc r11,r17
191 adc r19,r22 ; r22 is cleared above
192 ldi r17,$f7
193 sts adcsra,r17 ; clear interrupt flag
194 dec r14 ; countdown adc sample clock
195 brne shift_000003 ; get delay time if its been long enough
196 lsr r19 ; divide adc sample by 4
197 ror r11 ; makes adc value a 16b number
198 ror r10
199 lsr r19
200 ror r11
201 ror r10
202 ldi r16,$01 ; check if delay is below minimum
203 cp r10,r22 ; r22 is cleared above
204 cpc r11,r16
205 brsh deadband_000003 ; check if adc value changed enough to update delay
206 clr r10 ; set minimum delay to $0100 = 3ms
207 mov r11,r16
208
209 deadband_000003: ; set the low value of the delay
210
211 movw r17:r16,r11:r10 ; move adc sample to temporary register
212 sbc r16,r26 ; find difference between adc sample and desired delay time
213 sbc r17,r27
214 brsh check_000003 ; check for deadband if positive
215 neg r16 ; invert if negative
216 adc r17,r22 ; r22 is cleared above
217 neg r17 ; converts ones complement to twos complement
218
219 check_000003: ; check if difference is greater than deadband
220
221 cpi r16,$40 ; check if difference is less than 1 lsb of adc
222 cpc r17,r22 ; r22 cleared above
223 brlo empty_000003 ; do nothing if less than 1 lsb
224 movw r27:r26,r11:r10 ; move adc sample to delay time if large enough change
225 andi r26,$fc ; make sure delay time is a multiple of 4
226
227 empty_000003: ; empty accumulation registers and finish off
228
229 clr r10 ; empty accumulation registers
230 clr r11
231 clr r19
232
233 shift_000003: ; check if delay time is correct
234
235 cp r26,r12 ; compare desired delay to actual delay
236 cpc r27,r13
237 breq switchsample_000003 ; do nothing if the same
238 brlo indexdown_000003
239 ldi r17,$04 ; increment delay register (4 is used for stereo data)
240 add r12,r17 ; this makes it play forward at double speed
241 adc r13,r22 ; until desired delay is reached
242 rjmp switchsample_000003
243
244 indexdown_000003:
245
246 ldi r17,$02 ; decrement delay register (2 is used for stereo data)
247 sub r12,r17 ; this makes is play backwards until desired delay is reached
248 sbc r13,r22 ; r22 is cleared above
249
250 switchsample_000003: ; check state of rotary switch
251
252 dec r15 ; countdown switch counter
253 brne done_000003 ; finish off if not ready yet
254 lds r16,pinj ; get switch data
255 andi r16,$78 ; mask off rotary switch
256 lsr r16 ; adjust switch position to program memory location
257 lsr r16
258 ldi r17,$02
259 add r16,r17
260 cp r16,r31 ; check if location has changed
261 breq done_000003 ; finish off if no change
262 clr r30 ; reset jump register to new function if changed
263 mov r31,r16
264
265 done_000003:
266
267 movw r29:r28,r25:r24 ; move write address to read destination register
268 sub r28,r12 ; remove delay time
269 sbc r29,r13
270 reti ; return to waiting
271