Mercurial > hg > beaglert
comparison pru_rtaudio.p @ 0:8a575ba3ab52
Initial commit.
author | andrewm |
---|---|
date | Fri, 31 Oct 2014 19:10:17 +0100 |
parents | |
children | a6beeba3a648 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:8a575ba3ab52 |
---|---|
1 .origin 0 | |
2 .entrypoint START | |
3 | |
4 #define DBOX_CAPE // Define this to use new cape hardware | |
5 | |
6 #define CLOCK_BASE 0x44E00000 | |
7 #define CLOCK_SPI0 0x4C | |
8 #define CLOCK_SPI1 0x50 | |
9 #define CLOCK_L4LS 0x60 | |
10 | |
11 #define SPI0_BASE 0x48030100 | |
12 #define SPI1_BASE 0x481A0100 | |
13 #define SPI_BASE SPI0_BASE | |
14 | |
15 #define SPI_SYSCONFIG 0x10 | |
16 #define SPI_SYSSTATUS 0x14 | |
17 #define SPI_MODULCTRL 0x28 | |
18 #define SPI_CH0CONF 0x2C | |
19 #define SPI_CH0STAT 0x30 | |
20 #define SPI_CH0CTRL 0x34 | |
21 #define SPI_CH0TX 0x38 | |
22 #define SPI_CH0RX 0x3C | |
23 #define SPI_CH1CONF 0x40 | |
24 #define SPI_CH1STAT 0x44 | |
25 #define SPI_CH1CTRL 0x48 | |
26 #define SPI_CH1TX 0x4C | |
27 #define SPI_CH1RX 0x50 | |
28 | |
29 #define GPIO0 0x44E07000 | |
30 #define GPIO1 0x4804C000 | |
31 #define GPIO_CLEARDATAOUT 0x190 | |
32 #define GPIO_SETDATAOUT 0x194 | |
33 | |
34 #define PRU0_ARM_INTERRUPT 19 | |
35 | |
36 #define C_ADC_DAC_MEM C24 // PRU0 mem | |
37 #ifdef DBOX_CAPE | |
38 #define DAC_GPIO GPIO0 | |
39 #define DAC_CS_PIN (1<<5) // GPIO0:5 = P9 pin 17 | |
40 #else | |
41 #define DAC_GPIO GPIO1 | |
42 #define DAC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 | |
43 #endif | |
44 #define DAC_TRM 0 // SPI transmit and receive | |
45 #define DAC_WL 32 // Word length | |
46 #define DAC_CLK_MODE 1 // SPI mode | |
47 #define DAC_CLK_DIV 1 // Clock divider (48MHz / 2^n) | |
48 #define DAC_DPE 1 // d0 = receive, d1 = transmit | |
49 | |
50 #define AD5668_COMMAND_OFFSET 24 | |
51 #define AD5668_ADDRESS_OFFSET 20 | |
52 #define AD5668_DATA_OFFSET 4 | |
53 #define AD5668_REF_OFFSET 0 | |
54 | |
55 #ifdef DBOX_CAPE | |
56 #define ADC_GPIO GPIO1 | |
57 #define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 | |
58 #else | |
59 #define ADC_GPIO GPIO1 | |
60 #define ADC_CS_PIN (1<<17) // GPIO1:17 = P9 pin 23 | |
61 #endif | |
62 #define ADC_TRM 0 // SPI transmit and receive | |
63 #define ADC_WL 16 // Word length | |
64 #define ADC_CLK_MODE 0 // SPI mode | |
65 #define ADC_CLK_DIV 1 // Clock divider (48MHz / 2^n) | |
66 #define ADC_DPE 1 // d0 = receive, d1 = transmit | |
67 | |
68 #define AD7699_CFG_MASK 0xF120 // Mask for config update, unipolar, full BW | |
69 #define AD7699_CHANNEL_OFFSET 9 // 7 bits offset of a 14-bit left-justified word | |
70 #define AD7699_SEQ_OFFSET 3 // sequencer (0 = disable, 3 = scan all) | |
71 | |
72 #define SHARED_COMM_MEM_BASE 0x00010000 // Location where comm flags are written | |
73 #define COMM_SHOULD_STOP 0 // Set to be nonzero when loop should stop | |
74 #define COMM_CURRENT_BUFFER 4 // Which buffer we are on | |
75 #define COMM_BUFFER_FRAMES 8 // How many frames per buffer | |
76 #define COMM_SHOULD_SYNC 12 // Whether to synchronise to an external clock | |
77 #define COMM_SYNC_ADDRESS 16 // Which memory address to find the GPIO on | |
78 #define COMM_SYNC_PIN_MASK 20 // Which pin to read for the sync | |
79 #define COMM_LED_ADDRESS 24 // Which memory address to find the status LED on | |
80 #define COMM_LED_PIN_MASK 28 // Which pin to write to change LED | |
81 #define COMM_FRAME_COUNT 32 // How many frames have elapse since beginning | |
82 #define COMM_USE_SPI 36 // Whether or not to use SPI ADC and DAC | |
83 | |
84 #define MCASP0_BASE 0x48038000 | |
85 #define MCASP1_BASE 0x4803C000 | |
86 | |
87 #define MCASP_PWRIDLESYSCONFIG 0x04 | |
88 #define MCASP_PFUNC 0x10 | |
89 #define MCASP_PDIR 0x14 | |
90 #define MCASP_PDOUT 0x18 | |
91 #define MCASP_PDSET 0x1C | |
92 #define MCASP_PDIN 0x1C | |
93 #define MCASP_PDCLR 0x20 | |
94 #define MCASP_GBLCTL 0x44 | |
95 #define MCASP_AMUTE 0x48 | |
96 #define MCASP_DLBCTL 0x4C | |
97 #define MCASP_DITCTL 0x50 | |
98 #define MCASP_RGBLCTL 0x60 | |
99 #define MCASP_RMASK 0x64 | |
100 #define MCASP_RFMT 0x68 | |
101 #define MCASP_AFSRCTL 0x6C | |
102 #define MCASP_ACLKRCTL 0x70 | |
103 #define MCASP_AHCLKRCTL 0x74 | |
104 #define MCASP_RTDM 0x78 | |
105 #define MCASP_RINTCTL 0x7C | |
106 #define MCASP_RSTAT 0x80 | |
107 #define MCASP_RSLOT 0x84 | |
108 #define MCASP_RCLKCHK 0x88 | |
109 #define MCASP_REVTCTL 0x8C | |
110 #define MCASP_XGBLCTL 0xA0 | |
111 #define MCASP_XMASK 0xA4 | |
112 #define MCASP_XFMT 0xA8 | |
113 #define MCASP_AFSXCTL 0xAC | |
114 #define MCASP_ACLKXCTL 0xB0 | |
115 #define MCASP_AHCLKXCTL 0xB4 | |
116 #define MCASP_XTDM 0xB8 | |
117 #define MCASP_XINTCTL 0xBC | |
118 #define MCASP_XSTAT 0xC0 | |
119 #define MCASP_XSLOT 0xC4 | |
120 #define MCASP_XCLKCHK 0xC8 | |
121 #define MCASP_XEVTCTL 0xCC | |
122 #define MCASP_SRCTL0 0x180 | |
123 #define MCASP_SRCTL1 0x184 | |
124 #define MCASP_SRCTL2 0x188 | |
125 #define MCASP_SRCTL3 0x18C | |
126 #define MCASP_SRCTL4 0x190 | |
127 #define MCASP_SRCTL5 0x194 | |
128 #define MCASP_XBUF0 0x200 | |
129 #define MCASP_XBUF1 0x204 | |
130 #define MCASP_XBUF2 0x208 | |
131 #define MCASP_XBUF3 0x20C | |
132 #define MCASP_XBUF4 0x210 | |
133 #define MCASP_XBUF5 0x214 | |
134 #define MCASP_RBUF0 0x280 | |
135 #define MCASP_RBUF1 0x284 | |
136 #define MCASP_RBUF2 0x288 | |
137 #define MCASP_RBUF3 0x28C | |
138 #define MCASP_RBUF4 0x290 | |
139 #define MCASP_RBUF5 0x294 | |
140 #define MCASP_WFIFOCTL 0x1000 | |
141 #define MCASP_WFIFOSTS 0x1004 | |
142 #define MCASP_RFIFOCTL 0x1008 | |
143 #define MCASP_RFIFOSTS 0x100C | |
144 | |
145 #define MCASP_XSTAT_XDATA_BIT 5 // Bit to test for transmit ready | |
146 #define MCASP_RSTAT_RDATA_BIT 5 // Bit to test for receive ready | |
147 | |
148 // Constants used for this particular audio setup | |
149 #define MCASP_BASE MCASP0_BASE | |
150 #ifdef DBOX_CAPE | |
151 #define MCASP_SRCTL_X MCASP_SRCTL2 // Ser. 2 is transmitter | |
152 #define MCASP_SRCTL_R MCASP_SRCTL0 // Ser. 0 is receiver | |
153 #define MCASP_XBUF MCASP_XBUF2 | |
154 #define MCASP_RBUF MCASP_RBUF0 | |
155 #else | |
156 #define MCASP_SRCTL_X MCASP_SRCTL3 // Ser. 3 is transmitter | |
157 #define MCASP_SRCTL_R MCASP_SRCTL2 // Ser. 2 is receiver | |
158 #define MCASP_XBUF MCASP_XBUF3 | |
159 #define MCASP_RBUF MCASP_RBUF2 | |
160 #endif | |
161 | |
162 #define MCASP_PIN_AFSX (1 << 28) | |
163 #define MCASP_PIN_AHCLKX (1 << 27) | |
164 #define MCASP_PIN_ACLKX (1 << 26) | |
165 #define MCASP_PIN_AMUTE (1 << 25) // Also, 0 to 3 are XFR0 to XFR3 | |
166 | |
167 #ifdef DBOX_CAPE | |
168 #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs | |
169 #else | |
170 #define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs | |
171 #endif | |
172 | |
173 #define MCASP_DATA_MASK 0xFFFF // 16 bit data | |
174 #define MCASP_DATA_FORMAT 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits | |
175 | |
176 #define C_MCASP_MEM C28 // Shared PRU mem | |
177 | |
178 // Flags for the flags register | |
179 #define FLAG_BIT_BUFFER1 0 | |
180 #define FLAG_BIT_USE_SPI 1 | |
181 | |
182 // Registers used throughout | |
183 | |
184 // r1, r2, r3 are used for temporary storage | |
185 #define reg_frame_current r10 // Current frame count in SPI ADC/DAC transfer | |
186 #define reg_frame_total r11 // Total frame count for SPI ADC/DAC | |
187 #define reg_dac_data r12 // Current dword for SPI DAC | |
188 #define reg_adc_data r13 // Current dword for SPI ADC | |
189 #define reg_mcasp_dac_data r14 // Current dword for McASP DAC | |
190 #define reg_mcasp_adc_data r15 // Current dword for McASP ADC | |
191 #define reg_dac_buf0 r16 // Start pointer to SPI DAC buffer 0 | |
192 #define reg_dac_buf1 r17 // Start pointer to SPI DAC buffer 1 | |
193 #define reg_dac_current r18 // Pointer to current storage location of SPI DAC | |
194 #define reg_adc_current r19 // Pointer to current storage location of SPI ADC | |
195 #define reg_mcasp_buf0 r20 // Start pointer to McASP DAC buffer 0 | |
196 #define reg_mcasp_buf1 r21 // Start pointer to McASP DAC buffer 1 | |
197 #define reg_mcasp_dac_current r22 // Pointer to current storage location of McASP DAC | |
198 #define reg_mcasp_adc_current r23 // Pointer to current storage location of McASP ADC | |
199 #define reg_flags r24 // Buffer ID (0 and 1) and other flags | |
200 #define reg_comm_addr r25 // Memory address for communicating with ARM | |
201 #define reg_spi_addr r26 // Base address for SPI | |
202 // r27, r28 used in macros | |
203 #define reg_mcasp_addr r29 // Base address for McASP | |
204 | |
205 | |
206 // Bring CS line low to write to DAC | |
207 .macro DAC_CS_ASSERT | |
208 MOV r27, DAC_CS_PIN | |
209 MOV r28, DAC_GPIO + GPIO_CLEARDATAOUT | |
210 SBBO r27, r28, 0, 4 | |
211 .endm | |
212 | |
213 // Bring CS line high at end of DAC transaction | |
214 .macro DAC_CS_UNASSERT | |
215 MOV r27, DAC_CS_PIN | |
216 MOV r28, DAC_GPIO + GPIO_SETDATAOUT | |
217 SBBO r27, r28, 0, 4 | |
218 .endm | |
219 | |
220 // Write to DAC TX register | |
221 .macro DAC_TX | |
222 .mparam data | |
223 SBBO data, reg_spi_addr, SPI_CH0TX, 4 | |
224 .endm | |
225 | |
226 // Wait for SPI to finish (uses RXS indicator) | |
227 .macro DAC_WAIT_FOR_FINISH | |
228 LOOP: | |
229 LBBO r27, reg_spi_addr, SPI_CH0STAT, 4 | |
230 QBBC LOOP, r27, 0 | |
231 .endm | |
232 | |
233 // Read the RX word to clear | |
234 .macro DAC_DISCARD_RX | |
235 LBBO r27, reg_spi_addr, SPI_CH0RX, 4 | |
236 .endm | |
237 | |
238 // Complete DAC write with chip select | |
239 .macro DAC_WRITE | |
240 .mparam reg | |
241 DAC_CS_ASSERT | |
242 DAC_TX reg | |
243 DAC_WAIT_FOR_FINISH | |
244 DAC_CS_UNASSERT | |
245 DAC_DISCARD_RX | |
246 .endm | |
247 | |
248 // Bring CS line low to write to ADC | |
249 .macro ADC_CS_ASSERT | |
250 MOV r27, ADC_CS_PIN | |
251 MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT | |
252 SBBO r27, r28, 0, 4 | |
253 .endm | |
254 | |
255 // Bring CS line high at end of ADC transaction | |
256 .macro ADC_CS_UNASSERT | |
257 MOV r27, ADC_CS_PIN | |
258 MOV r28, ADC_GPIO + GPIO_SETDATAOUT | |
259 SBBO r27, r28, 0, 4 | |
260 .endm | |
261 | |
262 // Write to ADC TX register | |
263 .macro ADC_TX | |
264 .mparam data | |
265 SBBO data, reg_spi_addr, SPI_CH1TX, 4 | |
266 .endm | |
267 | |
268 // Wait for SPI to finish (uses RXS indicator) | |
269 .macro ADC_WAIT_FOR_FINISH | |
270 LOOP: | |
271 LBBO r27, reg_spi_addr, SPI_CH1STAT, 4 | |
272 QBBC LOOP, r27, 0 | |
273 .endm | |
274 | |
275 // Read the RX word to clear; store output | |
276 .macro ADC_RX | |
277 .mparam data | |
278 LBBO data, reg_spi_addr, SPI_CH1RX, 4 | |
279 .endm | |
280 | |
281 // Complete ADC write+read with chip select | |
282 .macro ADC_WRITE | |
283 .mparam in, out | |
284 ADC_CS_ASSERT | |
285 ADC_TX in | |
286 ADC_WAIT_FOR_FINISH | |
287 ADC_RX out | |
288 ADC_CS_UNASSERT | |
289 .endm | |
290 | |
291 // Write a McASP register | |
292 .macro MCASP_REG_WRITE | |
293 .mparam reg, value | |
294 MOV r27, value | |
295 SBBO r27, reg_mcasp_addr, reg, 4 | |
296 .endm | |
297 | |
298 // Write a McASP register beyond the 0xFF boundary | |
299 .macro MCASP_REG_WRITE_EXT | |
300 .mparam reg, value | |
301 MOV r27, value | |
302 MOV r28, reg | |
303 ADD r28, reg_mcasp_addr, r28 | |
304 SBBO r27, r28, 0, 4 | |
305 .endm | |
306 | |
307 // Read a McASP register | |
308 .macro MCASP_REG_READ | |
309 .mparam reg, value | |
310 LBBO value, reg_mcasp_addr, reg, 4 | |
311 .endm | |
312 | |
313 // Read a McASP register beyond the 0xFF boundary | |
314 .macro MCASP_REG_READ_EXT | |
315 .mparam reg, value | |
316 MOV r28, reg | |
317 ADD r28, reg_mcasp_addr, r28 | |
318 LBBO value, r28, 0, 4 | |
319 .endm | |
320 | |
321 // Set a bit and wait for it to come up | |
322 .macro MCASP_REG_SET_BIT_AND_POLL | |
323 .mparam reg, mask | |
324 MOV r27, mask | |
325 LBBO r28, reg_mcasp_addr, reg, 4 | |
326 OR r28, r28, r27 | |
327 SBBO r28, reg_mcasp_addr, reg, 4 | |
328 POLL: | |
329 LBBO r28, reg_mcasp_addr, reg, 4 | |
330 AND r28, r28, r27 | |
331 QBEQ POLL, r28, 0 | |
332 .endm | |
333 | |
334 START: | |
335 // Set up c24 and c25 offsets with CTBIR register | |
336 // Thus C24 points to start of PRU0 RAM | |
337 MOV r3, 0x22020 // CTBIR0 | |
338 MOV r2, 0 | |
339 SBBO r2, r3, 0, 4 | |
340 | |
341 // Set up c28 pointer offset for shared PRU RAM | |
342 MOV r3, 0x22028 // CTPPR0 | |
343 MOV r2, 0x00000120 // To get address 0x00012000 | |
344 SBBO r2, r3, 0, 4 | |
345 | |
346 // Load useful registers for addressing SPI | |
347 MOV reg_comm_addr, SHARED_COMM_MEM_BASE | |
348 MOV reg_spi_addr, SPI_BASE | |
349 MOV reg_mcasp_addr, MCASP_BASE | |
350 | |
351 // Set ARM such that PRU can write to registers | |
352 LBCO r0, C4, 4, 4 | |
353 CLR r0, r0, 4 | |
354 SBCO r0, C4, 4, 4 | |
355 | |
356 // Clear flags | |
357 MOV reg_flags, 0 | |
358 | |
359 // Find out whether we should use SPI ADC and DAC | |
360 LBBO r2, reg_comm_addr, COMM_USE_SPI, 4 | |
361 QBEQ SPI_FLAG_CHECK_DONE, r2, 0 | |
362 SET reg_flags, reg_flags, FLAG_BIT_USE_SPI | |
363 | |
364 SPI_FLAG_CHECK_DONE: | |
365 // If we don't use SPI, then skip all this init | |
366 QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI | |
367 | |
368 // Init SPI clock | |
369 MOV r2, 0x02 | |
370 MOV r3, CLOCK_BASE + CLOCK_SPI0 | |
371 SBBO r2, r3, 0, 4 | |
372 | |
373 // Reset SPI and wait for finish | |
374 MOV r2, 0x02 | |
375 SBBO r2, reg_spi_addr, SPI_SYSCONFIG, 4 | |
376 | |
377 SPI_WAIT_RESET: | |
378 LBBO r2, reg_spi_addr, SPI_SYSSTATUS, 4 | |
379 QBBC SPI_WAIT_RESET, r2, 0 | |
380 | |
381 // Turn off SPI channels | |
382 MOV r2, 0 | |
383 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4 | |
384 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4 | |
385 | |
386 // Set to master; chip select lines enabled (CS0 used for DAC) | |
387 MOV r2, 0x00 | |
388 SBBO r2, reg_spi_addr, SPI_MODULCTRL, 4 | |
389 | |
390 // Configure CH0 for DAC | |
391 MOV r2, (3 << 27) | (DAC_DPE << 16) | (DAC_TRM << 12) | ((DAC_WL - 1) << 7) | (DAC_CLK_DIV << 2) | DAC_CLK_MODE | (1 << 6) | |
392 SBBO r2, reg_spi_addr, SPI_CH0CONF, 4 | |
393 | |
394 // Configure CH1 for ADC | |
395 MOV r2, (3 << 27) | (ADC_DPE << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE | |
396 SBBO r2, reg_spi_addr, SPI_CH1CONF, 4 | |
397 | |
398 // Turn on SPI channels | |
399 MOV r2, 0x01 | |
400 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4 | |
401 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4 | |
402 | |
403 // DAC power-on reset sequence | |
404 MOV r2, (0x07 << AD5668_COMMAND_OFFSET) | |
405 DAC_WRITE r2 | |
406 | |
407 // Initialise ADC | |
408 MOV r2, AD7699_CFG_MASK | (0 << AD7699_CHANNEL_OFFSET) | (0 << AD7699_SEQ_OFFSET) | |
409 ADC_WRITE r2, r2 | |
410 | |
411 // Enable DAC internal reference | |
412 MOV r2, (0x08 << AD5668_COMMAND_OFFSET) | (0x01 << AD5668_REF_OFFSET) | |
413 DAC_WRITE r2 | |
414 | |
415 // Read ADC ch0 and ch1: result is always 2 samples behind so start here | |
416 MOV r2, AD7699_CFG_MASK | (0x00 << AD7699_CHANNEL_OFFSET) | |
417 ADC_WRITE r2, r2 | |
418 | |
419 MOV r2, AD7699_CFG_MASK | (0x01 << AD7699_CHANNEL_OFFSET) | |
420 ADC_WRITE r2, r2 | |
421 SPI_INIT_DONE: | |
422 | |
423 // Prepare McASP0 for audio | |
424 MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP | |
425 MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off | |
426 MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0 | |
427 MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0 | |
428 MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0 | |
429 MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0 | |
430 MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0 | |
431 | |
432 MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on | |
433 MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP | |
434 MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS // Set pin direction | |
435 MCASP_REG_WRITE MCASP_DLBCTL, 0x00 | |
436 MCASP_REG_WRITE MCASP_DITCTL, 0x00 | |
437 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive | |
438 MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format | |
439 MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode | |
440 MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge | |
441 MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant? | |
442 MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1 | |
443 MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts | |
444 MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit | |
445 MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format | |
446 MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode | |
447 MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv | |
448 MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX | |
449 MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1 | |
450 MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts | |
451 | |
452 MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser | |
453 MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser | |
454 MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x00 // Disable FIFOs | |
455 MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x00 | |
456 | |
457 MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors | |
458 MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors | |
459 | |
460 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1) // Set RHCLKRST | |
461 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9) // Set XHCLKRST | |
462 | |
463 // The above write sequence will have temporarily changed the AHCLKX frequency | |
464 // The PLL needs time to settle or the sample rate will be unstable and possibly | |
465 // cause an underrun. Give it ~1ms before going on. | |
466 // 10ns per loop iteration = 10^-8s --> 10^5 iterations needed | |
467 | |
468 MOV r2, 1 << 28 | |
469 MOV r3, GPIO1 + GPIO_SETDATAOUT | |
470 SBBO r2, r3, 0, 4 | |
471 | |
472 MOV r2, 100000 | |
473 MCASP_INIT_WAIT: | |
474 SUB r2, r2, 1 | |
475 QBNE MCASP_INIT_WAIT, r2, 0 | |
476 | |
477 MOV r2, 1 << 28 | |
478 MOV r3, GPIO1 + GPIO_CLEARDATAOUT | |
479 SBBO r2, r3, 0, 4 | |
480 | |
481 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0) // Set RCLKRST | |
482 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8) // Set XCLKRST | |
483 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2) // Set RSRCLR | |
484 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10) // Set XSRCLR | |
485 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3) // Set RSMRST | |
486 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST | |
487 | |
488 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00 // Write to the transmit buffer to prevent underflow | |
489 | |
490 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST | |
491 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST | |
492 | |
493 // Initialisation | |
494 LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4 // Total frame count (SPI; 2x for McASP) | |
495 MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer | |
496 LSL reg_dac_buf1, reg_frame_total, 4 // DAC buffer 1 start pointer = 8[ch]*2[bytes]*bufsize | |
497 MOV reg_mcasp_buf0, 0 // McASP DAC buffer 0 start pointer | |
498 LSL reg_mcasp_buf1, reg_frame_total, 3 // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*2[samples/spi]*bufsize | |
499 CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on | |
500 MOV r2, 0 | |
501 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0 | |
502 | |
503 // Here we are out of sync by one TDM slot since the 0 word transmitted above will have occupied | |
504 // the first output slot. Send one more word before jumping into the loop. | |
505 MCASP_DAC_WAIT_BEFORE_LOOP: | |
506 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4 | |
507 QBBC MCASP_DAC_WAIT_BEFORE_LOOP, r2, MCASP_XSTAT_XDATA_BIT | |
508 | |
509 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00 | |
510 | |
511 // Likewise, read and discard the first sample we get back from the ADC. This keeps the DAC and ADC | |
512 // in sync in terms of which TDM slot we are reading (empirically found that we should throw this away | |
513 // rather than keep it and invert the phase) | |
514 MCASP_ADC_WAIT_BEFORE_LOOP: | |
515 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4 | |
516 QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT | |
517 | |
518 MCASP_REG_READ_EXT MCASP_RBUF, r2 | |
519 | |
520 WRITE_ONE_BUFFER: | |
521 // Write a single buffer of DAC samples and read a buffer of ADC samples | |
522 // Load starting positions | |
523 MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer | |
524 LSL reg_adc_current, reg_frame_total, 5 // 16 * 2 * bufsize | |
525 ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts 16 * 2 * bufsize beyond DAC | |
526 MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer | |
527 LSL reg_mcasp_adc_current, reg_frame_total, 4 // McASP ADC: starts 4*2*2*bufsize beyond DAC | |
528 ADC reg_mcasp_adc_current, reg_mcasp_adc_current, reg_mcasp_dac_current | |
529 MOV reg_frame_current, 0 | |
530 | |
531 WRITE_LOOP: | |
532 // Write 8 channels to DAC from successive values in memory | |
533 // At the same time, read 8 channels from ADC | |
534 // Unrolled by a factor of 2 to get high and low words | |
535 MOV r1, 0 | |
536 ADC_DAC_LOOP: | |
537 QBBC SPI_DAC_LOAD_DONE, reg_flags, FLAG_BIT_USE_SPI | |
538 // Load next 2 SPI DAC samples and store zero in their place | |
539 LBCO reg_dac_data, C_ADC_DAC_MEM, reg_dac_current, 4 | |
540 MOV r2, 0 | |
541 SBCO r2, C_ADC_DAC_MEM, reg_dac_current, 4 | |
542 ADD reg_dac_current, reg_dac_current, 4 | |
543 SPI_DAC_LOAD_DONE: | |
544 | |
545 // On even iterations, load two more samples and choose the first one | |
546 // On odd iterations, transmit the second of the samples already loaded | |
547 QBBS MCASP_DAC_HIGH_WORD, r1, 1 | |
548 MCASP_DAC_LOW_WORD: | |
549 // Load next 2 Audio DAC samples and store zero in their place | |
550 LBCO reg_mcasp_dac_data, C_MCASP_MEM, reg_mcasp_dac_current, 4 | |
551 MOV r2, 0 | |
552 SBCO r2, C_MCASP_MEM, reg_mcasp_dac_current, 4 | |
553 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4 | |
554 | |
555 // Mask out the low word (first in little endian) | |
556 MOV r2, 0xFFFF | |
557 AND r7, reg_mcasp_dac_data, r2 | |
558 | |
559 QBA MCASP_WAIT_XSTAT | |
560 MCASP_DAC_HIGH_WORD: | |
561 // Take the high word of the previously loaded data | |
562 LSR r7, reg_mcasp_dac_data, 16 | |
563 | |
564 // Two audio frames per SPI frame = 4 audio samples per SPI frame | |
565 // Therefore every 2 channels we send one audio sample; this loop already | |
566 // sends exactly two SPI channels. | |
567 // Wait for McASP XSTAT[XDATA] to set indicating we can write more data | |
568 MCASP_WAIT_XSTAT: | |
569 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4 | |
570 QBBC MCASP_WAIT_XSTAT, r2, MCASP_XSTAT_XDATA_BIT | |
571 | |
572 MCASP_REG_WRITE_EXT MCASP_XBUF, r7 | |
573 | |
574 // Same idea with ADC: even iterations, load the sample into the low word, odd | |
575 // iterations, load the sample into the high word and store | |
576 QBBS MCASP_ADC_HIGH_WORD, r1, 1 | |
577 MCASP_ADC_LOW_WORD: | |
578 // Start ADC data at 0 | |
579 LDI reg_mcasp_adc_data, 0 | |
580 | |
581 // Now wait for a received word to become available from the audio ADC | |
582 MCASP_WAIT_RSTAT_LOW: | |
583 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4 | |
584 QBBC MCASP_WAIT_RSTAT_LOW, r2, MCASP_RSTAT_RDATA_BIT | |
585 | |
586 // Mask low word and store in ADC data register | |
587 MCASP_REG_READ_EXT MCASP_RBUF, r3 | |
588 MOV r2, 0xFFFF | |
589 AND reg_mcasp_adc_data, r3, r2 | |
590 QBA MCASP_ADC_DONE | |
591 | |
592 MCASP_ADC_HIGH_WORD: | |
593 // Wait for a received word to become available from the audio ADC | |
594 MCASP_WAIT_RSTAT_HIGH: | |
595 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4 | |
596 QBBC MCASP_WAIT_RSTAT_HIGH, r2, MCASP_RSTAT_RDATA_BIT | |
597 | |
598 // Read data and shift 16 bits to the left (into the high word) | |
599 MCASP_REG_READ_EXT MCASP_RBUF, r3 | |
600 LSL r3, r3, 16 | |
601 OR reg_mcasp_adc_data, reg_mcasp_adc_data, r3 | |
602 | |
603 // Now store the result and increment the pointer | |
604 SBCO reg_mcasp_adc_data, C_MCASP_MEM, reg_mcasp_adc_current, 4 | |
605 ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4 | |
606 MCASP_ADC_DONE: | |
607 QBBC SPI_SKIP_WRITE, reg_flags, FLAG_BIT_USE_SPI | |
608 | |
609 // DAC: transmit low word (first in little endian) | |
610 MOV r2, 0xFFFF | |
611 AND r7, reg_dac_data, r2 | |
612 LSL r7, r7, AD5668_DATA_OFFSET | |
613 MOV r8, (0x03 << AD5668_COMMAND_OFFSET) | |
614 OR r7, r7, r8 | |
615 LSL r8, r1, AD5668_ADDRESS_OFFSET | |
616 OR r7, r7, r8 | |
617 DAC_WRITE r7 | |
618 | |
619 // Read ADC channels: result is always 2 commands behind | |
620 // Start by reading channel 2 (result is channel 0) and go | |
621 // to 10, but masking the channel number to be between 0 and 7 | |
622 LDI reg_adc_data, 0 | |
623 MOV r7, AD7699_CFG_MASK | |
624 ADD r8, r1, 2 | |
625 AND r8, r8, 7 | |
626 LSL r8, r8, AD7699_CHANNEL_OFFSET | |
627 OR r7, r7, r8 | |
628 ADC_WRITE r7, r7 | |
629 | |
630 // Mask out only the relevant 16 bits and store in reg_adc_data | |
631 MOV r2, 0xFFFF | |
632 AND reg_adc_data, r7, r2 | |
633 | |
634 // Increment channel index | |
635 ADD r1, r1, 1 | |
636 | |
637 // DAC: transmit high word (second in little endian) | |
638 LSR r7, reg_dac_data, 16 | |
639 LSL r7, r7, AD5668_DATA_OFFSET | |
640 MOV r8, (0x03 << AD5668_COMMAND_OFFSET) | |
641 OR r7, r7, r8 | |
642 LSL r8, r1, AD5668_ADDRESS_OFFSET | |
643 OR r7, r7, r8 | |
644 DAC_WRITE r7 | |
645 | |
646 // Read ADC channels: result is always 2 commands behind | |
647 // Start by reading channel 2 (result is channel 0) and go | |
648 // to 10, but masking the channel number to be between 0 and 7 | |
649 MOV r7, AD7699_CFG_MASK | |
650 ADD r8, r1, 2 | |
651 AND r8, r8, 7 | |
652 LSL r8, r8, AD7699_CHANNEL_OFFSET | |
653 OR r7, r7, r8 | |
654 ADC_WRITE r7, r7 | |
655 | |
656 // Move this result up to the 16 high bits | |
657 LSL r7, r7, 16 | |
658 OR reg_adc_data, reg_adc_data, r7 | |
659 | |
660 // Store 2 ADC words in memory | |
661 SBCO reg_adc_data, C_ADC_DAC_MEM, reg_adc_current, 4 | |
662 ADD reg_adc_current, reg_adc_current, 4 | |
663 | |
664 // Repeat 4 times (2 samples per loop, r1 += 1 already happened) | |
665 ADD r1, r1, 1 | |
666 QBNE ADC_DAC_LOOP, r1, 8 | |
667 QBA ADC_DAC_LOOP_DONE | |
668 | |
669 SPI_SKIP_WRITE: | |
670 // We get here only if the SPI ADC and DAC are disabled | |
671 // Just keep the loop going for McASP | |
672 ADD r1, r1, 2 | |
673 QBNE ADC_DAC_LOOP, r1, 8 | |
674 | |
675 ADC_DAC_LOOP_DONE: | |
676 // Increment number of frames, see if we have more to write | |
677 ADD reg_frame_current, reg_frame_current, 1 | |
678 QBNE WRITE_LOOP, reg_frame_current, reg_frame_total | |
679 | |
680 WRITE_LOOP_DONE: | |
681 // Now done, swap the buffers and do the next one | |
682 // Use r2 as a temp register | |
683 MOV r2, reg_dac_buf0 | |
684 MOV reg_dac_buf0, reg_dac_buf1 | |
685 MOV reg_dac_buf1, r2 | |
686 MOV r2, reg_mcasp_buf0 | |
687 MOV reg_mcasp_buf0, reg_mcasp_buf1 | |
688 MOV reg_mcasp_buf1, r2 | |
689 | |
690 // Notify ARM of buffer swap | |
691 XOR reg_flags, reg_flags, (1 << FLAG_BIT_BUFFER1) | |
692 AND r2, reg_flags, (1 << FLAG_BIT_BUFFER1) // Mask out every but low bit | |
693 SBBO r2, reg_comm_addr, COMM_CURRENT_BUFFER, 4 | |
694 | |
695 // Increment the frame count in the comm buffer (for status monitoring) | |
696 LBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 | |
697 ADD r2, r2, reg_frame_total | |
698 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 | |
699 | |
700 // If LED blink enabled, toggle every 4096 frames | |
701 LBBO r3, reg_comm_addr, COMM_LED_ADDRESS, 4 | |
702 QBEQ LED_BLINK_DONE, r3, 0 | |
703 MOV r1, 0x1000 | |
704 AND r2, r2, r1 // Test (frame count & 4096) | |
705 QBEQ LED_BLINK_OFF, r2, 0 | |
706 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4 | |
707 MOV r1, GPIO_SETDATAOUT | |
708 ADD r3, r3, r1 // Address for GPIO set register | |
709 SBBO r2, r3, 0, 4 // Set GPIO pin | |
710 QBA LED_BLINK_DONE | |
711 LED_BLINK_OFF: | |
712 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4 | |
713 MOV r1, GPIO_CLEARDATAOUT | |
714 ADD r3, r3, r1 // Address for GPIO clear register | |
715 SBBO r2, r3, 0, 4 // Clear GPIO pin | |
716 LED_BLINK_DONE: | |
717 | |
718 QBBC TESTLOW, reg_flags, FLAG_BIT_BUFFER1 | |
719 MOV r2, 1 << 28 | |
720 MOV r3, GPIO1 + GPIO_SETDATAOUT | |
721 SBBO r2, r3, 0, 4 | |
722 QBA TESTDONE | |
723 TESTLOW: | |
724 MOV r2, 1 << 28 | |
725 MOV r3, GPIO1 + GPIO_CLEARDATAOUT | |
726 SBBO r2, r3, 0, 4 | |
727 TESTDONE: | |
728 | |
729 // Check if we should finish: flag is zero as long as it should run | |
730 LBBO r2, reg_comm_addr, COMM_SHOULD_STOP, 4 | |
731 QBEQ WRITE_ONE_BUFFER, r2, 0 | |
732 | |
733 CLEANUP: | |
734 MCASP_REG_WRITE MCASP_GBLCTL, 0x00 // Turn off McASP | |
735 | |
736 // Turn off SPI if enabled | |
737 QBBC SPI_CLEANUP_DONE, reg_flags, FLAG_BIT_USE_SPI | |
738 | |
739 MOV r3, SPI_BASE + SPI_CH0CONF | |
740 LBBO r2, r3, 0, 4 | |
741 CLR r2, r2, 13 | |
742 CLR r2, r2, 27 | |
743 SBBO r2, r3, 0, 4 | |
744 | |
745 MOV r3, SPI_BASE + SPI_CH0CTRL | |
746 LBBO r2, r3, 0, 4 | |
747 CLR r2, r2, 1 | |
748 SBBO r2, r3, 0, 4 | |
749 SPI_CLEANUP_DONE: | |
750 | |
751 // Signal the ARM that we have finished | |
752 MOV R31.b0, PRU0_ARM_INTERRUPT + 16 | |
753 HALT |