Multichannel Audio (XK-AUDIO-216-MC) How to read ADC values

If you have a simple question and just want an answer.
Post Reply
MisterQ
Member++
Posts: 21
Joined: Thu Jan 05, 2017 3:35 pm

Multichannel Audio (XK-AUDIO-216-MC) How to read ADC values

Post by MisterQ »

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


User avatar
larry
Respected Member
Posts: 275
Joined: Fri Mar 12, 2010 6:03 pm

Post by larry »

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
RitchRock
XCore Addict
Posts: 186
Joined: Tue Jan 17, 2017 9:25 pm

Post by RitchRock »

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:

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
        }
    }
}
Thanks for your help!
User avatar
larry
Respected Member
Posts: 275
Joined: Fri Mar 12, 2010 6:03 pm

Post by larry »

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

Code: Select all

xrun --dump-state
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.
RitchRock
XCore Addict
Posts: 186
Joined: Tue Jan 17, 2017 9:25 pm

Post by RitchRock »

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?
Attachments
DSP Thread Problem.zip
(513.94 KiB) Downloaded 256 times
DSP Thread Problem.zip
(513.94 KiB) Downloaded 256 times
User avatar
larry
Respected Member
Posts: 275
Joined: Fri Mar 12, 2010 6:03 pm

Post by larry »

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.

Image

Image
RitchRock
XCore Addict
Posts: 186
Joined: Tue Jan 17, 2017 9:25 pm

Post by RitchRock »

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.

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);

        }
    }
}

    
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?
RitchRock
XCore Addict
Posts: 186
Joined: Tue Jan 17, 2017 9:25 pm

Post by RitchRock »

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.
Post Reply