lib_i2s TDM performance on XS1

Technical questions regarding the XTC tools and programming with XMOS.
Post Reply
aelder
Active Member
Posts: 37
Joined: Mon Sep 24, 2012 1:45 pm

lib_i2s TDM performance on XS1

Post 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


User avatar
akp
XCore Expert
Posts: 578
Joined: Thu Nov 26, 2015 11:47 pm

Post 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?
aelder
Active Member
Posts: 37
Joined: Mon Sep 24, 2012 1:45 pm

Post 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
Last edited by aelder on Sat Mar 17, 2018 2:17 pm, edited 1 time in total.
aelder
Active Member
Posts: 37
Joined: Mon Sep 24, 2012 1:45 pm

Post by aelder »

Image again
Image
Post Reply