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@45
|
34 #define PRU0_ARM_INTERRUPT 19 // Interrupt signalling we're done
|
andrewm@45
|
35 #define PRU1_ARM_INTERRUPT 20 // Interrupt signalling a block is ready
|
andrewm@0
|
36
|
andrewm@0
|
37 #define C_ADC_DAC_MEM C24 // PRU0 mem
|
andrewm@0
|
38 #ifdef DBOX_CAPE
|
andrewm@0
|
39 #define DAC_GPIO GPIO0
|
andrewm@0
|
40 #define DAC_CS_PIN (1<<5) // GPIO0:5 = P9 pin 17
|
andrewm@0
|
41 #else
|
andrewm@0
|
42 #define DAC_GPIO GPIO1
|
andrewm@0
|
43 #define DAC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15
|
andrewm@0
|
44 #endif
|
andrewm@0
|
45 #define DAC_TRM 0 // SPI transmit and receive
|
andrewm@0
|
46 #define DAC_WL 32 // Word length
|
andrewm@0
|
47 #define DAC_CLK_MODE 1 // SPI mode
|
andrewm@0
|
48 #define DAC_CLK_DIV 1 // Clock divider (48MHz / 2^n)
|
andrewm@0
|
49 #define DAC_DPE 1 // d0 = receive, d1 = transmit
|
andrewm@0
|
50
|
andrewm@0
|
51 #define AD5668_COMMAND_OFFSET 24
|
andrewm@0
|
52 #define AD5668_ADDRESS_OFFSET 20
|
andrewm@0
|
53 #define AD5668_DATA_OFFSET 4
|
andrewm@0
|
54 #define AD5668_REF_OFFSET 0
|
andrewm@0
|
55
|
andrewm@0
|
56 #ifdef DBOX_CAPE
|
andrewm@0
|
57 #define ADC_GPIO GPIO1
|
andrewm@0
|
58 #define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15
|
andrewm@0
|
59 #else
|
andrewm@0
|
60 #define ADC_GPIO GPIO1
|
andrewm@0
|
61 #define ADC_CS_PIN (1<<17) // GPIO1:17 = P9 pin 23
|
andrewm@0
|
62 #endif
|
andrewm@0
|
63 #define ADC_TRM 0 // SPI transmit and receive
|
andrewm@0
|
64 #define ADC_WL 16 // Word length
|
andrewm@0
|
65 #define ADC_CLK_MODE 0 // SPI mode
|
andrewm@0
|
66 #define ADC_CLK_DIV 1 // Clock divider (48MHz / 2^n)
|
andrewm@0
|
67 #define ADC_DPE 1 // d0 = receive, d1 = transmit
|
andrewm@0
|
68
|
andrewm@0
|
69 #define AD7699_CFG_MASK 0xF120 // Mask for config update, unipolar, full BW
|
andrewm@0
|
70 #define AD7699_CHANNEL_OFFSET 9 // 7 bits offset of a 14-bit left-justified word
|
andrewm@0
|
71 #define AD7699_SEQ_OFFSET 3 // sequencer (0 = disable, 3 = scan all)
|
andrewm@0
|
72
|
andrewm@0
|
73 #define SHARED_COMM_MEM_BASE 0x00010000 // Location where comm flags are written
|
andrewm@0
|
74 #define COMM_SHOULD_STOP 0 // Set to be nonzero when loop should stop
|
andrewm@0
|
75 #define COMM_CURRENT_BUFFER 4 // Which buffer we are on
|
andrewm@0
|
76 #define COMM_BUFFER_FRAMES 8 // How many frames per buffer
|
andrewm@0
|
77 #define COMM_SHOULD_SYNC 12 // Whether to synchronise to an external clock
|
andrewm@0
|
78 #define COMM_SYNC_ADDRESS 16 // Which memory address to find the GPIO on
|
andrewm@0
|
79 #define COMM_SYNC_PIN_MASK 20 // Which pin to read for the sync
|
andrewm@0
|
80 #define COMM_LED_ADDRESS 24 // Which memory address to find the status LED on
|
andrewm@0
|
81 #define COMM_LED_PIN_MASK 28 // Which pin to write to change LED
|
andrewm@0
|
82 #define COMM_FRAME_COUNT 32 // How many frames have elapse since beginning
|
andrewm@0
|
83 #define COMM_USE_SPI 36 // Whether or not to use SPI ADC and DAC
|
andrewm@12
|
84 #define COMM_NUM_CHANNELS 40 // Low 2 bits indicate 8 [0x3], 4 [0x1] or 2 [0x0] channels
|
andrewm@253
|
85 #define COMM_USE_DIGITAL 44 // Whether or not to use DIGITAL
|
andrewm@253
|
86 #define COMM_PRU_NUMBER 48 // Which PRU this code is running on
|
andrewm@282
|
87 #define COMM_MUX_CONFIG 52 // Whether to use the mux capelet, and how many channels
|
andrewm@346
|
88 #define COMM_MUX_END_CHANNEL 56 // Which mux channel the last buffer ended on
|
andrewm@346
|
89
|
andrewm@282
|
90 // General constants for McASP peripherals (used for audio codec)
|
andrewm@0
|
91 #define MCASP0_BASE 0x48038000
|
andrewm@0
|
92 #define MCASP1_BASE 0x4803C000
|
andrewm@0
|
93
|
andrewm@0
|
94 #define MCASP_PWRIDLESYSCONFIG 0x04
|
andrewm@0
|
95 #define MCASP_PFUNC 0x10
|
andrewm@0
|
96 #define MCASP_PDIR 0x14
|
andrewm@0
|
97 #define MCASP_PDOUT 0x18
|
andrewm@0
|
98 #define MCASP_PDSET 0x1C
|
andrewm@0
|
99 #define MCASP_PDIN 0x1C
|
andrewm@0
|
100 #define MCASP_PDCLR 0x20
|
andrewm@0
|
101 #define MCASP_GBLCTL 0x44
|
andrewm@0
|
102 #define MCASP_AMUTE 0x48
|
andrewm@0
|
103 #define MCASP_DLBCTL 0x4C
|
andrewm@0
|
104 #define MCASP_DITCTL 0x50
|
andrewm@0
|
105 #define MCASP_RGBLCTL 0x60
|
andrewm@0
|
106 #define MCASP_RMASK 0x64
|
andrewm@0
|
107 #define MCASP_RFMT 0x68
|
andrewm@0
|
108 #define MCASP_AFSRCTL 0x6C
|
andrewm@0
|
109 #define MCASP_ACLKRCTL 0x70
|
andrewm@0
|
110 #define MCASP_AHCLKRCTL 0x74
|
andrewm@0
|
111 #define MCASP_RTDM 0x78
|
andrewm@0
|
112 #define MCASP_RINTCTL 0x7C
|
andrewm@0
|
113 #define MCASP_RSTAT 0x80
|
andrewm@0
|
114 #define MCASP_RSLOT 0x84
|
andrewm@0
|
115 #define MCASP_RCLKCHK 0x88
|
andrewm@0
|
116 #define MCASP_REVTCTL 0x8C
|
andrewm@0
|
117 #define MCASP_XGBLCTL 0xA0
|
andrewm@0
|
118 #define MCASP_XMASK 0xA4
|
andrewm@0
|
119 #define MCASP_XFMT 0xA8
|
andrewm@0
|
120 #define MCASP_AFSXCTL 0xAC
|
andrewm@0
|
121 #define MCASP_ACLKXCTL 0xB0
|
andrewm@0
|
122 #define MCASP_AHCLKXCTL 0xB4
|
andrewm@0
|
123 #define MCASP_XTDM 0xB8
|
andrewm@0
|
124 #define MCASP_XINTCTL 0xBC
|
andrewm@0
|
125 #define MCASP_XSTAT 0xC0
|
andrewm@0
|
126 #define MCASP_XSLOT 0xC4
|
andrewm@0
|
127 #define MCASP_XCLKCHK 0xC8
|
andrewm@0
|
128 #define MCASP_XEVTCTL 0xCC
|
andrewm@0
|
129 #define MCASP_SRCTL0 0x180
|
andrewm@0
|
130 #define MCASP_SRCTL1 0x184
|
andrewm@0
|
131 #define MCASP_SRCTL2 0x188
|
andrewm@0
|
132 #define MCASP_SRCTL3 0x18C
|
andrewm@0
|
133 #define MCASP_SRCTL4 0x190
|
andrewm@0
|
134 #define MCASP_SRCTL5 0x194
|
andrewm@0
|
135 #define MCASP_XBUF0 0x200
|
andrewm@0
|
136 #define MCASP_XBUF1 0x204
|
andrewm@0
|
137 #define MCASP_XBUF2 0x208
|
andrewm@0
|
138 #define MCASP_XBUF3 0x20C
|
andrewm@0
|
139 #define MCASP_XBUF4 0x210
|
andrewm@0
|
140 #define MCASP_XBUF5 0x214
|
andrewm@0
|
141 #define MCASP_RBUF0 0x280
|
andrewm@0
|
142 #define MCASP_RBUF1 0x284
|
andrewm@0
|
143 #define MCASP_RBUF2 0x288
|
andrewm@0
|
144 #define MCASP_RBUF3 0x28C
|
andrewm@0
|
145 #define MCASP_RBUF4 0x290
|
andrewm@0
|
146 #define MCASP_RBUF5 0x294
|
andrewm@0
|
147 #define MCASP_WFIFOCTL 0x1000
|
andrewm@0
|
148 #define MCASP_WFIFOSTS 0x1004
|
andrewm@0
|
149 #define MCASP_RFIFOCTL 0x1008
|
andrewm@0
|
150 #define MCASP_RFIFOSTS 0x100C
|
andrewm@0
|
151
|
giuliomoro@100
|
152 #define MCASP_XSTAT_XUNDRN_BIT 0 // Bit to test if there was an underrun
|
andrewm@0
|
153 #define MCASP_XSTAT_XDATA_BIT 5 // Bit to test for transmit ready
|
andrewm@0
|
154 #define MCASP_RSTAT_RDATA_BIT 5 // Bit to test for receive ready
|
andrewm@0
|
155
|
andrewm@0
|
156 // Constants used for this particular audio setup
|
andrewm@0
|
157 #define MCASP_BASE MCASP0_BASE
|
andrewm@0
|
158 #ifdef DBOX_CAPE
|
andrewm@0
|
159 #define MCASP_SRCTL_X MCASP_SRCTL2 // Ser. 2 is transmitter
|
andrewm@0
|
160 #define MCASP_SRCTL_R MCASP_SRCTL0 // Ser. 0 is receiver
|
andrewm@0
|
161 #define MCASP_XBUF MCASP_XBUF2
|
andrewm@0
|
162 #define MCASP_RBUF MCASP_RBUF0
|
andrewm@0
|
163 #else
|
andrewm@0
|
164 #define MCASP_SRCTL_X MCASP_SRCTL3 // Ser. 3 is transmitter
|
andrewm@0
|
165 #define MCASP_SRCTL_R MCASP_SRCTL2 // Ser. 2 is receiver
|
andrewm@0
|
166 #define MCASP_XBUF MCASP_XBUF3
|
andrewm@0
|
167 #define MCASP_RBUF MCASP_RBUF2
|
andrewm@0
|
168 #endif
|
andrewm@0
|
169
|
andrewm@0
|
170 #define MCASP_PIN_AFSX (1 << 28)
|
andrewm@0
|
171 #define MCASP_PIN_AHCLKX (1 << 27)
|
andrewm@0
|
172 #define MCASP_PIN_ACLKX (1 << 26)
|
andrewm@0
|
173 #define MCASP_PIN_AMUTE (1 << 25) // Also, 0 to 3 are XFR0 to XFR3
|
andrewm@0
|
174
|
andrewm@0
|
175 #ifdef DBOX_CAPE
|
andrewm@0
|
176 #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs
|
andrewm@0
|
177 #else
|
andrewm@0
|
178 #define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs
|
andrewm@0
|
179 #endif
|
andrewm@0
|
180
|
andrewm@0
|
181 #define MCASP_DATA_MASK 0xFFFF // 16 bit data
|
andrewm@0
|
182 #define MCASP_DATA_FORMAT 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits
|
andrewm@0
|
183
|
andrewm@12
|
184 #define C_MCASP_MEM C28 // Shared PRU mem
|
andrewm@0
|
185
|
andrewm@0
|
186 // Flags for the flags register
|
andrewm@0
|
187 #define FLAG_BIT_BUFFER1 0
|
andrewm@0
|
188 #define FLAG_BIT_USE_SPI 1
|
andrewm@12
|
189 #define FLAG_BIT_MCASP_HWORD 2 // Whether we are on the high word for McASP transmission
|
andrewm@282
|
190 #define FLAG_BIT_USE_DIGITAL 3
|
andrewm@282
|
191
|
andrewm@282
|
192 #define FLAG_BIT_MUX_CONFIG0 8 // Mux capelet configuration:
|
andrewm@282
|
193 #define FLAG_BIT_MUX_CONFIG1 9 // 00 = off, 01 = 2 ch., 10 = 4 ch., 11 = 8 ch.
|
andrewm@282
|
194 #define FLAG_MASK_MUX_CONFIG 0x0300
|
andrewm@346
|
195
|
andrewm@0
|
196 // Registers used throughout
|
andrewm@0
|
197
|
andrewm@0
|
198 // r1, r2, r3 are used for temporary storage
|
giuliomoro@19
|
199 #define MEM_DIGITAL_BASE 0x11000 //Base address for DIGITAL : Shared RAM + 0x400
|
giuliomoro@19
|
200 #define MEM_DIGITAL_BUFFER1_OFFSET 0x400 //Start pointer to DIGITAL_BUFFER1, which is 256 words after.
|
giuliomoro@16
|
201 // 256 is the maximum number of frames allowed
|
giuliomoro@16
|
202
|
giuliomoro@40
|
203 #define reg_digital_current r6 // Pointer to current storage location of DIGITAL
|
andrewm@12
|
204 #define reg_num_channels r9 // Number of SPI ADC/DAC channels to use
|
andrewm@0
|
205 #define reg_frame_current r10 // Current frame count in SPI ADC/DAC transfer
|
andrewm@0
|
206 #define reg_frame_total r11 // Total frame count for SPI ADC/DAC
|
andrewm@0
|
207 #define reg_dac_data r12 // Current dword for SPI DAC
|
andrewm@0
|
208 #define reg_adc_data r13 // Current dword for SPI ADC
|
andrewm@0
|
209 #define reg_mcasp_dac_data r14 // Current dword for McASP DAC
|
andrewm@0
|
210 #define reg_mcasp_adc_data r15 // Current dword for McASP ADC
|
andrewm@0
|
211 #define reg_dac_buf0 r16 // Start pointer to SPI DAC buffer 0
|
andrewm@0
|
212 #define reg_dac_buf1 r17 // Start pointer to SPI DAC buffer 1
|
andrewm@0
|
213 #define reg_dac_current r18 // Pointer to current storage location of SPI DAC
|
andrewm@0
|
214 #define reg_adc_current r19 // Pointer to current storage location of SPI ADC
|
andrewm@0
|
215 #define reg_mcasp_buf0 r20 // Start pointer to McASP DAC buffer 0
|
andrewm@0
|
216 #define reg_mcasp_buf1 r21 // Start pointer to McASP DAC buffer 1
|
andrewm@0
|
217 #define reg_mcasp_dac_current r22 // Pointer to current storage location of McASP DAC
|
andrewm@0
|
218 #define reg_mcasp_adc_current r23 // Pointer to current storage location of McASP ADC
|
andrewm@0
|
219 #define reg_flags r24 // Buffer ID (0 and 1) and other flags
|
andrewm@0
|
220 #define reg_comm_addr r25 // Memory address for communicating with ARM
|
andrewm@0
|
221 #define reg_spi_addr r26 // Base address for SPI
|
andrewm@0
|
222 // r27, r28 used in macros
|
andrewm@0
|
223 #define reg_mcasp_addr r29 // Base address for McASP
|
andrewm@282
|
224 #define reg_pru1_mux_pins r30 // Register mapped directly to P8 pins (PRU1 only)
|
andrewm@0
|
225
|
giuliomoro@16
|
226 //0 P8_07 36 0x890/090 66 gpio2[2]
|
giuliomoro@16
|
227 //1 P8_08 37 0x894/094 67 gpio2[3]
|
giuliomoro@16
|
228 //2 P8_09 39 0x89c/09c 69 gpio2[5]
|
giuliomoro@16
|
229 //3 P8_10 38 0x898/098 68 gpio2[4]
|
giuliomoro@16
|
230 //4 P8_11 13 0x834/034 45 gpio1[13]
|
giuliomoro@16
|
231 //5 P8_12 12 0x830/030 44 gpio1[12]
|
giuliomoro@16
|
232 //6 P9_12 30 0x878/078 60 gpio1[28]
|
giuliomoro@16
|
233 //7 P9_14 18 0x848/048 50 gpio1[18]
|
giuliomoro@16
|
234 //8 P8_15 15 0x83c/03c 47 gpio1[15]
|
giuliomoro@16
|
235 //9 P8_16 14 0x838/038 46 gpio1[14]
|
giuliomoro@16
|
236 //10 P9_16 19 0x84c/04c 51 gpio1[19]
|
giuliomoro@16
|
237 //11 P8_18 35 0x88c/08c 65 gpio2[1]
|
giuliomoro@16
|
238 //12 P8_27 56 0x8e0/0e0 86 gpio2[22]
|
giuliomoro@16
|
239 //13 P8_28 58 0x8e8/0e8 88 gpio2[24]
|
giuliomoro@16
|
240 //14 P8_29 57 0x8e4/0e4 87 gpio2[23]
|
giuliomoro@16
|
241 //15 P8_30 59 0x8ec/0ec 89 gpio2[25]
|
giuliomoro@16
|
242
|
giuliomoro@16
|
243 //generic GPIOs constants
|
giuliomoro@16
|
244 //#define GPIO1 0x4804c000
|
giuliomoro@16
|
245 #define GPIO2 0x481ac000
|
giuliomoro@16
|
246 //#define GPIO_CLEARDATAOUT 0x190 //SETDATAOUT is CLEARDATAOUT+4
|
giuliomoro@16
|
247 #define GPIO_OE 0x134
|
giuliomoro@16
|
248 #define GPIO_DATAIN 0x138
|
giuliomoro@16
|
249
|
giuliomoro@16
|
250 .macro READ_GPIO_BITS
|
giuliomoro@19
|
251 .mparam gpio_data, gpio_num_bit, digital_bit, digital
|
giuliomoro@19
|
252 QBBC DONE, digital, digital_bit //if the pin is set as an output, nothing to do here
|
giuliomoro@16
|
253 QBBC CLEAR, gpio_data, gpio_num_bit
|
giuliomoro@19
|
254 SET digital, digital_bit+16
|
giuliomoro@16
|
255 QBA DONE
|
giuliomoro@16
|
256 CLEAR:
|
giuliomoro@19
|
257 CLR digital, digital_bit+16
|
giuliomoro@16
|
258 QBA DONE
|
giuliomoro@16
|
259 DONE:
|
giuliomoro@16
|
260 .endm
|
giuliomoro@16
|
261
|
giuliomoro@16
|
262 .macro SET_GPIO_BITS
|
giuliomoro@19
|
263 .mparam gpio_oe, gpio_setdataout, gpio_cleardataout, gpio_num_bit, digital_bit, digital //sets the bits in GPIO_OE, GPIO_SETDATAOUT and GPIO_CLEARDATAOUT
|
giuliomoro@16
|
264 //Remember that the GPIO_OE Output data enable register behaves as follows for each bit:
|
giuliomoro@16
|
265 //0 = The corresponding GPIO pin is configured as an output.
|
giuliomoro@16
|
266 //1 = The corresponding GPIO pin is configured as an input.
|
giuliomoro@19
|
267 QBBS SETINPUT, digital, digital_bit
|
giuliomoro@16
|
268 CLR gpio_oe, gpio_num_bit //if it is an output, configure pin as output
|
giuliomoro@19
|
269 QBBC CLEARDATAOUT, digital, digital_bit+16 // check the output value. If it is 0, branch
|
giuliomoro@16
|
270 SET gpio_setdataout, gpio_num_bit //if it is 1, set output to high
|
giuliomoro@16
|
271 QBA DONE
|
giuliomoro@16
|
272 CLEARDATAOUT:
|
giuliomoro@16
|
273 SET gpio_cleardataout, gpio_num_bit // set output to low
|
giuliomoro@16
|
274 QBA DONE
|
giuliomoro@16
|
275 SETINPUT: //if it is an input, set the relevant bit
|
giuliomoro@16
|
276 SET gpio_oe, gpio_num_bit
|
giuliomoro@16
|
277 QBA DONE
|
giuliomoro@16
|
278 DONE:
|
giuliomoro@16
|
279 .endm
|
giuliomoro@16
|
280
|
giuliomoro@16
|
281 QBA START // when first starting, go to START, skipping this section.
|
giuliomoro@16
|
282
|
giuliomoro@19
|
283 DIGITAL:
|
giuliomoro@39
|
284 //IMPORTANT: do NOT use r28 in this macro, as it contains the return address for JAL
|
giuliomoro@39
|
285 //r27 is now the input word passed in render(), one word per frame
|
giuliomoro@16
|
286 //[31:16]: data(1=high, 0=low), [15:0]: direction (0=output, 1=input) )
|
giuliomoro@39
|
287
|
giuliomoro@39
|
288
|
giuliomoro@16
|
289 //Preparing the gpio_oe, gpio_cleardataout and gpio_setdataout for each module
|
giuliomoro@39
|
290 //r2 will hold GPIO1_OE
|
giuliomoro@39
|
291 //load current status of GPIO_OE in r2
|
giuliomoro@39
|
292 MOV r2, GPIO1 | GPIO_OE
|
giuliomoro@26
|
293 //it takes 190ns to go through the next instruction
|
giuliomoro@39
|
294 LBBO r2, r2, 0, 4
|
giuliomoro@16
|
295 //GPIO1-start
|
giuliomoro@16
|
296 //process oe and datain and prepare dataout for GPIO1
|
giuliomoro@39
|
297 //r7 will contain GPIO1_CLEARDATAOUT
|
giuliomoro@39
|
298 //r8 will contain GPIO1_SETDATAOUT
|
giuliomoro@39
|
299 MOV r8, 0
|
giuliomoro@39
|
300 MOV r7, 0
|
giuliomoro@39
|
301 //map GPIO_ANALOG to gpio1 pins,
|
giuliomoro@39
|
302 //r2 is gpio1_oe, r8 is gpio1_setdataout, r7 is gpio1_cleardataout, r27 is the input word
|
giuliomoro@39
|
303 //the following operations will read from r27 and update r2,r7,r8
|
giuliomoro@39
|
304 SET_GPIO_BITS r2, r8, r7, 13, 4, r27
|
giuliomoro@39
|
305 SET_GPIO_BITS r2, r8, r7, 12, 5, r27
|
giuliomoro@39
|
306 SET_GPIO_BITS r2, r8, r7, 28, 6, r27
|
giuliomoro@39
|
307 SET_GPIO_BITS r2, r8, r7, 18, 7, r27
|
giuliomoro@39
|
308 SET_GPIO_BITS r2, r8, r7, 15, 8, r27
|
giuliomoro@39
|
309 SET_GPIO_BITS r2, r8, r7, 14, 9, r27
|
giuliomoro@39
|
310 SET_GPIO_BITS r2, r8, r7, 19, 10, r27
|
giuliomoro@16
|
311 //set the output enable register for gpio1.
|
giuliomoro@39
|
312 MOV r3, GPIO1 | GPIO_OE //use r3 as a temp register
|
giuliomoro@39
|
313 SBBO r2, r3, 0, 4 //takes two cycles (10ns)
|
giuliomoro@16
|
314 //GPIO1-end
|
giuliomoro@39
|
315 // r2 is now unused
|
giuliomoro@16
|
316
|
giuliomoro@16
|
317 //GPIO2-start
|
giuliomoro@39
|
318 //r3 will hold GPIO1_OE
|
giuliomoro@39
|
319 //load current status of GPIO_OE in r3
|
giuliomoro@39
|
320 MOV r3, GPIO2 | GPIO_OE
|
giuliomoro@26
|
321 //it takes 200ns to go through the next instructions
|
giuliomoro@39
|
322 LBBO r3, r3, 0, 4
|
giuliomoro@16
|
323 //process oe and datain and prepare dataout for GPIO2
|
giuliomoro@39
|
324 //r4 will contain GPIO2_CLEARDATAOUT
|
giuliomoro@39
|
325 //r5 will contain GPIO2_SETDATAOUT
|
giuliomoro@39
|
326 MOV r5, 0
|
giuliomoro@39
|
327 MOV r4, 0
|
giuliomoro@39
|
328 //map GPIO_ANALOG to gpio2 pins
|
giuliomoro@39
|
329 //r3 is gpio2_oe, r5 is gpio2_setdataout, r4 is gpio2_cleardataout, r27 is the input word
|
giuliomoro@39
|
330 //the following operations will read from r27 and update r3,r4,r5
|
giuliomoro@39
|
331 SET_GPIO_BITS r3, r5, r4, 2, 0, r27
|
giuliomoro@39
|
332 SET_GPIO_BITS r3, r5, r4, 3, 1, r27
|
giuliomoro@39
|
333 SET_GPIO_BITS r3, r5, r4, 5, 2, r27
|
giuliomoro@39
|
334 SET_GPIO_BITS r3, r5, r4, 4, 3, r27
|
giuliomoro@39
|
335 SET_GPIO_BITS r3, r5, r4, 1, 11, r27
|
giuliomoro@39
|
336 SET_GPIO_BITS r3, r5, r4, 22, 12, r27
|
giuliomoro@39
|
337 SET_GPIO_BITS r3, r5, r4, 24, 13, r27
|
giuliomoro@39
|
338 SET_GPIO_BITS r3, r5, r4, 23, 14, r27
|
giuliomoro@39
|
339 SET_GPIO_BITS r3, r5, r4, 25, 15, r27
|
giuliomoro@16
|
340 //set the output enable register for gpio2.
|
giuliomoro@39
|
341 MOV r2, GPIO2 | GPIO_OE //use r2 as a temp registerp
|
giuliomoro@39
|
342 SBBO r3, r2, 0, 4 //takes two cycles (10ns)
|
giuliomoro@16
|
343 //GPIO2-end
|
giuliomoro@39
|
344 //r3 is now unused
|
giuliomoro@16
|
345
|
giuliomoro@39
|
346 //load current inputs in r2, r3
|
giuliomoro@39
|
347 //r2 will contain GPIO1_DATAIN
|
giuliomoro@39
|
348 //r3 will contain GPIO2_DATAIN
|
giuliomoro@39
|
349 //load the memory locations
|
giuliomoro@39
|
350 MOV r2, GPIO1 | GPIO_DATAIN
|
giuliomoro@39
|
351 MOV r3, GPIO2 | GPIO_DATAIN
|
giuliomoro@26
|
352 //takes 375 nns to go through the next two instructions
|
giuliomoro@39
|
353 //read the datain
|
giuliomoro@39
|
354 LBBO r2, r2, 0, 4
|
giuliomoro@39
|
355 LBBO r3, r3, 0, 4
|
giuliomoro@39
|
356 //now read from r2 and r3 only the channels that are set as input in the lower word of r27
|
giuliomoro@39
|
357 // and set their value in the high word of r27
|
giuliomoro@39
|
358 //GPIO1
|
giuliomoro@39
|
359 READ_GPIO_BITS r2, 13, 4, r27
|
giuliomoro@39
|
360 READ_GPIO_BITS r2, 12, 5, r27
|
giuliomoro@39
|
361 READ_GPIO_BITS r2, 28, 6, r27
|
giuliomoro@39
|
362 READ_GPIO_BITS r2, 18, 7, r27
|
giuliomoro@39
|
363 READ_GPIO_BITS r2, 15, 8, r27
|
giuliomoro@39
|
364 READ_GPIO_BITS r2, 14, 9, r27
|
giuliomoro@39
|
365 READ_GPIO_BITS r2, 19, 10, r27
|
giuliomoro@39
|
366 //GPIO2
|
giuliomoro@39
|
367 READ_GPIO_BITS r3, 2, 0, r27
|
giuliomoro@39
|
368 READ_GPIO_BITS r3, 3, 1, r27
|
giuliomoro@39
|
369 READ_GPIO_BITS r3, 5, 2, r27
|
giuliomoro@39
|
370 READ_GPIO_BITS r3, 4, 3, r27
|
giuliomoro@39
|
371 READ_GPIO_BITS r3, 1, 11, r27
|
giuliomoro@39
|
372 READ_GPIO_BITS r3, 22, 12, r27
|
giuliomoro@39
|
373 READ_GPIO_BITS r3, 24, 13, r27
|
giuliomoro@39
|
374 READ_GPIO_BITS r3, 23, 14, r27
|
giuliomoro@39
|
375 READ_GPIO_BITS r3, 25, 15, r27
|
giuliomoro@39
|
376 //r2, r3 are now unused
|
giuliomoro@16
|
377
|
giuliomoro@16
|
378 //now all the setdataout and cleardataout are ready to be written to the GPIO register.
|
giuliomoro@39
|
379 //CLEARDATAOUT and SETDATAOUT are consecutive positions in memory, so we just write 8 bytes to CLEARDATAOUT.
|
giuliomoro@39
|
380 //We can do this because we chose cleardata and setdata registers for a given GPIO to be consecutive
|
giuliomoro@16
|
381 //load the memory addresses to be written to
|
giuliomoro@39
|
382 MOV r2, GPIO1 | GPIO_CLEARDATAOUT //use r2 as a temp register
|
giuliomoro@39
|
383 MOV r3, GPIO2 | GPIO_CLEARDATAOUT //use r3 as a temp register
|
giuliomoro@16
|
384 //write 8 bytes for each GPIO
|
giuliomoro@39
|
385 //takes 30ns in total to go through the following two instructions
|
giuliomoro@39
|
386 SBBO r7, r2, 0, 8 //store r7 and r8 in GPIO1_CLEARDATAOUT and GPIO1_SETDATAOUT
|
giuliomoro@39
|
387 //takes 145ns to be effective when going low, 185ns when going high
|
giuliomoro@39
|
388 SBBO r4, r3, 0, 8 //store r4 and r5 in GPIO2_CLEARDATAOUT and GPIO2_SETDATAOUT
|
giuliomoro@39
|
389 //takes 95ns to be effective when going low, 130ns when going high
|
giuliomoro@16
|
390 //reversing the order of the two lines above will swap the performances between the GPIO modules
|
giuliomoro@16
|
391 //i.e.: the first line will always take 145ns/185ns and the second one will always take 95ns/130ns,
|
giuliomoro@16
|
392 //regardless of whether the order is gpio1-gpio2 or gpio2-gpio1
|
giuliomoro@39
|
393 JMP r28.w0 // go back to ADC_WRITE_AND_PROCESS_GPIO
|
giuliomoro@16
|
394
|
giuliomoro@39
|
395 .macro HANG //useful for debugging
|
giuliomoro@188
|
396 DALOOP:
|
giuliomoro@102
|
397 set r30.t14
|
giuliomoro@102
|
398 clr r30.t14
|
giuliomoro@38
|
399 QBA DALOOP
|
giuliomoro@38
|
400 .endm
|
giuliomoro@39
|
401
|
andrewm@0
|
402 // Bring CS line low to write to DAC
|
andrewm@0
|
403 .macro DAC_CS_ASSERT
|
giuliomoro@102
|
404 MOV r27, DAC_CS_PIN
|
giuliomoro@102
|
405 MOV r28, DAC_GPIO + GPIO_CLEARDATAOUT
|
giuliomoro@102
|
406 SBBO r27, r28, 0, 4
|
andrewm@0
|
407 .endm
|
andrewm@0
|
408
|
andrewm@0
|
409 // Bring CS line high at end of DAC transaction
|
andrewm@0
|
410 .macro DAC_CS_UNASSERT
|
giuliomoro@102
|
411 MOV r27, DAC_CS_PIN
|
giuliomoro@102
|
412 MOV r28, DAC_GPIO + GPIO_SETDATAOUT
|
giuliomoro@102
|
413 SBBO r27, r28, 0, 4
|
andrewm@0
|
414 .endm
|
andrewm@0
|
415
|
andrewm@0
|
416 // Write to DAC TX register
|
andrewm@0
|
417 .macro DAC_TX
|
andrewm@0
|
418 .mparam data
|
andrewm@0
|
419 SBBO data, reg_spi_addr, SPI_CH0TX, 4
|
andrewm@0
|
420 .endm
|
andrewm@0
|
421
|
andrewm@0
|
422 // Wait for SPI to finish (uses RXS indicator)
|
andrewm@0
|
423 .macro DAC_WAIT_FOR_FINISH
|
andrewm@0
|
424 LOOP:
|
giuliomoro@102
|
425 LBBO r27, reg_spi_addr, SPI_CH0STAT, 4
|
giuliomoro@102
|
426 QBBC LOOP, r27, 0
|
andrewm@0
|
427 .endm
|
andrewm@0
|
428
|
andrewm@0
|
429 // Read the RX word to clear
|
andrewm@0
|
430 .macro DAC_DISCARD_RX
|
giuliomoro@102
|
431 LBBO r27, reg_spi_addr, SPI_CH0RX, 4
|
andrewm@0
|
432 .endm
|
andrewm@0
|
433
|
andrewm@0
|
434 // Complete DAC write with chip select
|
andrewm@0
|
435 .macro DAC_WRITE
|
andrewm@0
|
436 .mparam reg
|
giuliomoro@102
|
437 DAC_CS_ASSERT
|
giuliomoro@102
|
438 DAC_TX reg
|
giuliomoro@102
|
439 DAC_WAIT_FOR_FINISH
|
giuliomoro@102
|
440 DAC_CS_UNASSERT
|
giuliomoro@102
|
441 DAC_DISCARD_RX
|
andrewm@0
|
442 .endm
|
andrewm@0
|
443
|
andrewm@346
|
444 // Transform channel order on DAC
|
andrewm@346
|
445 // (in) 01234567 --> (out) 64201357
|
andrewm@346
|
446 // This is to make the pin order on the Bela cape
|
andrewm@346
|
447 // make sense
|
andrewm@346
|
448 .macro DAC_CHANNEL_REORDER
|
andrewm@346
|
449 .mparam out, in
|
andrewm@346
|
450 QBBS DAC_CHANNEL_REORDER_HIGH, in, 2
|
andrewm@346
|
451 // Input channels 0,1,2,3 --> 6,4,2,0
|
andrewm@346
|
452 // out = (3 - in) << 1
|
andrewm@346
|
453 XOR out, in, 0x03
|
andrewm@346
|
454 LSL out, out, 1
|
andrewm@346
|
455 QBA DAC_CHANNEL_REORDER_DONE
|
andrewm@346
|
456 DAC_CHANNEL_REORDER_HIGH:
|
andrewm@346
|
457 // Input channels 4,5,6,7 --> 1,3,5,7
|
andrewm@346
|
458 // out = ((in & 0x03) << 1) + 1
|
andrewm@346
|
459 AND out, in, 0x03
|
andrewm@346
|
460 LSL out, out, 1
|
andrewm@346
|
461 ADD out, out, 1
|
andrewm@346
|
462 DAC_CHANNEL_REORDER_DONE:
|
andrewm@346
|
463 .endm
|
andrewm@346
|
464
|
andrewm@0
|
465 // Bring CS line low to write to ADC
|
andrewm@0
|
466 .macro ADC_CS_ASSERT
|
giuliomoro@102
|
467 MOV r27, ADC_CS_PIN
|
giuliomoro@102
|
468 MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT
|
giuliomoro@102
|
469 SBBO r27, r28, 0, 4
|
andrewm@0
|
470 .endm
|
andrewm@0
|
471
|
andrewm@0
|
472 // Bring CS line high at end of ADC transaction
|
andrewm@0
|
473 .macro ADC_CS_UNASSERT
|
giuliomoro@102
|
474 MOV r27, ADC_CS_PIN
|
giuliomoro@102
|
475 MOV r28, ADC_GPIO + GPIO_SETDATAOUT
|
giuliomoro@102
|
476 SBBO r27, r28, 0, 4
|
andrewm@0
|
477 .endm
|
andrewm@0
|
478
|
andrewm@0
|
479 // Write to ADC TX register
|
andrewm@0
|
480 .macro ADC_TX
|
andrewm@0
|
481 .mparam data
|
giuliomoro@102
|
482 SBBO data, reg_spi_addr, SPI_CH1TX, 4
|
andrewm@0
|
483 .endm
|
andrewm@0
|
484
|
andrewm@0
|
485 // Wait for SPI to finish (uses RXS indicator)
|
andrewm@0
|
486 .macro ADC_WAIT_FOR_FINISH
|
andrewm@0
|
487 LOOP:
|
giuliomoro@102
|
488 LBBO r27, reg_spi_addr, SPI_CH1STAT, 4
|
giuliomoro@102
|
489 QBBC LOOP, r27, 0
|
andrewm@0
|
490 .endm
|
andrewm@0
|
491
|
andrewm@0
|
492 // Read the RX word to clear; store output
|
andrewm@0
|
493 .macro ADC_RX
|
andrewm@0
|
494 .mparam data
|
giuliomoro@102
|
495 LBBO data, reg_spi_addr, SPI_CH1RX, 4
|
andrewm@0
|
496 .endm
|
andrewm@0
|
497
|
andrewm@0
|
498 // Complete ADC write+read with chip select
|
andrewm@0
|
499 .macro ADC_WRITE
|
andrewm@0
|
500 .mparam in, out
|
giuliomoro@102
|
501 ADC_CS_ASSERT
|
giuliomoro@102
|
502 ADC_TX in
|
giuliomoro@102
|
503 ADC_WAIT_FOR_FINISH
|
giuliomoro@102
|
504 ADC_RX out
|
giuliomoro@102
|
505 ADC_CS_UNASSERT
|
andrewm@0
|
506 .endm
|
andrewm@0
|
507
|
giuliomoro@19
|
508 // Complete ADC write+read with chip select and also performs IO for digital
|
giuliomoro@16
|
509 .macro ADC_WRITE_GPIO
|
giuliomoro@16
|
510 .mparam in, out, do_gpio
|
giuliomoro@102
|
511 ADC_CS_ASSERT
|
giuliomoro@102
|
512 ADC_TX in
|
giuliomoro@102
|
513 QBBC GPIO_DONE, reg_flags, FLAG_BIT_USE_DIGITAL //skip if DIGITAL is disabled
|
giuliomoro@188
|
514 QBLT CASE_4_OR_8_CHANNELS, reg_num_channels, 2
|
giuliomoro@188
|
515 CASE_2_CHANNELS:
|
giuliomoro@188
|
516 AND r27, reg_frame_current, 0x1
|
giuliomoro@188
|
517 QBNE GPIO_DONE, r27, 0
|
giuliomoro@188
|
518 JMP DO_GPIO
|
giuliomoro@188
|
519 CASE_4_OR_8_CHANNELS:
|
giuliomoro@102
|
520 AND r27, do_gpio, 0x3 // only do a DIGITAL every 2 SPI I/O
|
giuliomoro@102
|
521 QBNE GPIO_DONE, r27, 0
|
giuliomoro@188
|
522 DO_GPIO:
|
giuliomoro@16
|
523 //from here to GPIO_DONE takes 1.8us, while usually ADC_WAIT_FOR_FINISH only waits for 1.14us.
|
giuliomoro@19
|
524 //TODO: it would be better to split the DIGITAL stuff in two parts:
|
giuliomoro@16
|
525 //- one taking place during DAC_WRITE which sets the GPIO_OE
|
giuliomoro@16
|
526 //- and the other during ADC_WRITE which actually reads DATAIN and writes CLEAR/SET DATAOUT
|
giuliomoro@39
|
527 //r27 is actually r27, so do not use r27 from here to ...
|
giuliomoro@102
|
528 LBBO r27, reg_digital_current, 0, 4
|
giuliomoro@102
|
529 JAL r28.w0, DIGITAL // note that this is not called as a macro, but with JAL. r28 will contain the return address
|
giuliomoro@102
|
530 SBBO r27, reg_digital_current, 0, 4
|
giuliomoro@16
|
531 //..here you can start using r27 again
|
giuliomoro@102
|
532 ADD reg_digital_current, reg_digital_current, 4 //increment pointer
|
giuliomoro@16
|
533 GPIO_DONE:
|
giuliomoro@102
|
534 ADC_WAIT_FOR_FINISH
|
giuliomoro@102
|
535 ADC_RX out
|
giuliomoro@102
|
536 ADC_CS_UNASSERT
|
giuliomoro@16
|
537 .endm
|
giuliomoro@16
|
538
|
andrewm@0
|
539 // Write a McASP register
|
andrewm@0
|
540 .macro MCASP_REG_WRITE
|
andrewm@0
|
541 .mparam reg, value
|
giuliomoro@102
|
542 MOV r27, value
|
giuliomoro@102
|
543 SBBO r27, reg_mcasp_addr, reg, 4
|
andrewm@0
|
544 .endm
|
andrewm@0
|
545
|
andrewm@0
|
546 // Write a McASP register beyond the 0xFF boundary
|
andrewm@0
|
547 .macro MCASP_REG_WRITE_EXT
|
andrewm@0
|
548 .mparam reg, value
|
giuliomoro@102
|
549 MOV r27, value
|
giuliomoro@102
|
550 MOV r28, reg
|
giuliomoro@102
|
551 ADD r28, reg_mcasp_addr, r28
|
giuliomoro@102
|
552 SBBO r27, r28, 0, 4
|
andrewm@0
|
553 .endm
|
andrewm@0
|
554
|
andrewm@0
|
555 // Read a McASP register
|
andrewm@0
|
556 .macro MCASP_REG_READ
|
andrewm@0
|
557 .mparam reg, value
|
giuliomoro@102
|
558 LBBO value, reg_mcasp_addr, reg, 4
|
andrewm@0
|
559 .endm
|
andrewm@0
|
560
|
andrewm@0
|
561 // Read a McASP register beyond the 0xFF boundary
|
andrewm@0
|
562 .macro MCASP_REG_READ_EXT
|
andrewm@0
|
563 .mparam reg, value
|
giuliomoro@102
|
564 MOV r28, reg
|
giuliomoro@102
|
565 ADD r28, reg_mcasp_addr, r28
|
giuliomoro@102
|
566 LBBO value, r28, 0, 4
|
andrewm@0
|
567 .endm
|
andrewm@0
|
568
|
andrewm@0
|
569 // Set a bit and wait for it to come up
|
andrewm@0
|
570 .macro MCASP_REG_SET_BIT_AND_POLL
|
andrewm@0
|
571 .mparam reg, mask
|
giuliomoro@102
|
572 MOV r27, mask
|
giuliomoro@102
|
573 LBBO r28, reg_mcasp_addr, reg, 4
|
giuliomoro@102
|
574 OR r28, r28, r27
|
giuliomoro@102
|
575 SBBO r28, reg_mcasp_addr, reg, 4
|
andrewm@0
|
576 POLL:
|
giuliomoro@102
|
577 LBBO r28, reg_mcasp_addr, reg, 4
|
giuliomoro@102
|
578 AND r28, r28, r27
|
giuliomoro@102
|
579 QBEQ POLL, r28, 0
|
andrewm@0
|
580 .endm
|
andrewm@282
|
581
|
andrewm@282
|
582 // Multiplexer Capelet: Increment channel on muxes 0-3
|
andrewm@282
|
583 .macro MUX_INCREMENT_0_TO_3
|
andrewm@282
|
584 MOV r28, FLAG_MASK_MUX_CONFIG
|
andrewm@282
|
585 AND r28, reg_flags, r28 // Check flags
|
andrewm@282
|
586 QBEQ DONE, r28, 0 // Skip if disabled
|
andrewm@282
|
587 LSR r28, r28, FLAG_BIT_MUX_CONFIG0
|
andrewm@282
|
588 AND r27, reg_pru1_mux_pins, 0x07 // Current mux channel in r30 bits 2-0
|
andrewm@282
|
589 ADD r27, r27, 1 // Increment channel
|
andrewm@282
|
590 AND r27, r27, 0x07 // Mask to 8 channels
|
andrewm@282
|
591 QBEQ UPDATE, r28, 0x03
|
andrewm@282
|
592 AND r27, r27, 0x03 // Mask to 4 channels
|
andrewm@282
|
593 QBEQ UPDATE, r28, 0x02
|
andrewm@282
|
594 AND r27, r27, 0x01 // Mask to 2 channels
|
andrewm@282
|
595 UPDATE:
|
andrewm@282
|
596 MOV r28, 0xFFFFFFF8
|
andrewm@282
|
597 AND r28, reg_pru1_mux_pins, r28 // Mask out low 3 bits of r30
|
andrewm@282
|
598 OR r28, r28, r27 // Combine with new value
|
andrewm@282
|
599 MOV reg_pru1_mux_pins, r28 // Move back to r30 to propagate to pins
|
andrewm@282
|
600 DONE:
|
andrewm@282
|
601 .endm
|
andrewm@283
|
602
|
andrewm@283
|
603 // Multiplexer Capelet: Increment channel on muxes 4-7
|
andrewm@283
|
604 .macro MUX_INCREMENT_4_TO_7
|
andrewm@283
|
605 MOV r28, FLAG_MASK_MUX_CONFIG
|
andrewm@283
|
606 AND r28, reg_flags, r28 // Check flags
|
andrewm@283
|
607 QBEQ DONE, r28, 0 // Skip if disabled
|
andrewm@283
|
608 LSR r28, r28, FLAG_BIT_MUX_CONFIG0
|
andrewm@283
|
609 AND r27, reg_pru1_mux_pins, 0x38 // Current mux channel in r30 bits 5-3
|
andrewm@283
|
610 ADD r27, r27, 8 // Increment channel (+1 LSB starting at bit 3)
|
andrewm@283
|
611 AND r27, r27, 0x38 // Mask to 8 channels
|
andrewm@283
|
612 QBEQ UPDATE, r28, 0x03
|
andrewm@283
|
613 AND r27, r27, 0x18 // Mask to 4 channels
|
andrewm@283
|
614 QBEQ UPDATE, r28, 0x02
|
andrewm@283
|
615 AND r27, r27, 0x08 // Mask to 2 channels
|
andrewm@283
|
616 UPDATE:
|
andrewm@283
|
617 MOV r28, 0xFFFFFFC7
|
andrewm@283
|
618 AND r28, reg_pru1_mux_pins, r28 // Mask out bits 5-3 of r30
|
andrewm@283
|
619 OR r28, r28, r27 // Combine with new value
|
andrewm@283
|
620 MOV reg_pru1_mux_pins, r28 // Move back to r30 to propagate to pins
|
andrewm@283
|
621 DONE:
|
andrewm@283
|
622 .endm
|
andrewm@283
|
623
|
andrewm@282
|
624
|
andrewm@0
|
625 START:
|
andrewm@253
|
626 // Load useful registers for addressing SPI
|
andrewm@253
|
627 MOV reg_comm_addr, SHARED_COMM_MEM_BASE
|
andrewm@253
|
628 MOV reg_spi_addr, SPI_BASE
|
andrewm@253
|
629 MOV reg_mcasp_addr, MCASP_BASE
|
andrewm@253
|
630
|
andrewm@253
|
631 // Find out which PRU we are running on
|
andrewm@253
|
632 // This affects the following offsets
|
andrewm@253
|
633 MOV r0, 0x24000 // PRU1 control register offset
|
andrewm@253
|
634 LBBO r2, reg_comm_addr, COMM_PRU_NUMBER, 4
|
andrewm@253
|
635 QBEQ PRU_NUMBER_CHECK_DONE, r2, 1
|
andrewm@253
|
636 MOV r0, 0x22000 // PRU0 control register offset
|
andrewm@253
|
637 PRU_NUMBER_CHECK_DONE:
|
andrewm@253
|
638
|
giuliomoro@102
|
639 // Set up c24 and c25 offsets with CTBIR register
|
giuliomoro@102
|
640 // Thus C24 points to start of PRU0 RAM
|
andrewm@253
|
641 OR r3, r0, 0x20 // CTBIR0
|
giuliomoro@102
|
642 MOV r2, 0
|
giuliomoro@102
|
643 SBBO r2, r3, 0, 4
|
andrewm@0
|
644
|
giuliomoro@102
|
645 // Set up c28 pointer offset for shared PRU RAM
|
andrewm@253
|
646 OR r3, r0, 0x28 // CTPPR0
|
giuliomoro@102
|
647 MOV r2, 0x00000120 // To get address 0x00012000
|
giuliomoro@102
|
648 SBBO r2, r3, 0, 4
|
andrewm@0
|
649
|
giuliomoro@102
|
650 // Set ARM such that PRU can write to registers
|
giuliomoro@102
|
651 LBCO r0, C4, 4, 4
|
giuliomoro@102
|
652 CLR r0, r0, 4
|
giuliomoro@102
|
653 SBCO r0, C4, 4, 4
|
andrewm@0
|
654
|
giuliomoro@102
|
655 // Clear flags
|
giuliomoro@102
|
656 MOV reg_flags, 0
|
giuliomoro@102
|
657 // Default number of channels in case SPI disabled
|
giuliomoro@102
|
658 LDI reg_num_channels, 8
|
andrewm@0
|
659
|
giuliomoro@102
|
660 // Find out whether we should use DIGITAL
|
giuliomoro@102
|
661 LBBO r2, reg_comm_addr, COMM_USE_DIGITAL, 4
|
giuliomoro@102
|
662 QBEQ DIGITAL_INIT_DONE, r2, 0 // if we use digital
|
giuliomoro@102
|
663 SET reg_flags, reg_flags, FLAG_BIT_USE_DIGITAL
|
giuliomoro@38
|
664 /* This block of code is not really needed, as the memory is initialized by ARM before the PRU is started.
|
giuliomoro@38
|
665 Will leave it here for future reference
|
giuliomoro@38
|
666 DIGITAL_INIT: //set the digital buffer to 0x0000ffff (all inputs), to prevent unwanted high outputs
|
giuliomoro@38
|
667 //the loop is unrolled by a factor of four just to take advantage of the speed of SBBO on larger byte bursts, but there is no real need for it
|
giuliomoro@102
|
668 MOV r2, 0x0000ffff //value to store. 0x0000ffff means all inputs
|
giuliomoro@102
|
669 MOV r3, MEM_DIGITAL_BASE //start of the digital buffer
|
giuliomoro@102
|
670 MOV r4, MEM_DIGITAL_BASE+2*MEM_DIGITAL_BUFFER1_OFFSET //end of the digital buffer
|
giuliomoro@38
|
671 DIGITAL_INIT_BUFFER_LOOP:
|
giuliomoro@102
|
672 SBBO r2, r3, 0, 4
|
giuliomoro@102
|
673 ADD r3, r3, 4 //increment pointer
|
giuliomoro@102
|
674 QBGT DIGITAL_INIT_BUFFER_LOOP, r3, r4 //loop until we reach the end of the buffer
|
giuliomoro@38
|
675 */
|
giuliomoro@38
|
676 DIGITAL_INIT_DONE:
|
andrewm@282
|
677 // Check if we should use an external multiplexer capelet
|
andrewm@282
|
678 // The valid values are 0 (off), 1 (2 ch), 2 (4 ch), 3 (8 ch)
|
andrewm@282
|
679 // This can only happen on PRU1 because of how the pins are mapped
|
andrewm@282
|
680 LBBO r2, reg_comm_addr, COMM_PRU_NUMBER, 4
|
andrewm@282
|
681 QBNE MUX_INIT_DONE, r2, 1
|
andrewm@282
|
682 LBBO r2, reg_comm_addr, COMM_MUX_CONFIG, 4
|
andrewm@282
|
683 AND r2, r2, 0x03
|
andrewm@282
|
684 QBEQ MUX_INIT_DONE, r2, 0
|
andrewm@282
|
685 // If we get here, we are using the mux. Prepare flags and initial state.
|
andrewm@282
|
686 LSL r2, r2, FLAG_BIT_MUX_CONFIG0
|
andrewm@282
|
687 OR reg_flags, reg_flags, r2
|
andrewm@282
|
688 // Clear lower 6 bits of r30 which controls the mux pins
|
andrewm@282
|
689 MOV r2, 0xFFFFFFC0
|
andrewm@282
|
690 AND reg_pru1_mux_pins, reg_pru1_mux_pins, r2
|
andrewm@282
|
691 MUX_INIT_DONE:
|
andrewm@282
|
692
|
giuliomoro@102
|
693 // Find out whether we should use SPI ADC and DAC
|
giuliomoro@102
|
694 LBBO r2, reg_comm_addr, COMM_USE_SPI, 4
|
giuliomoro@102
|
695 QBEQ SPI_FLAG_CHECK_DONE, r2, 0
|
giuliomoro@102
|
696 SET reg_flags, reg_flags, FLAG_BIT_USE_SPI
|
andrewm@0
|
697 SPI_FLAG_CHECK_DONE:
|
giuliomoro@102
|
698 // If we don't use SPI, then skip all this init
|
giuliomoro@102
|
699 QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI
|
andrewm@12
|
700
|
giuliomoro@102
|
701 // Load the number of channels: valid values are 8, 4 or 2
|
giuliomoro@102
|
702 LBBO reg_num_channels, reg_comm_addr, COMM_NUM_CHANNELS, 4
|
giuliomoro@102
|
703 QBGT SPI_NUM_CHANNELS_LT8, reg_num_channels, 8 // 8 > num_channels ?
|
giuliomoro@102
|
704 LDI reg_num_channels, 8 // If N >= 8, N = 8
|
giuliomoro@102
|
705 QBA SPI_NUM_CHANNELS_DONE
|
andrewm@12
|
706 SPI_NUM_CHANNELS_LT8:
|
giuliomoro@102
|
707 QBGT SPI_NUM_CHANNELS_LT4, reg_num_channels, 4 // 4 > num_channels ?
|
giuliomoro@102
|
708 LDI reg_num_channels, 4 // If N >= 4, N = 4
|
giuliomoro@102
|
709 QBA SPI_NUM_CHANNELS_DONE
|
andrewm@12
|
710 SPI_NUM_CHANNELS_LT4:
|
giuliomoro@102
|
711 LDI reg_num_channels, 2 // else N = 2
|
andrewm@12
|
712 SPI_NUM_CHANNELS_DONE:
|
andrewm@0
|
713
|
giuliomoro@102
|
714 // Init SPI clock
|
giuliomoro@102
|
715 MOV r2, 0x02
|
giuliomoro@102
|
716 MOV r3, CLOCK_BASE + CLOCK_SPI0
|
giuliomoro@102
|
717 SBBO r2, r3, 0, 4
|
andrewm@0
|
718
|
giuliomoro@102
|
719 // Reset SPI and wait for finish
|
giuliomoro@102
|
720 MOV r2, 0x02
|
giuliomoro@102
|
721 SBBO r2, reg_spi_addr, SPI_SYSCONFIG, 4
|
andrewm@0
|
722
|
andrewm@0
|
723 SPI_WAIT_RESET:
|
giuliomoro@102
|
724 LBBO r2, reg_spi_addr, SPI_SYSSTATUS, 4
|
giuliomoro@102
|
725 QBBC SPI_WAIT_RESET, r2, 0
|
andrewm@0
|
726
|
giuliomoro@102
|
727 // Turn off SPI channels
|
giuliomoro@102
|
728 MOV r2, 0
|
giuliomoro@102
|
729 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
|
giuliomoro@102
|
730 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
|
andrewm@0
|
731
|
giuliomoro@102
|
732 // Set to master; chip select lines enabled (CS0 used for DAC)
|
giuliomoro@102
|
733 MOV r2, 0x00
|
giuliomoro@102
|
734 SBBO r2, reg_spi_addr, SPI_MODULCTRL, 4
|
andrewm@0
|
735
|
giuliomoro@102
|
736 // Configure CH0 for DAC
|
giuliomoro@102
|
737 MOV r2, (3 << 27) | (DAC_DPE << 16) | (DAC_TRM << 12) | ((DAC_WL - 1) << 7) | (DAC_CLK_DIV << 2) | DAC_CLK_MODE | (1 << 6)
|
giuliomoro@102
|
738 SBBO r2, reg_spi_addr, SPI_CH0CONF, 4
|
andrewm@0
|
739
|
giuliomoro@102
|
740 // Configure CH1 for ADC
|
giuliomoro@102
|
741 MOV r2, (3 << 27) | (ADC_DPE << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE
|
giuliomoro@102
|
742 SBBO r2, reg_spi_addr, SPI_CH1CONF, 4
|
andrewm@0
|
743
|
giuliomoro@102
|
744 // Turn on SPI channels
|
giuliomoro@102
|
745 MOV r2, 0x01
|
giuliomoro@102
|
746 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
|
giuliomoro@102
|
747 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
|
andrewm@0
|
748
|
giuliomoro@102
|
749 // DAC power-on reset sequence
|
giuliomoro@102
|
750 MOV r2, (0x07 << AD5668_COMMAND_OFFSET)
|
giuliomoro@102
|
751 DAC_WRITE r2
|
andrewm@0
|
752
|
giuliomoro@102
|
753 // Initialise ADC
|
giuliomoro@102
|
754 MOV r2, AD7699_CFG_MASK | (0 << AD7699_CHANNEL_OFFSET) | (0 << AD7699_SEQ_OFFSET)
|
giuliomoro@102
|
755 ADC_WRITE r2, r2
|
andrewm@0
|
756
|
giuliomoro@102
|
757 // Enable DAC internal reference
|
giuliomoro@102
|
758 MOV r2, (0x08 << AD5668_COMMAND_OFFSET) | (0x01 << AD5668_REF_OFFSET)
|
giuliomoro@102
|
759 DAC_WRITE r2
|
andrewm@0
|
760
|
giuliomoro@102
|
761 // Read ADC ch0 and ch1: result is always 2 samples behind so start here
|
giuliomoro@102
|
762 MOV r2, AD7699_CFG_MASK | (0x00 << AD7699_CHANNEL_OFFSET)
|
giuliomoro@102
|
763 ADC_WRITE r2, r2
|
andrewm@0
|
764
|
giuliomoro@102
|
765 MOV r2, AD7699_CFG_MASK | (0x01 << AD7699_CHANNEL_OFFSET)
|
giuliomoro@102
|
766 ADC_WRITE r2, r2
|
andrewm@0
|
767 SPI_INIT_DONE:
|
andrewm@0
|
768
|
giuliomoro@102
|
769 // Prepare McASP0 for audio
|
giuliomoro@102
|
770 MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP
|
giuliomoro@102
|
771 MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off
|
giuliomoro@102
|
772 MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0
|
giuliomoro@102
|
773 MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0
|
giuliomoro@102
|
774 MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0
|
giuliomoro@102
|
775 MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0
|
giuliomoro@102
|
776 MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0
|
andrewm@0
|
777
|
giuliomoro@102
|
778 MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on
|
giuliomoro@102
|
779 MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP
|
giuliomoro@102
|
780 MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS // Set pin direction
|
giuliomoro@102
|
781 MCASP_REG_WRITE MCASP_DLBCTL, 0x00
|
giuliomoro@102
|
782 MCASP_REG_WRITE MCASP_DITCTL, 0x00
|
giuliomoro@102
|
783 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive
|
giuliomoro@102
|
784 MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format
|
giuliomoro@102
|
785 MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode
|
giuliomoro@102
|
786 MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge
|
giuliomoro@102
|
787 MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant?
|
giuliomoro@102
|
788 MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1
|
giuliomoro@102
|
789 MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts
|
giuliomoro@102
|
790 MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit
|
giuliomoro@102
|
791 MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format
|
giuliomoro@102
|
792 MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode
|
giuliomoro@102
|
793 MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv
|
giuliomoro@102
|
794 MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX
|
giuliomoro@102
|
795 MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1
|
giuliomoro@102
|
796 MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts
|
andrewm@0
|
797
|
giuliomoro@102
|
798 MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser
|
giuliomoro@102
|
799 MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser
|
giuliomoro@102
|
800 MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x00 // Disable FIFOs
|
giuliomoro@102
|
801 MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x00
|
andrewm@0
|
802
|
giuliomoro@102
|
803 MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors
|
giuliomoro@102
|
804 MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors
|
andrewm@0
|
805
|
giuliomoro@102
|
806 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1) // Set RHCLKRST
|
giuliomoro@102
|
807 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9) // Set XHCLKRST
|
andrewm@0
|
808
|
andrewm@0
|
809 // The above write sequence will have temporarily changed the AHCLKX frequency
|
andrewm@0
|
810 // The PLL needs time to settle or the sample rate will be unstable and possibly
|
andrewm@0
|
811 // cause an underrun. Give it ~1ms before going on.
|
andrewm@0
|
812 // 10ns per loop iteration = 10^-8s --> 10^5 iterations needed
|
andrewm@0
|
813
|
giuliomoro@102
|
814 MOV r2, 1 << 28
|
giuliomoro@102
|
815 MOV r3, GPIO1 + GPIO_SETDATAOUT
|
giuliomoro@102
|
816 SBBO r2, r3, 0, 4
|
andrewm@0
|
817
|
andrewm@0
|
818 MOV r2, 100000
|
andrewm@0
|
819 MCASP_INIT_WAIT:
|
giuliomoro@102
|
820 SUB r2, r2, 1
|
giuliomoro@102
|
821 QBNE MCASP_INIT_WAIT, r2, 0
|
andrewm@0
|
822
|
giuliomoro@102
|
823 MOV r2, 1 << 28
|
giuliomoro@102
|
824 MOV r3, GPIO1 + GPIO_CLEARDATAOUT
|
giuliomoro@102
|
825 SBBO r2, r3, 0, 4
|
giuliomoro@102
|
826
|
andrewm@0
|
827 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0) // Set RCLKRST
|
andrewm@0
|
828 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8) // Set XCLKRST
|
andrewm@0
|
829 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2) // Set RSRCLR
|
andrewm@0
|
830 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10) // Set XSRCLR
|
andrewm@0
|
831 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3) // Set RSMRST
|
andrewm@0
|
832 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST
|
andrewm@0
|
833
|
andrewm@0
|
834 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00 // Write to the transmit buffer to prevent underflow
|
andrewm@0
|
835
|
andrewm@0
|
836 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST
|
andrewm@0
|
837 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST
|
andrewm@0
|
838
|
andrewm@0
|
839 // Initialisation
|
giuliomoro@38
|
840 LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4 // Total frame count (SPI; 0.5x-2x for McASP)
|
giuliomoro@38
|
841 MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer
|
giuliomoro@38
|
842 LSL reg_dac_buf1, reg_frame_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize
|
giuliomoro@38
|
843 LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels
|
giuliomoro@38
|
844 LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above
|
giuliomoro@38
|
845 MOV reg_mcasp_buf0, 0 // McASP DAC buffer 0 start pointer
|
giuliomoro@38
|
846 LSL reg_mcasp_buf1, reg_frame_total, r2 // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*(N/4)[samples/spi]*bufsize
|
giuliomoro@38
|
847 CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on
|
giuliomoro@38
|
848 MOV r2, 0
|
giuliomoro@38
|
849 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0
|
giuliomoro@38
|
850 /* This block of code is not really needed, as the memory is initialized by ARM before the PRU is started.
|
giuliomoro@38
|
851 Will leave it here for future reference
|
giuliomoro@38
|
852 //Initialise all SPI and audio buffers (DAC0, DAC1, ADC0, ADC1) to zero.
|
giuliomoro@38
|
853 //This is useful for analog outs so they do not have spikes during the first buffer.
|
giuliomoro@38
|
854 //This is not very useful for audio, as you still hear the initial "tumpf" when the converter starts
|
giuliomoro@38
|
855 //and each sample in the DAC buffer is reset to 0 after it is written to the DAC.
|
giuliomoro@38
|
856
|
giuliomoro@38
|
857 QBBC SPI_INIT_BUFFER_DONE, reg_flags, FLAG_BIT_USE_SPI
|
giuliomoro@38
|
858 //Initialize SPI buffers
|
giuliomoro@38
|
859 //compute the memory offset of the end of the audio buffer and store it in r4
|
giuliomoro@38
|
860 SUB r4, reg_dac_buf1, reg_dac_buf0 // length of the buffer, assumes reg_dac_buf1>ref_dac_buf0
|
giuliomoro@38
|
861 LSL r4, r4, 2 //length of four buffers (DAC0, DAC1, ADC0, ADC1)
|
giuliomoro@38
|
862 ADD r4, reg_dac_buf0, r4 //total offset
|
giuliomoro@38
|
863 MOV r2, 0// value to store
|
giuliomoro@38
|
864 MOV r3, 0 // offset counter
|
giuliomoro@38
|
865 SPI_INIT_BUFFER_LOOP:
|
giuliomoro@38
|
866 SBCO r2, C_ADC_DAC_MEM, r3, 4
|
giuliomoro@38
|
867 ADD r3, r3, 4
|
giuliomoro@38
|
868 QBGT SPI_INIT_BUFFER_LOOP, r3, r4
|
giuliomoro@38
|
869 SPI_INIT_BUFFER_DONE:
|
giuliomoro@38
|
870
|
giuliomoro@38
|
871 //Initialize audio buffers
|
giuliomoro@38
|
872 //compute the memory offset of the end of the audio buffer and store it in r4
|
giuliomoro@38
|
873 SUB r4, reg_mcasp_buf1, reg_mcasp_buf0 // length of the buffer, assumes reg_mcasp_buf1>ref_mcasp_buf0
|
giuliomoro@38
|
874 LSL r4, r4, 2 //length of four buffers (DAC0, DAC1, ADC0, ADC1)
|
giuliomoro@38
|
875 ADD r4, reg_mcasp_buf0, r4 //total offset
|
giuliomoro@38
|
876 MOV r2, 0 // value to store
|
giuliomoro@38
|
877 MOV r3, 0 // offset counter
|
giuliomoro@38
|
878 MCASP_INIT_BUFFER_LOOP:
|
giuliomoro@38
|
879 SBCO r2, C_MCASP_MEM, r3, 4
|
giuliomoro@38
|
880 ADD r3, r3, 4
|
giuliomoro@38
|
881 QBGT MCASP_INIT_BUFFER_LOOP, r3, r4
|
giuliomoro@38
|
882 */
|
andrewm@0
|
883 // Here we are out of sync by one TDM slot since the 0 word transmitted above will have occupied
|
andrewm@0
|
884 // the first output slot. Send one more word before jumping into the loop.
|
andrewm@0
|
885 MCASP_DAC_WAIT_BEFORE_LOOP:
|
giuliomoro@102
|
886 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
|
giuliomoro@102
|
887 QBBC MCASP_DAC_WAIT_BEFORE_LOOP, r2, MCASP_XSTAT_XDATA_BIT
|
andrewm@0
|
888
|
giuliomoro@102
|
889 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00
|
andrewm@0
|
890
|
andrewm@0
|
891 // Likewise, read and discard the first sample we get back from the ADC. This keeps the DAC and ADC
|
andrewm@0
|
892 // in sync in terms of which TDM slot we are reading (empirically found that we should throw this away
|
andrewm@0
|
893 // rather than keep it and invert the phase)
|
andrewm@0
|
894 MCASP_ADC_WAIT_BEFORE_LOOP:
|
giuliomoro@102
|
895 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
|
giuliomoro@102
|
896 QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT
|
andrewm@0
|
897
|
giuliomoro@102
|
898 MCASP_REG_READ_EXT MCASP_RBUF, r2
|
andrewm@0
|
899
|
andrewm@0
|
900 WRITE_ONE_BUFFER:
|
giuliomoro@38
|
901
|
giuliomoro@102
|
902 // Write a single buffer of DAC samples and read a buffer of ADC samples
|
giuliomoro@102
|
903 // Load starting positions
|
giuliomoro@102
|
904 MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer
|
giuliomoro@102
|
905 LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels
|
giuliomoro@102
|
906 LSL reg_adc_current, reg_frame_total, r2
|
giuliomoro@102
|
907 LSL reg_adc_current, reg_adc_current, 2 // N * 2 * 2 * bufsize
|
giuliomoro@102
|
908 ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts N * 2 * 2 * bufsize beyond DAC
|
giuliomoro@102
|
909 MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer
|
giuliomoro@102
|
910 LSL reg_mcasp_adc_current, reg_frame_total, r2 // McASP ADC: starts (N/2)*2*2*bufsize beyond DAC
|
giuliomoro@102
|
911 LSL reg_mcasp_adc_current, reg_mcasp_adc_current, 1
|
giuliomoro@102
|
912 ADC reg_mcasp_adc_current, reg_mcasp_adc_current, reg_mcasp_dac_current
|
giuliomoro@102
|
913 MOV reg_frame_current, 0
|
giuliomoro@102
|
914 QBBS DIGITAL_BASE_CHECK_SET, reg_flags, FLAG_BIT_BUFFER1 //check which buffer we are using for DIGITAL
|
giuliomoro@16
|
915 // if we are here, we are using buffer0
|
giuliomoro@102
|
916 MOV reg_digital_current, MEM_DIGITAL_BASE
|
giuliomoro@102
|
917 QBA DIGITAL_BASE_CHECK_DONE
|
giuliomoro@19
|
918 DIGITAL_BASE_CHECK_SET: //if we are here, we are using buffer1
|
giuliomoro@102
|
919 MOV reg_digital_current, MEM_DIGITAL_BASE+MEM_DIGITAL_BUFFER1_OFFSET //so adjust offset appropriately
|
giuliomoro@19
|
920 DIGITAL_BASE_CHECK_DONE:
|
giuliomoro@16
|
921
|
andrewm@0
|
922 WRITE_LOOP:
|
giuliomoro@102
|
923 // Write N channels to DAC from successive values in memory
|
giuliomoro@102
|
924 // At the same time, read N channels from ADC
|
giuliomoro@102
|
925 // Unrolled by a factor of 2 to get high and low words
|
giuliomoro@102
|
926 MOV r1, 0
|
andrewm@0
|
927 ADC_DAC_LOOP:
|
giuliomoro@102
|
928 QBBC SPI_DAC_LOAD_DONE, reg_flags, FLAG_BIT_USE_SPI
|
giuliomoro@102
|
929 // Load next 2 SPI DAC samples and store zero in their place
|
giuliomoro@102
|
930 LBCO reg_dac_data, C_ADC_DAC_MEM, reg_dac_current, 4
|
giuliomoro@102
|
931 MOV r2, 0
|
giuliomoro@102
|
932 SBCO r2, C_ADC_DAC_MEM, reg_dac_current, 4
|
giuliomoro@102
|
933 ADD reg_dac_current, reg_dac_current, 4
|
andrewm@0
|
934 SPI_DAC_LOAD_DONE:
|
andrewm@0
|
935
|
giuliomoro@102
|
936 // On even iterations, load two more samples and choose the first one
|
giuliomoro@102
|
937 // On odd iterations, transmit the second of the samples already loaded
|
giuliomoro@102
|
938 // QBBS MCASP_DAC_HIGH_WORD, r1, 1
|
giuliomoro@102
|
939 QBBS MCASP_DAC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
|
andrewm@0
|
940 MCASP_DAC_LOW_WORD:
|
giuliomoro@102
|
941 // Load next 2 Audio DAC samples and store zero in their place
|
giuliomoro@102
|
942 LBCO reg_mcasp_dac_data, C_MCASP_MEM, reg_mcasp_dac_current, 4
|
giuliomoro@102
|
943 MOV r2, 0
|
giuliomoro@102
|
944 SBCO r2, C_MCASP_MEM, reg_mcasp_dac_current, 4
|
giuliomoro@102
|
945 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4
|
andrewm@0
|
946
|
giuliomoro@102
|
947 // Mask out the low word (first in little endian)
|
giuliomoro@102
|
948 MOV r2, 0xFFFF
|
giuliomoro@102
|
949 AND r7, reg_mcasp_dac_data, r2
|
andrewm@0
|
950
|
giuliomoro@102
|
951 QBA MCASP_WAIT_XSTAT
|
andrewm@0
|
952 MCASP_DAC_HIGH_WORD:
|
giuliomoro@102
|
953 // Take the high word of the previously loaded data
|
giuliomoro@102
|
954 LSR r7, reg_mcasp_dac_data, 16
|
andrewm@0
|
955
|
giuliomoro@102
|
956 // Every 2 channels we send one audio sample; this loop already
|
giuliomoro@102
|
957 // sends exactly two SPI channels.
|
giuliomoro@102
|
958 // Wait for McASP XSTAT[XDATA] to set indicating we can write more data
|
andrewm@0
|
959 MCASP_WAIT_XSTAT:
|
giuliomoro@102
|
960 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
|
giuliomoro@102
|
961 QBBS START, r2, MCASP_XSTAT_XUNDRN_BIT // if underrun occurred, reset the PRU
|
giuliomoro@102
|
962 QBBC MCASP_WAIT_XSTAT, r2, MCASP_XSTAT_XDATA_BIT
|
andrewm@0
|
963
|
giuliomoro@102
|
964 MCASP_REG_WRITE_EXT MCASP_XBUF, r7
|
andrewm@0
|
965
|
giuliomoro@102
|
966 // Same idea with ADC: even iterations, load the sample into the low word, odd
|
giuliomoro@102
|
967 // iterations, load the sample into the high word and store
|
giuliomoro@102
|
968 // QBBS MCASP_ADC_HIGH_WORD, r1, 1
|
giuliomoro@102
|
969 QBBS MCASP_ADC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
|
andrewm@0
|
970 MCASP_ADC_LOW_WORD:
|
giuliomoro@102
|
971 // Start ADC data at 0
|
giuliomoro@102
|
972 LDI reg_mcasp_adc_data, 0
|
andrewm@0
|
973
|
giuliomoro@102
|
974 // Now wait for a received word to become available from the audio ADC
|
andrewm@0
|
975 MCASP_WAIT_RSTAT_LOW:
|
giuliomoro@102
|
976 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
|
giuliomoro@102
|
977 QBBC MCASP_WAIT_RSTAT_LOW, r2, MCASP_RSTAT_RDATA_BIT
|
andrewm@0
|
978
|
giuliomoro@102
|
979 // Mask low word and store in ADC data register
|
giuliomoro@102
|
980 MCASP_REG_READ_EXT MCASP_RBUF, r3
|
giuliomoro@102
|
981 MOV r2, 0xFFFF
|
giuliomoro@102
|
982 AND reg_mcasp_adc_data, r3, r2
|
giuliomoro@102
|
983 QBA MCASP_ADC_DONE
|
andrewm@0
|
984
|
andrewm@0
|
985 MCASP_ADC_HIGH_WORD:
|
giuliomoro@102
|
986 // Wait for a received word to become available from the audio ADC
|
andrewm@0
|
987 MCASP_WAIT_RSTAT_HIGH:
|
giuliomoro@102
|
988 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
|
giuliomoro@102
|
989 QBBC MCASP_WAIT_RSTAT_HIGH, r2, MCASP_RSTAT_RDATA_BIT
|
andrewm@0
|
990
|
giuliomoro@102
|
991 // Read data and shift 16 bits to the left (into the high word)
|
giuliomoro@102
|
992 MCASP_REG_READ_EXT MCASP_RBUF, r3
|
giuliomoro@102
|
993 LSL r3, r3, 16
|
giuliomoro@102
|
994 OR reg_mcasp_adc_data, reg_mcasp_adc_data, r3
|
andrewm@0
|
995
|
giuliomoro@102
|
996 // Now store the result and increment the pointer
|
giuliomoro@102
|
997 SBCO reg_mcasp_adc_data, C_MCASP_MEM, reg_mcasp_adc_current, 4
|
giuliomoro@102
|
998 ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4
|
andrewm@0
|
999 MCASP_ADC_DONE:
|
giuliomoro@102
|
1000 QBBC SPI_SKIP_WRITE, reg_flags, FLAG_BIT_USE_SPI
|
giuliomoro@26
|
1001
|
giuliomoro@102
|
1002 // DAC: transmit low word (first in little endian)
|
giuliomoro@102
|
1003 MOV r2, 0xFFFF
|
giuliomoro@102
|
1004 AND r7, reg_dac_data, r2
|
giuliomoro@102
|
1005 LSL r7, r7, AD5668_DATA_OFFSET
|
giuliomoro@102
|
1006 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
|
giuliomoro@102
|
1007 OR r7, r7, r8
|
andrewm@346
|
1008 DAC_CHANNEL_REORDER r8, r1
|
andrewm@346
|
1009 LSL r8, r8, AD5668_ADDRESS_OFFSET
|
giuliomoro@102
|
1010 OR r7, r7, r8
|
giuliomoro@102
|
1011 DAC_WRITE r7
|
andrewm@0
|
1012
|
giuliomoro@102
|
1013 // Read ADC channels: result is always 2 commands behind
|
giuliomoro@102
|
1014 // Start by reading channel 2 (result is channel 0) and go
|
giuliomoro@102
|
1015 // to N+2, but masking the channel number to be between 0 and N-1
|
giuliomoro@102
|
1016 LDI reg_adc_data, 0
|
giuliomoro@102
|
1017 ADD r8, r1, 2
|
giuliomoro@102
|
1018 SUB r7, reg_num_channels, 1
|
giuliomoro@102
|
1019 AND r8, r8, r7
|
giuliomoro@102
|
1020 LSL r8, r8, AD7699_CHANNEL_OFFSET
|
giuliomoro@102
|
1021 MOV r7, AD7699_CFG_MASK
|
giuliomoro@102
|
1022 OR r7, r7, r8
|
giuliomoro@38
|
1023
|
giuliomoro@102
|
1024 ADC_WRITE_GPIO r7, r7, r1
|
andrewm@0
|
1025
|
giuliomoro@102
|
1026 // Mask out only the relevant 16 bits and store in reg_adc_data
|
giuliomoro@102
|
1027 MOV r2, 0xFFFF
|
giuliomoro@102
|
1028 AND reg_adc_data, r7, r2
|
giuliomoro@102
|
1029 // Increment channel index
|
giuliomoro@102
|
1030 ADD r1, r1, 1
|
andrewm@0
|
1031
|
giuliomoro@102
|
1032 // DAC: transmit high word (second in little endian)
|
giuliomoro@102
|
1033 LSR r7, reg_dac_data, 16
|
giuliomoro@102
|
1034 LSL r7, r7, AD5668_DATA_OFFSET
|
giuliomoro@102
|
1035 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
|
giuliomoro@102
|
1036 OR r7, r7, r8
|
andrewm@346
|
1037 DAC_CHANNEL_REORDER r8, r1
|
andrewm@346
|
1038 LSL r8, r8, AD5668_ADDRESS_OFFSET
|
giuliomoro@102
|
1039 OR r7, r7, r8
|
giuliomoro@102
|
1040 DAC_WRITE r7
|
andrewm@0
|
1041
|
giuliomoro@102
|
1042 // Read ADC channels: result is always 2 commands behind
|
giuliomoro@102
|
1043 // Start by reading channel 2 (result is channel 0) and go
|
giuliomoro@102
|
1044 // to N+2, but masking the channel number to be between 0 and N-1
|
giuliomoro@102
|
1045 ADD r8, r1, 2
|
giuliomoro@102
|
1046 SUB r7, reg_num_channels, 1
|
giuliomoro@102
|
1047 AND r8, r8, r7
|
giuliomoro@102
|
1048 LSL r8, r8, AD7699_CHANNEL_OFFSET
|
giuliomoro@102
|
1049 MOV r7, AD7699_CFG_MASK
|
giuliomoro@102
|
1050 OR r7, r7, r8
|
giuliomoro@102
|
1051 ADC_WRITE r7, r7
|
andrewm@0
|
1052
|
giuliomoro@102
|
1053 // Move this result up to the 16 high bits
|
giuliomoro@102
|
1054 LSL r7, r7, 16
|
giuliomoro@102
|
1055 OR reg_adc_data, reg_adc_data, r7
|
andrewm@0
|
1056
|
giuliomoro@102
|
1057 // Store 2 ADC words in memory
|
giuliomoro@102
|
1058 SBCO reg_adc_data, C_ADC_DAC_MEM, reg_adc_current, 4
|
giuliomoro@102
|
1059 ADD reg_adc_current, reg_adc_current, 4
|
andrewm@0
|
1060
|
andrewm@282
|
1061 // If enabled, update the multiplexer settings
|
andrewm@282
|
1062 QBNE MUX_0_3_DONE, r1, 3 // Change mux settings for ch0-3 after reading ch. 3
|
andrewm@282
|
1063 MUX_INCREMENT_0_TO_3
|
andrewm@282
|
1064 MUX_0_3_DONE:
|
andrewm@283
|
1065 QBNE MUX_4_7_DONE, r1, 7 // Change mux settings for ch4-7 after reading ch. 7
|
andrewm@283
|
1066 MUX_INCREMENT_4_TO_7
|
andrewm@283
|
1067 MUX_4_7_DONE:
|
andrewm@282
|
1068
|
giuliomoro@102
|
1069 // Toggle the high/low word for McASP control (since we send one word out of
|
giuliomoro@102
|
1070 // 32 bits for each pair of SPI channels)
|
giuliomoro@102
|
1071 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
|
giuliomoro@102
|
1072
|
giuliomoro@102
|
1073 // Repeat 4 times for 8 channels (2 samples per loop, r1 += 1 already happened)
|
giuliomoro@102
|
1074 // For 4 or 2 channels, repeat 2 or 1 times, according to flags
|
giuliomoro@102
|
1075 ADD r1, r1, 1
|
giuliomoro@102
|
1076 QBNE ADC_DAC_LOOP, r1, reg_num_channels
|
giuliomoro@102
|
1077 QBA ADC_DAC_LOOP_DONE
|
giuliomoro@102
|
1078 SPI_SKIP_WRITE:
|
giuliomoro@102
|
1079 // We get here only if the SPI ADC and DAC are disabled
|
giuliomoro@102
|
1080 // Just keep the loop going for McASP
|
andrewm@0
|
1081
|
giuliomoro@102
|
1082 // Toggle the high/low word for McASP control (since we send one word out of
|
giuliomoro@102
|
1083 // 32 bits for each pair of SPI channels)
|
giuliomoro@102
|
1084 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
|
andrewm@12
|
1085
|
giuliomoro@102
|
1086 ADD r1, r1, 2
|
giuliomoro@102
|
1087 QBNE ADC_DAC_LOOP, r1, reg_num_channels
|
andrewm@0
|
1088
|
andrewm@282
|
1089 ADC_DAC_LOOP_DONE:
|
giuliomoro@102
|
1090 // Increment number of frames, see if we have more to write
|
giuliomoro@102
|
1091 ADD reg_frame_current, reg_frame_current, 1
|
giuliomoro@102
|
1092 QBNE WRITE_LOOP, reg_frame_current, reg_frame_total
|
andrewm@0
|
1093
|
andrewm@0
|
1094 WRITE_LOOP_DONE:
|
giuliomoro@102
|
1095 // Now done, swap the buffers and do the next one
|
giuliomoro@102
|
1096 // Use r2 as a temp register
|
giuliomoro@102
|
1097 MOV r2, reg_dac_buf0
|
giuliomoro@102
|
1098 MOV reg_dac_buf0, reg_dac_buf1
|
giuliomoro@102
|
1099 MOV reg_dac_buf1, r2
|
giuliomoro@102
|
1100 MOV r2, reg_mcasp_buf0
|
giuliomoro@102
|
1101 MOV reg_mcasp_buf0, reg_mcasp_buf1
|
giuliomoro@102
|
1102 MOV reg_mcasp_buf1, r2
|
giuliomoro@102
|
1103 XOR reg_flags, reg_flags, (1 << FLAG_BIT_BUFFER1) //flip the buffer flag
|
andrewm@0
|
1104
|
andrewm@346
|
1105 // If multiplexer capelet is enabled, save which channel we got to
|
andrewm@346
|
1106 // Muxes 0-3 change at a different time than muxes 4-7 but the first
|
andrewm@346
|
1107 // of these is sufficient to capture where we are
|
andrewm@346
|
1108 MOV r2, FLAG_MASK_MUX_CONFIG
|
andrewm@346
|
1109 AND r2, reg_flags, r2
|
andrewm@346
|
1110 QBEQ MUX_CHANNEL_SAVE_DONE, r2, 0
|
andrewm@346
|
1111 AND r2, reg_pru1_mux_pins, 0x03
|
andrewm@346
|
1112 SBBO r2, reg_comm_addr, COMM_MUX_END_CHANNEL, 4
|
andrewm@346
|
1113 MUX_CHANNEL_SAVE_DONE:
|
andrewm@346
|
1114
|
giuliomoro@102
|
1115 // Notify ARM of buffer swap
|
giuliomoro@102
|
1116 AND r2, reg_flags, (1 << FLAG_BIT_BUFFER1) // Mask out every but low bit
|
giuliomoro@102
|
1117 SBBO r2, reg_comm_addr, COMM_CURRENT_BUFFER, 4
|
giuliomoro@102
|
1118 MOV R31.b0, PRU1_ARM_INTERRUPT + 16 // Interrupt to host loop
|
andrewm@45
|
1119
|
giuliomoro@102
|
1120 // Increment the frame count in the comm buffer (for status monitoring)
|
giuliomoro@102
|
1121 LBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
|
giuliomoro@102
|
1122 ADD r2, r2, reg_frame_total
|
giuliomoro@102
|
1123 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
|
andrewm@0
|
1124
|
giuliomoro@102
|
1125 // If LED blink enabled, toggle every 4096 frames
|
giuliomoro@102
|
1126 LBBO r3, reg_comm_addr, COMM_LED_ADDRESS, 4
|
giuliomoro@102
|
1127 QBEQ LED_BLINK_DONE, r3, 0
|
giuliomoro@102
|
1128 MOV r1, 0x1000
|
giuliomoro@102
|
1129 AND r2, r2, r1 // Test (frame count & 4096)
|
giuliomoro@102
|
1130 QBEQ LED_BLINK_OFF, r2, 0
|
giuliomoro@102
|
1131 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
|
giuliomoro@102
|
1132 MOV r1, GPIO_SETDATAOUT
|
giuliomoro@102
|
1133 ADD r3, r3, r1 // Address for GPIO set register
|
giuliomoro@102
|
1134 SBBO r2, r3, 0, 4 // Set GPIO pin
|
giuliomoro@102
|
1135 QBA LED_BLINK_DONE
|
andrewm@0
|
1136 LED_BLINK_OFF:
|
giuliomoro@102
|
1137 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
|
giuliomoro@102
|
1138 MOV r1, GPIO_CLEARDATAOUT
|
giuliomoro@102
|
1139 ADD r3, r3, r1 // Address for GPIO clear register
|
giuliomoro@102
|
1140 SBBO r2, r3, 0, 4 // Clear GPIO pin
|
andrewm@0
|
1141 LED_BLINK_DONE:
|
giuliomoro@102
|
1142 // Check if we should finish: flag is zero as long as it should run
|
giuliomoro@102
|
1143 LBBO r2, reg_comm_addr, COMM_SHOULD_STOP, 4
|
giuliomoro@102
|
1144 QBEQ WRITE_ONE_BUFFER, r2, 0
|
andrewm@0
|
1145
|
andrewm@0
|
1146 CLEANUP:
|
giuliomoro@102
|
1147 MCASP_REG_WRITE MCASP_GBLCTL, 0x00 // Turn off McASP
|
andrewm@0
|
1148
|
giuliomoro@102
|
1149 // Turn off SPI if enabled
|
giuliomoro@102
|
1150 QBBC SPI_CLEANUP_DONE, reg_flags, FLAG_BIT_USE_SPI
|
andrewm@0
|
1151
|
giuliomoro@102
|
1152 MOV r3, SPI_BASE + SPI_CH0CONF
|
giuliomoro@102
|
1153 LBBO r2, r3, 0, 4
|
giuliomoro@102
|
1154 CLR r2, r2, 13
|
giuliomoro@102
|
1155 CLR r2, r2, 27
|
giuliomoro@102
|
1156 SBBO r2, r3, 0, 4
|
andrewm@0
|
1157
|
giuliomoro@102
|
1158 MOV r3, SPI_BASE + SPI_CH0CTRL
|
giuliomoro@102
|
1159 LBBO r2, r3, 0, 4
|
giuliomoro@102
|
1160 CLR r2, r2, 1
|
giuliomoro@102
|
1161 SBBO r2, r3, 0, 4
|
andrewm@0
|
1162 SPI_CLEANUP_DONE:
|
giuliomoro@102
|
1163 // Signal the ARM that we have finished
|
giuliomoro@102
|
1164 MOV R31.b0, PRU0_ARM_INTERRUPT + 16
|
giuliomoro@102
|
1165 HALT
|