Multi-channel Audio - How to add data to an audio stream? Topic is solved

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

Post by MisterQ »

Nope. Channels 9 and 10 are empty.

I2S_CHANS_ADC=8
NUM_USB_CHAN_IN=10

TARGET = xk-audio-216-mc.xn
Build Configuration: 2i10o10xxxxxx
xTIMEcomposer Version: Community_14.2.4 (build 15898, Dec-20-2016)

I have tried with fresh project from XMOS web site.

What is your compiler, project and build configuration?

Maybe there is a difference in some settings of compiler at your and mine system,
because compiler can manage buffer variables at your system, and not at mine ?

Please advice.

Regards,
Dragan
View Solution
User avatar
infiniteimprobability
Verified
XCore Legend
Posts: 1142
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

I'm on the same versions as you - I don't think this is compiler related, likely more related to the source version I'm using against yours. I am now looking at 6.15.2 (see sw_usb_audio/changelog.rst)

The key thing is for the samples sent out by DoSampleTransfer() are written to just before this is called in the main loop. So look at this function - you'll see that the ADC ones are sent then remaining ones not mapped to ADC are sent afterwards:

Code: Select all

        for(int i = I2S_CHANS_ADC; i < NUM_USB_CHAN_IN; i++)
        {
            outuint(c_out, samplesIn_0[i]);
        }
So it's in fact samplesIn_0[8] and samplesIn_0[9] that need to be set to send your data across.

Try this...
MisterQ
Member++
Posts: 21
Joined: Thu Jan 05, 2017 3:35 pm

Post by MisterQ »

infiniteimprobability,

EVERYTHING WORK !

I have tried everything with Studio One Audio application.

To repeat infiniteimprobability suggestions at one place for future reference:

Declarations in the customdefines.h file:

Code: Select all

/* Number of USB streaming channels - Default is 10 in 10 out */
#define NUM_USB_CHAN_IN   (10)         /* Device to Host */
#define NUM_USB_CHAN_OUT  (10)         /* Host to Device */

/* Number of IS2 chans to DAC..*/
#define I2S_CHANS_DAC     (8)

/* Number of I2S chans from ADC */
#define I2S_CHANS_ADC     (8)
Additional lines in the audio.xc file just under the line:
static unsigned samplesOut[NUM_USB_CHAN_OUT];)

Code: Select all

static unsigned samplesIn[2][32];
unsigned my_data[2];
Additional lines in the audio.xc file just under lines:
/* Send over the digi channels - no odd buffering required */
#pragma loop unroll

Code: Select all

my_data[0] = 0xAAAAAAAA; // Some 32-bit value
my_data[1] = 0xCCCCCCCC; // Some 32-bit value
samplesIn_0[8] = my_data[0];
samplesIn_0[9] = my_data[1];
Additional lines in the Makefile file just under the line:
# Test build configs (Note these make use of the defaults in customdefines.h)

Code: Select all

# Audio Class 2, Input (10), Output (10), No MIDI, No SPDIF IN, No ADAT i/o, No TDM mode
XCC_FLAGS_2i10o10xxxxxx  = $(BUILD_FLAGS)
INCLUDE_ONLY_IN_2i10o10xxxxxx =
And that is all. Build project, download it to your board and enjoy.

THANKS to infiniteimprobability for the excellent idea!

Best regards,
Dragan
You do not have the required permissions to view the files attached to this post.
User avatar
infiniteimprobability
Verified
XCore Legend
Posts: 1142
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

Glad it works! Thanks for sharing the solution summary - it will likely help others.
Oh the joys of Windows..
MisterQ
Member++
Posts: 21
Joined: Thu Jan 05, 2017 3:35 pm

Post by MisterQ »

infiniteimprobability,

can you help with data passing from the main.xc file to the audio.xc file.

In the audio.xc file I have variables which I use for feeding audio channels 9 and 10:

Code: Select all

unsigned my_data[2];
In the main.xc file I have a gpio_handler function which handle inputs and outputs:

I need to send values from gpio_handler function in the main.xc file to the function Receive_Data in the audio.xc file which use global variables my_data[2].

I have made a streaming chan and streaming chanend function in the audio.xc file, which correctly receive values from the gpio_handler in the main.xc file (tested on XSCOPE), but when I try to assign values to global variables my_data in the function Receive_Data error occur:

Code: Select all

