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