comparison core/PRU.cpp @ 45:579c86316008 newapi

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