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