Mercurial > hg > beaglert
diff core/PRU.cpp @ 16:670be80463a3 matrix_gpio
- analog matrixIn/matrixOut are now mapped as floats from 0 to 1
- use of an external PRU code can be enabled with -P <filename>
- 16 channels of programmable GPIO can be accessed straight from render() either writing directly to the matrixGpio[] array or using digitalWrite(),
digitalRead(), setDigitalDirection() macros from Utilities.h .
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Mon, 27 Apr 2015 13:01:57 +0100 |
parents | 901d205d1a3c |
children | c98863e63174 |
line wrap: on
line diff
--- a/core/PRU.cpp Sat Feb 07 16:41:56 2015 +0000 +++ b/core/PRU.cpp Mon Apr 27 13:01:57 2015 +0100 @@ -16,6 +16,7 @@ #include "../include/PRU.h" #include "../include/prussdrv.h" #include "../include/pruss_intc_mapping.h" +#include "../include/matrix_gpio_mapping.h" #include "../include/GPIOcontrol.h" #include "../include/render.h" #include "../include/pru_rtaudio_bin.h" @@ -26,6 +27,7 @@ #include <cerrno> #include <fcntl.h> #include <sys/mman.h> +#include <unistd.h> // Xenomai-specific includes #include <sys/mman.h> @@ -40,7 +42,9 @@ #define PRU_MEM_DAC_OFFSET 0x0 // Offset within PRU0 RAM #define PRU_MEM_DAC_LENGTH 0x2000 // Length of ADC+DAC memory, in bytes #define PRU_MEM_COMM_OFFSET 0x0 // Offset within PRU-SHARED RAM - +#define PRU_MEM_MATRIX_GPIO_OFFSET 0x1000 //Offset within PRU-SHARED RAM +#define MEM_MATRIX_GPIO_BUFFER1_OFFSET 0x400 //Start pointer to MATRIX_GPIO_BUFFER1, which is 256 words. + // 256 is the maximum number of frames allowed #define PRU_SHOULD_STOP 0 #define PRU_CURRENT_BUFFER 1 #define PRU_BUFFER_FRAMES 2 @@ -52,6 +56,26 @@ #define PRU_FRAME_COUNT 8 #define PRU_USE_SPI 9 #define PRU_SPI_NUM_CHANNELS 10 +#define PRU_USE_GPIO_MATRIX 11 + +short int matrixGpioPins[NUM_MATRIX_GPIOS]={ + GPIO_NO_BIT_0, + GPIO_NO_BIT_1, + GPIO_NO_BIT_2, + GPIO_NO_BIT_3, + GPIO_NO_BIT_4, + GPIO_NO_BIT_5, + GPIO_NO_BIT_6, + GPIO_NO_BIT_7, + GPIO_NO_BIT_8, + GPIO_NO_BIT_9, + GPIO_NO_BIT_10, + GPIO_NO_BIT_11, + GPIO_NO_BIT_12, + GPIO_NO_BIT_13, + GPIO_NO_BIT_14, + GPIO_NO_BIT_15, +}; #define PRU_SAMPLE_INTERVAL_NS 11338 // 88200Hz per SPI sample = 11.338us @@ -103,7 +127,7 @@ // viewed on a scope. If include_led is set, // user LED 3 on the BBB is taken over by the PRU // to indicate activity -int PRU::prepareGPIO(int use_spi, int include_test_pin, int include_led) +int PRU::prepareGPIO(int use_spi, int use_matrix_gpio, int include_test_pin, int include_led) { if(use_spi) { // Prepare DAC CS/ pin: output, high to begin @@ -141,6 +165,27 @@ spi_enabled = true; } + if(use_matrix_gpio){ + printf("gNumMatrixGpioChannels: %d;\n",gNumMatrixGpioChannels); + for(int i=0; i<gNumMatrixGpioChannels; i++){ + if(gpio_export(matrixGpioPins[i])) { + if(gRTAudioVerbose) + cout << "Warning: couldn't export matrix GPIO pin " << matrixGpioPins[i] << "\n"; + } + if(gpio_set_dir(matrixGpioPins[i], OUTPUT_PIN)) { + if(gRTAudioVerbose) + cout << "Couldn't set direction on matrix GPIO pin " << matrixGpioPins[i] << "\n"; + return -1; + } + if(gpio_set_value(matrixGpioPins[i], HIGH)) { + if(gRTAudioVerbose) + cout << "Couldn't set value on matrix GPIO pin " << matrixGpioPins[i] << "\n"; + return -1; + } + } + matrix_gpio_enabled=true; + } + if(include_test_pin) { // Prepare GPIO test output (for debugging), low to begin if(gpio_export(kPruGPIOTestPin)) { @@ -210,6 +255,11 @@ gpio_unexport(kPruGPIODACSyncPin); gpio_unexport(kPruGPIOADCSyncPin); } + if(matrix_gpio_enabled){ + for(int i=0; i<gNumMatrixGpioChannels; i++){ + gpio_unexport(matrixGpioPins[i]); + } + } if(gpio_test_pin_enabled) { gpio_unexport(kPruGPIOTestPin); gpio_unexport(kPruGPIOTestPin2); @@ -221,7 +271,6 @@ // rather than the system default led_set_trigger(3, "mmc1"); } - gpio_enabled = gpio_test_pin_enabled = false; } @@ -260,6 +309,7 @@ spi_buffer_frames = frames_per_buffer; audio_buffer_frames = spi_buffer_frames * spi_num_channels / 4; + matrix_gpio_buffer_frames = audio_buffer_frames; /* Map PRU memory to pointers */ prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem); @@ -280,6 +330,13 @@ pru_buffer_spi_dac = pru_buffer_spi_adc = 0; } + if(matrix_gpio_enabled) { + prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem); + pru_buffer_matrix_gpio = (uint32_t *)&pruMem[PRU_MEM_MATRIX_GPIO_OFFSET/sizeof(uint32_t)]; + } + else { + pru_buffer_matrix_gpio = 0; + } /* Set up flags */ pru_buffer_comm[PRU_SHOULD_STOP] = 0; pru_buffer_comm[PRU_CURRENT_BUFFER] = 0; @@ -303,6 +360,14 @@ pru_buffer_comm[PRU_USE_SPI] = 0; pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = 0; } + if(matrix_gpio_enabled) { + pru_buffer_comm[PRU_USE_GPIO_MATRIX] = 1; + pru_buffer_comm[NUM_MATRIX_GPIOS] = spi_num_channels; + } + else { + pru_buffer_comm[PRU_USE_GPIO_MATRIX] = 0; + pru_buffer_comm[NUM_MATRIX_GPIOS] = 0; + } /* Clear ADC and DAC memory */ if(spi_enabled) { @@ -311,7 +376,7 @@ } for(int i = 0; i < PRU_MEM_MCASP_LENGTH / 2; i++) pru_buffer_audio_dac[i] = 0; - +//TODO: maybe the lines below are to be deleted, as we removed the test code from pru_rtaudio.p ? /* If using GPIO test pin for Xenomai (for debugging), initialise the pointer now */ if(xenomai_test_pin && xenomai_gpio_fd < 0) { xenomai_gpio_fd = open("/dev/mem", O_RDWR); @@ -332,23 +397,34 @@ } // Run the code image in the specified file -int PRU::start() +int PRU::start(char * const filename) { /* Clear any old interrupt */ if(pru_number == 0) prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); else prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT); - - /* Load and execute binary on PRU */ - if(prussdrv_exec_code(pru_number, PRUcode, sizeof(PRUcode))) { - rt_printf("Failed to execute PRU code\n"); - return 1; - } + /* Load and execute binary on PRU */ + if(filename[0] == '\0') { //if the string is empty, load the embedded code + if(gRTAudioVerbose) + rt_printf("Using embedded PRU code\n"); + if(prussdrv_exec_code(pru_number, PRUcode, sizeof(PRUcode))) { + rt_printf("Failed to execute PRU code\n"); + return 1; + } + } else { + if(gRTAudioVerbose) + rt_printf("Using PRU code from %s\n",filename); + if(prussdrv_exec_program(pru_number, filename)) { + rt_printf("Failed to execute PRU code from %s\n", filename); + return 1; + } + } running = true; return 0; } +uint32_t empty[1024]={0x0}; // Main loop to read and write data from/to PRU void PRU::loop() @@ -356,15 +432,34 @@ // Polling interval is 1/4 of the period RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * (spi_num_channels / 2) * spi_buffer_frames / 4; float *audioInBuffer, *audioOutBuffer; + float *matrixInBuffer, *matrixOutBuffer; + uint32_t *matrixGpioBuffer0, *matrixGpioBuffer1, *matrixGpioBufferTemp; audioInBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float)); audioOutBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float)); - + matrixInBuffer = (float *)malloc(spi_num_channels * spi_buffer_frames * sizeof(float)); + matrixOutBuffer = (float *)malloc(spi_num_channels * spi_buffer_frames * sizeof(float)); + matrixGpioBuffer0 = pru_buffer_matrix_gpio; + matrixGpioBuffer1 = pru_buffer_matrix_gpio+MEM_MATRIX_GPIO_BUFFER1_OFFSET/sizeof(uint32_t); + matrix_gpio_buffer_frames = matrix_gpio_enabled ? audio_buffer_frames : 0; //TODO: find a more elegant solution for when the matrix_gpio is disabled e.g.: + // - embed in the digitalWrite/Read macros a check whether matrix_gpio is enabled + // - allocate some memory in ARM just to allow render() to run regardless. + // in this case it can be matrixGpioBuffer0 == matrixGpioBuffer1 + printf("matrix_gpio_buffer_frames: %d;\n",matrix_gpio_buffer_frames); + matrixGpioBufferTemp = (uint32_t *)malloc(matrix_gpio_buffer_frames*sizeof(uint32_t)); //temp buffer to hold previous states if(audioInBuffer == 0 || audioOutBuffer == 0) { - rt_printf("Error: couldn't allocated audio buffers\n"); + rt_printf("Error: couldn't allocate audio buffers\n"); return; } - + if(matrixInBuffer == 0 || matrixOutBuffer == 0) { + rt_printf("Error: couldn't allocate matrix buffers\n"); + return; + } + if(matrixGpioBufferTemp == 0) { + rt_printf("Error: couldn't allocate matrix GPIO buffers\n"); + return; + } + while(!gShouldStop) { // Wait for PRU to move to buffer 1 while(pru_buffer_comm[PRU_CURRENT_BUFFER] == 0 && !gShouldStop) { @@ -383,14 +478,40 @@ // Convert short (16-bit) samples to float for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) audioInBuffer[n] = (float)pru_buffer_audio_adc[n] / 32768.0; - - if(spi_enabled) - render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer, - pru_buffer_spi_adc, pru_buffer_spi_dac); + if(spi_enabled) { + for(unsigned int n = 0; n < spi_num_channels * spi_buffer_frames; n++) + matrixInBuffer[n] = (float)pru_buffer_spi_adc[n] / 65536.0; + //use past matrix_gpio values to initialize the array properly: + //- pins previously set as outputs will keep their previously set output value, + //- pins previously set as inputs will carry the newly read input value + if(matrix_gpio_enabled){ + for(unsigned int n = 0; n < matrix_gpio_buffer_frames; n++){ + uint16_t inputs=matrixGpioBufferTemp[n]&0xffff;//half-word, has 1 for inputs and 0 for outputs +// printf("inputs: 0x%x\n",inputs); + uint16_t outputs=~inputs; //half-word has 1 for outputs and 0 for inputs; + matrixGpioBuffer0[n]=(matrixGpioBufferTemp[n]&(outputs<<16))| //keep output values set in previous matrixGpioBuffer1[n] + (matrixGpioBuffer0[n]&(inputs<<16)) | //inputs from current matrixGpioBuffer0[n]; + (matrixGpioBufferTemp[n]&(inputs)); //keep pin configuration from previous matrixGpioBuffer1[n] +// matrixGpioBuffer0[n]=matrixGpioBufferTemp[n]; //ignores inputs + } + } + render(spi_buffer_frames, matrix_gpio_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer, + matrixInBuffer, matrixOutBuffer, matrixGpioBuffer0); + for(unsigned int n = 0; n < spi_num_channels * spi_buffer_frames; n++) { + int out = matrixOutBuffer[n] * 65536.0; + if(out < 0) out = 0; + else if(out > 65535) out = 65535; + pru_buffer_spi_dac[n] = (uint16_t)out; + } + if(matrix_gpio_enabled){ // keep track of past matrix_gpio values + for(unsigned int n = 0; n < matrix_gpio_buffer_frames; n++){ + matrixGpioBufferTemp[n]=matrixGpioBuffer0[n]; + } + } + } else - render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0); - - // Convert float back to short + render(0, 0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0, 0); // we still pass matrixGpioBuffer, just it is unused + // Convert float back to short for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) { int out = audioOutBuffer[n] * 32768.0; if(out < -32768) out = -32768; @@ -422,11 +543,39 @@ for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) audioInBuffer[n] = (float)pru_buffer_audio_adc[n + audio_buffer_frames * 2] / 32768.0; - if(spi_enabled) - render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer, - &pru_buffer_spi_adc[spi_buffer_frames * spi_num_channels], &pru_buffer_spi_dac[spi_buffer_frames * spi_num_channels]); + if(spi_enabled) { + for(unsigned int n = 0; n < spi_num_channels * spi_buffer_frames; n++) + matrixInBuffer[n] = (float)pru_buffer_spi_adc[n + spi_buffer_frames * spi_num_channels] / 65536.0; + + //use past matrix_gpio values to initialize the array properly: + //- pins previously set as outputs will keep their previously set output value, + //- pins previously set as inputs will carry the newly read input value + if(matrix_gpio_enabled){ + for(unsigned int n = 0; n < matrix_gpio_buffer_frames; n++){ + uint16_t inputs=matrixGpioBufferTemp[n]&0xffff;//half-word, has 1 for inputs and 0 for outputs + uint16_t outputs=~inputs; //half-word has 1 for outputs and one for inputs; + matrixGpioBuffer1[n]=(matrixGpioBufferTemp[n]&(outputs<<16))| //keep output values set in previous matrixGpioBuffer1[n] + (matrixGpioBuffer1[n]&(inputs<<16)) | //inputs from current matrixGpioBuffer1[n]; + (matrixGpioBufferTemp[n]&(inputs)); //keep pin configuration from previous matrixGpioBuffer1[n] +// matrixGpioBuffer1[n]=matrixGpioBufferTemp[n]; //ignores inputs + } + } + render(spi_buffer_frames, matrix_gpio_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer, + matrixInBuffer, matrixOutBuffer, matrixGpioBuffer1); + for(unsigned int n = 0; n < spi_num_channels * spi_buffer_frames; n++) { + int out = matrixOutBuffer[n] * 65536.0; + if(out < 0) out = 0; + else if(out > 65535) out = 65535; + pru_buffer_spi_dac[n + spi_buffer_frames * spi_num_channels] = (uint16_t)out; + } + if(matrix_gpio_enabled){ // keep track of past matrix_gpio values + for(unsigned int n = 0; n < matrix_gpio_buffer_frames; n++){ + matrixGpioBufferTemp[n]=matrixGpioBuffer1[n]; + } + } + } else - render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0); + render(0, 0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0, 0); // we still pass matrixGpioBuffer, just it is unused // Convert float back to short for(unsigned int n = 0; n < 2 * audio_buffer_frames; n++) { @@ -445,8 +594,11 @@ // Tell PRU to stop pru_buffer_comm[PRU_SHOULD_STOP] = 1; + free(matrixOutBuffer); free(audioInBuffer); free(audioOutBuffer); + free(matrixInBuffer); + free(matrixGpioBufferTemp); } // Wait for an interrupt from the PRU indicate it is finished