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