Mercurial > hg > beaglert
diff pru_rtaudio.p @ 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 | 6adb088196a7 |
children | c98863e63174 |
line wrap: on
line diff
--- a/pru_rtaudio.p Sat Feb 07 16:41:56 2015 +0000 +++ b/pru_rtaudio.p Mon Apr 27 13:01:57 2015 +0100 @@ -81,7 +81,8 @@ #define COMM_FRAME_COUNT 32 // How many frames have elapse since beginning #define COMM_USE_SPI 36 // Whether or not to use SPI ADC and DAC #define COMM_NUM_CHANNELS 40 // Low 2 bits indicate 8 [0x3], 4 [0x1] or 2 [0x0] channels - +#define COMM_USE_MATRIX_GPIO 44 // Whether or not to use MATRIX_GPIO + #define MCASP0_BASE 0x48038000 #define MCASP1_BASE 0x4803C000 @@ -180,10 +181,18 @@ #define FLAG_BIT_BUFFER1 0 #define FLAG_BIT_USE_SPI 1 #define FLAG_BIT_MCASP_HWORD 2 // Whether we are on the high word for McASP transmission - +#define FLAG_BIT_USE_MATRIX_GPIO 3 +/*#define FLAG_BIT_MATRIX_GPIO_BUFFER 4 //Whether we are using buffer located at + // 0: MEM_MATRIX_GPIO_BASE or +*/ // 1: MEM_MATRIX_GPIO_BASE + 512 // Registers used throughout // r1, r2, r3 are used for temporary storage +#define MEM_MATRIX_GPIO_BASE 0x11000 //Base address for MATRIX_GPIO : Shared RAM + 0x400 +#define MEM_MATRIX_GPIO_BUFFER1_OFFSET 0x400 //Start pointer to MATRIX_GPIO_BUFFER1, which is 256 words after. +// 256 is the maximum number of frames allowed + +#define reg_matrix_gpio_current r6 // Pointer to current storage location of MATRIX_GPIO #define reg_num_channels r9 // Number of SPI ADC/DAC channels to use #define reg_frame_current r10 // Current frame count in SPI ADC/DAC transfer #define reg_frame_total r11 // Total frame count for SPI ADC/DAC @@ -205,6 +214,209 @@ // r27, r28 used in macros #define reg_mcasp_addr r29 // Base address for McASP +// MATRIX_GPIO new code starts here +//0 P8_07 36 0x890/090 66 gpio2[2] +//1 P8_08 37 0x894/094 67 gpio2[3] +//2 P8_09 39 0x89c/09c 69 gpio2[5] +//3 P8_10 38 0x898/098 68 gpio2[4] +//4 P8_11 13 0x834/034 45 gpio1[13] +//5 P8_12 12 0x830/030 44 gpio1[12] +//6 P9_12 30 0x878/078 60 gpio1[28] +//7 P9_14 18 0x848/048 50 gpio1[18] +//8 P8_15 15 0x83c/03c 47 gpio1[15] +//9 P8_16 14 0x838/038 46 gpio1[14] +//10 P9_16 19 0x84c/04c 51 gpio1[19] +//11 P8_18 35 0x88c/08c 65 gpio2[1] +//12 P8_27 56 0x8e0/0e0 86 gpio2[22] +//13 P8_28 58 0x8e8/0e8 88 gpio2[24] +//14 P8_29 57 0x8e4/0e4 87 gpio2[23] +//15 P8_30 59 0x8ec/0ec 89 gpio2[25] + +//TODO during initialization, set the pinmuxers to mode 7, input enable + +//generic GPIOs constants +//#define GPIO1 0x4804c000 +#define GPIO2 0x481ac000 +//#define GPIO_CLEARDATAOUT 0x190 //SETDATAOUT is CLEARDATAOUT+4 +#define GPIO_OE 0x134 +#define GPIO_DATAIN 0x138 + +//gpioX_oe must be adjacent to gpioX_datain +//gpioX_cleardataout must be adjacent to gpioX_setdataout +#define reg_gpio1_oe r2 +#define reg_gpio2_oe r3 +#define reg_gpio2_cleardataout r4 +#define reg_gpio2_setdataout r5 +#define reg_gpio1_cleardataout r7 +#define reg_gpio1_setdataout r8 +#define reg_matrix_gpio r27 //will first contain matrixGpioOut from render() and matrixGpioIn to render() later +//aliases +#define reg_gpio1_datain reg_gpio1_oe +#define reg_gpio2_datain reg_gpio2_oe + +.macro SET_GPIO1_BITS +.mparam gpio_num_bit, matrix_gpio_bit + SET_GPIO_BITS reg_gpio1_oe, reg_gpio1_setdataout, reg_gpio1_cleardataout, gpio_num_bit, matrix_gpio_bit, reg_matrix_gpio +.endm +.macro SET_GPIO2_BITS +.mparam gpio_num_bit, matrix_gpio_bit + SET_GPIO_BITS reg_gpio2_oe, reg_gpio2_setdataout, reg_gpio2_cleardataout, gpio_num_bit, matrix_gpio_bit, reg_matrix_gpio +.endm +.macro READ_GPIO1_BITS +.mparam gpio_num_bit, matrix_gpio_bit + READ_GPIO_BITS reg_gpio1_datain, gpio_num_bit, matrix_gpio_bit, reg_matrix_gpio +.endm +.macro READ_GPIO2_BITS +.mparam gpio_num_bit, matrix_gpio_bit + READ_GPIO_BITS reg_gpio2_datain, gpio_num_bit, matrix_gpio_bit, reg_matrix_gpio +.endm + +.macro READ_GPIO_BITS +.mparam gpio_data, gpio_num_bit, matrix_gpio_bit, matrix_gpio + QBBC DONE, matrix_gpio, matrix_gpio_bit //if the pin is set as an output, nothing to do here +SET r30.t14 + QBBC CLEAR, gpio_data, gpio_num_bit + SET matrix_gpio, matrix_gpio_bit+16 + QBA DONE + CLEAR: + CLR matrix_gpio, matrix_gpio_bit+16 + QBA DONE + DONE: +CLR r30.t14 +.endm + +.macro SET_GPIO_BITS +.mparam gpio_oe, gpio_setdataout, gpio_cleardataout, gpio_num_bit, matrix_gpio_bit, matrix_gpio //sets the bits in GPIO_OE, GPIO_SETDATAOUT and GPIO_CLEARDATAOUT +//Remember that the GPIO_OE Output data enable register behaves as follows for each bit: +//0 = The corresponding GPIO pin is configured as an output. +//1 = The corresponding GPIO pin is configured as an input. + QBBS SETINPUT, matrix_gpio, matrix_gpio_bit + CLR gpio_oe, gpio_num_bit //if it is an output, configure pin as output + QBBC CLEARDATAOUT, matrix_gpio, matrix_gpio_bit+16 // check the output value. If it is 0, branch + SET gpio_setdataout, gpio_num_bit //if it is 1, set output to high + QBA DONE +CLEARDATAOUT: + SET gpio_cleardataout, gpio_num_bit // set output to low + QBA DONE +SETINPUT: //if it is an input, set the relevant bit + SET gpio_oe, gpio_num_bit + QBA DONE +DONE: +.endm + +.macro PROCESS_GPIO1_BITS +//- sets appropriate bits for output in reg_gpio1_oe, reg_gpio1_cleardataout, reg_gpio1_data +//- sets appropriate bits in reg_matrix_gpio to reflect the input values +.mparam gpio_num_bit, matrix_gpio_bit +// params to SET_GPIO_BITS gpio_oe, gpio_setdataout, gpio_cleardataout, gpio_num_bit, matrix_gpio_bit, matrix_gpio //sets the bits in GPIO_OE, GPIO_SETDATAOUT and GPIO_CLEARDATAOUT + SET_GPIO_BITS reg_gpio1_oe, reg_gpio1_setdataout, reg_gpio1_cleardataout, gpio_num_bit, matrix_gpio_bit, reg_matrix_gpio + READ_GPIO_BITS reg_gpio1_oe, reg_gpio1_datain, gpio_num_bit, matrix_gpio_bit, reg_matrix_gpio +.endm + +.macro PROCESS_GPIO2_BITS +//- sets appropriate bits for output in reg_gpio2_oe, reg_gpio2_cleardataout, reg_gpio2_data +//- sets appropriate bits in reg_matrix_gpio to reflect the input values +.mparam gpio_num_bit, matrix_gpio_bit + SET_GPIO_BITS reg_gpio2_oe, reg_gpio2_setdataout, reg_gpio2_cleardataout, gpio_num_bit, matrix_gpio_bit, reg_matrix_gpio + READ_GPIO_BITS reg_gpio2_oe, reg_gpio2_datain, gpio_num_bit, matrix_gpio_bit, reg_matrix_gpio +.endm + +QBA START // when first starting, go to START, skipping this section. + +MATRIX_GPIO: +//reg_matrix_gpio is now the input word passed in render(), one word per frame +//[31:16]: data(1=high, 0=low), [15:0]: direction (0=output, 1=input) ) +//Preparing the gpio_oe, gpio_cleardataout and gpio_setdataout for each module + +//load current status of GPIO_OE in reg_gpioX_oe + MOV reg_gpio1_oe, GPIO1 | GPIO_OE + //takes ...ns to go through the next two instructions + LBBO reg_gpio1_oe, reg_gpio1_oe, 0, 4 +//GPIO1-start +//process oe and datain and prepare dataout for GPIO1 + LDI reg_gpio1_setdataout, 0 + LDI reg_gpio1_cleardataout, 0 +//map GPIO_MATRIX to gpio1 pins, affects reg_gpio1_oe, reg_gpio1_cleardataout, reg_gpio1_data, reg_matrix_gpio + SET_GPIO1_BITS 13, 4 + SET_GPIO1_BITS 12, 5 + SET_GPIO1_BITS 28, 6 + SET_GPIO1_BITS 18, 7 + SET_GPIO1_BITS 15, 8 + SET_GPIO1_BITS 14, 9 + SET_GPIO1_BITS 19, 10 +//set the output enable register for gpio1. + MOV reg_gpio2_oe, GPIO1 | GPIO_OE //reg_gpio2_oe is now unused. It is here used as a temp + SBBO reg_gpio1_oe, reg_gpio2_oe, 0, 4 //takes two cycles (10ns) +//GPIO1-end + +// reg_gpio1_oe is now unused, its register is taken by gpio2_cleardataout +// reg_gpio1_datain now unused, its register is taken by gpio2_setdataout +//GPIO2-start +//load current status of GPIO_OE in reg_gpioX_oe + MOV reg_gpio2_oe, GPIO2 | GPIO_OE + //takes ...ns to go through the next two instructions + LBBO reg_gpio2_oe, reg_gpio1_oe, 0, 4 +//process oe and datain and prepare dataout for GPIO2 + LDI reg_gpio2_setdataout, 0 + LDI reg_gpio2_cleardataout, 0 +//map GPIO_MATRIX to gpio2 pins, affects reg_gpio2_oe, reg_gpio2_cleardataout, reg_gpio2_data, reg_matrix_gpio + SET_GPIO2_BITS 2, 0 + SET_GPIO2_BITS 3, 1 + SET_GPIO2_BITS 5, 2 + SET_GPIO2_BITS 4, 3 + SET_GPIO2_BITS 1, 11 + SET_GPIO2_BITS 22, 12 + SET_GPIO2_BITS 24, 13 + SET_GPIO2_BITS 23, 14 + SET_GPIO2_BITS 25, 15 +//set the output enable register for gpio2. + MOV reg_gpio1_oe, GPIO2 | GPIO_OE //reg_gpio1_oe is now unused. It is here used as a temp + SBBO reg_gpio2_oe, reg_gpio1_oe, 0, 4 //takes two cycles (10ns) +//GPIO2-end + +//load current inputs in reg_gpioX_datain + MOV reg_gpio1_datain, GPIO1 | GPIO_DATAIN + MOV reg_gpio2_datain, GPIO2 | GPIO_DATAIN + //takes ...ns to go through the next two instructions + LBBO reg_gpio1_datain, reg_gpio1_datain, 0, 4 + LBBO reg_gpio2_datain, reg_gpio2_datain, 0, 4 +//TODO: read inputs + READ_GPIO1_BITS 13, 4 + READ_GPIO1_BITS 12, 5 + READ_GPIO1_BITS 28, 6 + READ_GPIO1_BITS 18, 7 + READ_GPIO1_BITS 15, 8 + READ_GPIO1_BITS 14, 9 + READ_GPIO1_BITS 19, 10 + READ_GPIO2_BITS 2, 0 + READ_GPIO2_BITS 3, 1 + READ_GPIO2_BITS 5, 2 + READ_GPIO2_BITS 4, 3 + READ_GPIO2_BITS 1, 11 + READ_GPIO2_BITS 22, 12 + READ_GPIO2_BITS 24, 13 + READ_GPIO2_BITS 23, 14 + READ_GPIO2_BITS 25, 15 +//reg_gpio2_oe is now unused, so reg_temp1 is available for temporary storage from now on +//reg_gpio2_datain is now unsued, so reg_temp2 is available for temporary storage from now on + +//now all the setdataout and cleardataout are ready to be written to the GPIO register. +//CLEARDATAOUT and SETDATAOUT are consecutive positions in memory, so we write 8 bytes to CLEARDATAOUT. +//We can do this because we chose reg_gpio1_cleardataout and reg_gpioX_setdataout to be consecutive +//load the memory addresses to be written to + MOV reg_gpio1_datain, GPIO1 | GPIO_CLEARDATAOUT //reg_gpio1_datain is now unused and is used here as a temp + MOV reg_gpio2_datain, GPIO2 | GPIO_CLEARDATAOUT //reg_gpio2_datain is now unused and is used here as a temp +//write 8 bytes for each GPIO +//takes 30ns in total to go through the followint two lines + SBBO reg_gpio1_cleardataout, reg_gpio1_datain, 0, 8 // takes 145ns to be effective when going low, 185ns when going high + SBBO reg_gpio2_cleardataout, reg_gpio2_datain, 0, 8 //takes 95ns to be effective when going low, 130ns when going high +//reversing the order of the two lines above will swap the performances between the GPIO modules +//i.e.: the first line will always take 145ns/185ns and the second one will always take 95ns/130ns, +//regardless of whether the order is gpio1-gpio2 or gpio2-gpio1 +JMP r28.w0 // go back to ADC_WRITE_GPIO + +// MATRIX_GPIO new code ends here + // Bring CS line low to write to DAC .macro DAC_CS_ASSERT @@ -291,6 +503,30 @@ ADC_CS_UNASSERT .endm +// Complete ADC write+read with chip select and also performs IO for matrix_gpio +.macro ADC_WRITE_GPIO +.mparam in, out, do_gpio + ADC_CS_ASSERT + ADC_TX in + QBBC GPIO_DONE, reg_flags, FLAG_BIT_USE_MATRIX_GPIO //skip if MATRIX_GPIO is disabled + AND r27, do_gpio, 0x3 // only do a MATRIX_GPIO every 2 SPI I/O + QBNE GPIO_DONE, r27, 0 +//from here to GPIO_DONE takes 1.8us, while usually ADC_WAIT_FOR_FINISH only waits for 1.14us. +//TODO: it would be better to split the MATRIX_GPIO stuff in two parts: +//- one taking place during DAC_WRITE which sets the GPIO_OE +//- and the other during ADC_WRITE which actually reads DATAIN and writes CLEAR/SET DATAOUT + //reg_matrix_gpio is actually r27, so do not use r27 from here to ... + LBBO reg_matrix_gpio, reg_matrix_gpio_current, 0, 4 + JAL r28.w0, MATRIX_GPIO + SBBO reg_matrix_gpio, reg_matrix_gpio_current, 0, 4 + //..here you can start using r27 again + ADD reg_matrix_gpio_current, reg_matrix_gpio_current, 4 //increment pointer +GPIO_DONE: + ADC_WAIT_FOR_FINISH + ADC_RX out + ADC_CS_UNASSERT +.endm + // Write a McASP register .macro MCASP_REG_WRITE .mparam reg, value @@ -335,6 +571,7 @@ .endm START: + MOV r30, 0 // Set up c24 and c25 offsets with CTBIR register // Thus C24 points to start of PRU0 RAM MOV r3, 0x22020 // CTBIR0 @@ -362,6 +599,12 @@ // Default number of channels in case SPI disabled LDI reg_num_channels, 8 + // Find out whether we should use MATRIX_GPIO + LBBO r2, reg_comm_addr, COMM_USE_MATRIX_GPIO, 4 + QBEQ MATRIX_GPIO_FLAG_CHECK_DONE, r2, 0 + SET reg_flags, reg_flags, FLAG_BIT_USE_MATRIX_GPIO +// SET reg_flags, reg_flags, FLAG_BIT_MATRIX_GPIO_BUFFER //set the flag, so that in WRITE_ONE_BUFFER we will start from buffer0 +MATRIX_GPIO_FLAG_CHECK_DONE: // Find out whether we should use SPI ADC and DAC LBBO r2, reg_comm_addr, COMM_USE_SPI, 4 QBEQ SPI_FLAG_CHECK_DONE, r2, 0 @@ -541,6 +784,7 @@ WRITE_ONE_BUFFER: // Write a single buffer of DAC samples and read a buffer of ADC samples // Load starting positions +SET r30.t15 MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels LSL reg_adc_current, reg_frame_total, r2 @@ -551,7 +795,17 @@ LSL reg_mcasp_adc_current, reg_mcasp_adc_current, 1 ADC reg_mcasp_adc_current, reg_mcasp_adc_current, reg_mcasp_dac_current MOV reg_frame_current, 0 - + QBBS MATRIX_GPIO_BASE_CHECK_SET, reg_flags, FLAG_BIT_BUFFER1 //check which buffer we are using for MATRIX_GPIO + // if we are here, we are using buffer0 + MOV r2, 0 //so adjust offset appropriately + QBA MATRIX_GPIO_BASE_CHECK_DONE +MATRIX_GPIO_BASE_CHECK_SET: //if we are here, we are using buffer1 + MOV r2, MEM_MATRIX_GPIO_BUFFER1_OFFSET //so adjust offset appropriately +MATRIX_GPIO_BASE_CHECK_DONE: + MOV reg_matrix_gpio_current, MEM_MATRIX_GPIO_BASE + ADD reg_matrix_gpio_current, reg_matrix_gpio_current, r2 + +CLR r30.t15 WRITE_LOOP: // Write N channels to DAC from successive values in memory // At the same time, read N channels from ADC @@ -651,7 +905,8 @@ LSL r8, r8, AD7699_CHANNEL_OFFSET MOV r7, AD7699_CFG_MASK OR r7, r7, r8 - ADC_WRITE r7, r7 +//ssssssssssssssssssssssssssss + ADC_WRITE_GPIO r7, r7, r1 // Mask out only the relevant 16 bits and store in reg_adc_data MOV r2, 0xFFFF @@ -723,9 +978,9 @@ MOV r2, reg_mcasp_buf0 MOV reg_mcasp_buf0, reg_mcasp_buf1 MOV reg_mcasp_buf1, r2 + XOR reg_flags, reg_flags, (1 << FLAG_BIT_BUFFER1) //flip the buffer flag // Notify ARM of buffer swap - XOR reg_flags, reg_flags, (1 << FLAG_BIT_BUFFER1) AND r2, reg_flags, (1 << FLAG_BIT_BUFFER1) // Mask out every but low bit SBBO r2, reg_comm_addr, COMM_CURRENT_BUFFER, 4 @@ -752,17 +1007,6 @@ SBBO r2, r3, 0, 4 // Clear GPIO pin LED_BLINK_DONE: - QBBC TESTLOW, reg_flags, FLAG_BIT_BUFFER1 - MOV r2, 1 << 28 - MOV r3, GPIO1 + GPIO_SETDATAOUT - SBBO r2, r3, 0, 4 - QBA TESTDONE -TESTLOW: - MOV r2, 1 << 28 - MOV r3, GPIO1 + GPIO_CLEARDATAOUT - SBBO r2, r3, 0, 4 -TESTDONE: - // Check if we should finish: flag is zero as long as it should run LBBO r2, reg_comm_addr, COMM_SHOULD_STOP, 4 QBEQ WRITE_ONE_BUFFER, r2, 0 @@ -787,4 +1031,4 @@ // Signal the ARM that we have finished MOV R31.b0, PRU0_ARM_INTERRUPT + 16 - HALT \ No newline at end of file + HALT