error: use of `my_data' violates parallel usage rules
Obviously variable my_data is being called in two cores (as in the code example bellow), but I don't know how to pass data without breaking parallel usage rules.

Code: Select all

int g = 7;
void task1() { g = 7; }
void task2() { printf("%d",g);}
int main() {
  par {
    task1();
    task2();
  }
  return 0;
}
Please advice.

Regards,
Dragan
User avatar
infiniteimprobability
Verified
XCore Legend
Posts: 1142
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

if you really want to do this via shared memory (and both tasks are on the same tile which is needed as there is no shared memory between tiles), then the first example here using unsafe pointers https://www.xcore.com/forum/viewtopic.php?f=26&t=3061 may help.

The natural way to do this in xc/xmos (which is a CSP machine) is to use an interface or channel. . Channels are easiest for simple data value passing. Remember that normal channel passing synchrnoises both side so that they only drop through when the data has been received and acknowledged. The example in section 2.2.3 here shows you how https://www.xmos.com/download/private/X ... 28F%29.pdf
MisterQ
Member++
Posts: 21
Joined: Thu Jan 05, 2017 3:35 pm

Post by MisterQ »

infiniteimprobability,

what should I change in this code:

Function in main.xc:

Code: Select all

unsigned My_GPIO_Data[2];

void gpio_handler(streaming chanend c_Inputs, streaming chanend c_Outputs,
                  client input_gpio_if INPUT_1, client input_gpio_if INPUT_2,
                  client input_gpio_if INPUT_3, client input_gpio_if INPUT_4,
                  client output_gpio_if OUTPUT_1, client output_gpio_if OUTPUT_2,
                  client output_gpio_if OUTPUT_3, client output_gpio_if OUTPUT_4) {

// Initially switch state set to OFF (LOW) and switch trigger set to HIGH
INPUT_4.event_when_pins_eq(1);    // Active HIGH (Trigger transition from LOW to HIGH)

while (1)
    {
    select
        {
        // Trigger event on INPUT_4
        case INPUT_4.event():
            if (INPUT_4.input() == 1)
                {
                OUTPUT_4.output(1);
                delay_milliseconds(250);         // Debounce
                INPUT_4.event_when_pins_eq(0);   // Active LOW (Trigger transition from HIGH to LOW)
                My_GPIO_Data[0] = 0xAAAAAA00;
                My_GPIO_Data[1] = 0xCCCCCC00;
                c_Inputs <: My_GPIO_Data[0];
                c_Outputs <: My_GPIO_Data[1];
                }
            else
                {
                OUTPUT_4.output(0);
                delay_milliseconds(250);         // Debounce
                INPUT_4.event_when_pins_eq(1);   // Active HIGH (Trigger transition from LOW to HIGH)
                My_GPIO_Data[0] = 0x00000000;
                My_GPIO_Data[1] = 0x00000000;
                c_Inputs <: My_GPIO_Data[0];
                c_Outputs <: My_GPIO_Data[1];
                }
            break;
        }       // END Event Select

    }           // END while(1)

}
Function in audio.xc:

Code: Select all

unsigned my_data[2];

void Receive_Data(streaming chanend c_Inputs, streaming chanend c_Outputs) {

unsigned Inputs;
unsigned Outputs;

while (1)
    {
    select {

    case c_Inputs :> Inputs:
        my_data[0] = Inputs;  // <<<<< ******************* ERROR
        printf("IN:  %0.8X\n",Inputs);
        break;

    case c_Outputs :> Outputs:
        my_data[1] = Outputs;  // <<<<< ******************* ERROR
        printf("OUT: %0.8X\n",Outputs);
        break;

    default:
        break;
    }
  }
}
To mention that, if I omit lines with use of my_data variables, printf values of received data from the main.xc file are corect (tested with XSCOPE).
Please advice.

Regards,
Dragan
User avatar
infiniteimprobability
Verified
XCore Legend
Posts: 1142
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

I'm not exactly sure what is going on your situation - it depends how you are calling those functions?

Where does the debugger say it's stuck?

I assume they are from the par{} so are tasks. One looks like a proxy from a GPIO interface to pass on a channel communication (which is a bit of a waste of a thread/core but should work) and the other is a receiver to dump into shared memory.

An alternative is you could just have the select with default case inline in audio.xc (saves a thread) and that gives you a poll in effect. However, there's no way it could tolerate a length printf call in that inner loop (it's generatring the I2S signals in real time).

Please read my previous post/link about how to use shared memory to solve your compiler issue - the info's already in there.
MisterQ
Member++
Posts: 21
Joined: Thu Jan 05, 2017 3:35 pm

Post by MisterQ »

I have solved problem with parallel use of data in more than two tasks, without channeling data and sharing memory between cores.

First, values of samplesIn_0[8] and samplesIn_0[9] can not be altered from some other core or task without massive modifications of USB Audio 2.0 Reference Software, because they are already used in two parallel tasks inside the USB Audio 2.0 reference software.

SOLUTION: You must write your code in the same task, on the same core, where samplesIn_0[8] and samplesIn_0[9] are used.

Be aware that you have only 2 microseconds spare time for duration of your inserted code to be possible for audio stream at speed of 192 ksps to stay intact.

Trying to solve this problem I learned a lot about data transfer trough channels, but I am surprised, that so simple things in other compilers as creating threads and tasks, are such hard in XMOS xTIME. When I write code in, for example, Visual Studio C++ and want to open a new thread, I don't care where this thread is executing, at which core, or task, and is it parallel or not. Compiler must resolve this, not programmer.

Regards,
Dragan