Questions on source code of AN00201: a startkit demo

New to XMOS and XCore? Get started here.
cjf1699
Active Member
Posts: 48
Joined: Fri Mar 16, 2018 2:30 pm

Questions on source code of AN00201: a startkit demo

Post by cjf1699 »

Dear Everyone!
I am a new player on XMOS and recently I am so confused about some of the source code of AN00201,which is a demo running on the startkit ,looping an audio input back to an audio output with a biquad filter and a modulating gain applied to the signal. They belong to the i2s_handler funtion:

Image

1.what does the "channel exchange"mean?
2.why "2" inside the "for" loop? Is it due to the "biquad" filter or there are 2 channels in total? I prefer the former reason but I want to ensure it.
3.and last , I have to admit that I don't really understand what is the "for" loop inside the "if" condition is doing exactly.

Thank you a lot! and the following is entire code of the i2s_handler function:

Code: Select all

[[distributable]]
void i2s_handler(server i2s_callback_if i2s,
                 client i2c_master_if i2c,
                 client output_gpio_if clock_select,
                 client output_gpio_if codec_reset,
                 streaming chanend c_dsp)
{
  int32_t in_samps[2] = {0};
  int32_t out_samps[2] = {0};
  while (1) {
    select {
    case i2s.init(i2s_config_t &?i2s_config, tdm_config_t &?tdm_config):
      /* Set CODEC in reset */
      codec_reset.output(0);

      /* Set master clock select appropriately */
      if ((SAMPLE_FREQUENCY % 22050) == 0) {
        clock_select.output(0);
      }else {
        clock_select.output(1);
      }

      /* Hold in reset for 2ms while waiting for MCLK to stabilise */
      delay_milliseconds(2);

      /* CODEC out of reset */
      codec_reset.output(1);

      cs4270_configure(i2c, CODEC_I2C_DEVICE_ADDR,
                       SAMPLE_FREQUENCY, MASTER_CLOCK_FREQUENCY,
                       CODEC_IS_I2S_SLAVE);

      /* Configure the I2S bus */
      i2s_config.mode = I2S_MODE_I2S;
      i2s_config.mclk_bclk_ratio = (MASTER_CLOCK_FREQUENCY/SAMPLE_FREQUENCY)/64;
      break;

    case i2s.restart_check() -> i2s_restart_t restart:
      // This application never restarts the I2S bus
      restart = I2S_NO_RESTART;
      break;

    case i2s.receive(size_t index, int32_t sample):
      if (index == 0) {
        for (size_t i = 0; i < 2; i++) {
          c_dsp <: in_samps[i];
          c_dsp :> out_samps[i];
        }
      }
      in_samps[index] = sample;
      break;

    case i2s.send(size_t index) -> int32_t sample:
      sample = out_samps[index];
      break; // end of select
    }
  }
};


User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Hi.

1) Please review the documentation for this project which is fairly in depth and is posted here:

https://www.xmos.com/support/appnotes/AN00201

2)
what does the "channel exchange"mean?
Channels is a method used on XMOS processors to allow for streaming of data to / from another processor core. The processor (XS1 type) onboard the StartKit offers a single user tile with 8 logical processor cores. The 2nd tile on this same CPU is hard-coded to act like the JTAG programmer and debugger. The more recent XCORE-200 processors offer additional features over the XS1 type.

https://www.xmos.com/published/how-stre ... er-channel

scroll down this webpage till you see the details on Channel Communication:

https://www.xmos.com/published/xc-concurrency

http://www.xcore.com/viewtopic.php?t=1787


3) for your 2nd and 3rd question:


Image
cjf1699
Active Member
Posts: 48
Joined: Fri Mar 16, 2018 2:30 pm

Post by cjf1699 »

Hi,
I'm sorry but I don't think that you have given an answer to what I asked. I have reviewed the app note AN00201.pdf and didn't found any explanation and that's why I made a topic here .And.. you didn't answer my 2nd and 3rd questions? for I only saw a picture with nothing attached to it.
And another question ,which is related to the last 2 ones:
where does the variable "index" change? perhaps in the callback function "receive" ,if so , how can I find the definition of it? and where if not? I tried to right click on its name and click on the "open the declaration" but it can't move, nothing happened. And incredibly,when I found the definition of the function "i2s_master",there's nothing in it! It's empty as the following:

Code: Select all

void i2s_master(client i2s_callback_if i2s_i,
                out buffered port:32 (&?p_dout)[num_out],
                static const size_t num_out,
                in buffered port:32 (&?p_din)[num_in],
                static const size_t num_in,
                out buffered port:32 p_bclk,
                out buffered port:32 p_lrclk,
                clock bclk,
                const clock mclk)
{}
I can't understand all the above and the app not doesn't give an answer at all. And I 'm sorry for putting up so many questions for I 'm really anxious and confused.
Thanks a lot!
cjf
User avatar
akp
XCore Expert
Posts: 578
Joined: Thu Nov 26, 2015 11:47 pm

