Page 1 of 1

lib_i2s TDM performance on XS1

Posted: Thu Mar 15, 2018 2:59 pm
by aelder
I'm getting started with the TDM master module in lib_i2s. My first goal is 16 channels in/out @ 96 kHz. This is implemented as 2 TDM data lines, each with 8 channels. If I clock SCLK at 25 MHz, I see that the data signal is not frame aligned correctly between the two TDM data output lines. If I slow the clock down to 48 kHz everything looks to be correct.

My TDM loopback is just dummy code at present

void tdm_loopback(server i2s_callback_if i2s)
{
int32_t samples[32];
while (1) {
select {
case i2s.init(i2s_config_t &?i2s_config, tdm_config_t &?tdm_config):
tdm_config.offset = 0;
tdm_config.sync_len = 1;
tdm_config.channels_per_frame = 8;
break;

case i2s.restart_check() -> i2s_restart_t restart:
restart = I2S_NO_RESTART;
break;

case i2s.receive(size_t index, int32_t sample):
samples[index] = sample;
break;

case i2s.send(size_t index) -> int32_t sample:
//sample = samples[index];
sample = 0xffff0000;
break;
}
}
}


I've read about i2s_frame, but that doesn't run on the XS1. Could I update the TDM code to forward samples to a streaming channel instead of using callbacks? Would that be expected to make a significant difference? Or, would a better approach be to try reduce the number of callbacks in the same manner that i2s_frame does?

Thanks,
Andrew

Re: lib_i2s TDM performance on XS1

Posted: Fri Mar 16, 2018 8:31 pm
by akp
Just wondering why you would clock BCLK at 25MHz? Surely it's 96kHz * 8 * 32 = 24.576MHz? Perhaps you were using a shorthand, just like to be precise on these things.
What I can tell you is I can easily clock in 2 TDM lanes of 96kHz * 8 ch or 192kHz * 4 ch using this code. I am running it on XS2 but it doesn't require any special XS2 stuff so far as I know. So I would expect you could clock out without any problems. What is the exact frame alignment problem you are seeing?

Re: lib_i2s TDM performance on XS1

Posted: Sat Mar 17, 2018 2:14 pm
by aelder
Hi akp,
Thanks for the feedback. The reason for the 25 MHz is that I'm running in the simulator and 25MHz is any easy clock rate to generate. I posted an image (see next post) showing SCLK, FS and 2 dout TDM signals.

The entire code looks like

Code: Select all

// Copyright (c) 2015-2016, XMOS Ltd, All rights reserved
#include <platform.h>
#include <xs1.h>
#include <i2s.h>
#include <stdlib.h>
#include <stdio.h>

out buffered port:32 mclk_outp = XS1_PORT_1E;
out port mclk_outp_clk = XS1_PORT_1A;

out buffered port:32 p_dout[2] = {XS1_PORT_1D, XS1_PORT_1F};
in buffered port:32 p_din[2] = {XS1_PORT_1I, XS1_PORT_1J};
in port p_bclk = XS1_PORT_1O;
out buffered port:32 p_fsync = XS1_PORT_1P;

clock bclk  = XS1_CLKBLK_1;
clock clk25 = XS1_CLKBLK_2;


static void output_mclk(out buffered port:32 p)
{
    while (1)
    {
        p <: 0xaaaaaaaa;
    }
}


void tdm_loopback(server i2s_callback_if i2s)
{
  int32_t samples[32];
  while (1) {
    select {
    case i2s.init(i2s_config_t &?i2s_config, tdm_config_t &?tdm_config):
      tdm_config.offset = 0;
      tdm_config.sync_len = 1;
      tdm_config.channels_per_frame = 8;
      break;

    case i2s.restart_check() -> i2s_restart_t restart:
      restart = I2S_NO_RESTART;
      break;

    case i2s.receive(size_t index, int32_t sample):
      samples[index] = sample;
      break;

    case i2s.send(size_t index) -> int32_t sample:
      //sample = samples[index];
      sample = 0xffff0000;
      break;
    }
  }
}

int main(void)
{
    i2s_callback_if i_i2s;

    configure_clock_rate(clk25, 100, 4);
    configure_out_port(mclk_outp, clk25, 0);
    configure_port_clock_output(mclk_outp, clk25);
    start_clock(clk25);

    configure_clock_src(bclk, p_bclk);
    par {
        tdm_master(i_i2s, p_fsync, p_dout, 2, p_din, 2, bclk);
        tdm_loopback(i_i2s);
        output_mclk(mclk_outp);
    }
    return 0;
}
I load the simulator with a sliceKit with L16 device on it. I then configure the pin loopback in the simulator to loop back port 1A to 1O so the generated bit clock is exposed and feed back in. I realize the bit clock generation code could be done better, but this was my first shot at it. I compile with -O2 -g. In the simulator I set up to view the frame sync, bit clock and 2 dout pins. You can see I'm sending a constant pattern of 0xffff0000 out both TDM pins, so they should be exactly aligned, but they are not.

I'm processing 96000 * 16 * 2 (in/out) = 1,440,000 samples/sec
100,000,000 instructions/sec / 1,440,000 samples/sec = 79 instructions/sample
is this enough for the server callback to operate?

Actually, I'm leaning towards getting rid of the server completely and just doing my own TDM module. It looks to be simpler and simpler and simpler the more I work with the code.

Thanks,
Andrew

Re: lib_i2s TDM performance on XS1

Posted: Sat Mar 17, 2018 2:16 pm
by aelder
Image again
Image