Streaming Channels in parallel

Technical questions regarding the XTC tools and programming with XMOS.
stdefeber
Active Member
Posts: 35
Joined: Wed Dec 18, 2013 9:20 pm

Streaming Channels in parallel

Post by stdefeber »

I'd like to have streaming channels in parallel.

A picture says more than .....

Image

xtimecomposer reports that I use Channel1 in more than 2 parallel statements.

How else to solve this ? and how to synchronize the outputs ?

Most probably I can run all filters and Delay on 1 core. This is just an experiment.

best regards

Simon


User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am
Contact:

Post by segher »

A channel connects exactly two channel ends. You can just
split channel 1 into two channels, say 1a and 1b, and output
the same data to both. If you output the correct amount of
data everywhere, things are always synchronised.
stdefeber
Active Member
Posts: 35
Joined: Wed Dec 18, 2013 9:20 pm

Post by stdefeber »

How do I split a channel without completely rewriting the I2S master code ?

The I2S master function is called by

Code: Select all

i2s_master( i2s_resource_s ,c_aud ,mclk_bclk_div );
I need to have one ADC channel in and 2 DAC channels out.

So I'd like to call my split function with

Code: Select all

i2s_split(i2s_resource_s, AdcCannel, DacChannel0, DacChannel1, mclk_bclk_div);
or hide the i2s resources and mcl/bclk settings

Code: Select all

i2s_split(AdcCannel, DacChannel0, DacChannel1);
Would it be someting like :

Code: Select all


void i2s_split( streaming chanend AdcChannel,
	        streaming chanend DacChannel0,
	        streaming chanend DacChannel1 )
{
  unsigned mclk_bclk_div = MCLK_FREQ/(SAMP_FREQ * 64);
  audio_hw_init();

  audio_hw_config( SAMP_FREQ ); // Configure the clocking

  i2s_master( i2s_resource_s ,AdcChannel ,mclk_bclk_div );
  i2s_master( i2s_resource_s ,DacChannel0 ,mclk_bclk_div );
  i2s_master( i2s_resource_s ,DacChannel1 ,mclk_bclk_div );

}
User avatar
sethu_jangala
XCore Expert
Posts: 589
Joined: Wed Feb 29, 2012 10:03 am

Post by sethu_jangala »

segher wrote:A channel connects exactly two channel ends. You can just
split channel 1 into two channels, say 1a and 1b, and output
the same data to both. If you output the correct amount of
data everywhere, things are always synchronised.
By splitting the channel he means using two channels and send same data over both the channels as shown below:

Code: Select all

void i2s_master(chanend channel_1a, chanend channel_1b )
{
  unsigned data;
  data = read_i2s_data();
  channel_1a<:data;
  channel_1b<:data;
}
Attachments
unnamed.jpg
(27.23 KiB) Not downloaded yet
unnamed.jpg
(27.23 KiB) Not downloaded yet
stdefeber
Active Member
Posts: 35
Joined: Wed Dec 18, 2013 9:20 pm

Post by stdefeber »

By splitting the channel he means using two channels and send same data over both the channels as shown below:
I do understand that.

However the I2S module found on xcore github has no i2s_read function.
The i2s_master which is present has a different interface.
Being :

Code: Select all

 void i2s_master(r_i2s &r_i2s, streaming chanend c_data, unsigned mclk_bclk_div) 
So i need to get the data from streaming channel c_data and split it again into 2 new channels
and push the new samples from 2 receiving channels in to 1 channel c_data again.

Schematically :

Code: Select all

                AdcChannel0 
            /
c_data -
            \
               AdcChannel1 
and

Code: Select all

DacChannel0
                  \
                   - c_data
                  /
DacChannel1
Would it be something like this ?

Code: Select all


for (i=0; i< NUM_OF_IN_CHANNELS; i++)
{
  c_data :> InputSamples;
  AdcChannel0 <: InputSamples;
  AdcChannel1 <: InputSamples;
}

for (i=0; i< NUM_OF_OUT_CHANNELS; i++)
{
  OutputSamples <: DacChannel0;  
  c_data <: OutputSamples;
  OutputSamples <: DacChannel1;   
  c_data <: OutputSamples;
}


Pops up the next question.
Streaming channels do not seem to require a handshake.