Post by akp »

Yes the 2 is because it is stereo. index is a parameter in the receive callback from the i2s_master that tells you what audio channel index the received sample is from (i.e. 0 for left and 1 for right in stereo). Likewise the send callback tells you the channel index the i2s_master wants a new sample for. You will have to dig into the references mon2 posted and get familiar with the xc syntax. Advise you to try to get familiar with the simulator too, it will be helpful for adding code especially hardware interfaces.
cjf1699
Active Member
Posts: 48
Joined: Fri Mar 16, 2018 2:30 pm

Post by cjf1699 »

akp wrote:Yes the 2 is because it is stereo. index is a parameter in the receive callback from the i2s_master that tells you what audio channel index the received sample is from (i.e. 0 for left and 1 for right in stereo). Likewise the send callback tells you the channel index the i2s_master wants a new sample for. You will have to dig into the references mon2 posted and get familiar with the xc syntax. Advise you to try to get familiar with the simulator too, it will be helpful for adding code especially hardware interfaces.
Hi,thank you for your answer. I have reviewed the related materials but yet I don't understand about some points. For example, in the i2s_handler function of AN00201,

Code: Select all

case i2s.receive(size_t index, int32_t sample):
      if (index == 0) {
        for (size_t i = 0; i < 2; i++) {
          c_dsp <: in_samps[i];
          c_dsp :> out_samps[i];
        }
      }
      in_samps[index] = sample;
      break;
As we all know, the method "receive" is called by the i2s_master when a new sample is read in by the I2S bus. However,there are two kinds of "being read in". One is the "raw" samples which haven't been processed by the function "audio_effect", and the other kind is the processed samples. How can the "receive" function distinguish them? And the two lines of code inside the for loop, the first line outputs the data to the streaming channel and at once read the same data(same?) from the channel .Why not using out_samps = in_sampls directly? Or am I not understanding what this step is actually doing?
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

the first line outputs the data to the streaming channel and at once read the same data(same?) from the channel
No.

Code: Select all

c_dsp <: in_samps[i];
First line will stream out (output) the data to the other end of the streaming channel.

Code: Select all

c_dsp :> out_samps[i];
Next line will now read back (input) the processed data from the streaming channel. These 2 actions are executed sequentially so follow in this order.
Why not using out_samps = in_sampls directly?


With the above, you are only assigning or copying the array value(s) and no audio processing is being performed. The c_dsp streaming channel performs the audio processing work using 2 endpoints.

Maybe some confusion about parallel processing of the XMOS CPU? There is a lot to read on this forum and XMOS.com articles but if you use the par construct then the routines inside this block will run in parallel. However, once you launch the parallel routine, the code inside that routine will execute sequentially and in parallel to another code run. Best to consider as logical CPUs that are requested to run a chunk of code. XMOS offers many permutations of designs which vary with 4-8 processor cores per tile and then there are multiple tiles on a physical device. So respectively, 4-8 threads could run in parallel, if coded to do so.
cjf1699
Active Member
Posts: 48
Joined: Fri Mar 16, 2018 2:30 pm

Post by cjf1699 »

mon2 wrote:
the first line outputs the data to the streaming channel and at once read the same data(same?) from the channel
No.

Code: Select all

c_dsp <: in_samps[i];
First line will stream out (output) the data to the other end of the streaming channel.

Code: Select all

c_dsp :> out_samps[i];
Next line will now read back (input) the processed data from the streaming channel. These 2 actions are executed sequentially so follow in this order.
Why not using out_samps = in_sampls directly?


With the above, you are only assigning or copying the array value(s) and no audio processing is being performed. The c_dsp streaming channel performs the audio processing work using 2 endpoints.

Maybe some confusion about parallel processing of the XMOS CPU? There is a lot to read on this forum and XMOS.com articles but if you use the par construct then the routines inside this block will run in parallel. However, once you launch the parallel routine, the code inside that routine will execute sequentially and in parallel to another code run. Best to consider as logical CPUs that are requested to run a chunk of code. XMOS offers many permutations of designs which vary with 4-8 processor cores per tile and then there are multiple tiles on a physical device. So respectively, 4-8 threads could run in parallel, if coded to do so.


Dear mon2,
Thank you very much for your answer. I have forgotten that the streaming channel has two endpoints at work. You mean that one endpoint receives the unprocessed data from in_samps[] and the other sends the processed data to the out_samps[]?
I do use the par construct to finish my work. I am an undergraduate student in China and I am working on my graduation project. My goal is to realize an Active noise cancellation headphone using a normal headphone, 4 microphones,and a XMOS board(xcore-200 Multichannel Audio Platform). I will run on the board the FX-LMS algorithm ,which will do the audio processing to the data collected by the microphones. I have done my 1st edition code, referring to the examples :AN00201 and AN00162, and I am debugging at the moment.

Now, I have 4 mic ,two put outside the headphone(collecting the noise) and two inside(collecting the error of the primary noise and the anti-noise).So I have 4 input channels but only two output channels, because none but the anti-noise ,which is a stereo, should be played by the speaker of the headphone. In this case, how should I code in this section? At first, I coded like this:

