# HG changeset patch
# User andrewm
# Date 1421953222 0
# Node ID a6beeba3a648db1961fcf0c6b12df23a0186b46f
# Parent 517715b23df0f0be8bdd21b6c5681e91079e9953
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.
diff -r 517715b23df0 -r a6beeba3a648 .cproject
--- a/.cproject Thu Nov 13 16:02:59 2014 +0100
+++ b/.cproject Thu Jan 22 19:00:22 2015 +0000
@@ -49,17 +49,8 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -82,7 +73,7 @@
-
+
@@ -156,7 +147,7 @@
-
+
diff -r 517715b23df0 -r a6beeba3a648 core/PRU.cpp
--- a/core/PRU.cpp Thu Nov 13 16:02:59 2014 +0100
+++ b/core/PRU.cpp Thu Jan 22 19:00:22 2015 +0000
@@ -50,8 +50,9 @@
#define PRU_LED_PIN_MASK 7
#define PRU_FRAME_COUNT 8
#define PRU_USE_SPI 9
+#define PRU_SPI_NUM_CHANNELS 10
-#define PRU_SAMPLE_INTERVAL_NS 45351 // 22050Hz per SPI sample = 45.351us
+#define PRU_SAMPLE_INTERVAL_NS 11338 // 88200Hz per SPI sample = 11.338us
#define GPIO0_ADDRESS 0x44E07000
#define GPIO1_ADDRESS 0x4804C000
@@ -79,7 +80,7 @@
// Constructor: specify a PRU number (0 or 1)
PRU::PRU()
: pru_number(0), running(false), spi_enabled(false), gpio_enabled(false), led_enabled(false),
- gpio_test_pin_enabled(false), xenomai_gpio_fd(-1), xenomai_gpio(0)
+ gpio_test_pin_enabled(false), spi_num_channels(0), xenomai_gpio_fd(-1), xenomai_gpio(0)
{
}
@@ -224,7 +225,7 @@
}
// Initialise and open the PRU
-int PRU::initialise(int pru_num, int frames_per_buffer, bool xenomai_test_pin)
+int PRU::initialise(int pru_num, int frames_per_buffer, int spi_channels, bool xenomai_test_pin)
{
uint32_t *pruMem = 0;
@@ -235,6 +236,13 @@
pru_number = pru_num;
+ /* Set number of SPI ADC / DAC channels to use. This implicitly
+ * also determines the sample rate relative to the audio clock
+ * (half audio clock for 8 channels, full audio clock for 4,
+ * double audio clock for 2)
+ */
+ spi_num_channels = spi_channels;
+
/* Initialize structure used by prussdrv_pruintc_intc */
/* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */
tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
@@ -250,22 +258,22 @@
prussdrv_pruintc_init(&pruss_intc_initdata);
spi_buffer_frames = frames_per_buffer;
- audio_buffer_frames = spi_buffer_frames * 2;
+ audio_buffer_frames = spi_buffer_frames * spi_num_channels / 4;
/* Map PRU memory to pointers */
prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruMem);
pru_buffer_comm = (uint32_t *)&pruMem[PRU_MEM_COMM_OFFSET/sizeof(uint32_t)];
pru_buffer_audio_dac = (int16_t *)&pruMem[PRU_MEM_MCASP_OFFSET/sizeof(uint32_t)];
- /* ADC memory starts 2(ch)*2(buffers)*2(samples/spi)*bufsize samples later */
- pru_buffer_audio_adc = &pru_buffer_audio_dac[8 * spi_buffer_frames];
+ /* ADC memory starts 2(ch)*2(buffers)*bufsize samples later */
+ pru_buffer_audio_adc = &pru_buffer_audio_dac[4 * audio_buffer_frames];
if(spi_enabled) {
prussdrv_map_prumem (pru_number == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, (void **)&pruMem);
pru_buffer_spi_dac = (uint16_t *)&pruMem[PRU_MEM_DAC_OFFSET/sizeof(uint32_t)];
- /* ADC memory starts after 8(ch)*2(buffers)*bufsize samples */
- pru_buffer_spi_adc = &pru_buffer_spi_dac[16 * spi_buffer_frames];
+ /* ADC memory starts after N(ch)*2(buffers)*bufsize samples */
+ pru_buffer_spi_adc = &pru_buffer_spi_dac[2 * spi_num_channels * spi_buffer_frames];
}
else {
pru_buffer_spi_dac = pru_buffer_spi_adc = 0;
@@ -288,9 +296,11 @@
}
if(spi_enabled) {
pru_buffer_comm[PRU_USE_SPI] = 1;
+ pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = spi_num_channels;
}
else {
pru_buffer_comm[PRU_USE_SPI] = 0;
+ pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = 0;
}
/* Clear ADC and DAC memory */
@@ -340,7 +350,7 @@
void PRU::loop()
{
// Polling interval is 1/4 of the period
- RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * spi_buffer_frames / 4;
+ RTIME sleepTime = PRU_SAMPLE_INTERVAL_NS * (spi_num_channels / 2) * spi_buffer_frames / 4;
float *audioInBuffer, *audioOutBuffer;
audioInBuffer = (float *)malloc(2 * audio_buffer_frames * sizeof(float));
@@ -410,7 +420,7 @@
if(spi_enabled)
render(spi_buffer_frames, audio_buffer_frames, audioInBuffer, audioOutBuffer,
- &pru_buffer_spi_adc[spi_buffer_frames * 8], &pru_buffer_spi_dac[spi_buffer_frames * 8]);
+ &pru_buffer_spi_adc[spi_buffer_frames * spi_num_channels], &pru_buffer_spi_dac[spi_buffer_frames * spi_num_channels]);
else
render(0, audio_buffer_frames, audioInBuffer, audioOutBuffer, 0, 0);
diff -r 517715b23df0 -r a6beeba3a648 core/RTAudio.cpp
--- a/core/RTAudio.cpp Thu Nov 13 16:02:59 2014 +0100
+++ b/core/RTAudio.cpp Thu Jan 22 19:00:22 2015 +0000
@@ -67,7 +67,8 @@
// periodSize indicates the number of _sensor_ frames per period: the audio period size
// is twice this value. In total, the audio latency in frames will be 4*periodSize,
// plus any latency inherent in the ADCs and DACs themselves.
-// useMatrix indicates whether to use the ADC and DAC or just the audio codec.
+// useMatrix indicates whether to enable the ADC and DAC or just use the audio codec.
+// numMatrixChannels indicates how many ADC and DAC channels to use.
// userData is an opaque pointer which will be passed through to the initialise_render()
// function for application-specific use
//
@@ -114,6 +115,24 @@
}
}
+ // Limit the matrix channels to sane values
+ if(settings->numMatrixChannels >= 8)
+ settings->numMatrixChannels = 8;
+ else if(settings->numMatrixChannels >= 4)
+ settings->numMatrixChannels = 4;
+ else
+ settings->numMatrixChannels = 2;
+
+ // Sanity check the combination of channels and period size
+ if(settings->numMatrixChannels <= 4 && settings->periodSize < 2) {
+ cout << "Error: " << settings->numMatrixChannels << " channels and period size of " << settings->periodSize << " not supported.\n";
+ return 1;
+ }
+ if(settings->numMatrixChannels <= 2 && settings->periodSize < 4) {
+ cout << "Error: " << settings->numMatrixChannels << " channels and period size of " << settings->periodSize << " not supported.\n";
+ return 1;
+ }
+
// Use PRU for audio
gPRU = new PRU();
gAudioCodec = new I2c_Codec();
@@ -122,7 +141,7 @@
cout << "Error: unable to prepare GPIO for PRU audio\n";
return 1;
}
- if(gPRU->initialise(0, settings->periodSize, true)) {
+ if(gPRU->initialise(0, settings->periodSize, settings->numMatrixChannels, true)) {
cout << "Error: unable to initialise PRU\n";
return 1;
}
@@ -140,7 +159,23 @@
BeagleRT_setADCLevel(settings->adcLevel);
BeagleRT_setHeadphoneLevel(settings->headphoneLevel);
- if(!initialise_render(2, settings->useMatrix ? settings->periodSize : 0, settings->periodSize * 2, 22050.0, 44100.0, userData)) {
+ // Initialise the rendering environment: pass the number of audio and matrix
+ // channels, the period size for matrix and audio, and the sample rates
+
+ int audioPeriodSize = settings->periodSize * 2;
+ float audioSampleRate = 44100.0;
+ float matrixSampleRate = 22050.0;
+ if(settings->useMatrix) {
+ audioPeriodSize = settings->periodSize * settings->numMatrixChannels / 4;
+ matrixSampleRate = audioSampleRate * 4.0 / (float)settings->numMatrixChannels;
+ }
+
+ if(!initialise_render(settings->useMatrix ? settings->numMatrixChannels : 0, /* matrix channels */
+ 2, /* audio channels */
+ settings->useMatrix ? settings->periodSize : 0, /* matrix period size */
+ audioPeriodSize,
+ matrixSampleRate, audioSampleRate,
+ userData)) {
cout << "Couldn't initialise audio rendering\n";
return 1;
}
diff -r 517715b23df0 -r a6beeba3a648 core/RTAudioCommandLine.cpp
--- a/core/RTAudioCommandLine.cpp Thu Nov 13 16:02:59 2014 +0100
+++ b/core/RTAudioCommandLine.cpp Thu Jan 22 19:00:22 2015 +0000
@@ -18,6 +18,7 @@
{"period", 1, NULL, 'p'},
{"verbose", 0, NULL, 'v'},
{"use-matrix", 1, NULL, 'm'},
+ {"matrix-channels", 1, NULL, 'C'},
{"mute-speaker", 1, NULL, 'M'},
{"dac-level", 1, NULL, 'D'},
{"adc-level", 1, NULL, 'A'},
@@ -25,7 +26,7 @@
{NULL, 0, NULL, 0}
};
-const char gDefaultShortOptions[] = "p:vm:M:D:A:H:";
+const char gDefaultShortOptions[] = "p:vm:M:C:D:A:H:";
// This function sets the default settings for the RTAudioSettings structure
void BeagleRT_defaultSettings(RTAudioSettings *settings)
@@ -37,6 +38,7 @@
settings->adcLevel = DEFAULT_ADC_LEVEL;
settings->headphoneLevel = DEFAULT_HP_LEVEL;
settings->useMatrix = 1;
+ settings->numMatrixChannels = 8;
settings->verbose = 0;
settings->codecI2CAddress = CODEC_I2C_ADDRESS;
settings->ampMutePin = kAmplifierMutePin;
@@ -123,6 +125,15 @@
case 'm':
settings->useMatrix = atoi(optarg);
break;
+ case 'C':
+ settings->numMatrixChannels = atoi(optarg);
+ if(settings->numMatrixChannels >= 8)
+ settings->numMatrixChannels = 8;
+ else if(settings->numMatrixChannels >= 4)
+ settings->numMatrixChannels = 4;
+ else
+ settings->numMatrixChannels = 2;
+ break;
case 'M':
settings->beginMuted = atoi(optarg);
break;
@@ -146,11 +157,12 @@
// Call from within your own usage function
void BeagleRT_usage()
{
- std::cerr << " --period [-p] period: Set the hardware period (buffer) size in matrix samples\n";
- std::cerr << " --dac-level [-D] dBs: Set the DAC output level (0dB max; -63.5dB min)\n";
- std::cerr << " --adc-level [-A] dBs: Set the ADC input level (0dB max; -12dB min)\n";
- std::cerr << " --hp-level [-H] dBs: Set the headphone output level (0dB max; -63.5dB min)\n";
- std::cerr << " --mute-speaker [-M] val: Set whether to mute the speaker initially (default: no)\n";
- std::cerr << " --use-matrix [-m] val: Set whether to use ADC/DAC matrix\n";
- std::cerr << " --verbose [-v]: Enable verbose logging information\n";
+ std::cerr << " --period [-p] period: Set the hardware period (buffer) size in matrix samples\n";
+ std::cerr << " --dac-level [-D] dBs: Set the DAC output level (0dB max; -63.5dB min)\n";
+ std::cerr << " --adc-level [-A] dBs: Set the ADC input level (0dB max; -12dB min)\n";
+ std::cerr << " --hp-level [-H] dBs: Set the headphone output level (0dB max; -63.5dB min)\n";
+ std::cerr << " --mute-speaker [-M] val: Set whether to mute the speaker initially (default: no)\n";
+ std::cerr << " --use-matrix [-m] val: Set whether to use ADC/DAC matrix\n";
+ std::cerr << " --matrix-channels [-C] val: Set the number of ADC/DAC channels (default: 8)\n";
+ std::cerr << " --verbose [-v]: Enable verbose logging information\n";
}
diff -r 517715b23df0 -r a6beeba3a648 include/PRU.h
--- a/include/PRU.h Thu Nov 13 16:02:59 2014 +0100
+++ b/include/PRU.h Thu Jan 22 19:00:22 2015 +0000
@@ -33,7 +33,8 @@
void cleanupGPIO();
// Initialise and open the PRU
- int initialise(int pru_num, int frames_per_buffer, bool xenomai_test_pin = false);
+ int initialise(int pru_num, int frames_per_buffer, int spi_channels,
+ bool xenomai_test_pin = false);
// Run the code image in the specified file
int start(char * const filename);
@@ -58,6 +59,7 @@
bool gpio_enabled; // Whether GPIO has been prepared
bool led_enabled; // Whether a user LED is enabled
bool gpio_test_pin_enabled; // Whether the test pin was also enabled
+ int spi_num_channels; // How many channels to use for SPI ADC/DAC
volatile uint32_t *pru_buffer_comm;
uint16_t *pru_buffer_spi_dac;
diff -r 517715b23df0 -r a6beeba3a648 include/RTAudio.h
--- a/include/RTAudio.h Thu Nov 13 16:02:59 2014 +0100
+++ b/include/RTAudio.h Thu Jan 22 19:00:22 2015 +0000
@@ -43,7 +43,8 @@
float dacLevel; // Level for the audio DAC output
float adcLevel; // Level for the audio ADC input
float headphoneLevel; // Level for the headphone output
- int useMatrix; // Whether to enable the ADC and DAC
+ int useMatrix; // Whether to use the matrix
+ int numMatrixChannels; // How many channels for the ADC and DAC
int verbose; // Whether to use verbose logging
// These items are hardware-dependent and should only be changed
diff -r 517715b23df0 -r a6beeba3a648 include/render.h
--- a/include/render.h Thu Nov 13 16:02:59 2014 +0100
+++ b/include/render.h Thu Jan 22 19:00:22 2015 +0000
@@ -33,7 +33,8 @@
#define MATRIX_MAX 65535.0
-bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
+bool initialise_render(int numMatrixChannels, int numAudioChannels,
+ int numMatrixFramesPerPeriod,
int numAudioFramesPerPeriod,
float matrixSampleRate, float audioSampleRate,
void *userData);
diff -r 517715b23df0 -r a6beeba3a648 projects/basic/render.cpp
--- a/projects/basic/render.cpp Thu Nov 13 16:02:59 2014 +0100
+++ b/projects/basic/render.cpp Thu Jan 22 19:00:22 2015 +0000
@@ -23,14 +23,16 @@
//
// Return true on success; returning false halts the program.
-bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
- int numAudioFramesPerPeriod, float matrixSampleRate,
- float audioSampleRate, void *userData)
+bool initialise_render(int numMatrixChannels, int numAudioChannels,
+ int numMatrixFramesPerPeriod,
+ int numAudioFramesPerPeriod,
+ float matrixSampleRate, float audioSampleRate,
+ void *userData)
{
// Retrieve a parameter passed in from the initAudio() call
gFrequency = *(float *)userData;
- gNumChannels = numChannels;
+ gNumChannels = numAudioChannels;
gInverseSampleRate = 1.0 / audioSampleRate;
gPhase = 0.0;
diff -r 517715b23df0 -r a6beeba3a648 projects/basic_analog_output/render.cpp
--- a/projects/basic_analog_output/render.cpp Thu Nov 13 16:02:59 2014 +0100
+++ b/projects/basic_analog_output/render.cpp Thu Jan 22 19:00:22 2015 +0000
@@ -19,6 +19,8 @@
float gPhase;
float gInverseSampleRate;
+int gMatrixChannels;
+
// initialise_render() is called once before the audio rendering starts.
// Use it to perform any initialisation and allocation which is dependent
// on the period size or sample rate.
@@ -28,19 +30,22 @@
//
// Return true on success; returning false halts the program.
-bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
- int numAudioFramesPerPeriod, float matrixSampleRate,
- float audioSampleRate, void *userData)
+bool initialise_render(int numMatrixChannels, int numAudioChannels,
+ int numMatrixFramesPerPeriod,
+ int numAudioFramesPerPeriod,
+ float matrixSampleRate, float audioSampleRate,
+ void *userData)
{
// Retrieve a parameter passed in from the initAudio() call
gFrequency = *(float *)userData;
- if(numMatrixFramesPerPeriod*2 != numAudioFramesPerPeriod) {
- rt_printf("Error: this example needs the matrix enabled, running at half audio rate\n");
+ if(numMatrixFramesPerPeriod == 0) {
+ rt_printf("Error: this example needs the matrix enabled\n");
return false;
}
- gInverseSampleRate = 1.0 / audioSampleRate;
+ gMatrixChannels = numMatrixChannels;
+ gInverseSampleRate = 1.0 / matrixSampleRate;
gPhase = 0.0;
return true;
@@ -57,12 +62,13 @@
for(int n = 0; n < numMatrixFrames; n++) {
// Set LED to different phase for each matrix channel
float relativePhase = 0.0;
- for(int channel = 0; channel < 8; channel++) {
+ for(int channel = 0; channel < gMatrixChannels; channel++) {
float out = kMinimumAmplitude + kAmplitudeRange * 0.5f * (1.0f + sinf(gPhase + relativePhase));
if(out > MATRIX_MAX)
out = MATRIX_MAX;
- analogWrite(channel, n, out);
+ matrixOut[n * gMatrixChannels + channel] = (uint16_t)out;
+ //analogWrite(channel, n, out);
// Advance by pi/4 (1/8 of a full rotation) for each channel
relativePhase += M_PI * 0.25;
diff -r 517715b23df0 -r a6beeba3a648 projects/basic_sensor/render.cpp
--- a/projects/basic_sensor/render.cpp Thu Nov 13 16:02:59 2014 +0100
+++ b/projects/basic_sensor/render.cpp Thu Jan 22 19:00:22 2015 +0000
@@ -31,16 +31,18 @@
//
// Return true on success; returning false halts the program.
-bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
- int numAudioFramesPerPeriod, float matrixSampleRate,
- float audioSampleRate, void *userData)
+bool initialise_render(int numMatrixChannels, int numAudioChannels,
+ int numMatrixFramesPerPeriod,
+ int numAudioFramesPerPeriod,
+ float matrixSampleRate, float audioSampleRate,
+ void *userData)
{
if(numMatrixFramesPerPeriod*2 != numAudioFramesPerPeriod) {
rt_printf("Error: this example needs the matrix enabled, running at half audio rate\n");
return false;
}
- gNumChannels = numChannels;
+ gNumChannels = numAudioChannels;
gInverseSampleRate = 1.0 / audioSampleRate;
gPhase = 0.0;
diff -r 517715b23df0 -r a6beeba3a648 pru_rtaudio.bin
Binary file pru_rtaudio.bin has changed
diff -r 517715b23df0 -r a6beeba3a648 pru_rtaudio.p
--- 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