Mercurial > hg > beaglert
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 { |