comparison core/PRU.cpp @ 67:472e892c6e41

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