1 /*
2 * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
3 *
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
15 * distribution.
16 *
17 * * Neither the name of Texas Instruments Incorporated nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
34 #include <stdint.h>
35 #include <pru_cfg.h>
36 #include <pru_ctrl.h>
37 #include "resource_table_empty.h"
39 volatile register uint32_t __R30;
40 volatile register uint32_t __R31;
42 /* Scratchpad constants */
43 #define SCRATCHPAD_0 10
44 #define SCRATCHPAD_1 11
45 #define SCRATCHPAD_2 12
47 /* Specific register numbers shared through the Scratchpads */
48 #define CONFIG_REG 15
49 #define DELAY_REG 21
50 #define RESULT_REG 22
51 #define STATUS_REG 28
52 #define REQUEST_REG 29
54 /* Request register bit mapping */
55 #define START_BIT (1 << 0)
56 #define CONTINUOUS_BIT (1 << 1)
57 #define RECV_READY_BIT (1 << 2)
58 #define RECV_ACK_BIT (1 << 3)
60 /* Response register bit mapping */
61 #define SEND_READY_BIT (1 << 0)
62 #define SEND_ACK_BIT (1 << 1)
63 #define SEND_DONE_BIT (1 << 2)
65 /* Sample/config mode */
66 #define ONE_SHOT 0
67 #define CONTINUOUS 1
69 /* ADS8688 configuration definitions */
70 /* Command Register formatting */
71 #define CMD_REG(x) (x << 8)
72 #define NOOP 0x00
73 #define STDBY 0x82
74 #define PWR_DN 0x83
75 #define AUTO_RST 0xA0
76 #define RST 0x85
77 #define MAN_CH(chan) (0xC0 | (4 * chan))
78 #define MAN_AUX 0xE0
79 /* Program Register formatting */
80 #define PROG_REG(reg, rw, data) ((reg << 9) | (rw << 8) | data)
81 #define AUTO_SEQ_EN (0x01)
82 #define CHAN_PWR_DN (0x02)
83 #define CHAN_INPUT_RANGE(chan) (0x05 + chan)
84 #define COMM_READ_BACK (0x3F)
85 /* Read or write for the program register formatting */
86 #define WRITE 1
87 #define READ 0
88 /* Channel input range constants */
89 #define PLUSMINUS25VREF 0
90 #define PLUSMINUS125VREF 1
91 #define PLUSMINUS0625VREF 2
92 #define PLUS25VREF 5
93 #define PLUS125VREF 6
95 /* Oversampling constants (must be a power of 2 to achieve timings in the PRU) */
96 #define OVERSAMPLE 1
98 /* Frequency estimation constants */
99 #define FREQ_EST_DEVICE 4
100 #define FREQ_EST_CHANNEL 5
101 #define FREQ_EST_CYCLES 5
102 #define MIN_DELAY 710 //55Hz
103 #define DEFAULT_DELAY 781 //50Hz
104 #define DEFAULT_COMP 2 //50Hz
105 #define MAX_DELAY 868 //45Hz
107 /* Information about devices and channels connected */
108 #define CHANS_PER_DEVICE 8
109 #define DEVICES 6
110 #define NUM_CHANS CHANS_PER_DEVICE * DEVICES
111 #define SAMPLES_PER_CYCLE 640
113 /* Ping and Pong buffer information */
114 #define PING_ADDR 0x9FFC0000
115 #define PONG_ADDR 0x9FFE0000
116 #define PING 0
117 #define PONG 1
118 #define DATA_READY 0x0000FFFF
119 #define IN_PROGRESS 0x00000000
122 uint32_t data_buf[DEVICES];
123 uint32_t config_buf[DEVICES];
125 /* Send cycle delay between samples value */
126 send_delay(uint32_t delay_val) {
127 /* Send the cycle delay to the other PRU through Scratchpad 0 */
128 __xout(SCRATCHPAD_0, DELAY_REG, 0, delay_val);
129 }
131 /* Send configurations or commands */
132 send_command(uint16_t continuous) {
133 uint32_t request, status = 0;
134 uint32_t temp;
136 /* Check to make sure the SPI coprocessor is ready */
137 while (!(status & SEND_READY_BIT)) {
138 __xin(SCRATCHPAD_1, STATUS_REG, 0, temp);
139 status = temp;
140 }
141 /* Push the configuration values for each ADC */
142 __xout(SCRATCHPAD_0, CONFIG_REG, 0, config_buf);
144 /* Send the start command to kick off the transfer */
145 request = START_BIT;
146 if (continuous)
147 request |= CONTINUOUS_BIT;
148 __xout(SCRATCHPAD_1, REQUEST_REG, 0, request);
150 /* Wait for SPI coprocessor to acknowledge the command */
151 while (!(status & SEND_ACK_BIT)) {
152 __xin(SCRATCHPAD_1, STATUS_REG, 0, temp);
153 status = temp;
154 }
156 /* Clear the start bit */
157 request &= ~START_BIT;
158 __xout(SCRATCHPAD_1, REQUEST_REG, 0, request);
159 }
161 /* Receive response */
162 receive_data() {
163 uint32_t request, status = 0;
164 uint32_t temp;
166 /* Read the current request to get start and continuous */
167 __xin(SCRATCHPAD_1, REQUEST_REG, 0, request);
169 /* Set the ready bit, clear the ack bit */
170 request |= RECV_READY_BIT;
171 request &= ~RECV_ACK_BIT;
172 __xout(SCRATCHPAD_1, REQUEST_REG, 0, request);
174 /* Clear the ready bit, set the ack bit in the temp variable
175 * Wait until after done signal is received to send
176 */
177 request &= ~RECV_READY_BIT;
178 request |= RECV_ACK_BIT;
180 /* Wait for the done signal */
181 while (!(status & SEND_DONE_BIT)) {
182 __xin(SCRATCHPAD_1, STATUS_REG, 0, temp);
183 status = temp;
184 }
186 /* Send ack bit one cycle before pulling data to save time */
187 __xout(SCRATCHPAD_1, REQUEST_REG, 0, request);
189 /* Pull the data into data_buf */
190 __xin(SCRATCHPAD_2, RESULT_REG, 0, data_buf);
191 }
193 /* Send intial ADC configurations */
194 adc_init() {
195 uint32_t status = 0;
196 uint32_t temp;
198 /* Check to make sure the SPI coprocessor is ready */
199 while (!(status & SEND_READY_BIT)) {
200 __xin(SCRATCHPAD_1, STATUS_REG, 0, temp);
201 status = temp;
202 }
204 /* Send reset command to all devices in parallel */
205 config_buf[0] = CMD_REG(RST);
206 config_buf[1] = CMD_REG(RST);
207 config_buf[2] = CMD_REG(RST);
208 config_buf[3] = CMD_REG(RST);
209 config_buf[4] = CMD_REG(RST);
210 config_buf[5] = CMD_REG(RST);
211 send_command(ONE_SHOT);
212 receive_data();
214 /* Set device 0 channel 0's input range to 0-2.5vRef */
215 /*
216 config_buf[0] = PROG_REG(CHAN_INPUT_RANGE(0), WRITE, PLUS125VREF);
217 send_command(ONE_SHOT);
218 receive_data();
219 */
221 /* Enable all 8 channels on all devices */
222 config_buf[0] = PROG_REG(AUTO_SEQ_EN, WRITE, 0xFF);
223 config_buf[1] = PROG_REG(AUTO_SEQ_EN, WRITE, 0xFF);
224 config_buf[2] = PROG_REG(AUTO_SEQ_EN, WRITE, 0xFF);
225 config_buf[3] = PROG_REG(AUTO_SEQ_EN, WRITE, 0xFF);
226 config_buf[4] = PROG_REG(AUTO_SEQ_EN, WRITE, 0xFF);
227 config_buf[5] = PROG_REG(AUTO_SEQ_EN, WRITE, 0xFF);
228 send_command(ONE_SHOT);
229 receive_data();
231 __delay_cycles(200);
233 /* Put devices into auto reset mode in parallel */
234 config_buf[0] = CMD_REG(AUTO_RST);
235 config_buf[1] = CMD_REG(AUTO_RST);
236 config_buf[2] = CMD_REG(AUTO_RST);
237 config_buf[3] = CMD_REG(AUTO_RST);
238 config_buf[4] = CMD_REG(AUTO_RST);
239 config_buf[5] = CMD_REG(AUTO_RST);
240 send_command(ONE_SHOT);
241 receive_data();
243 /* Initial delay set for 50Hz */
244 send_delay(DEFAULT_DELAY);
246 /* Send the NOOP command to kick off the sampling */
247 config_buf[0] = CMD_REG(NOOP);
248 config_buf[1] = CMD_REG(NOOP);
249 config_buf[2] = CMD_REG(NOOP);
250 config_buf[3] = CMD_REG(NOOP);
251 config_buf[4] = CMD_REG(NOOP);
252 config_buf[5] = CMD_REG(NOOP);
253 send_command(CONTINUOUS);
255 /* Enable the cycle counter */
256 PRU0_CTRL.CTRL_bit.CTR_EN = 1;
257 PRU0_CTRL.CYCLE = 0;
259 }
261 typedef struct {
262 int32_t chan_data[CHANS_PER_DEVICE];
263 } adc_device;
265 #pragma DATA_SECTION(debug, ".shared_mem")
266 volatile far int32_t debug[10];
268 uint32_t chan_data_temp[NUM_CHANS];
270 void main(void)
271 {
272 uint32_t i, j, idx;
273 uint32_t oversample = 1;
274 int32_t last_pol = 1;
275 uint32_t zero_crossings = 0;
276 uint32_t start, stop, elapsed, delay, compensation = 0;
277 uint32_t zero = 0;
278 uint32_t curr_addr;
279 uint8_t curr_buff;
280 uint32_t num_captured = 0;
282 delay = DEFAULT_DELAY;
283 compensation = DEFAULT_COMP;
285 /* Select the ping buffer first */
286 curr_addr = PING_ADDR + 8;
287 curr_buff = PING;
289 /* This PRU comes up first, zero out the status registers */
290 __xout(SCRATCHPAD_1, STATUS_REG, 0, zero);
291 __xout(SCRATCHPAD_1, REQUEST_REG, 0, zero);
293 /* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
294 CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
296 /* ADC init */
297 adc_init();
299 while (1) {
300 for (i = 0; i < CHANS_PER_DEVICE; i++) {
301 /* receive parallel data from the ADCs */
302 if (i < compensation)
303 send_delay(delay + 1);
304 else
305 send_delay(delay);
306 receive_data();
307 for (j = 0; j < DEVICES; j++) {
308 idx = j*CHANS_PER_DEVICE+i;
310 /* Clear the accumulated value if first sample */
311 if (oversample == 1)
312 chan_data_temp[idx] = 0;
314 /* Accumulate samples until oversample value is reached */
315 chan_data_temp[idx] += (uint16_t)data_buf[j];
317 /* Perform oversampling */
318 if (oversample == OVERSAMPLE) {
319 chan_data_temp[idx] = (uint16_t)((chan_data_temp[idx] + (OVERSAMPLE/2)) / OVERSAMPLE);
320 /* Frequency estimation using zero crossings */
321 if (j == FREQ_EST_DEVICE && i == FREQ_EST_CHANNEL) {
322 if (((last_pol > 0) && ((int16_t)(chan_data_temp[idx] - 0x8000) < 0)) ||
323 ((last_pol < 0) && ((int16_t)(chan_data_temp[idx] - 0x8000) > 0))) {
324 zero_crossings++;
325 last_pol = ~last_pol;
327 /* First crossing, get the start timestamp */
328 if (zero_crossings == 1) {
329 start = PRU0_CTRL.CYCLE;
330 }
331 /* Last crossing, get the stop timestamp */
332 else if (zero_crossings == ((FREQ_EST_CYCLES * 2) + 1)) {
333 stop = PRU0_CTRL.CYCLE;
334 elapsed = stop - start;
335 delay = elapsed/(SAMPLES_PER_CYCLE * FREQ_EST_CYCLES);
336 compensation = delay % CHANS_PER_DEVICE;
337 delay = delay / CHANS_PER_DEVICE;
338 if (delay < MIN_DELAY) {
339 delay = MIN_DELAY;
340 compensation = 0;
341 }
342 else if (delay > MAX_DELAY) {
343 delay = MAX_DELAY;
344 compensation = CHANS_PER_DEVICE - 1;
345 }
346 PRU0_CTRL.CYCLE = 0;
347 zero_crossings = 0;
348 }
349 }
350 }
351 }
352 }
353 }
354 if (oversample++ == OVERSAMPLE) {
355 oversample = 1;
356 /* Copy the oversampled data from each channel to the current buffer */
357 memcpy((void *)curr_addr, chan_data_temp, CHANS_PER_DEVICE * DEVICES * 4);
358 /* Increment the address for the next set of channel data */
359 curr_addr += CHANS_PER_DEVICE * DEVICES * 4;
361 /* A full sample has been captured, switch buffers */
362 if (++num_captured == SAMPLES_PER_CYCLE) {
363 if (curr_buff == PING) {
364 /* Mark the first 4 bytes of the ping buffer with the ready flag */
365 *(volatile uint32_t *)PING_ADDR = DATA_READY;
366 /* Mark the next 4 bytes of the ping buffer with delay and comp values */
367 *(volatile uint32_t *)(PING_ADDR + 4) = ((uint16_t)compensation) << 16 | ((uint16_t) delay);
368 /* Mark the first 4 bytes of the pong buffer with the in progress flag */
369 *(volatile uint32_t *)PONG_ADDR = IN_PROGRESS;
370 /* Set the current address for samples to the address after the flag */
371 curr_addr = PONG_ADDR + 8;
372 /* Update the current buffer */
373 curr_buff = PONG;
374 }
375 else {
376 /* Mark the first 4 bytes of the pong buffer with the ready flag */
377 *(volatile uint32_t *)PONG_ADDR = DATA_READY;
378 /* Mark the next 4 bytes of the pong buffer with delay and comp values */
379 *(volatile uint32_t *)(PONG_ADDR + 4) = ((uint16_t)compensation) << 16 | ((uint16_t) delay);
380 /* Mark the first 4 bytes of the ping buffer with the in progress flag */
381 *(volatile uint32_t *)PING_ADDR = IN_PROGRESS;
382 /* Set the current address for samples to the address after the flag */
383 curr_addr = PING_ADDR + 8;
384 /* Update the current buffer */
385 curr_buff = PING;
386 }
387 num_captured = 0;
388 }
389 }
390 }
391 }