diff pru_rtaudio.p @ 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 6adb088196a7
line wrap: on
line diff
--- a/pru_rtaudio.p	Thu Nov 13 16:02:59 2014 +0100
+++ b/pru_rtaudio.p	Thu Jan 22 19:00:22 2015 +0000
@@ -80,6 +80,7 @@
 #define COMM_LED_PIN_MASK     28          // Which pin to write to change LED
 #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 MCASP0_BASE 0x48038000
 #define MCASP1_BASE 0x4803C000
@@ -173,15 +174,17 @@
 #define MCASP_DATA_MASK 	0xFFFF		// 16 bit data
 #define MCASP_DATA_FORMAT	0x807C		// MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits
 
-#define C_MCASP_MEM             C28     // Shared PRU mem
+#define C_MCASP_MEM             C28     	// Shared PRU mem
 
 // Flags for the flags register
 #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
 	
 // Registers used throughout
 
 // r1, r2, r3 are used for temporary storage
+#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
 #define reg_dac_data		r12		// Current dword for SPI DAC
@@ -356,6 +359,9 @@
       // Clear flags
       MOV reg_flags, 0
 
+      // Default number of channels in case SPI disabled
+      LDI reg_num_channels, 8
+	
       // 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
@@ -364,6 +370,19 @@
 SPI_FLAG_CHECK_DONE:
       // If we don't use SPI, then skip all this init
       QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI
+
+      // Load the number of channels: valid values are 8, 4 or 2
+      LBBO reg_num_channels, reg_comm_addr, COMM_NUM_CHANNELS, 4
+      QBGT SPI_NUM_CHANNELS_LT8, reg_num_channels, 8 // 8 > num_channels ?
+      LDI reg_num_channels, 8		// If N >= 8, N = 8
+      QBA SPI_NUM_CHANNELS_DONE
+SPI_NUM_CHANNELS_LT8:	
+      QBGT SPI_NUM_CHANNELS_LT4, reg_num_channels, 4 // 4 > num_channels ?
+      LDI reg_num_channels, 4		// If N >= 4, N = 4
+      QBA SPI_NUM_CHANNELS_DONE
+SPI_NUM_CHANNELS_LT4:
+      LDI reg_num_channels, 2		// else N = 2
+SPI_NUM_CHANNELS_DONE:	
 	
       // Init SPI clock
       MOV r2, 0x02
@@ -491,11 +510,13 @@
 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12)	// Set XFRST
 
 // Initialisation
-LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4  // Total frame count (SPI; 2x for McASP)
+LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4  // Total frame count (SPI; 0.5x-2x for McASP)
 MOV reg_dac_buf0, 0                      // DAC buffer 0 start pointer
-LSL reg_dac_buf1, reg_frame_total, 4     // DAC buffer 1 start pointer = 8[ch]*2[bytes]*bufsize
+LSL reg_dac_buf1, reg_frame_total, 1     // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize
+LMBD r2, reg_num_channels, 1		 // Returns 1, 2 or 3 depending on the number of channels
+LSL reg_dac_buf1, reg_dac_buf1, r2	 // Multiply by 2, 4 or 8 to get the N[ch] scaling above
 MOV reg_mcasp_buf0, 0			 // McASP DAC buffer 0 start pointer
-LSL reg_mcasp_buf1, reg_frame_total, 3   // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*2[samples/spi]*bufsize
+LSL reg_mcasp_buf1, reg_frame_total, r2  // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*(N/4)[samples/spi]*bufsize
 CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1  // Bit 0 holds which buffer we are on
 MOV r2, 0
 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4  // Start with frame count of 0
@@ -521,16 +542,19 @@
       // Write a single buffer of DAC samples and read a buffer of ADC samples
       // Load starting positions
       MOV reg_dac_current, reg_dac_buf0         // DAC: reg_dac_current is current pointer
-      LSL reg_adc_current, reg_frame_total, 5   // 16 * 2 * bufsize
-      ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts 16 * 2 * bufsize beyond DAC
+      LMBD r2, reg_num_channels, 1		// 1, 2 or 3 for 2, 4 or 8 channels
+      LSL reg_adc_current, reg_frame_total, r2
+      LSL reg_adc_current, reg_adc_current, 2   // N * 2 * 2 * bufsize
+      ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts N * 2 * 2 * bufsize beyond DAC
       MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer
-      LSL reg_mcasp_adc_current, reg_frame_total, 4 // McASP ADC: starts 4*2*2*bufsize beyond DAC
+      LSL reg_mcasp_adc_current, reg_frame_total, r2 // McASP ADC: starts (N/2)*2*2*bufsize beyond DAC
+      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
 	
 WRITE_LOOP:
