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