Respected Colleagues,
I have a xCORE-200 Multichannel Audio Platform (XK-AUDIO-216-MC-AB). It works OK with Audio 8 Channels IN / 8 Channels OUT configuration in Windows with ASIO driver.
I am new to XMOS programming, and I can't successfully implement any DSP function in the XMOS USB AUDIO 2.0 REFERENCE SOFTWARE and alter ADC input channels values, because the main problem for me is how to read the Audio (ADC) inputs buffer, and to write back the altered values in it. For a start, I do not understand a format of that data and where to read that data (Can it be in the module_usb_audio folder, file main.xc, or somewhere else?).
Can somebody help with some function which can read the ADC Audio (ADC) inputs buffer in some data format which can be presented in XSCOPE real time. In that way I can see did I altered data correctly with some DSP filter. I know how to work with global data arrays, pointers, and so (Keil, Visual Studio), but the exchange data values between functions with interfaces and channels is new for me, and for now, I do not understand that in the way I can use it.
Please help.
Regards,
Dragan
Multichannel Audio (XK-AUDIO-216-MC) How to read ADC values
-
- Member++
- Posts: 21
- Joined: Thu Jan 05, 2017 3:35 pm
-
- Respected Member
- Posts: 275
- Joined: Fri Mar 12, 2010 6:03 pm
Have a look at AN01008: Adding DSP to the USB Audio 2.0 L1 Reference Design
While this app note applies to the XS1 architecture and an older version of the USB audio code, much remains the same
While this app note applies to the XS1 architecture and an older version of the USB audio code, much remains the same
-
- XCore Addict
- Posts: 189
- Joined: Tue Jan 17, 2017 9:25 pm
Hi there,
I've followed AN01008 as closely as possible, tried some code that was mentioned in this post, but still can't get my DSP thread to pass audio.
The device enumerates, but won't pass audio and then after a while disconnects. That sort of tells me it's getting stuck inside the DSP loop.
For testing, I've made it so there is no processing going on, just what should be a pass-through. I'm building as 4 in/ 4 out and started with a clean version of app_usb_aud_xk_216_mc (6.15.2). If I bypass the DSP thread everything returns to normal. Ultimately, I'm looking to apply FIRs to audio playback from computer.
Is there something else that needs to change for the XK-AUDIO-216-MC board or is there an updated adding DSP app note? I must be getting stuck on something simple. Here is what is inside of my DSP thread, again based on app note AN01008:
Thanks for your help!
I've followed AN01008 as closely as possible, tried some code that was mentioned in this post, but still can't get my DSP thread to pass audio.
The device enumerates, but won't pass audio and then after a while disconnects. That sort of tells me it's getting stuck inside the DSP loop.
For testing, I've made it so there is no processing going on, just what should be a pass-through. I'm building as 4 in/ 4 out and started with a clean version of app_usb_aud_xk_216_mc (6.15.2). If I bypass the DSP thread everything returns to normal. Ultimately, I'm looking to apply FIRs to audio playback from computer.
Is there something else that needs to change for the XK-AUDIO-216-MC board or is there an updated adding DSP app note? I must be getting stuck on something simple. Here is what is inside of my DSP thread, again based on app note AN01008:
Code: Select all
// DSP core.
#include <xs1.h>
#include "devicedefines.h"
#include <print.h>
#include "coeffs.h"
#include <biquadCascade.h>
#include "commands.h"
//give/get functions based on mixer.xc then simplified.
#pragma unsafe arrays
void giveSamplesToHost(chanend c, const int samples[])
{
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
int sample;
sample = samples[i + NUM_USB_CHAN_OUT];
outuint(c,sample);
}
}
#pragma unsafe arrays
static void getSamplesFromHost(chanend c, int samples[])
{
unsigned int l_samp[NUM_USB_CHAN_OUT];
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
//int sample, x;
/* Receive sample from decouple */
l_samp[i] = inuint(c);
}
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
samples[i] = l_samp[i];
}
}
#pragma unsafe arrays
void giveSamplesToDevice(chanend c, const int samples[])
{
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
int sample;
sample = samples[i];
outuint(c, sample);
}
}
#pragma unsafe arrays
void getSamplesFromDevice(chanend c, int samples[])
{
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
int sample;
sample = inuint(c);
samples[NUM_USB_CHAN_OUT+i] = sample;
}
}
void dsp (chanend c_audio, chanend c_decouple) {
/* One larger for an "off" channel for mixer sources" */
int samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1];
unsigned underflow;
unsigned command;
unsigned value;
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
{
samples[i] = 0;
}
while(1){ //Implements channel protocol between decouple and audio cores
inuint(c_audio); //Get sample request from audio
outuint(c_decouple, 0); //Send sample request to decouple
if(testct(c_decouple)){ //Test for sample frequency change .
command = inct(c_decouple); //Get the CT and command - See commands.h
value = inuint(c_decouple); // Get command value from decouple core - normally SR value
outct (c_audio, command); //Send control token to audio (SR change)
outuint (c_audio, value); //Now send value to audio
chkct (c_audio, XS1_CT_END); //wait for handshake
outct (c_decouple, XS1_CT_END); //Forward handshake to decouple
}
else{ // Normal audio loop
underflow = inuint(c_decouple); // Get confirmation from decouple indicating we're ready
outuint (c_audio, underflow); // Pass it on to audio
getSamplesFromDevice (c_audio, samples);//Always get input samples from device and send to audio
if (!underflow) giveSamplesToDevice (c_audio, samples); //Only send audio if not in underflow
giveSamplesToHost (c_decouple, samples);//Always send samples to decouple
if (!underflow) getSamplesFromHost (c_decouple, samples);//Only get samples from decouple if no underflow
}
}
}
-
- Respected Member
- Posts: 275
- Joined: Fri Mar 12, 2010 6:03 pm
AN01008 might be slightly out of date. I see the most recent version, 1.0.1, is dated January 2016. While USB Audio software version 6.15.2 is from April 2016. I wouldn't expect significant changes between the two, however, that would stop a simple thread like you have there from working.
It does sound from your description that something is blocked
You can get snapshots of processor state when you pause the visual debugger or do on the command line. It's easy to spot blocking calls. But it can be difficult to judge which calls are blocking permanently and which are blocking only to wait for another thread to reach a given execution barrier (a channel I/O).
I would want to check is that the sequence of outuint and inuint calls on both sides of the DSP thread, that is the audio and decouple threads. This is best seen in preprocessed source audio_io.xi and decouple.xi in the .build directory for your selected build config. You need to add the -save-temps compile flag to get the XI files generated.
It does sound from your description that something is blocked
You can get snapshots of processor state when you pause the visual debugger or do
Code: Select all
xrun --dump-state
I would want to check is that the sequence of outuint and inuint calls on both sides of the DSP thread, that is the audio and decouple threads. This is best seen in preprocessed source audio_io.xi and decouple.xi in the .build directory for your selected build config. You need to add the -save-temps compile flag to get the XI files generated.
-
- XCore Addict
- Posts: 189
- Joined: Tue Jan 17, 2017 9:25 pm
Hi Larry and thanks for the reply! I hope to get this all sorted out soon.
I attached a .zip file with the .xi files. It seems like it gets hung up on the inuinit(c_audio) - what do you think?
I attached a .zip file with the .xi files. It seems like it gets hung up on the inuinit(c_audio) - what do you think?
You do not have the required permissions to view the files attached to this post.
-
- Respected Member
- Posts: 275
- Joined: Fri Mar 12, 2010 6:03 pm
Thanks. I had a look in history of sc_usb_audio and the API from audio task has changed between versions 6.12.5 and 6.12.6. It used to be outputs first then inputs in the audio task. It's now inputs first then outputs. AN01008 is definitely out of date in that respect.
The thing to do is to match the API on both sides. It should be very clear if you put the XI files side by side in what order should your DSP task do the inputs, outputs, checks and tests. I've attached screenshots to illustrate.
The thing to do is to match the API on both sides. It should be very clear if you put the XI files side by side in what order should your DSP task do the inputs, outputs, checks and tests. I've attached screenshots to illustrate.
-
- XCore Addict
- Posts: 189
- Joined: Tue Jan 17, 2017 9:25 pm
Thank you for your help on this problem. This should now be the correct sequence. I verified by looking at mixer.xc (which seems to work fine), however I'm still not getting any audio. Again, if I bypass this DSP thread, audio plays back properly.
Going through and following closely the sequence of events from USB Audio Design Guide (page 25 and 26) hasn't seemed to help either. While the tests and checks match, this sequence transfer, based on whats in audio.xc and decouple.xc do not. Of course, I will defer to what's actually in the reference code..
It seems that while there are differences between this and mixer.xc (volume, level meters, mixing...), the main thing is that samples is declared as a static int in mixer.xc. I don't think should make a difference however, as I pass samples in when I call the various functions.
Any further thoughts or ideas on the best way to debug this?
Code: Select all
// DSP core.
#include <xs1.h>
#include "devicedefines.h"
#include <print.h>
#include "commands.h"
#include "mydsp.h"
//give/get functions based on mixer.xc then simplified.
#pragma unsafe arrays
static inline void giveSamplesToHost(chanend c, const int samples[])
{
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
int sample;
sample = samples[i + NUM_USB_CHAN_OUT];
outuint(c,sample);
}
}
#pragma unsafe arrays
static inline void getSamplesFromHost(chanend c, int samples[])
{
// unsigned int l_samp[NUM_USB_CHAN_OUT];
// unsigned int sample[NUM_USB_CHAN_OUT];
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
int sample;
sample = inuint(c);
samples[i] = sample;
/* Receive sample from decouple */
//l_samp[i] = inuint(c);
}
/*
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
samples[i] = l_samp[i];
}*/
}
#pragma unsafe arrays
static inline void giveSamplesToDevice(chanend c, const int samples[])
{
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
int sample;
sample = samples[i];
outuint(c, sample);
}
}
#pragma unsafe arrays
static inline void getSamplesFromDevice(chanend c, int samples[])
{
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
int sample;
sample = inuint(c);
samples[NUM_USB_CHAN_OUT+i] = sample;
}
}
void mydsp(chanend c_audio, chanend c_decouple) {
/* One larger for an "off" channel for mixer sources" */
int samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1];
unsigned request = 0;
//intiialize samples to zero
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
{
samples[i] = 0;
}
while(1){ //Implements channel protocol between decouple and audio cores
request = inuint(c_audio); //Get sample request from audio
outuint(c_decouple, request); //Send sample request to decouple
if(testct(c_decouple))
{
int sampFreq;
unsigned command = inct(c_decouple);
switch(command)
{
case SET_SAMPLE_FREQ:
sampFreq = inuint(c_decouple);
/* Inform audio (or audio()) about freq change */
outct(c_audio, command);
outuint(c_audio, sampFreq);
break;
case SET_STREAM_FORMAT_OUT:
case SET_STREAM_FORMAT_IN:
/* Inform audio about format change */
outct(c_audio, command);
outuint(c_audio, inuint(c_decouple));
outuint(c_audio, inuint(c_decouple));
break;
default:
break;
}
#pragma loop unroll
/* Reset the samples values back to 0 */
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
{
samples[i] = 0;
}
/* Wait for handshake and pass on */
chkct(c_audio, XS1_CT_END);
outct(c_decouple, XS1_CT_END);
}
else{ // Normal audio loop
inuint(c_decouple);
outuint(c_audio, 0);
giveSamplesToDevice (c_audio, samples);
getSamplesFromDevice (c_audio, samples);
getSamplesFromHost(c_decouple, samples);
giveSamplesToHost(c_decouple, samples);
}
}
}
It seems that while there are differences between this and mixer.xc (volume, level meters, mixing...), the main thing is that samples is declared as a static int in mixer.xc. I don't think should make a difference however, as I pass samples in when I call the various functions.
Any further thoughts or ideas on the best way to debug this?
-
- XCore Addict
- Posts: 189
- Joined: Tue Jan 17, 2017 9:25 pm
I got it to work. The problem was the final inuint(c_decouple and outuin(c_audio,0) just before the sample transfers. Took them out and it now works as expected.