annotate core/PRU.cpp @ 12:a6beeba3a648

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