Mercurial > hg > beaglert
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