If the process of retrieving new samples is busy for NUM_OF_INPUT_CHANNELS-1, being a left sample and right sample, is it blocking the writing of the output samples ? or not ?
How is this performed on HW ?
User avatar
sethu_jangala
XCore Expert
Posts: 589
Joined: Wed Feb 29, 2012 10:03 am

Post by sethu_jangala »

stdefeber wrote: Would it be something like this ?

Code: Select all


for (i=0; i< NUM_OF_IN_CHANNELS; i++)
{
  c_data :> InputSamples;
  AdcChannel0 <: InputSamples;
  AdcChannel1 <: InputSamples;
}

for (i=0; i< NUM_OF_OUT_CHANNELS; i++)
{
  OutputSamples <: DacChannel0;  
  c_data <: OutputSamples;
  OutputSamples <: DacChannel1;   
  c_data <: OutputSamples;
}

Yes.
stdefeber wrote: Pops up the next question.
Streaming channels do not seem to require a handshake.

If the process of retrieving new samples is busy for NUM_OF_INPUT_CHANNELS-1, being a left sample and right sample, is it blocking the writing of the output samples ? or not ?
How is this performed on HW ?
Streaming channels are same as normal channels except that handshake is not done for each data transfer.

Yes, the code you wrote above blocks until there is some data available in the c_data channel. If you want to make this non blocking, you need to use select statement:

Code: Select all

select
{
   case c_data :> InputSamples:
    AdcChannel0 <: InputSamples;
    AdcChannel1 <: InputSamples;
  break;

  default:
 //write your code here
  break;
}
stdefeber
Active Member
Posts: 35
Joined: Wed Dec 18, 2013 9:20 pm

Post by stdefeber »

Concluding, to split and to combine all channels (AdcChannel0, AdcChannel1, DacChannel0, DacChannel1) to one channel (c_data) again, it would to be something like below.

Code: Select all


select
{
   case c_data :> InputSamples:
    AdcChannel0 <: InputSamples;
    AdcChannel1 <: InputSamples;
  break;

  case DacChannel0 :> OutputSample;
    c_data <: OutputSample; 

  case DacChannel1 :> OutputSample;
    c_data <: OutputSample; 
    break;
 
  default:
    i2s_master(r_i2s &r_i2s, streaming chanend c_data, unsigned mclk_bclk_div);
    break;
}

stdefeber
Active Member
Posts: 35
Joined: Wed Dec 18, 2013 9:20 pm

Post by stdefeber »

Code: Select all

void audio_io_test(streaming chanend AdcChannel0,
                   streaming chanend AdcChannel1,
                   streaming chanend DacChannel0,
                   streaming chanend DacChannel1 )
{
  int InputSample;
  int OutputSample;
  streaming chan c_data;

  while(1)
  {
    select
    {
       case c_data :> InputSample:
         AdcChannel0 <: InputSample;
         AdcChannel1 <: InputSample;
         break;

       case DacChannel0 :> OutputSample;
         c_data <: OutputSample;
         break;

       case DacChannel1 :> OutputSample;
         c_data <: OutputSample;
         break;

       default:
         i2s_source(c_data);
         break;
    }
  }
}

This does not seem to work !
I am getting

Code: Select all

xmake CONFIG=Release all 
Creating dependencies for audio_io_test.xc
Compiling audio_io_test.xc
../src/audio_io_test.xc: In function `audio_io_test':
../src/audio_io_test.xc:57: error: parse error before ';' token
xmake[1]: *** [.build_Release/src/audio_io_test.xc.o] Error 1
xmake: *** [bin/Release/app_loopback.xe] Error 2

Is it due to the triggering on channel ends instead of channels ?
User avatar
Bianco
XCore Expert
Posts: 754
Joined: Thu Dec 10, 2009 6:56 pm
Contact:

Post by Bianco »

I haven't looked into your case specifically but you can declare a chan variable only inside a multicore main function. It needs to be passed exactly to two functions at the place of the chanend argument of those two functions. This instructs the tools that these two functions communicate with each other through a channel and will setup the chanends accordingly. A chan variable is not a real variable, it does not exist after building the application, just an instruction to the tools.
stdefeber
Active Member
Posts: 35
Joined: Wed Dec 18, 2013 9:20 pm

Post by stdefeber »

Forgot to mention, the error is on case 2 and 3 only.

@bianco

Then why am I able to assign channels in case 1 and default statement ?
Post Reply