Code: Select all

if (index == 0) {
              for (size_t i = 0; i < 4; i++) {
                 c_dsp <: in_samps[i];
                 
                 c_dsp :> out_samps[i];
                
              }
          }
But yesterday I read in the forum that some block will happen if the streaming channel is filled with more than two "int_32" data, i.e. it can't hold more than 8 bytes data at the same time. And exactly I found that my project would stop somewhere when I was debugging, so I thought of that reason and changed this way:

Code: Select all

if (index == 0) {
                 for (size_t i = 0; i < 4; i++) {
                          c_dsp <: in_samps[i];
                          if(i <= 1){
                              c_dsp :> out_samps[i];
                          }
                 }
          }
Do you think it's right? And then I run my code but it didn't work .The speaker only made a buzz . Now the problem is that I don't know whether the above codes or my algorithm is wrong .
And one more problem, is that the "Debug" function can't be used normally. Always have messages like this :".gdbinit" file not found .It isn't a file or directory. And the "step into""step over" button are all grey can't be clicked. So I used "printf" to print the value of some variables on the console. But when doing this way, all the hardware don't work. I mean the mic can't collect sounds and the speaker can't play sounds. I have proved this by running the example: AN00162. How did it come?
Thanks again!!
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Hi. Interesting project.

1) Channels are blocking but do not believe this will be a factor for your audio processing. Not an audio developer so cannot be sure but keep in mind that you have 60-100 MIPS per core
* (MIPS value varies with the # of active cores / threads that are being ran on the single tile) - you should not be concerned on this "limitation"

2) What platform are you using for this development? Consider to fix up your setup so it is working correctly so you can continue to work with the posted sample code. Otherwise you may break something else and waste valuable time.

You cannot use printf for real time debugging. The use of standard printf is blocking and this will hinder your progress for real time processing. Instead, review the following alternatives:

Debug with printf in real-time:

https://www.xmos.com/support/tools/docu ... ion=X1093A

XSCOPE:

https://www.xmos.com/support/appnotes/AN00196

Audio demo:

https://www.youtube.com/watch?v=4FxB8RBPtKU

3) Similar project here but not sure if the full source code is supplied:

http://www.xmos.com/products/voice/voca ... -stereoavs

Perhaps next time in China, want to visit the mega electronics parts mall we see on Youtube in Shenzhen. Nice!
cjf1699
Active Member
Posts: 48
Joined: Fri Mar 16, 2018 2:30 pm

Post by cjf1699 »

mon2 wrote:Hi. Interesting project.

1) Channels are blocking but do not believe this will be a factor for your audio processing. Not an audio developer so cannot be sure but keep in mind that you have 60-100 MIPS per core
* (MIPS value varies with the # of active cores / threads that are being ran on the single tile) - you should not be concerned on this "limitation"

2) What platform are you using for this development? Consider to fix up your setup so it is working correctly so you can continue to work with the posted sample code. Otherwise you may break something else and waste valuable time.

You cannot use printf for real time debugging. The use of standard printf is blocking and this will hinder your progress for real time processing. Instead, review the following alternatives:

Debug with printf in real-time:

https://www.xmos.com/support/tools/docu ... ion=X1093A

XSCOPE:

https://www.xmos.com/support/appnotes/AN00196

Audio demo:

https://www.youtube.com/watch?v=4FxB8RBPtKU

3) Similar project here but not sure if the full source code is supplied:

http://www.xmos.com/products/voice/voca ... -stereoavs

Perhaps next time in China, want to visit the mega electronics parts mall we see on Youtube in Shenzhen. Nice!
Hi ,I entered here and did what it said.
Debug with printf in real-time:

https://www.xmos.com/support/tools/docu ... ion=X1093A

It said that in order to use xCOPE, the option "-fxcope" must be added to the variable "XCC_FLAG" in the makefile. I did ,but when I built the project, it still gave errors:
Description Resource Path Location Type
Undefined reference to '__sodEnd' (using xScope without specifying -fxscope?) ANC_headphone_V1.0 C/C++ Problem
Description Resource Path Location Type
Undefined reference to '__sodFlag' (using xScope without specifying -fxscope?) ANC_headphone_V1.0 C/C++ Problem
I have already specified it and I don't know why. I am working on the xCORE-200 Multichannel Audio Platform. I tried to clean the project and rebuild it ,but didn't work.
I also run the AN00196,which shows how to use xSCOPE,but I didn't see the generated sine wave as the note said,either... Maybe I missed to set something ?
You are right I must fix up my setup as soon as possible, and that's why I am eager to learn to debug ,without which I can't even know the values of the variable and what to do next to fix the project. Thanks!
Last edited by cjf1699 on Sun Apr 01, 2018 1:11 pm, edited 1 time in total.
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Are you on Linux or Windows? Which IDE toolchain version from XMOS is installed?
Post Reply