Mercurial > hg > beaglert
comparison core/PRU.cpp @ 67:472e892c6e41
Merge newapi into default
author | Andrew McPherson <a.mcpherson@qmul.ac.uk> |
---|---|
date | Fri, 17 Jul 2015 15:28:18 +0100 |
parents | 3c3a1357657d |
children | 92145ba7aabf |
comparison
equal
deleted
inserted
replaced
21:0d80ff9e2227 | 67:472e892c6e41 |
---|---|
14 */ | 14 */ |
15 | 15 |
16 #include "../include/PRU.h" | 16 #include "../include/PRU.h" |
17 #include "../include/prussdrv.h" | 17 #include "../include/prussdrv.h" |
18 #include "../include/pruss_intc_mapping.h" | 18 #include "../include/pruss_intc_mapping.h" |
19 #include "../include/digital_gpio_mapping.h" | |
19 #include "../include/GPIOcontrol.h" | 20 #include "../include/GPIOcontrol.h" |
20 #include "../include/render.h" | 21 #include "../include/BeagleRT.h" |
21 #include "../include/pru_rtaudio_bin.h" | 22 #include "../include/pru_rtaudio_bin.h" |
22 | 23 |
23 #include <iostream> | 24 #include <iostream> |
24 #include <stdlib.h> | 25 #include <stdlib.h> |
25 #include <cstdio> | 26 #include <cstdio> |
26 #include <cerrno> | 27 #include <cerrno> |
27 #include <fcntl.h> | 28 #include <fcntl.h> |
28 #include <sys/mman.h> | 29 #include <sys/mman.h> |
30 #include <unistd.h> | |
29 | 31 |
30 // Xenomai-specific includes | 32 // Xenomai-specific includes |
31 #include <sys/mman.h> | 33 #include <sys/mman.h> |
32 #include <native/task.h> | 34 #include <native/task.h> |
33 #include <native/timer.h> | 35 #include <native/timer.h> |
38 #define PRU_MEM_MCASP_OFFSET 0x2000 // Offset within PRU-SHARED RAM | 40 #define PRU_MEM_MCASP_OFFSET 0x2000 // Offset within PRU-SHARED RAM |
39 #define PRU_MEM_MCASP_LENGTH 0x2000 // Length of McASP memory, in bytes | 41 #define PRU_MEM_MCASP_LENGTH 0x2000 // Length of McASP memory, in bytes |
40 #define PRU_MEM_DAC_OFFSET 0x0 // Offset within PRU0 RAM | 42 #define PRU_MEM_DAC_OFFSET 0x0 // Offset within PRU0 RAM |
41 #define PRU_MEM_DAC_LENGTH 0x2000 // Length of ADC+DAC memory, in bytes | 43 #define PRU_MEM_DAC_LENGTH 0x2000 // Length of ADC+DAC memory, in bytes |
42 #define PRU_MEM_COMM_OFFSET 0x0 // Offset within PRU-SHARED RAM | 44 #define PRU_MEM_COMM_OFFSET 0x0 // Offset within PRU-SHARED RAM |
43 | 45 #define PRU_MEM_DIGITAL_OFFSET 0x1000 //Offset within PRU-SHARED RAM |
46 #define MEM_DIGITAL_BUFFER1_OFFSET 0x400 //Start pointer to DIGITAL_BUFFER1, which is 256 words. | |
47 // 256 is the maximum number of frames allowed | |
44 #define PRU_SHOULD_STOP 0 | 48 #define PRU_SHOULD_STOP 0 |
45 #define PRU_CURRENT_BUFFER 1 | 49 #define PRU_CURRENT_BUFFER 1 |
46 #define PRU_BUFFER_FRAMES 2 | 50 #define PRU_BUFFER_FRAMES 2 |
47 #define PRU_SHOULD_SYNC 3 | 51 #define PRU_SHOULD_SYNC 3 |
48 #define PRU_SYNC_ADDRESS 4 | 52 #define PRU_SYNC_ADDRESS 4 |
50 #define PRU_LED_ADDRESS 6 | 54 #define PRU_LED_ADDRESS 6 |
51 #define PRU_LED_PIN_MASK 7 | 55 #define PRU_LED_PIN_MASK 7 |
52 #define PRU_FRAME_COUNT 8 | 56 #define PRU_FRAME_COUNT 8 |
53 #define PRU_USE_SPI 9 | 57 #define PRU_USE_SPI 9 |
54 #define PRU_SPI_NUM_CHANNELS 10 | 58 #define PRU_SPI_NUM_CHANNELS 10 |
59 #define PRU_USE_DIGITAL 11 | |
60 | |
61 short int digitalPins[NUM_DIGITALS]={ | |
62 GPIO_NO_BIT_0, | |
63 GPIO_NO_BIT_1, | |
64 GPIO_NO_BIT_2, | |
65 GPIO_NO_BIT_3, | |
66 GPIO_NO_BIT_4, | |
67 GPIO_NO_BIT_5, | |
68 GPIO_NO_BIT_6, | |
69 GPIO_NO_BIT_7, | |
70 GPIO_NO_BIT_8, | |
71 GPIO_NO_BIT_9, | |
72 GPIO_NO_BIT_10, | |
73 GPIO_NO_BIT_11, | |
74 GPIO_NO_BIT_12, | |
75 GPIO_NO_BIT_13, | |
76 GPIO_NO_BIT_14, | |
77 GPIO_NO_BIT_15, | |
78 }; | |
55 | 79 |
56 #define PRU_SAMPLE_INTERVAL_NS 11338 // 88200Hz per SPI sample = 11.338us | 80 #define PRU_SAMPLE_INTERVAL_NS 11338 // 88200Hz per SPI sample = 11.338us |
57 | 81 |
58 #define GPIO0_ADDRESS 0x44E07000 | 82 #define GPIO0_ADDRESS 0x44E07000 |
59 #define GPIO1_ADDRESS 0x4804C000 | 83 #define GPIO1_ADDRESS 0x4804C000 |
73 | 97 |
74 const unsigned int PRU::kPruGPIOTestPin = 60; // GPIO1(28); P9-12 | 98 const unsigned int PRU::kPruGPIOTestPin = 60; // GPIO1(28); P9-12 |
75 const unsigned int PRU::kPruGPIOTestPin2 = 31; // GPIO0(31); P9-13 | 99 const unsigned int PRU::kPruGPIOTestPin2 = 31; // GPIO0(31); P9-13 |
76 const unsigned int PRU::kPruGPIOTestPin3 = 26; // GPIO0(26); P8-14 | 100 const unsigned int PRU::kPruGPIOTestPin3 = 26; // GPIO0(26); P8-14 |
77 | 101 |
78 extern int gShouldStop; | 102 extern bool gShouldStop; |
79 extern int gRTAudioVerbose; | 103 extern int gRTAudioVerbose; |
80 | 104 |
81 // Constructor: specify a PRU number (0 or 1) | 105 // Constructor: specify a PRU number (0 or 1) |
82 PRU::PRU() | 106 PRU::PRU(BeagleRTContext *input_context) |
83 : pru_number(0), running(false), spi_enabled(false), gpio_enabled(false), led_enabled(false), | 107 : context(input_context), pru_number(0), running(false), analog_enabled(false), |
84 gpio_test_pin_enabled(false), spi_num_channels(0), xenomai_gpio_fd(-1), xenomai_gpio(0) | 108 digital_enabled(false), gpio_enabled(false), led_enabled(false), |
109 gpio_test_pin_enabled(false), | |
110 pru_buffer_comm(0), pru_buffer_spi_dac(0), pru_buffer_spi_adc(0), | |
111 pru_buffer_digital(0), pru_buffer_audio_dac(0), pru_buffer_audio_adc(0), | |
112 xenomai_gpio_fd(-1), xenomai_gpio(0) | |
85 { | 113 { |
86 | 114 |
87 } | 115 } |
88 | 116 |
89 // Destructor | 117 // Destructor |
101 // If include_test_pin is set, the GPIO output | 129 // If include_test_pin is set, the GPIO output |
102 // is also prepared for an output which can be | 130 // is also prepared for an output which can be |
103 // viewed on a scope. If include_led is set, | 131 // viewed on a scope. If include_led is set, |
104 // user LED 3 on the BBB is taken over by the PRU | 132 // user LED 3 on the BBB is taken over by the PRU |
105 // to indicate activity | 133 // to indicate activity |
106 int PRU::prepareGPIO(int use_spi, int include_test_pin, int include_led) | 134 int PRU::prepareGPIO(int include_test_pin, int include_led) |
107 { | 135 { |
108 if(use_spi) { | 136 if(context->analogFrames != 0) { |
109 // Prepare DAC CS/ pin: output, high to begin | 137 // Prepare DAC CS/ pin: output, high to begin |
110 if(gpio_export(kPruGPIODACSyncPin)) { | 138 if(gpio_export(kPruGPIODACSyncPin)) { |
111 if(gRTAudioVerbose) | 139 if(gRTAudioVerbose) |
112 cout << "Warning: couldn't export DAC sync pin\n"; | 140 cout << "Warning: couldn't export DAC sync pin\n"; |
113 } | 141 } |
136 if(gRTAudioVerbose) | 164 if(gRTAudioVerbose) |
137 cout << "Couldn't set value on ADC sync pin\n"; | 165 cout << "Couldn't set value on ADC sync pin\n"; |
138 return -1; | 166 return -1; |
139 } | 167 } |
140 | 168 |
141 spi_enabled = true; | 169 analog_enabled = true; |
170 } | |
171 | |
172 if(context->digitalFrames != 0){ | |
173 for(unsigned int i = 0; i < context->digitalChannels; i++){ | |
174 if(gpio_export(digitalPins[i])) { | |
175 if(gRTAudioVerbose) | |
176 cerr << "Warning: couldn't export digital GPIO pin " << digitalPins[i] << "\n"; // this is left as a warning because if the pin has been exported by somebody else, can still be used | |
177 } | |
178 if(gpio_set_dir(digitalPins[i], INPUT_PIN)) { | |
179 if(gRTAudioVerbose) | |
180 cerr << "Error: Couldn't set direction on digital GPIO pin " << digitalPins[i] << "\n"; | |
181 return -1; | |
182 } | |
183 } | |
184 digital_enabled = true; | |
142 } | 185 } |
143 | 186 |
144 if(include_test_pin) { | 187 if(include_test_pin) { |
145 // Prepare GPIO test output (for debugging), low to begin | 188 // Prepare GPIO test output (for debugging), low to begin |
146 if(gpio_export(kPruGPIOTestPin)) { | 189 if(gpio_export(kPruGPIOTestPin)) { |
204 // Clean up the GPIO at the end | 247 // Clean up the GPIO at the end |
205 void PRU::cleanupGPIO() | 248 void PRU::cleanupGPIO() |
206 { | 249 { |
207 if(!gpio_enabled) | 250 if(!gpio_enabled) |
208 return; | 251 return; |
209 if(spi_enabled) { | 252 if(analog_enabled) { |
210 gpio_unexport(kPruGPIODACSyncPin); | 253 gpio_unexport(kPruGPIODACSyncPin); |
211 gpio_unexport(kPruGPIOADCSyncPin); | 254 gpio_unexport(kPruGPIOADCSyncPin); |
255 } | |
256 if(digital_enabled){ | |
257 for(unsigned int i = 0; i < context->digitalChannels; i++){ | |
258 gpio_unexport(digitalPins[i]); | |
259 } | |
212 } | 260 } |
213 if(gpio_test_pin_enabled) { | 261 if(gpio_test_pin_enabled) { |
214 gpio_unexport(kPruGPIOTestPin); | 262 gpio_unexport(kPruGPIOTestPin); |
215 gpio_unexport(kPruGPIOTestPin2); | 263 gpio_unexport(kPruGPIOTestPin2); |
216 gpio_unexport(kPruGPIOTestPin3); | 264 gpio_unexport(kPruGPIOTestPin3); |
219 // Set LED back to default eMMC status | 267 // Set LED back to default eMMC status |
220 // TODO: make it go back to its actual value before this program, | 268 // TODO: make it go back to its actual value before this program, |
221 // rather than the system default | 269 // rather than the system default |
222 led_set_trigger(3, "mmc1"); | 270 led_set_trigger(3, "mmc1"); |
223 } | 271 } |
224 | |
225 gpio_enabled = gpio_test_pin_enabled = false; | 272 gpio_enabled = gpio_test_pin_enabled = false; |
226 } | 273 } |
227 | 274 |
228 // Initialise and open the PRU | 275 // Initialise and open the PRU |
229 int PRU::initialise(int pru_num, int frames_per_buffer, int spi_channels, bool xenomai_test_pin) | 276 int PRU::initialise(int pru_num, int frames_per_buffer, int spi_channels, bool xenomai_test_pin) |
235 return 1; | 282 return 1; |
236 } | 283 } |
237 | 284 |
238 pru_number = pru_num; | 285 pru_number = pru_num; |
239 | 286 |
240 /* Set number of SPI ADC / DAC channels to use. This implicitly | |
241 * also determines the sample rate relative to the audio clock | |
242 * (half audio clock for 8 channels, full audio clock for 4, | |
243 * double audio clock for 2) | |
244 */ | |
245 spi_num_channels = spi_channels; | |
246 | |
247 /* Initialize structure used by prussdrv_pruintc_intc */ | 287 /* Initialize structure used by prussdrv_pruintc_intc */ |
248 /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ | 288 /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ |
249 tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; | 289 tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; |
250 | 290 |
251 /* Allocate and initialize memory */ | 291 /* Allocate and initialize memory */ |
252 prussdrv_init(); | 292 prussdrv_init(); |
253 if(prussdrv_open(pru_number == 0 ? PRU_EVTOUT_0 : PRU_EVTOUT_1)) { | 293 if(prussdrv_open(PRU_EVTOUT_0)) { |
254 rt_printf("Failed to open PRU driver\n"); | 294 rt_printf("Failed to open PRU driver\n"); |
255 return 1; | 295 return 1; |
256 } | 296 } |
257 | 297 |
258 /* Map PRU's INTC */ | 298 /* Map PRU's INTC */ |
259 prussdrv_pruintc_init(&pruss_intc_initdata); | 299 prussdrv_pruintc_init(&pruss_intc_initdata); |
260 | |
261 spi_buffer_frames = frames_per_buffer; | |
262 audio_buffer_frames = spi_buffer_frames * spi_num_channels / 4; | |
263 | 300 |
264 /* Map PRU memory to pointers */ | 301 /* Map PRU memory to pointers */ |
265 prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem); | 302 prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem); |
266 pru_buffer_comm = (uint32_t *)&pruMem[PRU_MEM_COMM_OFFSET/sizeof(uint32_t)]; | 303 pru_buffer_comm = (uint32_t *)&pruMem[PRU_MEM_COMM_OFFSET/sizeof(uint32_t)]; |
267 pru_buffer_audio_dac = (int16_t *)&pruMem[PRU_MEM_MCASP_OFFSET/sizeof(uint32_t)]; | 304 pru_buffer_audio_dac = (int16_t *)&pruMem[PRU_MEM_MCASP_OFFSET/sizeof(uint32_t)]; |
268 | 305 |
269 /* ADC memory starts 2(ch)*2(buffers)*bufsize samples later */ | 306 /* ADC memory starts 2(ch)*2(buffers)*bufsize samples later */ |
270 pru_buffer_audio_adc = &pru_buffer_audio_dac[4 * audio_buffer_frames]; | 307 pru_buffer_audio_adc = &pru_buffer_audio_dac[4 * context->audioFrames]; |
271 | 308 |
272 if(spi_enabled) { | 309 if(analog_enabled) { |
273 prussdrv_map_prumem (pru_number == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, (void **)&pruMem); | 310 prussdrv_map_prumem (pru_number == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, (void **)&pruMem); |
274 pru_buffer_spi_dac = (uint16_t *)&pruMem[PRU_MEM_DAC_OFFSET/sizeof(uint32_t)]; | 311 pru_buffer_spi_dac = (uint16_t *)&pruMem[PRU_MEM_DAC_OFFSET/sizeof(uint32_t)]; |
275 | 312 |
276 /* ADC memory starts after N(ch)*2(buffers)*bufsize samples */ | 313 /* ADC memory starts after N(ch)*2(buffers)*bufsize samples */ |
277 pru_buffer_spi_adc = &pru_buffer_spi_dac[2 * spi_num_channels * spi_buffer_frames]; | 314 pru_buffer_spi_adc = &pru_buffer_spi_dac[2 * context->analogChannels * context->analogFrames]; |
278 } | 315 } |
279 else { | 316 else { |
280 pru_buffer_spi_dac = pru_buffer_spi_adc = 0; | 317 pru_buffer_spi_dac = pru_buffer_spi_adc = 0; |
318 } | |
319 | |
320 if(digital_enabled) { | |
321 prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem); | |
322 pru_buffer_digital = (uint32_t *)&pruMem[PRU_MEM_DIGITAL_OFFSET/sizeof(uint32_t)]; | |
323 } | |
324 else { | |
325 pru_buffer_digital = 0; | |
281 } | 326 } |
282 | 327 |
283 /* Set up flags */ | 328 /* Set up flags */ |
284 pru_buffer_comm[PRU_SHOULD_STOP] = 0; | 329 pru_buffer_comm[PRU_SHOULD_STOP] = 0; |
285 pru_buffer_comm[PRU_CURRENT_BUFFER] = 0; | 330 pru_buffer_comm[PRU_CURRENT_BUFFER] = 0; |
286 pru_buffer_comm[PRU_BUFFER_FRAMES] = spi_buffer_frames; | 331 pru_buffer_comm[PRU_BUFFER_FRAMES] = context->analogFrames; |
287 pru_buffer_comm[PRU_SHOULD_SYNC] = 0; | 332 pru_buffer_comm[PRU_SHOULD_SYNC] = 0; |
288 pru_buffer_comm[PRU_SYNC_ADDRESS] = 0; | 333 pru_buffer_comm[PRU_SYNC_ADDRESS] = 0; |
289 pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0; | 334 pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0; |
290 if(led_enabled) { | 335 if(led_enabled) { |
291 pru_buffer_comm[PRU_LED_ADDRESS] = USERLED3_GPIO_BASE; | 336 pru_buffer_comm[PRU_LED_ADDRESS] = USERLED3_GPIO_BASE; |
293 } | 338 } |
294 else { | 339 else { |
295 pru_buffer_comm[PRU_LED_ADDRESS] = 0; | 340 pru_buffer_comm[PRU_LED_ADDRESS] = 0; |
296 pru_buffer_comm[PRU_LED_PIN_MASK] = 0; | 341 pru_buffer_comm[PRU_LED_PIN_MASK] = 0; |
297 } | 342 } |
298 if(spi_enabled) { | 343 if(analog_enabled) { |
299 pru_buffer_comm[PRU_USE_SPI] = 1; | 344 pru_buffer_comm[PRU_USE_SPI] = 1; |
300 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = spi_num_channels; | 345 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = context->analogChannels; |
301 } | 346 } |
302 else { | 347 else { |
303 pru_buffer_comm[PRU_USE_SPI] = 0; | 348 pru_buffer_comm[PRU_USE_SPI] = 0; |
304 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = 0; | 349 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = 0; |
305 } | 350 } |
306 | 351 if(digital_enabled) { |
307 /* Clear ADC and DAC memory */ | 352 pru_buffer_comm[PRU_USE_DIGITAL] = 1; |
308 if(spi_enabled) { | 353 //TODO: add mask |
354 } | |
355 else { | |
356 pru_buffer_comm[PRU_USE_DIGITAL] = 0; | |
357 | |
358 } | |
359 | |
360 /* Clear ADC and DAC memory.*/ | |
361 //TODO: this initialisation should only address the memory effectively used by these buffers, i.e.:depend on the number of frames | |
362 // (otherwise might cause issues if we move memory locations later on) | |
363 if(analog_enabled) { | |
309 for(int i = 0; i < PRU_MEM_DAC_LENGTH / 2; i++) | 364 for(int i = 0; i < PRU_MEM_DAC_LENGTH / 2; i++) |
310 pru_buffer_spi_dac[i] = 0; | 365 pru_buffer_spi_dac[i] = 0; |
366 if(digital_enabled){ | |
367 for(int i = 0; i < PRU_MEM_DIGITAL_OFFSET*2; i++) | |
368 pru_buffer_digital[i] = 0x0000ffff; // set to all inputs, to avoid unexpected spikes | |
369 } | |
311 } | 370 } |
312 for(int i = 0; i < PRU_MEM_MCASP_LENGTH / 2; i++) | 371 for(int i = 0; i < PRU_MEM_MCASP_LENGTH / 2; i++) |
313 pru_buffer_audio_dac[i] = 0; | 372 pru_buffer_audio_dac[i] = 0; |
314 | 373 |
315 /* If using GPIO test pin for Xenomai (for debugging), initialise the pointer now */ | 374 /* If using GPIO test pin for Xenomai (for debugging), initialise the pointer now */ |
330 | 389 |
331 return 0; | 390 return 0; |
332 } | 391 } |
333 | 392 |
334 // Run the code image in the specified file | 393 // Run the code image in the specified file |
335 int PRU::start() | 394 int PRU::start(char * const filename) |
336 { | 395 { |
337 /* Clear any old interrupt */ | 396 /* Clear any old interrupt */ |
338 if(pru_number == 0) | 397 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); |
339 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); | 398 |
340 else | 399 /* Load and execute binary on PRU */ |
341 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT); | 400 if(filename[0] == '\0') { //if the string is empty, load the embedded code |
342 | 401 if(gRTAudioVerbose) |
343 /* Load and execute binary on PRU */ | 402 rt_printf("Using embedded PRU code\n"); |
344 if(prussdrv_exec_code(pru_number, PRUcode, sizeof(PRUcode))) { | 403 if(prussdrv_exec_code(pru_number, PRUcode, sizeof(PRUcode))) { |
345 rt_printf("Failed to execute PRU code\n"); | 404 rt_printf("Failed to execute PRU code\n"); |
346 return 1; | 405 return 1; |
347 } | 406 } |
407 } else { | |
408 if(gRTAudioVerbose) | |
409 rt_printf("Using PRU code from %s\n",filename); | |
410 if(prussdrv_exec_program(pru_number, filename)) { | |
411 rt_printf("Failed to execute PRU code from %s\n", filename); | |
412 return 1; | |
413 } | |
414 } | |
348 | 415 |
349 running = true; | 416 running = true; |
350 return 0; | 417 return 0; |
351 } | 418 } |
352 | 419 |
353 // Main loop to read and write data from/to PRU | 420 // Main loop to read and write data from/to PRU |
354 void PRU::loop() | 421 void PRU::loop(RT_INTR *pru_interrupt, void *userData) |
355 { | 422 { |
423 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS | |
424 RTIME irqTimeout = PRU_SAMPLE_INTERVAL_NS * 1024; // Timeout for PRU interrupt: about 10ms, much longer than any expected period | |
425 #else | |
356 // Polling interval is 1/4 of the period | 426 // Polling interval is 1/4 of the period |
357 RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * (spi_num_channels / 2) * spi_buffer_frames / 4; | 427 RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * (context->analogChannels / 2) * context->analogFrames / 4; |
358 float *audioInBuffer, *audioOutBuffer; | 428 #endif |
359 | 429 |
360 audioInBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float)); | 430 float *lastAnalogOutFrame; |
361 audioOutBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float)); | 431 uint32_t *digitalBuffer0, *digitalBuffer1, *lastDigitalBuffer; |
362 | 432 uint32_t pru_audio_offset, pru_spi_offset; |
363 if(audioInBuffer == 0 || audioOutBuffer == 0) { | 433 |
364 rt_printf("Error: couldn't allocated audio buffers\n"); | 434 // Allocate audio buffers |
435 context->audioIn = (float *)malloc(2 * context->audioFrames * sizeof(float)); | |
436 context->audioOut = (float *)malloc(2 * context->audioFrames * sizeof(float)); | |
437 if(context->audioIn == 0 || context->audioOut == 0) { | |
438 rt_printf("Error: couldn't allocate audio buffers\n"); | |
365 return; | 439 return; |
366 } | 440 } |
367 | 441 |
442 // Allocate analog buffers | |
443 if(analog_enabled) { | |
444 context->analogIn = (float *)malloc(context->analogChannels * context->analogFrames * sizeof(float)); | |
445 context->analogOut = (float *)malloc(context->analogChannels * context->analogFrames * sizeof(float)); | |
446 lastAnalogOutFrame = (float *)malloc(context->analogChannels * sizeof(float)); | |
447 | |
448 if(context->analogIn == 0 || context->analogOut == 0 || lastAnalogOutFrame == 0) { | |
449 rt_printf("Error: couldn't allocate analog buffers\n"); | |
450 return; | |
451 } | |
452 | |
453 memset(lastAnalogOutFrame, 0, context->analogChannels * sizeof(float)); | |
454 } | |
455 | |
456 // Allocate digital buffers | |
457 digitalBuffer0 = pru_buffer_digital; | |
458 digitalBuffer1 = pru_buffer_digital + MEM_DIGITAL_BUFFER1_OFFSET / sizeof(uint32_t); | |
459 if(digital_enabled) { | |
460 lastDigitalBuffer = (uint32_t *)malloc(context->digitalFrames * sizeof(uint32_t)); //temp buffer to hold previous states | |
461 if(lastDigitalBuffer == 0) { | |
462 rt_printf("Error: couldn't allocate digital buffers\n"); | |
463 return; | |
464 } | |
465 | |
466 for(unsigned int n = 0; n < context->digitalFrames; n++){ | |
467 // Initialize lastDigitalFrames to all inputs | |
468 lastDigitalBuffer[n] = 0x0000ffff; | |
469 } | |
470 } | |
471 | |
472 // TESTING | |
473 // uint32_t testCount = 0; | |
474 // RTIME startTime = rt_timer_read(); | |
475 | |
476 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS | |
477 int result; | |
478 #else | |
479 // Which buffer the PRU was last processing | |
480 uint32_t lastPRUBuffer = 0; | |
481 #endif | |
482 | |
368 while(!gShouldStop) { | 483 while(!gShouldStop) { |
369 // Wait for PRU to move to buffer 1 | 484 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS |
370 while(pru_buffer_comm[PRU_CURRENT_BUFFER] == 0 && !gShouldStop) { | 485 // Wait for PRU to move to change buffers; |
486 // PRU will send an interrupts which we wait for | |
487 rt_intr_enable(pru_interrupt); | |
488 while(!gShouldStop) { | |
489 result = rt_intr_wait(pru_interrupt, irqTimeout); | |
490 if(result >= 0) | |
491 break; | |
492 else if(result == -ETIMEDOUT) | |
493 rt_printf("Warning: PRU timeout!\n"); | |
494 else { | |
495 rt_printf("Error: wait for interrupt failed (%d)\n", result); | |
496 gShouldStop = 1; | |
497 } | |
498 } | |
499 | |
500 // Clear pending PRU interrupt | |
501 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT); | |
502 #else | |
503 // Poll | |
504 while(pru_buffer_comm[PRU_CURRENT_BUFFER] == lastPRUBuffer && !gShouldStop) { | |
371 rt_task_sleep(sleepTime); | 505 rt_task_sleep(sleepTime); |
372 } | 506 } |
507 | |
508 lastPRUBuffer = pru_buffer_comm[PRU_CURRENT_BUFFER]; | |
509 #endif | |
510 | |
373 if(gShouldStop) | 511 if(gShouldStop) |
374 break; | 512 break; |
513 | |
514 // Check which buffer we're on-- will have been set right | |
515 // before the interrupt was asserted | |
516 if(pru_buffer_comm[PRU_CURRENT_BUFFER] == 1) { | |
517 // PRU is on buffer 1. We read and write to buffer 0 | |
518 pru_audio_offset = 0; | |
519 pru_spi_offset = 0; | |
520 if(digital_enabled) | |
521 context->digital = digitalBuffer0; | |
522 } | |
523 else { | |
524 // PRU is on buffer 0. We read and write to buffer 1 | |
525 pru_audio_offset = context->audioFrames * 2; | |
526 pru_spi_offset = context->analogFrames * context->analogChannels; | |
527 if(digital_enabled) | |
528 context->digital = digitalBuffer1; | |
529 } | |
530 | |
531 // FIXME: some sort of margin is needed here to prevent the audio | |
532 // code from completely eating the Linux system | |
533 // testCount++; | |
534 //rt_task_sleep(sleepTime*4); | |
535 //rt_task_sleep(sleepTime/4); | |
375 | 536 |
376 if(xenomai_gpio != 0) { | 537 if(xenomai_gpio != 0) { |
377 // Set the test pin high | 538 // Set the test pin high |
378 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK; | 539 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK; |
379 } | 540 } |
380 | 541 |
381 // Render from/to buffer 0 | |
382 | |
383 // Convert short (16-bit) samples to float | 542 // Convert short (16-bit) samples to float |
384 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) | 543 // TODO: NEON |
385 audioInBuffer[n] = (float)pru_buffer_audio_adc[n] / 32768.0; | 544 for(unsigned int n = 0; n < 2 * context->audioFrames; n++) |
386 | 545 context->audioIn[n] = (float)pru_buffer_audio_adc[n + pru_audio_offset] / 32768.0; |
387 if(spi_enabled) | 546 |
388 render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer, | 547 if(analog_enabled) { |
389 pru_buffer_spi_adc, pru_buffer_spi_dac); | 548 // TODO: NEON |
390 else | 549 for(unsigned int n = 0; n < context->analogChannels * context->analogFrames; n++) |
391 render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0); | 550 context->analogIn[n] = (float)pru_buffer_spi_adc[n + pru_spi_offset] / 65536.0; |
392 | 551 |
393 // Convert float back to short | 552 if(context->flags & BEAGLERT_FLAG_ANALOG_OUTPUTS_PERSIST) { |
394 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) { | 553 // Initialize the output buffer with the values that were in the last frame of the previous output |
395 int out = audioOutBuffer[n] * 32768.0; | 554 for(unsigned int ch = 0; ch < context->analogChannels; ch++){ |
555 for(unsigned int n = 0; n < context->analogFrames; n++){ | |
556 context->analogOut[n * context->analogChannels + ch] = lastAnalogOutFrame[ch]; | |
557 } | |
558 } | |
559 } | |
560 else { | |
561 // Outputs are 0 unless set otherwise | |
562 memset(context->analogOut, 0, context->analogChannels * context->analogFrames * sizeof(float)); | |
563 } | |
564 } | |
565 | |
566 if(digital_enabled){ | |
567 // Use past digital values to initialize the array properly. | |
568 // For each frame: | |
569 // - pins previously set as outputs will keep the output value they had in the last frame of the previous buffer, | |
570 // - pins previously set as inputs will carry the newly read input value | |
571 | |
572 for(unsigned int n = 0; n < context->digitalFrames; n++){ | |
573 uint16_t inputs = lastDigitalBuffer[n] & 0xffff; // half-word, has 1 for inputs and 0 for outputs | |
574 | |
575 uint16_t outputs = ~inputs; // half-word has 1 for outputs and 0 for inputs; | |
576 context->digital[n] = (lastDigitalBuffer[context->digitalFrames - 1] & (outputs << 16)) | // keep output values set in the last frame of the previous buffer | |
577 (context->digital[n] & (inputs << 16)) | // inputs from current context->digital[n]; | |
578 (lastDigitalBuffer[n] & (inputs)); // keep pin configuration from previous context->digital[n] | |
579 // context->digital[n]=digitalBufferTemp[n]; //ignores inputs | |
580 } | |
581 } | |
582 | |
583 // Call user render function | |
584 // *********************** | |
585 render(context, userData); | |
586 // *********************** | |
587 | |
588 if(analog_enabled) { | |
589 if(context->flags & BEAGLERT_FLAG_ANALOG_OUTPUTS_PERSIST) { | |
590 // Remember the content of the lastAnalogOutFrame | |
591 for(unsigned int ch = 0; ch < context->analogChannels; ch++){ | |
592 lastAnalogOutFrame[ch] = context->analogOut[context->analogChannels * (context->analogFrames - 1) + ch]; | |
593 } | |
594 } | |
595 | |
596 // Convert float back to short for SPI output | |
597 for(unsigned int n = 0; n < context->analogChannels * context->analogFrames; n++) { | |
598 int out = context->analogOut[n] * 65536.0; | |
599 if(out < 0) out = 0; | |
600 else if(out > 65535) out = 65535; | |
601 pru_buffer_spi_dac[n + pru_spi_offset] = (uint16_t)out; | |
602 } | |
603 } | |
604 | |
605 if(digital_enabled) { // keep track of past digital values | |
606 for(unsigned int n = 0; n < context->digitalFrames; n++){ | |
607 lastDigitalBuffer[n] = context->digital[n]; | |
608 } | |
609 } | |
610 | |
611 // Convert float back to short for audio | |
612 // TODO: NEON | |
613 for(unsigned int n = 0; n < 2 * context->audioFrames; n++) { | |
614 int out = context->audioOut[n] * 32768.0; | |
396 if(out < -32768) out = -32768; | 615 if(out < -32768) out = -32768; |
397 else if(out > 32767) out = 32767; | 616 else if(out > 32767) out = 32767; |
398 pru_buffer_audio_dac[n] = (int16_t)out; | 617 pru_buffer_audio_dac[n + pru_audio_offset] = (int16_t)out; |
399 } | 618 } |
619 | |
620 // Increment total number of samples that have elapsed | |
621 context->audioSampleCount += context->audioFrames; | |
400 | 622 |
401 if(xenomai_gpio != 0) { | 623 if(xenomai_gpio != 0) { |
402 // Set the test pin high | 624 // Set the test pin high |
403 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK; | 625 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK; |
404 } | 626 } |
405 | 627 |
406 // Wait for PRU to move to buffer 0 | 628 // FIXME: TESTING!! |
407 while(pru_buffer_comm[PRU_CURRENT_BUFFER] != 0 && !gShouldStop) { | 629 // if(testCount > 100000) |
408 rt_task_sleep(sleepTime); | 630 // break; |
409 } | 631 } |
410 | 632 |
411 if(gShouldStop) | 633 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS |
412 break; | 634 // Turn off the interrupt for the PRU if it isn't already off |
413 | 635 rt_intr_disable(pru_interrupt); |
414 if(xenomai_gpio != 0) { | 636 #endif |
415 // Set the test pin high | 637 |
416 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK; | 638 // FIXME: TESTING |
417 } | 639 // RTIME endTime = rt_timer_read(); |
418 | 640 // RTIME diffTime = endTime - startTime; |
419 // Render from/to buffer 1 | 641 // rt_printf("%d blocks elapsed in %f seconds, %f Hz block rate\n", testCount, ((float)diffTime / 1.0e9), (float)testCount / ((float)diffTime / 1.0e9)); |
420 | |
421 // Convert short (16-bit) samples to float | |
422 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) | |
423 audioInBuffer[n] = (float)pru_buffer_audio_adc[n + audio_buffer_frames * 2] / 32768.0; | |
424 | |
425 if(spi_enabled) | |
426 render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer, | |
427 &pru_buffer_spi_adc[spi_buffer_frames * spi_num_channels], &pru_buffer_spi_dac[spi_buffer_frames * spi_num_channels]); | |
428 else | |
429 render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0); | |
430 | |
431 // Convert float back to short | |
432 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) { | |
433 int out = audioOutBuffer[n] * 32768.0; | |
434 if(out < -32768) out = -32768; | |
435 else if(out > 32767) out = 32767; | |
436 pru_buffer_audio_dac[n + audio_buffer_frames * 2] = (int16_t)out; | |
437 } | |
438 | |
439 if(xenomai_gpio != 0) { | |
440 // Set the test pin high | |
441 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK; | |
442 } | |
443 } | |
444 | 642 |
445 // Tell PRU to stop | 643 // Tell PRU to stop |
446 pru_buffer_comm[PRU_SHOULD_STOP] = 1; | 644 pru_buffer_comm[PRU_SHOULD_STOP] = 1; |
447 | 645 |
448 free(audioInBuffer); | 646 // Wait two buffer lengths for the PRU to finish |
449 free(audioOutBuffer); | 647 rt_task_sleep(PRU_SAMPLE_INTERVAL_NS * context->analogFrames * 4 * 2); |
648 | |
649 // Clean up after ourselves | |
650 free(context->audioIn); | |
651 free(context->audioOut); | |
652 | |
653 if(analog_enabled) { | |
654 free(context->analogIn); | |
655 free(context->analogOut); | |
656 free(lastAnalogOutFrame); | |
657 } | |
658 | |
659 if(digital_enabled) { | |
660 free(lastDigitalBuffer); | |
661 } | |
662 | |
663 context->audioIn = context->audioOut = 0; | |
664 context->analogIn = context->analogOut = 0; | |
665 context->digital = 0; | |
450 } | 666 } |
451 | 667 |
452 // Wait for an interrupt from the PRU indicate it is finished | 668 // Wait for an interrupt from the PRU indicate it is finished |
453 void PRU::waitForFinish() | 669 void PRU::waitForFinish() |
454 { | 670 { |
455 if(!running) | 671 if(!running) |
456 return; | 672 return; |
457 prussdrv_pru_wait_event (pru_number == 0 ? PRU_EVTOUT_0 : PRU_EVTOUT_1); | 673 prussdrv_pru_wait_event (PRU_EVTOUT_0); |
458 if(pru_number == 0) | 674 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); |
459 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); | |
460 else | |
461 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT); | |
462 } | 675 } |
463 | 676 |
464 // Turn off the PRU when done | 677 // Turn off the PRU when done |
465 void PRU::disable() | 678 void PRU::disable() |
466 { | 679 { |