-      // Write 8 channels to DAC from successive values in memory
-      // At the same time, read 8 channels from ADC
+      // Write N channels to DAC from successive values in memory
+      // At the same time, read N channels from ADC
       // Unrolled by a factor of 2 to get high and low words
       MOV r1, 0
 ADC_DAC_LOOP:
@@ -544,7 +568,8 @@
 
       // On even iterations, load two more samples and choose the first one
       // On odd iterations, transmit the second of the samples already loaded
-      QBBS MCASP_DAC_HIGH_WORD, r1, 1
+      // QBBS MCASP_DAC_HIGH_WORD, r1, 1
+      QBBS MCASP_DAC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
 MCASP_DAC_LOW_WORD:	
       // Load next 2 Audio DAC samples and store zero in their place
       LBCO reg_mcasp_dac_data, C_MCASP_MEM, reg_mcasp_dac_current, 4
@@ -561,8 +586,7 @@
       // Take the high word of the previously loaded data
       LSR r7, reg_mcasp_dac_data, 16
 	
-      // Two audio frames per SPI frame = 4 audio samples per SPI frame
-      // Therefore every 2 channels we send one audio sample; this loop already
+      // Every 2 channels we send one audio sample; this loop already
       // sends exactly two SPI channels.
       // Wait for McASP XSTAT[XDATA] to set indicating we can write more data
 MCASP_WAIT_XSTAT:
@@ -573,7 +597,8 @@
 	
       // Same idea with ADC: even iterations, load the sample into the low word, odd
       // iterations, load the sample into the high word and store
-      QBBS MCASP_ADC_HIGH_WORD, r1, 1
+      // QBBS MCASP_ADC_HIGH_WORD, r1, 1
+      QBBS MCASP_ADC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
 MCASP_ADC_LOW_WORD:	
       // Start ADC data at 0
       LDI reg_mcasp_adc_data, 0
@@ -618,12 +643,13 @@
 
       // Read ADC channels: result is always 2 commands behind
       // Start by reading channel 2 (result is channel 0) and go
-      // to 10, but masking the channel number to be between 0 and 7
+      // to N+2, but masking the channel number to be between 0 and N-1
       LDI reg_adc_data, 0
+      ADD r8, r1, 2
+      SUB r7, reg_num_channels, 1
+      AND r8, r8, r7
+      LSL r8, r8, AD7699_CHANNEL_OFFSET
       MOV r7, AD7699_CFG_MASK
-      ADD r8, r1, 2
-      AND r8, r8, 7
-      LSL r8, r8, AD7699_CHANNEL_OFFSET
       OR r7, r7, r8
       ADC_WRITE r7, r7
 
@@ -645,11 +671,13 @@
 
       // Read ADC channels: result is always 2 commands behind
       // Start by reading channel 2 (result is channel 0) and go
-      // to 10, but masking the channel number to be between 0 and 7
+      // to N+2, but masking the channel number to be between 0 and N-1
+      LDI reg_adc_data, 0
+      ADD r8, r1, 2
+      SUB r7, reg_num_channels, 1
+      AND r8, r8, r7
+      LSL r8, r8, AD7699_CHANNEL_OFFSET
       MOV r7, AD7699_CFG_MASK
-      ADD r8, r1, 2
-      AND r8, r8, 7
-      LSL r8, r8, AD7699_CHANNEL_OFFSET
       OR r7, r7, r8
       ADC_WRITE r7, r7
 
@@ -661,16 +689,26 @@
       SBCO reg_adc_data, C_ADC_DAC_MEM, reg_adc_current, 4
       ADD reg_adc_current, reg_adc_current, 4
 
-      // Repeat 4 times (2 samples per loop, r1 += 1 already happened)
+      // Toggle the high/low word for McASP control (since we send one word out of
+      // 32 bits for each pair of SPI channels)
+      XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
+	
+      // Repeat 4 times for 8 channels (2 samples per loop, r1 += 1 already happened)
+      // For 4 or 2 channels, repeat 2 or 1 times, according to flags
       ADD r1, r1, 1
-      QBNE ADC_DAC_LOOP, r1, 8
+      QBNE ADC_DAC_LOOP, r1, reg_num_channels
       QBA ADC_DAC_LOOP_DONE
-	
+
 SPI_SKIP_WRITE:
       // We get here only if the SPI ADC and DAC are disabled
       // Just keep the loop going for McASP
+
+      // Toggle the high/low word for McASP control (since we send one word out of
+      // 32 bits for each pair of SPI channels)
+      XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
+
       ADD r1, r1, 2
-      QBNE ADC_DAC_LOOP, r1, 8
+      QBNE ADC_DAC_LOOP, r1, reg_num_channels
 	
 ADC_DAC_LOOP_DONE:	
       // Increment number of frames, see if we have more to write