andrewm@0
|
1 /*
|
andrewm@0
|
2 * PRU.cpp
|
andrewm@0
|
3 *
|
andrewm@0
|
4 * Code for communicating with the Programmable Realtime Unit (PRU)
|
andrewm@0
|
5 * on the BeagleBone AM335x series processors. The PRU loads and runs
|
andrewm@0
|
6 * a separate code image compiled from an assembly file. Here it is
|
andrewm@0
|
7 * used to handle audio and SPI ADC/DAC data.
|
andrewm@0
|
8 *
|
andrewm@0
|
9 * This code is specific to the PRU code in the assembly file; for example,
|
andrewm@0
|
10 * it uses certain GPIO resources that correspond to that image.
|
andrewm@0
|
11 *
|
andrewm@0
|
12 * Created on: May 27, 2014
|
andrewm@0
|
13 * Author: andrewm
|
andrewm@0
|
14 */
|
andrewm@0
|
15
|
andrewm@0
|
16 #include "../include/PRU.h"
|
andrewm@0
|
17 #include "../include/prussdrv.h"
|
andrewm@0
|
18 #include "../include/pruss_intc_mapping.h"
|
andrewm@0
|
19 #include "../include/GPIOcontrol.h"
|
andrewm@0
|
20 #include "../include/render.h"
|
andrewm@15
|
21 #include "../include/pru_rtaudio_bin.h"
|
andrewm@0
|
22
|
andrewm@0
|
23 #include <iostream>
|
andrewm@0
|
24 #include <stdlib.h>
|
andrewm@0
|
25 #include <cstdio>
|
andrewm@0
|
26 #include <cerrno>
|
andrewm@0
|
27 #include <fcntl.h>
|
andrewm@0
|
28 #include <sys/mman.h>
|
andrewm@0
|
29
|
andrewm@0
|
30 // Xenomai-specific includes
|
andrewm@0
|
31 #include <sys/mman.h>
|
andrewm@0
|
32 #include <native/task.h>
|
andrewm@0
|
33 #include <native/timer.h>
|
andrewm@0
|
34 #include <rtdk.h>
|
andrewm@0
|
35
|
andrewm@0
|
36 using namespace std;
|
andrewm@0
|
37
|
andrewm@0
|
38 #define PRU_MEM_MCASP_OFFSET 0x2000 // Offset within PRU-SHARED RAM
|
andrewm@0
|
39 #define PRU_MEM_MCASP_LENGTH 0x2000 // Length of McASP memory, in bytes
|
andrewm@0
|
40 #define PRU_MEM_DAC_OFFSET 0x0 // Offset within PRU0 RAM
|
andrewm@0
|
41 #define PRU_MEM_DAC_LENGTH 0x2000 // Length of ADC+DAC memory, in bytes
|
andrewm@0
|
42 #define PRU_MEM_COMM_OFFSET 0x0 // Offset within PRU-SHARED RAM
|
andrewm@0
|
43
|
andrewm@0
|
44 #define PRU_SHOULD_STOP 0
|
andrewm@0
|
45 #define PRU_CURRENT_BUFFER 1
|
andrewm@0
|
46 #define PRU_BUFFER_FRAMES 2
|
andrewm@0
|
47 #define PRU_SHOULD_SYNC 3
|
andrewm@0
|
48 #define PRU_SYNC_ADDRESS 4
|
andrewm@0
|
49 #define PRU_SYNC_PIN_MASK 5
|
andrewm@0
|
50 #define PRU_LED_ADDRESS 6
|
andrewm@0
|
51 #define PRU_LED_PIN_MASK 7
|
andrewm@0
|
52 #define PRU_FRAME_COUNT 8
|
andrewm@0
|
53 #define PRU_USE_SPI 9
|
andrewm@12
|
54 #define PRU_SPI_NUM_CHANNELS 10
|
andrewm@0
|
55
|
andrewm@12
|
56 #define PRU_SAMPLE_INTERVAL_NS 11338 // 88200Hz per SPI sample = 11.338us
|
andrewm@0
|
57
|
andrewm@0
|
58 #define GPIO0_ADDRESS 0x44E07000
|
andrewm@0
|
59 #define GPIO1_ADDRESS 0x4804C000
|
andrewm@0
|
60 #define GPIO_SIZE 0x198
|
andrewm@0
|
61 #define GPIO_CLEARDATAOUT (0x190 / 4)
|
andrewm@0
|
62 #define GPIO_SETDATAOUT (0x194 / 4)
|
andrewm@0
|
63
|
andrewm@0
|
64 #define TEST_PIN_GPIO_BASE GPIO0_ADDRESS // Use GPIO0(31) for debugging
|
andrewm@0
|
65 #define TEST_PIN_MASK (1 << 31)
|
andrewm@0
|
66 #define TEST_PIN2_MASK (1 << 26)
|
andrewm@0
|
67
|
andrewm@0
|
68 #define USERLED3_GPIO_BASE GPIO1_ADDRESS // GPIO1(24) is user LED 3
|
andrewm@0
|
69 #define USERLED3_PIN_MASK (1 << 24)
|
andrewm@0
|
70
|
andrewm@0
|
71 const unsigned int PRU::kPruGPIODACSyncPin = 5; // GPIO0(5); P9-17
|
andrewm@0
|
72 const unsigned int PRU::kPruGPIOADCSyncPin = 48; // GPIO1(16); P9-15
|
andrewm@0
|
73
|
andrewm@0
|
74 const unsigned int PRU::kPruGPIOTestPin = 60; // GPIO1(28); P9-12
|
andrewm@0
|
75 const unsigned int PRU::kPruGPIOTestPin2 = 31; // GPIO0(31); P9-13
|
andrewm@0
|
76 const unsigned int PRU::kPruGPIOTestPin3 = 26; // GPIO0(26); P8-14
|
andrewm@0
|
77
|
andrewm@0
|
78 extern int gShouldStop;
|
andrewm@0
|
79 extern int gRTAudioVerbose;
|
andrewm@0
|
80
|
andrewm@0
|
81 // Constructor: specify a PRU number (0 or 1)
|
andrewm@0
|
82 PRU::PRU()
|
andrewm@0
|
83 : pru_number(0), running(false), spi_enabled(false), gpio_enabled(false), led_enabled(false),
|
andrewm@12
|
84 gpio_test_pin_enabled(false), spi_num_channels(0), xenomai_gpio_fd(-1), xenomai_gpio(0)
|
andrewm@0
|
85 {
|
andrewm@0
|
86
|
andrewm@0
|
87 }
|
andrewm@0
|
88
|
andrewm@0
|
89 // Destructor
|
andrewm@0
|
90 PRU::~PRU()
|
andrewm@0
|
91 {
|
andrewm@0
|
92 if(running)
|
andrewm@0
|
93 disable();
|
andrewm@0
|
94 if(gpio_enabled)
|
andrewm@0
|
95 cleanupGPIO();
|
andrewm@0
|
96 if(xenomai_gpio_fd >= 0)
|
andrewm@0
|
97 close(xenomai_gpio_fd);
|
andrewm@0
|
98 }
|
andrewm@0
|
99
|
andrewm@0
|
100 // Prepare the GPIO pins needed for the PRU
|
andrewm@0
|
101 // If include_test_pin is set, the GPIO output
|
andrewm@0
|
102 // is also prepared for an output which can be
|
andrewm@0
|
103 // viewed on a scope. If include_led is set,
|
andrewm@0
|
104 // user LED 3 on the BBB is taken over by the PRU
|
andrewm@0
|
105 // to indicate activity
|
andrewm@0
|
106 int PRU::prepareGPIO(int use_spi, int include_test_pin, int include_led)
|
andrewm@0
|
107 {
|
andrewm@0
|
108 if(use_spi) {
|
andrewm@0
|
109 // Prepare DAC CS/ pin: output, high to begin
|
andrewm@0
|
110 if(gpio_export(kPruGPIODACSyncPin)) {
|
andrewm@0
|
111 if(gRTAudioVerbose)
|
andrewm@0
|
112 cout << "Warning: couldn't export DAC sync pin\n";
|
andrewm@0
|
113 }
|
andrewm@0
|
114 if(gpio_set_dir(kPruGPIODACSyncPin, OUTPUT_PIN)) {
|
andrewm@0
|
115 if(gRTAudioVerbose)
|
andrewm@0
|
116 cout << "Couldn't set direction on DAC sync pin\n";
|
andrewm@0
|
117 return -1;
|
andrewm@0
|
118 }
|
andrewm@0
|
119 if(gpio_set_value(kPruGPIODACSyncPin, HIGH)) {
|
andrewm@0
|
120 if(gRTAudioVerbose)
|
andrewm@0
|
121 cout << "Couldn't set value on DAC sync pin\n";
|
andrewm@0
|
122 return -1;
|
andrewm@0
|
123 }
|
andrewm@0
|
124
|
andrewm@0
|
125 // Prepare ADC CS/ pin: output, high to begin
|
andrewm@0
|
126 if(gpio_export(kPruGPIOADCSyncPin)) {
|
andrewm@0
|
127 if(gRTAudioVerbose)
|
andrewm@0
|
128 cout << "Warning: couldn't export ADC sync pin\n";
|
andrewm@0
|
129 }
|
andrewm@0
|
130 if(gpio_set_dir(kPruGPIOADCSyncPin, OUTPUT_PIN)) {
|
andrewm@0
|
131 if(gRTAudioVerbose)
|
andrewm@0
|
132 cout << "Couldn't set direction on ADC sync pin\n";
|
andrewm@0
|
133 return -1;
|
andrewm@0
|
134 }
|
andrewm@0
|
135 if(gpio_set_value(kPruGPIOADCSyncPin, HIGH)) {
|
andrewm@0
|
136 if(gRTAudioVerbose)
|
andrewm@0
|
137 cout << "Couldn't set value on ADC sync pin\n";
|
andrewm@0
|
138 return -1;
|
andrewm@0
|
139 }
|
andrewm@0
|
140
|
andrewm@0
|
141 spi_enabled = true;
|
andrewm@0
|
142 }
|
andrewm@0
|
143
|
andrewm@0
|
144 if(include_test_pin) {
|
andrewm@0
|
145 // Prepare GPIO test output (for debugging), low to begin
|
andrewm@0
|
146 if(gpio_export(kPruGPIOTestPin)) {
|
andrewm@0
|
147 if(gRTAudioVerbose)
|
andrewm@0
|
148 cout << "Warning: couldn't export GPIO test pin\n";
|
andrewm@0
|
149 }
|
andrewm@0
|
150 if(gpio_set_dir(kPruGPIOTestPin, OUTPUT_PIN)) {
|
andrewm@0
|
151 if(gRTAudioVerbose)
|
andrewm@0
|
152 cout << "Couldn't set direction on GPIO test pin\n";
|
andrewm@0
|
153 return -1;
|
andrewm@0
|
154 }
|
andrewm@0
|
155 if(gpio_set_value(kPruGPIOTestPin, LOW)) {
|
andrewm@0
|
156 if(gRTAudioVerbose)
|
andrewm@0
|
157 cout << "Couldn't set value on GPIO test pin\n";
|
andrewm@0
|
158 return -1;
|
andrewm@0
|
159 }
|
andrewm@0
|
160
|
andrewm@0
|
161 if(gpio_export(kPruGPIOTestPin2)) {
|
andrewm@0
|
162 if(gRTAudioVerbose)
|
andrewm@0
|
163 cout << "Warning: couldn't export GPIO test pin 2\n";
|
andrewm@0
|
164 }
|
andrewm@0
|
165 if(gpio_set_dir(kPruGPIOTestPin2, OUTPUT_PIN)) {
|
andrewm@0
|
166 if(gRTAudioVerbose)
|
andrewm@0
|
167 cout << "Couldn't set direction on GPIO test pin 2\n";
|
andrewm@0
|
168 return -1;
|
andrewm@0
|
169 }
|
andrewm@0
|
170 if(gpio_set_value(kPruGPIOTestPin2, LOW)) {
|
andrewm@0
|
171 if(gRTAudioVerbose)
|
andrewm@0
|
172 cout << "Couldn't set value on GPIO test pin 2\n";
|
andrewm@0
|
173 return -1;
|
andrewm@0
|
174 }
|
andrewm@0
|
175
|
andrewm@0
|
176 if(gpio_export(kPruGPIOTestPin3)) {
|
andrewm@0
|
177 if(gRTAudioVerbose)
|
andrewm@0
|
178 cout << "Warning: couldn't export GPIO test pin 3\n";
|
andrewm@0
|
179 }
|
andrewm@0
|
180 if(gpio_set_dir(kPruGPIOTestPin3, OUTPUT_PIN)) {
|
andrewm@0
|
181 if(gRTAudioVerbose)
|
andrewm@0
|
182 cout << "Couldn't set direction on GPIO test pin 3\n";
|
andrewm@0
|
183 return -1;
|
andrewm@0
|
184 }
|
andrewm@0
|
185 if(gpio_set_value(kPruGPIOTestPin3, LOW)) {
|
andrewm@0
|
186 if(gRTAudioVerbose)
|
andrewm@0
|
187 cout << "Couldn't set value on GPIO test pin 3\n";
|
andrewm@0
|
188 return -1;
|
andrewm@0
|
189 }
|
andrewm@0
|
190 gpio_test_pin_enabled = true;
|
andrewm@0
|
191 }
|
andrewm@0
|
192
|
andrewm@0
|
193 if(include_led) {
|
andrewm@0
|
194 // Turn off system function for LED3 so it can be reused by PRU
|
andrewm@0
|
195 led_set_trigger(3, "none");
|
andrewm@0
|
196 led_enabled = true;
|
andrewm@0
|
197 }
|
andrewm@0
|
198
|
andrewm@0
|
199 gpio_enabled = true;
|
andrewm@0
|
200
|
andrewm@0
|
201 return 0;
|
andrewm@0
|
202 }
|
andrewm@0
|
203
|
andrewm@0
|
204 // Clean up the GPIO at the end
|
andrewm@0
|
205 void PRU::cleanupGPIO()
|
andrewm@0
|
206 {
|
andrewm@0
|
207 if(!gpio_enabled)
|
andrewm@0
|
208 return;
|
andrewm@0
|
209 if(spi_enabled) {
|
andrewm@0
|
210 gpio_unexport(kPruGPIODACSyncPin);
|
andrewm@0
|
211 gpio_unexport(kPruGPIOADCSyncPin);
|
andrewm@0
|
212 }
|
andrewm@0
|
213 if(gpio_test_pin_enabled) {
|
andrewm@0
|
214 gpio_unexport(kPruGPIOTestPin);
|
andrewm@0
|
215 gpio_unexport(kPruGPIOTestPin2);
|
andrewm@0
|
216 gpio_unexport(kPruGPIOTestPin3);
|
andrewm@0
|
217 }
|
andrewm@0
|
218 if(led_enabled) {
|
andrewm@0
|
219 // Set LED back to default eMMC status
|
andrewm@0
|
220 // TODO: make it go back to its actual value before this program,
|
andrewm@0
|
221 // rather than the system default
|
andrewm@0
|
222 led_set_trigger(3, "mmc1");
|
andrewm@0
|
223 }
|
andrewm@0
|
224
|
andrewm@0
|
225 gpio_enabled = gpio_test_pin_enabled = false;
|
andrewm@0
|
226 }
|
andrewm@0
|
227
|
andrewm@0
|
228 // Initialise and open the PRU
|
andrewm@12
|
229 int PRU::initialise(int pru_num, int frames_per_buffer, int spi_channels, bool xenomai_test_pin)
|
andrewm@0
|
230 {
|
andrewm@0
|
231 uint32_t *pruMem = 0;
|
andrewm@0
|
232
|
andrewm@0
|
233 if(!gpio_enabled) {
|
andrewm@0
|
234 rt_printf("initialise() called before GPIO enabled\n");
|
andrewm@0
|
235 return 1;
|
andrewm@0
|
236 }
|
andrewm@0
|
237
|
andrewm@0
|
238 pru_number = pru_num;
|
andrewm@0
|
239
|
andrewm@12
|
240 /* Set number of SPI ADC / DAC channels to use. This implicitly
|
andrewm@12
|
241 * also determines the sample rate relative to the audio clock
|
andrewm@12
|
242 * (half audio clock for 8 channels, full audio clock for 4,
|
andrewm@12
|
243 * double audio clock for 2)
|
andrewm@12
|
244 */
|
andrewm@12
|
245 spi_num_channels = spi_channels;
|
andrewm@12
|
246
|
andrewm@0
|
247 /* Initialize structure used by prussdrv_pruintc_intc */
|
andrewm@0
|
248 /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */
|
andrewm@0
|
249 tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
|
andrewm@0
|
250
|
andrewm@0
|
251 /* Allocate and initialize memory */
|
andrewm@0
|
252 prussdrv_init();
|
andrewm@15
|
253 if(prussdrv_open(pru_number == 0 ? PRU_EVTOUT_0 : PRU_EVTOUT_1)) {
|
andrewm@0
|
254 rt_printf("Failed to open PRU driver\n");
|
andrewm@0
|
255 return 1;
|
andrewm@0
|
256 }
|
andrewm@0
|
257
|
andrewm@0
|
258 /* Map PRU's INTC */
|
andrewm@0
|
259 prussdrv_pruintc_init(&pruss_intc_initdata);
|
andrewm@0
|
260
|
andrewm@0
|
261 spi_buffer_frames = frames_per_buffer;
|
andrewm@12
|
262 audio_buffer_frames = spi_buffer_frames * spi_num_channels / 4;
|
andrewm@0
|
263
|
andrewm@0
|
264 /* Map PRU memory to pointers */
|
andrewm@0
|
265 prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem);
|
andrewm@0
|
266 pru_buffer_comm = (uint32_t *)&pruMem[PRU_MEM_COMM_OFFSET/sizeof(uint32_t)];
|
andrewm@0
|
267 pru_buffer_audio_dac = (int16_t *)&pruMem[PRU_MEM_MCASP_OFFSET/sizeof(uint32_t)];
|
andrewm@0
|
268
|
andrewm@12
|
269 /* ADC memory starts 2(ch)*2(buffers)*bufsize samples later */
|
andrewm@12
|
270 pru_buffer_audio_adc = &pru_buffer_audio_dac[4 * audio_buffer_frames];
|
andrewm@0
|
271
|
andrewm@0
|
272 if(spi_enabled) {
|
andrewm@0
|
273 prussdrv_map_prumem (pru_number == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, (void **)&pruMem);
|
andrewm@0
|
274 pru_buffer_spi_dac = (uint16_t *)&pruMem[PRU_MEM_DAC_OFFSET/sizeof(uint32_t)];
|
andrewm@0
|
275
|
andrewm@12
|
276 /* ADC memory starts after N(ch)*2(buffers)*bufsize samples */
|
andrewm@12
|
277 pru_buffer_spi_adc = &pru_buffer_spi_dac[2 * spi_num_channels * spi_buffer_frames];
|
andrewm@0
|
278 }
|
andrewm@0
|
279 else {
|
andrewm@0
|
280 pru_buffer_spi_dac = pru_buffer_spi_adc = 0;
|
andrewm@0
|
281 }
|
andrewm@0
|
282
|
andrewm@0
|
283 /* Set up flags */
|
andrewm@0
|
284 pru_buffer_comm[PRU_SHOULD_STOP] = 0;
|
andrewm@0
|
285 pru_buffer_comm[PRU_CURRENT_BUFFER] = 0;
|
andrewm@0
|
286 pru_buffer_comm[PRU_BUFFER_FRAMES] = spi_buffer_frames;
|
andrewm@0
|
287 pru_buffer_comm[PRU_SHOULD_SYNC] = 0;
|
andrewm@0
|
288 pru_buffer_comm[PRU_SYNC_ADDRESS] = 0;
|
andrewm@0
|
289 pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0;
|
andrewm@0
|
290 if(led_enabled) {
|
andrewm@0
|
291 pru_buffer_comm[PRU_LED_ADDRESS] = USERLED3_GPIO_BASE;
|
andrewm@0
|
292 pru_buffer_comm[PRU_LED_PIN_MASK] = USERLED3_PIN_MASK;
|
andrewm@0
|
293 }
|
andrewm@0
|
294 else {
|
andrewm@0
|
295 pru_buffer_comm[PRU_LED_ADDRESS] = 0;
|
andrewm@0
|
296 pru_buffer_comm[PRU_LED_PIN_MASK] = 0;
|
andrewm@0
|
297 }
|
andrewm@0
|
298 if(spi_enabled) {
|
andrewm@0
|
299 pru_buffer_comm[PRU_USE_SPI] = 1;
|
andrewm@12
|
300 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = spi_num_channels;
|
andrewm@0
|
301 }
|
andrewm@0
|
302 else {
|
andrewm@0
|
303 pru_buffer_comm[PRU_USE_SPI] = 0;
|
andrewm@12
|
304 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = 0;
|
andrewm@0
|
305 }
|
andrewm@0
|
306
|
andrewm@0
|
307 /* Clear ADC and DAC memory */
|
andrewm@0
|
308 if(spi_enabled) {
|
andrewm@0
|
309 for(int i = 0; i < PRU_MEM_DAC_LENGTH / 2; i++)
|
andrewm@0
|
310 pru_buffer_spi_dac[i] = 0;
|
andrewm@0
|
311 }
|
andrewm@0
|
312 for(int i = 0; i < PRU_MEM_MCASP_LENGTH / 2; i++)
|
andrewm@0
|
313 pru_buffer_audio_dac[i] = 0;
|
andrewm@0
|
314
|
andrewm@0
|
315 /* If using GPIO test pin for Xenomai (for debugging), initialise the pointer now */
|
andrewm@0
|
316 if(xenomai_test_pin && xenomai_gpio_fd < 0) {
|
andrewm@0
|
317 xenomai_gpio_fd = open("/dev/mem", O_RDWR);
|
andrewm@0
|
318 if(xenomai_gpio_fd < 0)
|
andrewm@0
|
319 rt_printf("Unable to open /dev/mem for GPIO test pin\n");
|
andrewm@0
|
320 else {
|
andrewm@0
|
321 xenomai_gpio = (uint32_t *)mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, xenomai_gpio_fd, TEST_PIN_GPIO_BASE);
|
andrewm@0
|
322 if(xenomai_gpio == MAP_FAILED) {
|
andrewm@0
|
323 rt_printf("Unable to map GPIO address for test pin\n");
|
andrewm@0
|
324 xenomai_gpio = 0;
|
andrewm@0
|
325 close(xenomai_gpio_fd);
|
andrewm@0
|
326 xenomai_gpio_fd = -1;
|
andrewm@0
|
327 }
|
andrewm@0
|
328 }
|
andrewm@0
|
329 }
|
andrewm@0
|
330
|
andrewm@0
|
331 return 0;
|
andrewm@0
|
332 }
|
andrewm@0
|
333
|
andrewm@0
|
334 // Run the code image in the specified file
|
andrewm@15
|
335 int PRU::start()
|
andrewm@0
|
336 {
|
andrewm@0
|
337 /* Clear any old interrupt */
|
andrewm@15
|
338 if(pru_number == 0)
|
andrewm@15
|
339 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
|
andrewm@15
|
340 else
|
andrewm@15
|
341 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);
|
andrewm@0
|
342
|
andrewm@0
|
343 /* Load and execute binary on PRU */
|
andrewm@15
|
344 if(prussdrv_exec_code(pru_number, PRUcode, sizeof(PRUcode))) {
|
andrewm@15
|
345 rt_printf("Failed to execute PRU code\n");
|
andrewm@0
|
346 return 1;
|
andrewm@0
|
347 }
|
andrewm@0
|
348
|
andrewm@0
|
349 running = true;
|
andrewm@0
|
350 return 0;
|
andrewm@0
|
351 }
|
andrewm@0
|
352
|
andrewm@0
|
353 // Main loop to read and write data from/to PRU
|
andrewm@0
|
354 void PRU::loop()
|
andrewm@0
|
355 {
|
andrewm@0
|
356 // Polling interval is 1/4 of the period
|
andrewm@12
|
357 RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * (spi_num_channels / 2) * spi_buffer_frames / 4;
|
andrewm@0
|
358 float *audioInBuffer, *audioOutBuffer;
|
andrewm@0
|
359
|
andrewm@0
|
360 audioInBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float));
|
andrewm@0
|
361 audioOutBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float));
|
andrewm@0
|
362
|
andrewm@0
|
363 if(audioInBuffer == 0 || audioOutBuffer == 0) {
|
andrewm@0
|
364 rt_printf("Error: couldn't allocated audio buffers\n");
|
andrewm@0
|
365 return;
|
andrewm@0
|
366 }
|
andrewm@0
|
367
|
andrewm@0
|
368 while(!gShouldStop) {
|
andrewm@0
|
369 // Wait for PRU to move to buffer 1
|
andrewm@0
|
370 while(pru_buffer_comm[PRU_CURRENT_BUFFER] == 0 && !gShouldStop) {
|
andrewm@0
|
371 rt_task_sleep(sleepTime);
|
andrewm@0
|
372 }
|
andrewm@0
|
373 if(gShouldStop)
|
andrewm@0
|
374 break;
|
andrewm@0
|
375
|
andrewm@0
|
376 if(xenomai_gpio != 0) {
|
andrewm@0
|
377 // Set the test pin high
|
andrewm@0
|
378 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK;
|
andrewm@0
|
379 }
|
andrewm@0
|
380
|
andrewm@0
|
381 // Render from/to buffer 0
|
andrewm@0
|
382
|
andrewm@0
|
383 // Convert short (16-bit) samples to float
|
andrewm@0
|
384 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++)
|
andrewm@0
|
385 audioInBuffer[n] = (float)pru_buffer_audio_adc[n] / 32768.0;
|
andrewm@0
|
386
|
andrewm@0
|
387 if(spi_enabled)
|
andrewm@0
|
388 render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer,
|
andrewm@0
|
389 pru_buffer_spi_adc, pru_buffer_spi_dac);
|
andrewm@0
|
390 else
|
andrewm@0
|
391 render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0);
|
andrewm@0
|
392
|
andrewm@0
|
393 // Convert float back to short
|
andrewm@0
|
394 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) {
|
andrewm@0
|
395 int out = audioOutBuffer[n] * 32768.0;
|
andrewm@0
|
396 if(out < -32768) out = -32768;
|
andrewm@0
|
397 else if(out > 32767) out = 32767;
|
andrewm@0
|
398 pru_buffer_audio_dac[n] = (int16_t)out;
|
andrewm@0
|
399 }
|
andrewm@0
|
400
|
andrewm@0
|
401 if(xenomai_gpio != 0) {
|
andrewm@0
|
402 // Set the test pin high
|
andrewm@0
|
403 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK;
|
andrewm@0
|
404 }
|
andrewm@0
|
405
|
andrewm@0
|
406 // Wait for PRU to move to buffer 0
|
andrewm@0
|
407 while(pru_buffer_comm[PRU_CURRENT_BUFFER] != 0 && !gShouldStop) {
|
andrewm@0
|
408 rt_task_sleep(sleepTime);
|
andrewm@0
|
409 }
|
andrewm@0
|
410
|
andrewm@0
|
411 if(gShouldStop)
|
andrewm@0
|
412 break;
|
andrewm@0
|
413
|
andrewm@0
|
414 if(xenomai_gpio != 0) {
|
andrewm@0
|
415 // Set the test pin high
|
andrewm@0
|
416 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK;
|
andrewm@0
|
417 }
|
andrewm@0
|
418
|
andrewm@0
|
419 // Render from/to buffer 1
|
andrewm@0
|
420
|
andrewm@0
|
421 // Convert short (16-bit) samples to float
|
andrewm@0
|
422 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++)
|
andrewm@0
|
423 audioInBuffer[n] = (float)pru_buffer_audio_adc[n + audio_buffer_frames * 2] / 32768.0;
|
andrewm@0
|
424
|
andrewm@0
|
425 if(spi_enabled)
|
andrewm@0
|
426 render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer,
|
andrewm@12
|
427 &pru_buffer_spi_adc[spi_buffer_frames * spi_num_channels], &pru_buffer_spi_dac[spi_buffer_frames * spi_num_channels]);
|
andrewm@0
|
428 else
|
andrewm@0
|
429 render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0);
|
andrewm@0
|
430
|
andrewm@0
|
431 // Convert float back to short
|
andrewm@0
|
432 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) {
|
andrewm@0
|
433 int out = audioOutBuffer[n] * 32768.0;
|
andrewm@0
|
434 if(out < -32768) out = -32768;
|
andrewm@0
|
435 else if(out > 32767) out = 32767;
|
andrewm@0
|
436 pru_buffer_audio_dac[n + audio_buffer_frames * 2] = (int16_t)out;
|
andrewm@0
|
437 }
|
andrewm@0
|
438
|
andrewm@0
|
439 if(xenomai_gpio != 0) {
|
andrewm@0
|
440 // Set the test pin high
|
andrewm@0
|
441 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK;
|
andrewm@0
|
442 }
|
andrewm@0
|
443 }
|
andrewm@0
|
444
|
andrewm@0
|
445 // Tell PRU to stop
|
andrewm@0
|
446 pru_buffer_comm[PRU_SHOULD_STOP] = 1;
|
andrewm@0
|
447
|
andrewm@0
|
448 free(audioInBuffer);
|
andrewm@0
|
449 free(audioOutBuffer);
|
andrewm@0
|
450 }
|
andrewm@0
|
451
|
andrewm@0
|
452 // Wait for an interrupt from the PRU indicate it is finished
|
andrewm@0
|
453 void PRU::waitForFinish()
|
andrewm@0
|
454 {
|
andrewm@0
|
455 if(!running)
|
andrewm@0
|
456 return;
|
andrewm@15
|
457 prussdrv_pru_wait_event (pru_number == 0 ? PRU_EVTOUT_0 : PRU_EVTOUT_1);
|
andrewm@15
|
458 if(pru_number == 0)
|
andrewm@15
|
459 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
|
andrewm@15
|
460 else
|
andrewm@15
|
461 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);
|
andrewm@0
|
462 }
|
andrewm@0
|
463
|
andrewm@0
|
464 // Turn off the PRU when done
|
andrewm@0
|
465 void PRU::disable()
|
andrewm@0
|
466 {
|
andrewm@0
|
467 /* Disable PRU and close memory mapping*/
|
andrewm@0
|
468 prussdrv_pru_disable(pru_number);
|
andrewm@0
|
469 prussdrv_exit();
|
andrewm@0
|
470 running = false;
|
andrewm@0
|
471 }
|
andrewm@0
|
472
|
andrewm@0
|
473 // Debugging
|
andrewm@0
|
474 void PRU::setGPIOTestPin()
|
andrewm@0
|
475 {
|
andrewm@0
|
476 if(!xenomai_gpio)
|
andrewm@0
|
477 return;
|
andrewm@0
|
478 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN2_MASK;
|
andrewm@0
|
479 }
|
andrewm@0
|
480
|
andrewm@0
|
481 void PRU::clearGPIOTestPin()
|
andrewm@0
|
482 {
|
andrewm@0
|
483 if(!xenomai_gpio)
|
andrewm@0
|
484 return;
|
andrewm@0
|
485 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN2_MASK;
|
andrewm@0
|
486 }
|