annotate core/PRU.cpp @ 15:901d205d1a3c

Updated to latest PRU library; external PRU file no longer needed. Also catch SIGTERM as well as SIGINT to clean up gracefully.
author andrewm
date Sat, 07 Feb 2015 16:41:56 +0000
parents a6beeba3a648
children 670be80463a3
rev   line source
andrewm@0 1 /*
andrewm@0 2 * PRU.cpp
andrewm@0 3 *
andrewm@0 4 * Code for communicating with the Programmable Realtime Unit (PRU)
andrewm@0 5 * on the BeagleBone AM335x series processors. The PRU loads and runs
andrewm@0 6 * a separate code image compiled from an assembly file. Here it is
andrewm@0 7 * used to handle audio and SPI ADC/DAC data.
andrewm@0 8 *
andrewm@0 9 * This code is specific to the PRU code in the assembly file; for example,
andrewm@0 10 * it uses certain GPIO resources that correspond to that image.
andrewm@0 11 *
andrewm@0 12 * Created on: May 27, 2014
andrewm@0 13 * Author: andrewm
andrewm@0 14 */
andrewm@0 15
andrewm@0 16 #include "../include/PRU.h"
andrewm@0 17 #include "../include/prussdrv.h"
andrewm@0 18 #include "../include/pruss_intc_mapping.h"
andrewm@0 19 #include "../include/GPIOcontrol.h"
andrewm@0 20 #include "../include/render.h"
andrewm@15 21 #include "../include/pru_rtaudio_bin.h"
andrewm@0 22
andrewm@0 23 #include <iostream>
andrewm@0 24 #include <stdlib.h>
andrewm@0 25 #include <cstdio>
andrewm@0 26 #include <cerrno>
andrewm@0 27 #include <fcntl.h>
andrewm@0 28 #include <sys/mman.h>
andrewm@0 29
andrewm@0 30 // Xenomai-specific includes
andrewm@0 31 #include <sys/mman.h>
andrewm@0 32 #include <native/task.h>
andrewm@0 33 #include <native/timer.h>
andrewm@0 34 #include <rtdk.h>
andrewm@0 35
andrewm@0 36 using namespace std;
andrewm@0 37
andrewm@0 38 #define PRU_MEM_MCASP_OFFSET 0x2000 // Offset within PRU-SHARED RAM
andrewm@0 39 #define PRU_MEM_MCASP_LENGTH 0x2000 // Length of McASP memory, in bytes
andrewm@0 40 #define PRU_MEM_DAC_OFFSET 0x0 // Offset within PRU0 RAM
andrewm@0 41 #define PRU_MEM_DAC_LENGTH 0x2000 // Length of ADC+DAC memory, in bytes
andrewm@0 42 #define PRU_MEM_COMM_OFFSET 0x0 // Offset within PRU-SHARED RAM
andrewm@0 43
andrewm@0 44 #define PRU_SHOULD_STOP 0
andrewm@0 45 #define PRU_CURRENT_BUFFER 1
andrewm@0 46 #define PRU_BUFFER_FRAMES 2
andrewm@0 47 #define PRU_SHOULD_SYNC 3
andrewm@0 48 #define PRU_SYNC_ADDRESS 4
andrewm@0 49 #define PRU_SYNC_PIN_MASK 5
andrewm@0 50 #define PRU_LED_ADDRESS 6
andrewm@0 51 #define PRU_LED_PIN_MASK 7
andrewm@0 52 #define PRU_FRAME_COUNT 8
andrewm@0 53 #define PRU_USE_SPI 9
andrewm@12 54 #define PRU_SPI_NUM_CHANNELS 10
andrewm@0 55
andrewm@12 56 #define PRU_SAMPLE_INTERVAL_NS 11338 // 88200Hz per SPI sample = 11.338us
andrewm@0 57
andrewm@0 58 #define GPIO0_ADDRESS 0x44E07000
andrewm@0 59 #define GPIO1_ADDRESS 0x4804C000
andrewm@0 60 #define GPIO_SIZE 0x198
andrewm@0 61 #define GPIO_CLEARDATAOUT (0x190 / 4)
andrewm@0 62 #define GPIO_SETDATAOUT (0x194 / 4)
andrewm@0 63
andrewm@0 64 #define TEST_PIN_GPIO_BASE GPIO0_ADDRESS // Use GPIO0(31) for debugging
andrewm@0 65 #define TEST_PIN_MASK (1 << 31)
andrewm@0 66 #define TEST_PIN2_MASK (1 << 26)
andrewm@0 67
andrewm@0 68 #define USERLED3_GPIO_BASE GPIO1_ADDRESS // GPIO1(24) is user LED 3
andrewm@0 69 #define USERLED3_PIN_MASK (1 << 24)
andrewm@0 70
andrewm@0 71 const unsigned int PRU::kPruGPIODACSyncPin = 5; // GPIO0(5); P9-17
andrewm@0 72 const unsigned int PRU::kPruGPIOADCSyncPin = 48; // GPIO1(16); P9-15
andrewm@0 73
andrewm@0 74 const unsigned int PRU::kPruGPIOTestPin = 60; // GPIO1(28); P9-12
andrewm@0 75 const unsigned int PRU::kPruGPIOTestPin2 = 31; // GPIO0(31); P9-13
andrewm@0 76 const unsigned int PRU::kPruGPIOTestPin3 = 26; // GPIO0(26); P8-14
andrewm@0 77
andrewm@0 78 extern int gShouldStop;
andrewm@0 79 extern int gRTAudioVerbose;
andrewm@0 80
andrewm@0 81 // Constructor: specify a PRU number (0 or 1)
andrewm@0 82 PRU::PRU()
andrewm@0 83 : pru_number(0), running(false), spi_enabled(false), gpio_enabled(false), led_enabled(false),
andrewm@12 84 gpio_test_pin_enabled(false), spi_num_channels(0), xenomai_gpio_fd(-1), xenomai_gpio(0)
andrewm@0 85 {
andrewm@0 86
andrewm@0 87 }
andrewm@0 88
andrewm@0 89 // Destructor
andrewm@0 90 PRU::~PRU()
andrewm@0 91 {
andrewm@0 92 if(running)
andrewm@0 93 disable();
andrewm@0 94 if(gpio_enabled)
andrewm@0 95 cleanupGPIO();
andrewm@0 96 if(xenomai_gpio_fd >= 0)
andrewm@0 97 close(xenomai_gpio_fd);
andrewm@0 98 }
andrewm@0 99
andrewm@0 100 // Prepare the GPIO pins needed for the PRU
andrewm@0 101 // If include_test_pin is set, the GPIO output
andrewm@0 102 // is also prepared for an output which can be
andrewm@0 103 // viewed on a scope. If include_led is set,
andrewm@0 104 // user LED 3 on the BBB is taken over by the PRU
andrewm@0 105 // to indicate activity
andrewm@0 106 int PRU::prepareGPIO(int use_spi, int include_test_pin, int include_led)
andrewm@0 107 {
andrewm@0 108 if(use_spi) {
andrewm@0 109 // Prepare DAC CS/ pin: output, high to begin
andrewm@0 110 if(gpio_export(kPruGPIODACSyncPin)) {
andrewm@0 111 if(gRTAudioVerbose)
andrewm@0 112 cout << "Warning: couldn't export DAC sync pin\n";
andrewm@0 113 }
andrewm@0 114 if(gpio_set_dir(kPruGPIODACSyncPin, OUTPUT_PIN)) {
andrewm@0 115 if(gRTAudioVerbose)
andrewm@0 116 cout << "Couldn't set direction on DAC sync pin\n";
andrewm@0 117 return -1;
andrewm@0 118 }
andrewm@0 119 if(gpio_set_value(kPruGPIODACSyncPin, HIGH)) {
andrewm@0 120 if(gRTAudioVerbose)
andrewm@0 121 cout << "Couldn't set value on DAC sync pin\n";
andrewm@0 122 return -1;
andrewm@0 123 }
andrewm@0 124
andrewm@0 125 // Prepare ADC CS/ pin: output, high to begin
andrewm@0 126 if(gpio_export(kPruGPIOADCSyncPin)) {
andrewm@0 127 if(gRTAudioVerbose)
andrewm@0 128 cout << "Warning: couldn't export ADC sync pin\n";
andrewm@0 129 }
andrewm@0 130 if(gpio_set_dir(kPruGPIOADCSyncPin, OUTPUT_PIN)) {
andrewm@0 131 if(gRTAudioVerbose)
andrewm@0 132 cout << "Couldn't set direction on ADC sync pin\n";
andrewm@0 133 return -1;
andrewm@0 134 }
andrewm@0 135 if(gpio_set_value(kPruGPIOADCSyncPin, HIGH)) {
andrewm@0 136 if(gRTAudioVerbose)
andrewm@0 137 cout << "Couldn't set value on ADC sync pin\n";
andrewm@0 138 return -1;
andrewm@0 139 }
andrewm@0 140
andrewm@0 141 spi_enabled = true;
andrewm@0 142 }
andrewm@0 143
andrewm@0 144 if(include_test_pin) {
andrewm@0 145 // Prepare GPIO test output (for debugging), low to begin
andrewm@0 146 if(gpio_export(kPruGPIOTestPin)) {
andrewm@0 147 if(gRTAudioVerbose)
andrewm@0 148 cout << "Warning: couldn't export GPIO test pin\n";
andrewm@0 149 }
andrewm@0 150 if(gpio_set_dir(kPruGPIOTestPin, OUTPUT_PIN)) {
andrewm@0 151 if(gRTAudioVerbose)
andrewm@0 152 cout << "Couldn't set direction on GPIO test pin\n";
andrewm@0 153 return -1;
andrewm@0 154 }
andrewm@0 155 if(gpio_set_value(kPruGPIOTestPin, LOW)) {
andrewm@0 156 if(gRTAudioVerbose)
andrewm@0 157 cout << "Couldn't set value on GPIO test pin\n";
andrewm@0 158 return -1;
andrewm@0 159 }
andrewm@0 160
andrewm@0 161 if(gpio_export(kPruGPIOTestPin2)) {
andrewm@0 162 if(gRTAudioVerbose)
andrewm@0 163 cout << "Warning: couldn't export GPIO test pin 2\n";
andrewm@0 164 }
andrewm@0 165 if(gpio_set_dir(kPruGPIOTestPin2, OUTPUT_PIN)) {
andrewm@0 166 if(gRTAudioVerbose)
andrewm@0 167 cout << "Couldn't set direction on GPIO test pin 2\n";
andrewm@0 168 return -1;
andrewm@0 169 }
andrewm@0 170 if(gpio_set_value(kPruGPIOTestPin2, LOW)) {
andrewm@0 171 if(gRTAudioVerbose)
andrewm@0 172 cout << "Couldn't set value on GPIO test pin 2\n";
andrewm@0 173 return -1;
andrewm@0 174 }
andrewm@0 175
andrewm@0 176 if(gpio_export(kPruGPIOTestPin3)) {
andrewm@0 177 if(gRTAudioVerbose)
andrewm@0 178 cout << "Warning: couldn't export GPIO test pin 3\n";
andrewm@0 179 }
andrewm@0 180 if(gpio_set_dir(kPruGPIOTestPin3, OUTPUT_PIN)) {
andrewm@0 181 if(gRTAudioVerbose)
andrewm@0 182 cout << "Couldn't set direction on GPIO test pin 3\n";
andrewm@0 183 return -1;
andrewm@0 184 }
andrewm@0 185 if(gpio_set_value(kPruGPIOTestPin3, LOW)) {
andrewm@0 186 if(gRTAudioVerbose)
andrewm@0 187 cout << "Couldn't set value on GPIO test pin 3\n";
andrewm@0 188 return -1;
andrewm@0 189 }
andrewm@0 190 gpio_test_pin_enabled = true;
andrewm@0 191 }
andrewm@0 192
andrewm@0 193 if(include_led) {
andrewm@0 194 // Turn off system function for LED3 so it can be reused by PRU
andrewm@0 195 led_set_trigger(3, "none");
andrewm@0 196 led_enabled = true;
andrewm@0 197 }
andrewm@0 198
andrewm@0 199 gpio_enabled = true;
andrewm@0 200
andrewm@0 201 return 0;
andrewm@0 202 }
andrewm@0 203
andrewm@0 204 // Clean up the GPIO at the end
andrewm@0 205 void PRU::cleanupGPIO()
andrewm@0 206 {
andrewm@0 207 if(!gpio_enabled)
andrewm@0 208 return;
andrewm@0 209 if(spi_enabled) {
andrewm@0 210 gpio_unexport(kPruGPIODACSyncPin);
andrewm@0 211 gpio_unexport(kPruGPIOADCSyncPin);
andrewm@0 212 }
andrewm@0 213 if(gpio_test_pin_enabled) {
andrewm@0 214 gpio_unexport(kPruGPIOTestPin);
andrewm@0 215 gpio_unexport(kPruGPIOTestPin2);
andrewm@0 216 gpio_unexport(kPruGPIOTestPin3);
andrewm@0 217 }
andrewm@0 218 if(led_enabled) {
andrewm@0 219 // Set LED back to default eMMC status
andrewm@0 220 // TODO: make it go back to its actual value before this program,
andrewm@0 221 // rather than the system default
andrewm@0 222 led_set_trigger(3, "mmc1");
andrewm@0 223 }
andrewm@0 224
andrewm@0 225 gpio_enabled = gpio_test_pin_enabled = false;
andrewm@0 226 }
andrewm@0 227
andrewm@0 228 // Initialise and open the PRU
andrewm@12 229 int PRU::initialise(int pru_num, int frames_per_buffer, int spi_channels, bool xenomai_test_pin)
andrewm@0 230 {
andrewm@0 231 uint32_t *pruMem = 0;
andrewm@0 232
andrewm@0 233 if(!gpio_enabled) {
andrewm@0 234 rt_printf("initialise() called before GPIO enabled\n");
andrewm@0 235 return 1;
andrewm@0 236 }
andrewm@0 237
andrewm@0 238 pru_number = pru_num;
andrewm@0 239
andrewm@12 240 /* Set number of SPI ADC / DAC channels to use. This implicitly
andrewm@12 241 * also determines the sample rate relative to the audio clock
andrewm@12 242 * (half audio clock for 8 channels, full audio clock for 4,
andrewm@12 243 * double audio clock for 2)
andrewm@12 244 */
andrewm@12 245 spi_num_channels = spi_channels;
andrewm@12 246
andrewm@0 247 /* Initialize structure used by prussdrv_pruintc_intc */
andrewm@0 248 /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */
andrewm@0 249 tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
andrewm@0 250
andrewm@0 251 /* Allocate and initialize memory */
andrewm@0 252 prussdrv_init();
andrewm@15 253 if(prussdrv_open(pru_number == 0 ? PRU_EVTOUT_0 : PRU_EVTOUT_1)) {
andrewm@0 254 rt_printf("Failed to open PRU driver\n");
andrewm@0 255 return 1;
andrewm@0 256 }
andrewm@0 257
andrewm@0 258 /* Map PRU's INTC */
andrewm@0 259 prussdrv_pruintc_init(&pruss_intc_initdata);
andrewm@0 260
andrewm@0 261 spi_buffer_frames = frames_per_buffer;
andrewm@12 262 audio_buffer_frames = spi_buffer_frames * spi_num_channels / 4;
andrewm@0 263
andrewm@0 264 /* Map PRU memory to pointers */
andrewm@0 265 prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem);
andrewm@0 266 pru_buffer_comm = (uint32_t *)&pruMem[PRU_MEM_COMM_OFFSET/sizeof(uint32_t)];
andrewm@0 267 pru_buffer_audio_dac = (int16_t *)&pruMem[PRU_MEM_MCASP_OFFSET/sizeof(uint32_t)];
andrewm@0 268
andrewm@12 269 /* ADC memory starts 2(ch)*2(buffers)*bufsize samples later */
andrewm@12 270 pru_buffer_audio_adc = &pru_buffer_audio_dac[4 * audio_buffer_frames];
andrewm@0 271
andrewm@0 272 if(spi_enabled) {
andrewm@0 273 prussdrv_map_prumem (pru_number == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, (void **)&pruMem);
andrewm@0 274 pru_buffer_spi_dac = (uint16_t *)&pruMem[PRU_MEM_DAC_OFFSET/sizeof(uint32_t)];
andrewm@0 275
andrewm@12 276 /* ADC memory starts after N(ch)*2(buffers)*bufsize samples */
andrewm@12 277 pru_buffer_spi_adc = &pru_buffer_spi_dac[2 * spi_num_channels * spi_buffer_frames];
andrewm@0 278 }
andrewm@0 279 else {
andrewm@0 280 pru_buffer_spi_dac = pru_buffer_spi_adc = 0;
andrewm@0 281 }
andrewm@0 282
andrewm@0 283 /* Set up flags */
andrewm@0 284 pru_buffer_comm[PRU_SHOULD_STOP] = 0;
andrewm@0 285 pru_buffer_comm[PRU_CURRENT_BUFFER] = 0;
andrewm@0 286 pru_buffer_comm[PRU_BUFFER_FRAMES] = spi_buffer_frames;
andrewm@0 287 pru_buffer_comm[PRU_SHOULD_SYNC] = 0;
andrewm@0 288 pru_buffer_comm[PRU_SYNC_ADDRESS] = 0;
andrewm@0 289 pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0;
andrewm@0 290 if(led_enabled) {
andrewm@0 291 pru_buffer_comm[PRU_LED_ADDRESS] = USERLED3_GPIO_BASE;
andrewm@0 292 pru_buffer_comm[PRU_LED_PIN_MASK] = USERLED3_PIN_MASK;
andrewm@0 293 }
andrewm@0 294 else {
andrewm@0 295 pru_buffer_comm[PRU_LED_ADDRESS] = 0;
andrewm@0 296 pru_buffer_comm[PRU_LED_PIN_MASK] = 0;
andrewm@0 297 }
andrewm@0 298 if(spi_enabled) {
andrewm@0 299 pru_buffer_comm[PRU_USE_SPI] = 1;
andrewm@12 300 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = spi_num_channels;
andrewm@0 301 }
andrewm@0 302 else {
andrewm@0 303 pru_buffer_comm[PRU_USE_SPI] = 0;
andrewm@12 304 pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = 0;
andrewm@0 305 }
andrewm@0 306
andrewm@0 307 /* Clear ADC and DAC memory */
andrewm@0 308 if(spi_enabled) {
andrewm@0 309 for(int i = 0; i < PRU_MEM_DAC_LENGTH / 2; i++)
andrewm@0 310 pru_buffer_spi_dac[i] = 0;
andrewm@0 311 }
andrewm@0 312 for(int i = 0; i < PRU_MEM_MCASP_LENGTH / 2; i++)
andrewm@0 313 pru_buffer_audio_dac[i] = 0;
andrewm@0 314
andrewm@0 315 /* If using GPIO test pin for Xenomai (for debugging), initialise the pointer now */
andrewm@0 316 if(xenomai_test_pin && xenomai_gpio_fd < 0) {
andrewm@0 317 xenomai_gpio_fd = open("/dev/mem", O_RDWR);
andrewm@0 318 if(xenomai_gpio_fd < 0)
andrewm@0 319 rt_printf("Unable to open /dev/mem for GPIO test pin\n");
andrewm@0 320 else {
andrewm@0 321 xenomai_gpio = (uint32_t *)mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, xenomai_gpio_fd, TEST_PIN_GPIO_BASE);
andrewm@0 322 if(xenomai_gpio == MAP_FAILED) {
andrewm@0 323 rt_printf("Unable to map GPIO address for test pin\n");
andrewm@0 324 xenomai_gpio = 0;
andrewm@0 325 close(xenomai_gpio_fd);
andrewm@0 326 xenomai_gpio_fd = -1;
andrewm@0 327 }
andrewm@0 328 }
andrewm@0 329 }
andrewm@0 330
andrewm@0 331 return 0;
andrewm@0 332 }
andrewm@0 333
andrewm@0 334 // Run the code image in the specified file
andrewm@15 335 int PRU::start()
andrewm@0 336 {
andrewm@0 337 /* Clear any old interrupt */
andrewm@15 338 if(pru_number == 0)
andrewm@15 339 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
andrewm@15 340 else
andrewm@15 341 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);
andrewm@0 342
andrewm@0 343 /* Load and execute binary on PRU */
andrewm@15 344 if(prussdrv_exec_code(pru_number, PRUcode, sizeof(PRUcode))) {
andrewm@15 345 rt_printf("Failed to execute PRU code\n");
andrewm@0 346 return 1;
andrewm@0 347 }
andrewm@0 348
andrewm@0 349 running = true;
andrewm@0 350 return 0;
andrewm@0 351 }
andrewm@0 352
andrewm@0 353 // Main loop to read and write data from/to PRU
andrewm@0 354 void PRU::loop()
andrewm@0 355 {
andrewm@0 356 // Polling interval is 1/4 of the period
andrewm@12 357 RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * (spi_num_channels / 2) * spi_buffer_frames / 4;
andrewm@0 358 float *audioInBuffer, *audioOutBuffer;
andrewm@0 359
andrewm@0 360 audioInBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float));
andrewm@0 361 audioOutBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float));
andrewm@0 362
andrewm@0 363 if(audioInBuffer == 0 || audioOutBuffer == 0) {
andrewm@0 364 rt_printf("Error: couldn't allocated audio buffers\n");
andrewm@0 365 return;
andrewm@0 366 }
andrewm@0 367
andrewm@0 368 while(!gShouldStop) {
andrewm@0 369 // Wait for PRU to move to buffer 1
andrewm@0 370 while(pru_buffer_comm[PRU_CURRENT_BUFFER] == 0 && !gShouldStop) {
andrewm@0 371 rt_task_sleep(sleepTime);
andrewm@0 372 }
andrewm@0 373 if(gShouldStop)
andrewm@0 374 break;
andrewm@0 375
andrewm@0 376 if(xenomai_gpio != 0) {
andrewm@0 377 // Set the test pin high
andrewm@0 378 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK;
andrewm@0 379 }
andrewm@0 380
andrewm@0 381 // Render from/to buffer 0
andrewm@0 382
andrewm@0 383 // Convert short (16-bit) samples to float
andrewm@0 384 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++)
andrewm@0 385 audioInBuffer[n] = (float)pru_buffer_audio_adc[n] / 32768.0;
andrewm@0 386
andrewm@0 387 if(spi_enabled)
andrewm@0 388 render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer,
andrewm@0 389 pru_buffer_spi_adc, pru_buffer_spi_dac);
andrewm@0 390 else
andrewm@0 391 render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0);
andrewm@0 392
andrewm@0 393 // Convert float back to short
andrewm@0 394 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) {
andrewm@0 395 int out = audioOutBuffer[n] * 32768.0;
andrewm@0 396 if(out < -32768) out = -32768;
andrewm@0 397 else if(out > 32767) out = 32767;
andrewm@0 398 pru_buffer_audio_dac[n] = (int16_t)out;
andrewm@0 399 }
andrewm@0 400
andrewm@0 401 if(xenomai_gpio != 0) {
andrewm@0 402 // Set the test pin high
andrewm@0 403 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK;
andrewm@0 404 }
andrewm@0 405
andrewm@0 406 // Wait for PRU to move to buffer 0
andrewm@0 407 while(pru_buffer_comm[PRU_CURRENT_BUFFER] != 0 && !gShouldStop) {
andrewm@0 408 rt_task_sleep(sleepTime);
andrewm@0 409 }
andrewm@0 410
andrewm@0 411 if(gShouldStop)
andrewm@0 412 break;
andrewm@0 413
andrewm@0 414 if(xenomai_gpio != 0) {
andrewm@0 415 // Set the test pin high
andrewm@0 416 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN_MASK;
andrewm@0 417 }
andrewm@0 418
andrewm@0 419 // Render from/to buffer 1
andrewm@0 420
andrewm@0 421 // Convert short (16-bit) samples to float
andrewm@0 422 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++)
andrewm@0 423 audioInBuffer[n] = (float)pru_buffer_audio_adc[n + audio_buffer_frames * 2] / 32768.0;
andrewm@0 424
andrewm@0 425 if(spi_enabled)
andrewm@0 426 render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer,
andrewm@12 427 &pru_buffer_spi_adc[spi_buffer_frames * spi_num_channels], &pru_buffer_spi_dac[spi_buffer_frames * spi_num_channels]);
andrewm@0 428 else
andrewm@0 429 render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0);
andrewm@0 430
andrewm@0 431 // Convert float back to short
andrewm@0 432 for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) {
andrewm@0 433 int out = audioOutBuffer[n] * 32768.0;
andrewm@0 434 if(out < -32768) out = -32768;
andrewm@0 435 else if(out > 32767) out = 32767;
andrewm@0 436 pru_buffer_audio_dac[n + audio_buffer_frames * 2] = (int16_t)out;
andrewm@0 437 }
andrewm@0 438
andrewm@0 439 if(xenomai_gpio != 0) {
andrewm@0 440 // Set the test pin high
andrewm@0 441 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN_MASK;
andrewm@0 442 }
andrewm@0 443 }
andrewm@0 444
andrewm@0 445 // Tell PRU to stop
andrewm@0 446 pru_buffer_comm[PRU_SHOULD_STOP] = 1;
andrewm@0 447
andrewm@0 448 free(audioInBuffer);
andrewm@0 449 free(audioOutBuffer);
andrewm@0 450 }
andrewm@0 451
andrewm@0 452 // Wait for an interrupt from the PRU indicate it is finished
andrewm@0 453 void PRU::waitForFinish()
andrewm@0 454 {
andrewm@0 455 if(!running)
andrewm@0 456 return;
andrewm@15 457 prussdrv_pru_wait_event (pru_number == 0 ? PRU_EVTOUT_0 : PRU_EVTOUT_1);
andrewm@15 458 if(pru_number == 0)
andrewm@15 459 prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
andrewm@15 460 else
andrewm@15 461 prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);
andrewm@0 462 }
andrewm@0 463
andrewm@0 464 // Turn off the PRU when done
andrewm@0 465 void PRU::disable()
andrewm@0 466 {
andrewm@0 467 /* Disable PRU and close memory mapping*/
andrewm@0 468 prussdrv_pru_disable(pru_number);
andrewm@0 469 prussdrv_exit();
andrewm@0 470 running = false;
andrewm@0 471 }
andrewm@0 472
andrewm@0 473 // Debugging
andrewm@0 474 void PRU::setGPIOTestPin()
andrewm@0 475 {
andrewm@0 476 if(!xenomai_gpio)
andrewm@0 477 return;
andrewm@0 478 xenomai_gpio[GPIO_SETDATAOUT] = TEST_PIN2_MASK;
andrewm@0 479 }
andrewm@0 480
andrewm@0 481 void PRU::clearGPIOTestPin()
andrewm@0 482 {
andrewm@0 483 if(!xenomai_gpio)
andrewm@0 484 return;
andrewm@0 485 xenomai_gpio[GPIO_CLEARDATAOUT] = TEST_PIN2_MASK;
andrewm@0 486 }