comparison core/PRU.cpp @ 108:3068421c0737 ultra-staging

Merged default into ultra-staging
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 18 Aug 2015 00:35:15 +0100
parents 4255ecbb9bec 92145ba7aabf
children
comparison
equal deleted inserted replaced
54:d3f869b98147 108:3068421c0737
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/digital_gpio_mapping.h"
20 #include "../include/GPIOcontrol.h" 20 #include "../include/GPIOcontrol.h"
21 #include "../include/render.h" 21 #include "../include/BeagleRT.h"
22 #include "../include/pru_rtaudio_bin.h" 22 #include "../include/pru_rtaudio_bin.h"
23 #include "../include/intervals.h"
24 23
25 #include <iostream> 24 #include <iostream>
26 #include <stdlib.h> 25 #include <stdlib.h>
27 #include <cstdio> 26 #include <cstdio>
28 #include <cerrno> 27 #include <cerrno>
98 97
99 const unsigned int PRU::kPruGPIOTestPin = 60; // GPIO1(28); P9-12 98 const unsigned int PRU::kPruGPIOTestPin = 60; // GPIO1(28); P9-12
100 const unsigned int PRU::kPruGPIOTestPin2 = 31; // GPIO0(31); P9-13 99 const unsigned int PRU::kPruGPIOTestPin2 = 31; // GPIO0(31); P9-13
101 const unsigned int PRU::kPruGPIOTestPin3 = 26; // GPIO0(26); P8-14 100 const unsigned int PRU::kPruGPIOTestPin3 = 26; // GPIO0(26); P8-14
102 101
103 //extern int gShouldStop; 102 extern bool gShouldStop;
104 extern int gRTAudioVerbose; 103 extern int gRTAudioVerbose;
105 extern PRU *gPRU;
106 104
107 // Constructor: specify a PRU number (0 or 1) 105 // Constructor: specify a PRU number (0 or 1)
108 PRU::PRU() 106 PRU::PRU(BeagleRTContext *input_context)
109 : renderTimer(100,0,44100.0,"renderTimer"), sleepTimer(100,0,44100.0,"sleepTimer"), 107 : context(input_context), pru_number(0), running(false), analog_enabled(false),
110 pru_number(0), running(false), spi_enabled(false), gpio_enabled(false), led_enabled(false), 108 digital_enabled(false), gpio_enabled(false), led_enabled(false),
111 gpio_test_pin_enabled(false), spi_num_channels(0), xenomai_gpio_fd(-1), xenomai_gpio(0) 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)
112 { 113 {
113 114
114 } 115 }
115 116
116 // Destructor 117 // Destructor
128 // If include_test_pin is set, the GPIO output 129 // If include_test_pin is set, the GPIO output
129 // is also prepared for an output which can be 130 // is also prepared for an output which can be
130 // viewed on a scope. If include_led is set, 131 // viewed on a scope. If include_led is set,
131 // 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
132 // to indicate activity 133 // to indicate activity
133 int PRU::prepareGPIO(int use_spi, int use_digital, int include_test_pin, int include_led) 134 int PRU::prepareGPIO(int include_test_pin, int include_led)
134 { 135 {
135 if(use_spi) { 136 if(context->analogFrames != 0) {
136 // Prepare DAC CS/ pin: output, high to begin 137 // Prepare DAC CS/ pin: output, high to begin
137 if(gpio_export(kPruGPIODACSyncPin)) { 138 if(gpio_export(kPruGPIODACSyncPin)) {
138 if(gRTAudioVerbose) 139 if(gRTAudioVerbose)
139 cout << "Warning: couldn't export DAC sync pin\n"; 140 cout << "Warning: couldn't export DAC sync pin\n";
140 } 141 }
163 if(gRTAudioVerbose) 164 if(gRTAudioVerbose)
164 cout << "Couldn't set value on ADC sync pin\n"; 165 cout << "Couldn't set value on ADC sync pin\n";
165 return -1; 166 return -1;
166 } 167 }
167 168
168 spi_enabled = true; 169 analog_enabled = true;
169 } 170 }
170 171
171 if(use_digital){ 172 if(context->digitalFrames != 0){
172 printf("gNumDigitalChannels: %d;\n",gNumDigitalChannels); 173 for(unsigned int i = 0; i < context->digitalChannels; i++){
173 for(int i=0; i<gNumDigitalChannels; i++){
174 if(gpio_export(digitalPins[i])) { 174 if(gpio_export(digitalPins[i])) {
175 if(gRTAudioVerbose) 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 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 } 177 }
178 if(gpio_set_dir(digitalPins[i], INPUT_PIN)) { 178 if(gpio_set_dir(digitalPins[i], INPUT_PIN)) {
179 if(gRTAudioVerbose) 179 if(gRTAudioVerbose)
180 cerr << "Error: Couldn't set direction on digital GPIO pin " << digitalPins[i] << "\n"; 180 cerr << "Error: Couldn't set direction on digital GPIO pin " << digitalPins[i] << "\n";
181 return -1; 181 return -1;
182 } 182 }
183 } 183 }
184 digital_enabled=true; 184 digital_enabled = true;
185 } 185 }
186 186
187 if(include_test_pin) { 187 if(include_test_pin) {
188 // Prepare GPIO test output (for debugging), low to begin 188 // Prepare GPIO test output (for debugging), low to begin
189 if(gpio_export(kPruGPIOTestPin)) { 189 if(gpio_export(kPruGPIOTestPin)) {
247 // Clean up the GPIO at the end 247 // Clean up the GPIO at the end
248 void PRU::cleanupGPIO() 248 void PRU::cleanupGPIO()
249 { 249 {
250 if(!gpio_enabled) 250 if(!gpio_enabled)
251 return; 251 return;
252 if(spi_enabled) { 252 if(analog_enabled) {
253 gpio_unexport(kPruGPIODACSyncPin); 253 gpio_unexport(kPruGPIODACSyncPin);
254 gpio_unexport(kPruGPIOADCSyncPin); 254 gpio_unexport(kPruGPIOADCSyncPin);
255 } 255 }
256 if(digital_enabled){ 256 if(digital_enabled){
257 for(int i=0; i<gNumDigitalChannels; i++){ 257 for(unsigned int i = 0; i < context->digitalChannels; i++){
258 gpio_unexport(digitalPins[i]); 258 gpio_unexport(digitalPins[i]);
259 } 259 }
260 } 260 }
261 if(gpio_test_pin_enabled) { 261 if(gpio_test_pin_enabled) {
262 gpio_unexport(kPruGPIOTestPin); 262 gpio_unexport(kPruGPIOTestPin);
282 return 1; 282 return 1;
283 } 283 }
284 284
285 pru_number = pru_num; 285 pru_number = pru_num;
286 286
287 /* Set number of SPI ADC / DAC channels to use. This implicitly
288 * also determines the sample rate relative to the audio clock
289 * (half audio clock for 8 channels, full audio clock for 4,
290 * double audio clock for 2)
291 */
292 spi_num_channels = spi_channels;
293
294 /* Initialize structure used by prussdrv_pruintc_intc */ 287 /* Initialize structure used by prussdrv_pruintc_intc */
295 /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 288 /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */
296 tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 289 tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
297 290
298 /* Allocate and initialize memory */ 291 /* Allocate and initialize memory */
299 prussdrv_init(); 292 prussdrv_init();
300 if(prussdrv_open(pru_number == 0 ? PRU_EVTOUT_0 : PRU_EVTOUT_1)) { 293 if(prussdrv_open(PRU_EVTOUT_0)) {
301 rt_printf("Failed to open PRU driver\n"); 294 rt_printf("Failed to open PRU driver\n");
302 return 1; 295 return 1;
303 } 296 }
304 297
305 /* Map PRU's INTC */ 298 /* Map PRU's INTC */
306 prussdrv_pruintc_init(&pruss_intc_initdata); 299 prussdrv_pruintc_init(&pruss_intc_initdata);
307
308 spi_buffer_frames = frames_per_buffer;
309 audio_buffer_frames = spi_buffer_frames * spi_num_channels / 4;
310 digital_buffer_frames = audio_buffer_frames;
311 300
312 /* Map PRU memory to pointers */ 301 /* Map PRU memory to pointers */
313 prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem); 302 prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem);
314 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)];
315 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)];
316 305
317 /* ADC memory starts 2(ch)*2(buffers)*bufsize samples later */ 306 /* ADC memory starts 2(ch)*2(buffers)*bufsize samples later */
318 pru_buffer_audio_adc = &pru_buffer_audio_dac[4 * audio_buffer_frames]; 307 pru_buffer_audio_adc = &pru_buffer_audio_dac[4 * context->audioFrames];
319 308
320 if(spi_enabled) { 309 if(analog_enabled) {
321 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);
322 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)];
323 312
324 /* ADC memory starts after N(ch)*2(buffers)*bufsize samples */ 313 /* ADC memory starts after N(ch)*2(buffers)*bufsize samples */
325 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];
326 } 315 }
327 else { 316 else {
328 pru_buffer_spi_dac = pru_buffer_spi_adc = 0; 317 pru_buffer_spi_dac = pru_buffer_spi_adc = 0;
329 } 318 }
330 319
333 pru_buffer_digital = (uint32_t *)&pruMem[PRU_MEM_DIGITAL_OFFSET/sizeof(uint32_t)]; 322 pru_buffer_digital = (uint32_t *)&pruMem[PRU_MEM_DIGITAL_OFFSET/sizeof(uint32_t)];
334 } 323 }
335 else { 324 else {
336 pru_buffer_digital = 0; 325 pru_buffer_digital = 0;
337 } 326 }
327
338 /* Set up flags */ 328 /* Set up flags */
339 pru_buffer_comm[PRU_SHOULD_STOP] = 0; 329 pru_buffer_comm[PRU_SHOULD_STOP] = 0;
340 pru_buffer_comm[PRU_CURRENT_BUFFER] = 0; 330 pru_buffer_comm[PRU_CURRENT_BUFFER] = 0;
341 pru_buffer_comm[PRU_BUFFER_FRAMES] = spi_buffer_frames; 331 pru_buffer_comm[PRU_BUFFER_FRAMES] = context->analogFrames;
342 pru_buffer_comm[PRU_SHOULD_SYNC] = 0; 332 pru_buffer_comm[PRU_SHOULD_SYNC] = 0;
343 pru_buffer_comm[PRU_SYNC_ADDRESS] = 0; 333 pru_buffer_comm[PRU_SYNC_ADDRESS] = 0;
344 pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0; 334 pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0;
345 if(led_enabled) { 335 if(led_enabled) {
346 pru_buffer_comm[PRU_LED_ADDRESS] = USERLED3_GPIO_BASE; 336 pru_buffer_comm[PRU_LED_ADDRESS] = USERLED3_GPIO_BASE;
348 } 338 }
349 else { 339 else {
350 pru_buffer_comm[PRU_LED_ADDRESS] = 0; 340 pru_buffer_comm[PRU_LED_ADDRESS] = 0;
351 pru_buffer_comm[PRU_LED_PIN_MASK] = 0; 341 pru_buffer_comm[PRU_LED_PIN_MASK] = 0;
352 } 342 }
353 if(spi_enabled) { 343 if(analog_enabled) {
354 pru_buffer_comm[PRU_USE_SPI] = 1; 344 pru_buffer_comm[PRU_USE_SPI] = 1;
355 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = spi_num_channels; 345 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = context->analogChannels;
356 } 346 }
357 else { 347 else {
358 pru_buffer_comm[PRU_USE_SPI] = 0; 348 pru_buffer_comm[PRU_USE_SPI] = 0;
359 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = 0; 349 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = 0;
360 } 350 }
368 } 358 }
369 359
370 /* Clear ADC and DAC memory.*/ 360 /* Clear ADC and DAC memory.*/
371 //TODO: this initialisation should only address the memory effectively used by these buffers, i.e.:depend on the number of frames 361 //TODO: this initialisation should only address the memory effectively used by these buffers, i.e.:depend on the number of frames
372 // (otherwise might cause issues if we move memory locations later on) 362 // (otherwise might cause issues if we move memory locations later on)
373 if(spi_enabled) { 363 if(analog_enabled) {
374 for(int i = 0; i < PRU_MEM_DAC_LENGTH / 2; i++) 364 for(int i = 0; i < PRU_MEM_DAC_LENGTH / 2; i++)
375 pru_buffer_spi_dac[i] = 0; 365 pru_buffer_spi_dac[i] = 0;
376 if(digital_enabled){ 366 if(digital_enabled){
377 for(int i = 0; i < PRU_MEM_DIGITAL_OFFSET*2; i++) 367 for(int i = 0; i < PRU_MEM_DIGITAL_OFFSET*2; i++)
378 pru_buffer_digital[i] = 0x0000ffff; // set to all inputs, to avoid unexpected spikes 368 pru_buffer_digital[i] = 0x0000ffff; // set to all inputs, to avoid unexpected spikes
379 } 369 }
380 } 370 }
381 for(int i = 0; i < PRU_MEM_MCASP_LENGTH / 2; i++) 371 for(int i = 0; i < PRU_MEM_MCASP_LENGTH / 2; i++)
382 pru_buffer_audio_dac[i] = 0; 372 pru_buffer_audio_dac[i] = 0;
383 //TODO: maybe the lines below are to be deleted, as we removed the test code from pru_rtaudio.p ? 373
384 /* 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 */
385 if(xenomai_test_pin && xenomai_gpio_fd < 0) { 375 if(xenomai_test_pin && xenomai_gpio_fd < 0) {
386 xenomai_gpio_fd = open("/dev/mem", O_RDWR); 376 xenomai_gpio_fd = open("/dev/mem", O_RDWR);
387 if(xenomai_gpio_fd < 0) 377 if(xenomai_gpio_fd < 0)
388 rt_printf("Unable to open /dev/mem for GPIO test pin\n"); 378 rt_printf("Unable to open /dev/mem for GPIO test pin\n");
395 xenomai_gpio_fd = -1; 385 xenomai_gpio_fd = -1;
396 } 386 }
397 } 387 }
398 } 388 }
399 389
390 // Allocate audio buffers
391 context->audioIn = (float *)malloc(2 * context->audioFrames * sizeof(float));
392 context->audioOut = (float *)malloc(2 * context->audioFrames * sizeof(float));
393 if(context->audioIn == 0 || context->audioOut == 0) {
394 rt_printf("Error: couldn't allocate audio buffers\n");
395 return 1;
396 }
397
398 // Allocate analog buffers
399 if(analog_enabled) {
400 context->analogIn = (float *)malloc(context->analogChannels * context->analogFrames * sizeof(float));
401 context->analogOut = (float *)malloc(context->analogChannels * context->analogFrames * sizeof(float));
402 last_analog_out_frame = (float *)malloc(context->analogChannels * sizeof(float));
403
404 if(context->analogIn == 0 || context->analogOut == 0 || last_analog_out_frame == 0) {
405 rt_printf("Error: couldn't allocate analog buffers\n");
406 return 1;
407 }
408
409 memset(last_analog_out_frame, 0, context->analogChannels * sizeof(float));
410 }
411
412 // Allocate digital buffers
413 digital_buffer0 = pru_buffer_digital;
414 digital_buffer1 = pru_buffer_digital + MEM_DIGITAL_BUFFER1_OFFSET / sizeof(uint32_t);
415 if(digital_enabled) {
416 last_digital_buffer = (uint32_t *)malloc(context->digitalFrames * sizeof(uint32_t)); //temp buffer to hold previous states
417 if(last_digital_buffer == 0) {
418 rt_printf("Error: couldn't allocate digital buffers\n");
419 return 1;
420 }
421
422 for(unsigned int n = 0; n < context->digitalFrames; n++){
423 // Initialize lastDigitalFrames to all inputs
424 last_digital_buffer[n] = 0x0000ffff;
425 }
426 }
427
428 context->digital = digital_buffer0;
429
400 return 0; 430 return 0;
401 } 431 }
402 432
403 // Run the code image in the specified file 433 // Run the code image in the specified file
404 int PRU::start(char * const filename) 434 int PRU::start(char * const filename)
405 { 435 {
406 /* Clear any old interrupt */ 436 /* Clear any old interrupt */
407 if(pru_number == 0) 437 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
408 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); 438
409 else
410 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);
411 /* Load and execute binary on PRU */ 439 /* Load and execute binary on PRU */
412 if(filename[0] == '\0') { //if the string is empty, load the embedded code 440 if(filename[0] == '\0') { //if the string is empty, load the embedded code
413 if(gRTAudioVerbose) 441 if(gRTAudioVerbose)
414 rt_printf("Using embedded PRU code\n"); 442 rt_printf("Using embedded PRU code\n");
415 if(prussdrv_exec_code(pru_number, PRUcode, sizeof(PRUcode))) { 443 if(prussdrv_exec_code(pru_number, PRUcode, sizeof(PRUcode))) {
426 } 454 }
427 455
428 running = true; 456 running = true;
429 return 0; 457 return 0;
430 } 458 }
431 uint32_t empty[1024]={0x0};
432 459
433 // Main loop to read and write data from/to PRU 460 // Main loop to read and write data from/to PRU
434 void PRU::loop() 461 void PRU::loop(RT_INTR *pru_interrupt, void *userData)
435 { 462 {
463 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS
464 RTIME irqTimeout = PRU_SAMPLE_INTERVAL_NS * 1024; // Timeout for PRU interrupt: about 10ms, much longer than any expected period
465 #else
436 // Polling interval is 1/4 of the period 466 // Polling interval is 1/4 of the period
437 RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * (spi_num_channels / 2) * spi_buffer_frames / 4; 467 RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * (context->analogChannels / 2) * context->analogFrames / 4;
438 float *audioInBuffer, *audioOutBuffer; 468 #endif
439 float *analogInBuffer, *analogOutBuffer, *lastAnalogOutFrame; 469
440 uint32_t *digitalBuffer0, *digitalBuffer1, *lastDigitalBuffer; 470 uint32_t pru_audio_offset, pru_spi_offset;
441 audioInBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float)); 471
442 audioOutBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float)); 472 // Before starting, look at the last state of the analog and digital outputs which might
443 analogInBuffer = (float *)malloc(spi_num_channels * spi_buffer_frames * sizeof(float)); 473 // have been changed by the user during the setup() function. This lets us start with pin
444 analogOutBuffer = (float *)malloc(spi_num_channels * spi_buffer_frames * sizeof(float)); 474 // directions and output values at something other than defaults.
445 lastAnalogOutFrame = (float *)malloc(spi_num_channels * sizeof(float)); 475
446 digitalBuffer0 = pru_buffer_digital; 476 if(analog_enabled) {
447 digitalBuffer1 = pru_buffer_digital+MEM_DIGITAL_BUFFER1_OFFSET/sizeof(uint32_t); 477 if(context->flags & BEAGLERT_FLAG_ANALOG_OUTPUTS_PERSIST) {
448 digital_buffer_frames = digital_enabled ? audio_buffer_frames : 0; //TODO: find a more elegant solution for when the digital is disabled e.g.: 478 // Remember the content of the last_analog_out_frame
449 // - embed in the digitalWrite/Read macros a check whether digital is enabled 479 for(unsigned int ch = 0; ch < context->analogChannels; ch++){
450 // - allocate some memory in ARM just to allow render() to run regardless. 480 last_analog_out_frame[ch] = context->analogOut[context->analogChannels * (context->analogFrames - 1) + ch];
451 // in this case it can be digitalBuffer0 == digitalBuffer1 481 }
452 lastDigitalBuffer = (uint32_t *)malloc(digital_buffer_frames*sizeof(uint32_t)); //temp buffer to hold previous states 482 }
453 if(audioInBuffer == 0 || audioOutBuffer == 0) { 483 }
454 rt_printf("Error: couldn't allocate audio buffers\n"); 484
455 return; 485 if(digital_enabled) {
456 } 486 for(unsigned int n = 0; n < context->digitalFrames; n++){
457 if(analogInBuffer == 0 || analogOutBuffer == 0 || lastAnalogOutFrame == 0) { 487 last_digital_buffer[n] = context->digital[n];
458 rt_printf("Error: couldn't allocate analog buffers\n"); 488 }
459 return; 489 }
460 } 490
461 if(lastDigitalBuffer == 0) { 491 // TESTING
462 rt_printf("Error: couldn't allocate digital buffers\n"); 492 // uint32_t testCount = 0;
463 return; 493 // RTIME startTime = rt_timer_read();
464 } 494
465 495 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS
466 if(digital_enabled){ 496 int result;
467 for(unsigned int n=0; n<digital_buffer_frames; n++){ //initialize lastDigitalFrames to all inputs 497 #else
468 lastDigitalBuffer[n]= 0x0000ffff; 498 // Which buffer the PRU was last processing
469 } 499 uint32_t lastPRUBuffer = 0;
470 } 500 #endif
471 int count=0; 501
472 sleepTimer.setNumFrames(audio_buffer_frames);
473 renderTimer.setNumFrames(audio_buffer_frames);
474 while(!gShouldStop) { 502 while(!gShouldStop) {
475 // Wait for PRU to move to buffer 1 503 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS
476 sleepTimer.start(); 504 // Wait for PRU to move to change buffers;
477 while(pru_buffer_comm[PRU_CURRENT_BUFFER] == 0 && !gShouldStop) { 505 // PRU will send an interrupts which we wait for
506 rt_intr_enable(pru_interrupt);
507 while(!gShouldStop) {
508 result = rt_intr_wait(pru_interrupt, irqTimeout);
509 if(result >= 0)
510 break;
511 else if(result == -ETIMEDOUT)
512 rt_printf("Warning: PRU timeout!\n");
513 else {
514 rt_printf("Error: wait for interrupt failed (%d)\n", result);
515 gShouldStop = 1;
516 }
517 }
518
519 // Clear pending PRU interrupt
520 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);
521 #else
522 // Poll
523 while(pru_buffer_comm[PRU_CURRENT_BUFFER] == lastPRUBuffer && !gShouldStop) {
478 rt_task_sleep(sleepTime); 524 rt_task_sleep(sleepTime);
479 } 525 }
480 sleepTimer.split(); 526
527 lastPRUBuffer = pru_buffer_comm[PRU_CURRENT_BUFFER];
528 #endif
481 529
482 if(gShouldStop) 530 if(gShouldStop)
483 break; 531 break;
484 renderTimer.start(); 532
533 // Check which buffer we're on-- will have been set right
534 // before the interrupt was asserted
535 if(pru_buffer_comm[PRU_CURRENT_BUFFER] == 1) {
536 // PRU is on buffer 1. We read and write to buffer 0
537 pru_audio_offset = 0;
538 pru_spi_offset = 0;
539 if(digital_enabled)
540 context->digital = digital_buffer0;
541 }
542 else {
543 // PRU is on buffer 0. We read and write to buffer 1
544 pru_audio_offset = context->audioFrames * 2;
545 pru_spi_offset = context->analogFrames * context->analogChannels;
546 if(digital_enabled)
547 context->digital = digital_buffer1;
548 }
549
550 // FIXME: some sort of margin is needed here to prevent the audio
551 // code from completely eating the Linux system
552 // testCount++;
553 //rt_task_sleep(sleepTime*4);
554 //rt_task_sleep(sleepTime/4);
555
485 if(xenomai_gpio != 0) { 556 if(xenomai_gpio != 0) {
486 // Set the test pin high 557 // Set the test pin high
487 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK; 558 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK;
488 } 559 }
489 560
490 // Render from/to buffer 0
491
492 // Convert short (16-bit) samples to float 561 // Convert short (16-bit) samples to float
493 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) 562 // TODO: NEON
494 audioInBuffer[n] = (float)pru_buffer_audio_adc[n] / 32768.0; 563 for(unsigned int n = 0; n < 2 * context->audioFrames; n++)
495 if(spi_enabled) { 564 context->audioIn[n] = (float)pru_buffer_audio_adc[n + pru_audio_offset] / 32768.0;
496 for(unsigned int n = 0; n < spi_num_channels * spi_buffer_frames; n++) 565
497 analogInBuffer[n] = (float)pru_buffer_spi_adc[n] / 65536.0; 566 if(analog_enabled) {
498 //initialize the output buffer with the values that were in the last frame of the previous output 567 // TODO: NEON
499 for(int n = 0; n < spi_num_channels; n++){ 568 for(unsigned int n = 0; n < context->analogChannels * context->analogFrames; n++)
500 for(unsigned int j = 0; j < spi_buffer_frames; j++){ 569 context->analogIn[n] = (float)pru_buffer_spi_adc[n + pru_spi_offset] / 65536.0;
501 analogOutBuffer[j*spi_num_channels + n] = lastAnalogOutFrame[n]; 570
571 if(context->flags & BEAGLERT_FLAG_ANALOG_OUTPUTS_PERSIST) {
572 // Initialize the output buffer with the values that were in the last frame of the previous output
573 for(unsigned int ch = 0; ch < context->analogChannels; ch++){
574 for(unsigned int n = 0; n < context->analogFrames; n++){
575 context->analogOut[n * context->analogChannels + ch] = last_analog_out_frame[ch];
576 }
502 } 577 }
503 } 578 }
504 579 else {
505 //use past digital values to initialize the array properly. 580 // Outputs are 0 unless set otherwise
506 //For each frame: 581 memset(context->analogOut, 0, context->analogChannels * context->analogFrames * sizeof(float));
507 //- pins previously set as outputs will keep the output value they had in the last frame of the previous buffer, 582 }
508 //- pins previously set as inputs will carry the newly read input value 583 }
509 if(digital_enabled){ 584
510 for(unsigned int n = 0; n < digital_buffer_frames; n++){ 585 if(digital_enabled){
511 uint16_t inputs=lastDigitalBuffer[n]&0xffff;//half-word, has 1 for inputs and 0 for outputs 586 // Use past digital values to initialize the array properly.
512 // printf("inputs: 0x%x\n",inputs); 587 // For each frame:
513 uint16_t outputs=~inputs; //half-word has 1 for outputs and 0 for inputs; 588 // - pins previously set as outputs will keep the output value they had in the last frame of the previous buffer,
514 digitalBuffer0[n]=(lastDigitalBuffer[digital_buffer_frames-1]&(outputs<<16))| //keep output values set in the last frame of the previous buffer 589 // - pins previously set as inputs will carry the newly read input value
515 (digitalBuffer0[n]&(inputs<<16)) | //inputs from current digitalBuffer0[n]; 590
516 (lastDigitalBuffer[n]&(inputs)); //keep pin configuration from previous digitalBuffer1[n] 591 for(unsigned int n = 0; n < context->digitalFrames; n++){
517 // digitalBuffer0[n]=digitalBufferTemp[n]; //ignores inputs 592 uint16_t inputs = last_digital_buffer[n] & 0xffff; // half-word, has 1 for inputs and 0 for outputs
518 } 593
519 } 594 uint16_t outputs = ~inputs; // half-word has 1 for outputs and 0 for inputs;
520 render(spi_buffer_frames, digital_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer, 595 context->digital[n] = (last_digital_buffer[context->digitalFrames - 1] & (outputs << 16)) | // keep output values set in the last frame of the previous buffer
521 analogInBuffer, analogOutBuffer, digitalBuffer0); 596 (context->digital[n] & (inputs << 16)) | // inputs from current context->digital[n];
522 //remember the content of the lastAnalogOutFrame 597 (last_digital_buffer[n] & (inputs)); // keep pin configuration from previous context->digital[n]
523 for(int n = 0; n < spi_num_channels; n++){ 598 // context->digital[n]=digitalBufferTemp[n]; //ignores inputs
524 lastAnalogOutFrame[n] = analogOutBuffer[spi_buffer_frames*(spi_buffer_frames-1) + n]; 599 }
525 } 600 }
526 for(unsigned int n = 0; n < spi_num_channels * spi_buffer_frames; n++) { 601
527 int out = analogOutBuffer[n] * 65536.0; 602 // Call user render function
603 // ***********************
604 render(context, userData);
605 // ***********************
606
607 if(analog_enabled) {
608 if(context->flags & BEAGLERT_FLAG_ANALOG_OUTPUTS_PERSIST) {
609 // Remember the content of the last_analog_out_frame
610 for(unsigned int ch = 0; ch < context->analogChannels; ch++){
611 last_analog_out_frame[ch] = context->analogOut[context->analogChannels * (context->analogFrames - 1) + ch];
612 }
613 }
614
615 // Convert float back to short for SPI output
616 for(unsigned int n = 0; n < context->analogChannels * context->analogFrames; n++) {
617 int out = context->analogOut[n] * 65536.0;
528 if(out < 0) out = 0; 618 if(out < 0) out = 0;
529 else if(out > 65535) out = 65535; 619 else if(out > 65535) out = 65535;
530 pru_buffer_spi_dac[n] = (uint16_t)out; 620 pru_buffer_spi_dac[n + pru_spi_offset] = (uint16_t)out;
531 } 621 }
532 if(digital_enabled){ // keep track of past digital values 622 }
533 for(unsigned int n = 0; n < digital_buffer_frames; n++){ 623
534 lastDigitalBuffer[n]=digitalBuffer0[n]; 624 if(digital_enabled) { // keep track of past digital values
535 } 625 for(unsigned int n = 0; n < context->digitalFrames; n++){
536 } 626 last_digital_buffer[n] = context->digital[n];
537 } 627 }
538 else 628 }
539 render(0, 0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0, 0); // we still pass digitalBuffer, just it is unused 629
540 // Convert float back to short 630 // Convert float back to short for audio
541 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) { 631 // TODO: NEON
542 int out = audioOutBuffer[n] * 32768.0; 632 for(unsigned int n = 0; n < 2 * context->audioFrames; n++) {
633 int out = context->audioOut[n] * 32768.0;
543 if(out < -32768) out = -32768; 634 if(out < -32768) out = -32768;
544 else if(out > 32767) out = 32767; 635 else if(out > 32767) out = 32767;
545 pru_buffer_audio_dac[n] = (int16_t)out; 636 pru_buffer_audio_dac[n + pru_audio_offset] = (int16_t)out;
546 } 637 }
638
639 // Increment total number of samples that have elapsed
640 context->audioSampleCount += context->audioFrames;
547 641
548 if(xenomai_gpio != 0) { 642 if(xenomai_gpio != 0) {
549 // Set the test pin high 643 // Set the test pin high
550 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK; 644 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK;
551 } 645 }
552 renderTimer.split(); 646
553 // Wait for PRU to move to buffer 0 647 // FIXME: TESTING!!
554 sleepTimer.start(); 648 // if(testCount > 100000)
555 while(pru_buffer_comm[PRU_CURRENT_BUFFER] != 0 && !gShouldStop) { 649 // break;
556 rt_task_sleep(sleepTime); 650 }
557 } 651
558 sleepTimer.split(); 652 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS
559 if(gShouldStop) 653 // Turn off the interrupt for the PRU if it isn't already off
560 break; 654 rt_intr_disable(pru_interrupt);
561 655 #endif
562 renderTimer.start(); 656
563 if(xenomai_gpio != 0) { 657 // FIXME: TESTING
564 // Set the test pin high 658 // RTIME endTime = rt_timer_read();
565 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK; 659 // RTIME diffTime = endTime - startTime;
566 } 660 // rt_printf("%d blocks elapsed in %f seconds, %f Hz block rate\n", testCount, ((float)diffTime / 1.0e9), (float)testCount / ((float)diffTime / 1.0e9));
567
568 // Render from/to buffer 1
569
570 // Convert short (16-bit) samples to float
571 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++)
572 audioInBuffer[n] = (float)pru_buffer_audio_adc[n + audio_buffer_frames * 2] / 32768.0;
573
574 if(spi_enabled) {
575 //convert input values TODO: move to PRU
576 for(unsigned int n = 0; n < spi_num_channels * spi_buffer_frames; n++){
577 analogInBuffer[n] = (float)pru_buffer_spi_adc[n + spi_buffer_frames * spi_num_channels] / 65536.0;
578 }
579 //initialize the output buffer with the values that were in the last frame of the previous output
580 for(int n = 0; n < spi_num_channels; n++){
581 for(unsigned int j = 0; j < spi_buffer_frames; j++){
582 analogOutBuffer[j*spi_num_channels + n] = lastAnalogOutFrame[n];
583 }
584 }
585 if(digital_enabled){
586 for(unsigned int n = 0; n < digital_buffer_frames; n++){
587 uint16_t inputs=lastDigitalBuffer[n]&0xffff;//half-word, has 1 for inputs and 0 for outputs
588 uint16_t outputs=~inputs; //half-word has 1 for outputs and one for inputs;
589 digitalBuffer1[n]=(lastDigitalBuffer[digital_buffer_frames-1]&(outputs<<16))| //keep output values set in the last frame of the previous buffer
590 (digitalBuffer1[n]&(inputs<<16)) | //inputs from current digitalBuffer1[n];
591 (lastDigitalBuffer[n]&(inputs)); //keep pin configuration from previous digitalBuffer1[n]
592 // digitalBuffer1[n]=digitalBufferTemp[n]; //ignores inputs
593 }
594 }
595 render(spi_buffer_frames, digital_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer,
596 analogInBuffer, analogOutBuffer, digitalBuffer1);
597 //remember the content of the lastAnalogOutFrame
598 for(int n = 0; n < spi_num_channels; n++){
599 lastAnalogOutFrame[n] = analogOutBuffer[spi_buffer_frames*(spi_buffer_frames-1) + n];
600 }
601
602 for(unsigned int n = 0; n < spi_num_channels * spi_buffer_frames; n++) {
603 int out = analogOutBuffer[n] * 65536.0;
604 if(out < 0) out = 0;
605 else if(out > 65535) out = 65535;
606 pru_buffer_spi_dac[n + spi_buffer_frames * spi_num_channels] = (uint16_t)out;
607 }
608 if(digital_enabled){ // keep track of past digital values
609 for(unsigned int n = 0; n < digital_buffer_frames; n++){
610 lastDigitalBuffer[n]=digitalBuffer1[n];
611 }
612 }
613 }
614 else
615 render(0, 0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0, 0); // we still pass digitalBuffer, just it is unused
616
617 // Convert float back to short
618 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) {
619 int out = audioOutBuffer[n] * 32768.0;
620 if(out < -32768) out = -32768;
621 else if(out > 32767) out = 32767;
622 pru_buffer_audio_dac[n + audio_buffer_frames * 2] = (int16_t)out;
623 }
624
625 if(xenomai_gpio != 0) {
626 // Set the test pin high
627 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK;
628 }
629 renderTimer.split();
630 count+=audio_buffer_frames;
631 if((count&32767)==0){
632 scheduleAuxiliaryTask(gPRU->printIntervalsTask);
633 }
634 }
635 661
636 // Tell PRU to stop 662 // Tell PRU to stop
637 pru_buffer_comm[PRU_SHOULD_STOP] = 1; 663 pru_buffer_comm[PRU_SHOULD_STOP] = 1;
638 free(analogOutBuffer); 664
639 free(analogInBuffer); 665 // Wait two buffer lengths for the PRU to finish
640 free(audioOutBuffer); 666 rt_task_sleep(PRU_SAMPLE_INTERVAL_NS * context->analogFrames * 4 * 2);
641 free(audioInBuffer); 667
642 free(lastAnalogOutFrame); 668 // Clean up after ourselves
643 free(lastDigitalBuffer); 669 free(context->audioIn);
670 free(context->audioOut);
671
672 if(analog_enabled) {
673 free(context->analogIn);
674 free(context->analogOut);
675 free(last_analog_out_frame);
676 }
677
678 if(digital_enabled) {
679 free(last_digital_buffer);
680 }
681
682 context->audioIn = context->audioOut = 0;
683 context->analogIn = context->analogOut = 0;
684 context->digital = 0;
644 } 685 }
645 686
646 // Wait for an interrupt from the PRU indicate it is finished 687 // Wait for an interrupt from the PRU indicate it is finished
647 void PRU::waitForFinish() 688 void PRU::waitForFinish()
648 { 689 {
649 if(!running) 690 if(!running)
650 return; 691 return;
651 prussdrv_pru_wait_event (pru_number == 0 ? PRU_EVTOUT_0 : PRU_EVTOUT_1); 692 prussdrv_pru_wait_event (PRU_EVTOUT_0);
652 if(pru_number == 0) 693 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
653 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
654 else
655 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);
656 } 694 }
657 695
658 // Turn off the PRU when done 696 // Turn off the PRU when done
659 void PRU::disable() 697 void PRU::disable()
660 { 698 {