← Revision 3 as of 2010-07-18 03:12:37
Size: 16624
Comment:
|
← Revision 4 as of 2010-07-18 03:19:10 →
Size: 16649
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 63: | Line 63: |
; - all data we are saving and reading back (like our delay audio) travels over ports A and C ; - I am going to try to notate |
; - all data we are saving and reading back (like our delay audio) travels over ports A and C |
Line 122: | Line 122: |
nop ; read address msb hits the port, now wait for (1) nop ; a latch time of two cycles... (2) |
nop ; read address msb hits the port, now wait for (1) nop ; a latch time of two cycles... (2) |
Line 131: | Line 131: |
; ### now we've got a little time to kill, so... | ; now we've got a little time to kill, so... |
Line 245: | Line 245: |
; ### end of wait4, let's get our dry audio in in r8, spdr ; that's the right channel lsb |
; ### end of wait4, more new data! in r8, spdr ; bring in right channel lsb |
Line 278: | Line 278: |
dec r15 ; well, let's do a little debouncing: | dec r15 ; well, let's do a little debouncing anyway |
Line 280: | Line 280: |
; if r15 was not zero after the last operation, it will branch us to adjust_UID | ; if r15 was not zero after the last operation, it will branch us to adjust_UID |
DelayTutorial.asm
[Discussion of code elements, needed revision etc, can go here]
1 ; ****************************************************************************
2 ; * program: delay-16b-rotary.asm *
3 ; * UID = Tutorial - unique id to eliminate conflicts between variables, *
4 ; * replace each instance of UID in the code with this unique id. *
5 ; * 16b address space (.7s delay time) *
6 ; * stereo data *
7 ; * pot controlled delay time (0s - .7s) *
8 ; ****************************************************************************
9 ; * *
10 ; * PROGRAM OVERVIEW *
11 ; * *
12 ; * data is read in from memory and written to the codec at the same time *
13 ; * new data is written to the memory from the codec. the rotary encoder *
14 ; * increments or decrements the read address, adjusting the delay time. *
15 ; * *
16 ; * register usage - may be redefined in other sections *
17 ; * *
18 ; * r0 *
19 ; * r1 *
20 ; * r2 left lsb out *
21 ; * r3 left msb out *
22 ; * r4 right lsb out *
23 ; * r5 right msb out *
24 ; * r6 left lsb in *
25 ; * r7 left msb in *
26 ; * r8 right lsb in *
27 ; * r9 right msb in *
28 ; * r10 *
29 ; * r11 *
30 ; * r12 desired delay lsb *
31 ; * r13 desired delay msb *
32 ; * r14 *
33 ; * r15 switch sample counter *
34 ; * r16 temporary swap register *
35 ; * r17 temporary swap register *
36 ; * r18 *
37 ; * r19 *
38 ; * r20 *
39 ; * r21 *
40 ; * r22 write address third byte/null register *
41 ; * r23 *
42 ; * r24 write address lsb *
43 ; * r25 write address msb *
44 ; * r26 actual delay lsb *
45 ; * r27 actual delay msb *
46 ; * r28 read address lsb *
47 ; * r29 read address msb *
48 ; * r30 jump location for interrupt lsb *
49 ; * r31 jump location for interrupt msb *
50 ; ****************************************************************************
51
52
53 ; * NOTES: - all unprocessed (dry) raw data comes in off of the SPI port, via spdr
54 ; - all processed (wet) data goes out over the SPI port, also via spdr
55 ; - all external memory addressing happens over ports D and H
56 ; - all data we are saving and reading back (like our delay audio) travels over ports A and C
57
58
59
60
61
62 ; **********************
63 ; **** PROGRAM START
64 ; **********************
65
66 ; initiate data transfer to codec
67
68 sbi portb, portb0 ; set bit portb0 (aka DACLRC aka DAC sample rate left/right clock)
69 ;
70 ; **NOTE: from WM8731 data sheet, page 36:
71 ; "DACLRC is an alignment clock that controls whether Left or Right channel
72 ; data is present on DACTAT"
73
74 ; (now on SPI - LEFT MSB) *********************************************************************************************
75
76 out spdr, r3 ; send out processed left channel msb (or whatever's currently in r3) to SPI data register
77 cbi portb, portb0 ; clear DACLRC
78
79 adiw r25:r24, 0x01 ; increment write address pointer by 0x01
80 adiw r29:r28, 0x01 ; increment read address pointer by 0x01
81 ldi r22, 0x00 ; setup write high byte with null
82
83
84 ; **********************
85 ; **** wait1
86 ; **********************
87
88 wait1_UID: ; wait to see if processed left channel msb has been sent
89
90 in r17, spsr ; move spi status register to r17 so we can look at it
91 sbrs r17, spif ; skip next instruction if the SPIF (spi interrupt flag) bit is set
92 ; **NOTE: from atmega3250P data sheet, page 162:
93 ; "When a serial transfer is complete, the SPIF flag is set"
94 rjmp wait1_UID ; aka: loop until SPIF is set
95 ; and then...
96
97 ; ### after wait1, new spi data ready
98
99 in r7, spdr ; move spi data register into r7 (remember spdr is read/write, page 162)
100 ; this moves the incoming (dry) left channel msb to r7
101
102 ; (end of wet/dry left msb transfer) ***********************************************************************************
103
104 ; (now on SPI - LEFT LSB) ***********************************************************************************
105
106 out spdr, r2 ; send the processed (wet) left lsb out
107
108 ; ### retrieve stored left channel data from SRAM:
109
110 out portd, r28 ; move read address lsb pointer to portd (see schematic)
111 sts porth, r29 ; move read address msb pointer to portH
112 ; **NOTE: - this is a special instruction because the I/O portH register is wayyy up there in the sram
113 ; - 'out' completes in one cycle, 'sts' completes in two
114
115 nop ; read address msb hits the port, now wait for (1)
116 nop ; a latch time of two cycles... (2)
117
118 ; DING! your data is ready, please pick it up!
119 in r2, pina ; (see schematic) D0-7, aka lsb, is on port A, now stored in r2
120 in r3, pinc ; and D8-15, aka msb, is on port C, now stored in r3
121
122 ; ### left channel SRAM retrieve completed
123
124 ; now we've got a little time to kill, so...
125 adiw r29:r28, 0x01 ; increment read address pointer by 1
126
127
128 ; **********************
129 ; **** wait2
130 ; **********************
131
132 wait2_UID: ; wait to see if wet left channel lsb has been sent
133
134 in r17, spsr ; spi status reg. to r17 (looking familiar?)
135 sbrs r17, spif ; skip next if SPIF bit not set...
136 rjmp wait2_UID ; loop until SPIF set
137
138 ; **NOTE: and now a couple of words about rjmp:
139 ; - it can only move within 2k of memory (ie, can't jump all the way to the start, or end, of a long program)
140 ; - it doesn't do anything to the stack (so if it loops a thousand times, the stack isn't going to overflow)
141 ; - it takes two cycles
142
143 ; ### after wait2 is finished, new spi data ready
144
145 in r6, spdr ; receive in dry left channel lsb
146 ; **NOTE: that gives us both bytes of the incoming left channel, and both wet bytes have been sent
147 ; we can now move on to the right channel
148
149 ; (end of wet/dry left lsb transfer) ************************************************************************************
150
151 ; (now on SPI - RIGHT MSB) ************************************************************************************
152
153 out spdr, r5 ; send out (wet) right msb
154
155 ; ### writing (dry) left channel to SRAM:
156 out portd, r24 ; update data address ports to reflect where we want to write
157 sts porth, r25 ; remember 'out' and 'sts'?
158
159 out portg, r22 ; woah, portG? what's this? Check out the SRAM data sheet and the schematic:
160 ; r22 is currently 0x00, so we are pulling CE and WE low, and writing our high address bits to zero
161 ; CE (chip enable) and WE (write enable) are asserted low
162
163 ; **NOTE: from AS7C4098 data sheet, page 2:
164 ; "Data on input pins io1-io16 is written on the rising edge of WE..."
165 ; "To avoid bus contention, external devices should drio i/o pins only after
166 ; outputs have been disabled with OE (output enable) or WE"
167 ; "A read cycle is accomplished by asserting OE and CE, with WE high."
168
169 ldi r17, 0xFF ; prepare a salad of ones
170 out ddra, r17 ; send them to the portA direction register
171 out ddrC, r17 ; and to the portC direction register
172 ; (see ATmega3250P data sheet, page 65, 'Switching Between Input and Output')
173
174 out porta, r6 ; with these two 'out' instructions
175 out portc, r7 ; we send left channel dry data directly to the sram
176
177
178 sbi portg, portg2 ; and as soon as we pull WE (write enable) on portG_2 high,
179 ; zzztt! a single audio sample is written into memory, just like that.
180
181
182
183 ; ### left channel SRAM write completed
184
185
186 out ddra, r22 ; now, we happen to know that r22 contains a bunch of zeros
187 out ddrc, r22 ; so we can use that register to set ports A and C back to an input state.
188
189
190
191
192 ; **********************
193 ; **** wait3
194 ; **********************
195
196 wait3_UID: ; meanwhile, back at the codec, we are still transferring the right channel lsb
197
198 in r17, spsr ; check out the spsr, check out the spif,
199 sbrs r17, spif ; we know what we're doing here now, right?
200 rjmp wait3_UID ; loop until transfer completed
201
202 ; ### end of wait3, new data ready!
203
204 in r9, spdr ; recieve in (dry) right channel msb
205
206 ; (end of wet/dry right msb transfer) ***********************************************************************************
207
208 ; (now on SPI - RIGHT LSB) ***********************************************************************************
209
210 out spdr, r4 ; send out (wet) right channel lsb
211
212 ; ### retrieve stored right channel data from SRAM
213 out portd, r28 ; set up the address we want to read from
214 sts porth, r29 ; on ports d and h
215
216 nop ; killing time again...
217 nop ; two cycles, while the SRAM latches the address
218
219 ; and once more, ding! our data is now waiting on the SRAM data lines
220 in r4, pina ; right lsb
221 in r5, pinc ; right msb (this is audio data we saved in the past)
222
223 ; ### right channel SRAM data retrieval completed
224
225 adiw r25:r24, 0x01 ; increment the write address (we're going to be using that pointer next)
226
227
228 ; **********************
229 ; **** wait4
230 ; **********************
231
232 wait4_UID: ; checking up on that SPI transfer
233
234 in r17, spsr
235 sbrs r17, spif
236 rjmp wait4_UID ; loop until SPIF is set
237
238 ; ### end of wait4, more new data!
239 in r8, spdr ; bring in right channel lsb
240
241 ; (end of wet/dry right lsb transfer) ***********************************************************************************
242 ; now that we have both bytes of the right channel dry audio, we can store it in the SRAM
243
244 ; ### writing (dry) right channel to SRAM
245
246 out portd, r24 ; give the sram the write address, lsb
247 sts porth, r25 ; now msb
248
249 out portg, r22 ; pull WE low, (CE is already low, WE was high for read operations)
250 ldi r17, 0xFF ; prepare a bevy of ones
251 out ddra, r17 ; set porta as output
252 out ddrc, r17 ; set portc as output
253 out porta, r8 ; put the data on the ports, lsb
254 out portc, r9 ; msb
255 sbi portg, portg2 ; zzzt! pull WE high and write the data
256
257 out ddra, r22 ; reconfigure porta as input
258 out ddrc, r22 ; reconfigure portc as input
259
260
261 ; **********************************************************************************
262 ; **** check rotary encoder and adjust delay time
263 ; **********************************************************************************
264 ; * The rotary encoder is externally debounced, so we don't have to do that here.
265 ; * You'll see it in the schematic labeled MOD2 on portJ0, portJ1, and portJ2.
266 ; *
267 ; * The encoder's pin1 is sampled on a transition from high to low on pin0.
268 ; * if pin1 is high, a left turn occured, if pin1 is low, a right turn occured.
269 ; **********************************************************************************
270
271 dec r15 ; well, let's do a little debouncing anyway
272 brne adjust_UID ; brne checks the Z register,
273 ; if r15 was not zero after the last operation, it will branch us to adjust_UID
274
275 ldi r17, 0x40 ; prepare a constant in r17
276 mov r15, r17 ; put 0x40 in the sample freq bin to catch all rising edges (results in 1.5ms sampletime)
277 lds r17, pinj ; move port J data into r17
278 sbrs r17, PINJ0 ; skip next if PINJ0 is set
279 rjmp edgecheck_UID ; if it's not set, is it a falling edge?
280
281 clt ; clear T reg (in SREG)
282 rjmp switchsample_UID ; done looking at mod2, look at the program selector
283
284 ; **********************
285 ; **** edgecheck
286 ; **********************
287
288 edgecheck_UID: ; checks for falling edge
289 brts switchsample_UID ; if the T flag in SREG is set, assume the edge was already detected
290 set ; otherwise set the T flag
291 sbrs r17, PINJ1 ; check if PINJ1 is high
292 rjmp upcount_UID ; if PINJ0 has just gone low and PINJ1 is low, a right turn has transpired
293 ; upcount will therefore increase the delay
294 ; otherwise, PINJ1 is high and a left turn has transpired, so we should decrease the delay
295 ; **** downcount
296 ldi r17, 0x01 ; load our decrement amount into r17 (0x01 = 256 samples = 0.006s)
297 sub r13, r17 ; decrement delay MSB
298
299 rjmp switchsample_UID ; done looking at mod2, look at the program selector
300
301 ; **** upcount
302 upcount_UID: ; increment delay register
303 ldi r17, 0x01 ; load increment amount into r17
304 add r13, r17 ; increment MSB
305
306
307 ; **********************
308 ; **** switchsample
309 ; **********************
310
311 switchsample_UID: ; sample the program select dial
312
313 lds r31, pinj ; put switch data into jump location MSB reg
314 andi r31, 0x78 ; mask off rotary encoder 0b01111000
315 ldi r17, 0x02 ; 0x02 into r17
316 lsr r31 ; shift r31 to the right
317 lsr r31 ; shift again
318 add r31, r17 ; convert switch position data to program memory location
319
320
321 ; **********************
322 ; **** adjust
323 ; **********************
324
325 adjust_UID: ; since we've only changed the desired delay in the previous section, we need to implement that delay
326 ; this checks to see if the delay time is correct,
327 ; and if it's not it makes an effort to move slightly closer to the correct delay
328
329 andi r26, 0xFE ; is the delay time even?
330 cp r26, r22 ; compare actual delay lsb to zero
331 cpc r27, r13 ; compare with carry actual delay msb with desired delay msb
332 breq done_UID ; If equal, head to done, yay!
333 brsh indexdown_UID ; If the same or higher, branch to indexdown
334 ; otherwise, we can assume it is too low
335 ; **** indexup
336 adiw r27:r26, 0x04 ; so increment delay register by 0x04
337 rjmp done_UID ; and head to the end
338
339 ; **** indexdown
340 indexdown_UID:
341 sbiw r27:r26, 0x02 ; decrement delay reg by 0x02
342
343
344
345 ; **********************
346 ; **** done
347 ; **********************
348
349 done_UID: ; It's been a long hard row to hoe, but we did it!
350 ; oh wait, what? I'm going to have to do it again? from the beginning?
351 ; but I still need to get my pointers all lined up!
352
353 movw r29:r28, r25:r24 ; sync write destination and read address
354 sub r28, r26 ; now subtract by the delay in samples (first lsb)
355 sbc r29, r27 ; subtract msb with carry from previous
356
357 reti ; return from interrupt so we can get back to our idling
358