Modifying sc_i2s_slave to be full 32-bit input

New to XMOS and XCore? Get started here.
Post Reply
User avatar
tuck1s
Active Member
Posts: 32
Joined: Thu Sep 25, 2014 1:19 am

Modifying sc_i2s_slave to be full 32-bit input

Post by tuck1s »

The function i2s_slave_loop from the standard github library includes the below code.
I'm only really concerned with i2S input (not output), but I do want the full 32 bits in (in my application, the final 8 bits contain frame-sync info). I've tried various experimental values in the setpt and partout function but it doesn't seem obvious.

How can I modify this to be input-only, but full 32-bit?

Code: Select all

  while (1) {
    int t;

    // wait for WCK edge
    // timestamp this edge
    wck when pinsneq(lr) :> lr @ t;

    // set time for audio data input
    // split SETPT from IN using asm
    // basically a split transaction to allow multichannel timed input
    // input is always "up to" given time
    // I2S_SLAVE sample starts at t + 1, so capture "up to" t + 1 + 23
#pragma loop unroll
    for (int i = 0; i < I2S_SLAVE_NUM_OUT; i++) {
      asm("setpt res[%0], %1" :: "r"(din[i]), "r"(t + 24));
    }

    // output audio data
    // output is always "starting from" given time
    // next I2S_SLAVE sample starts at t + 33, so output at that time
    // must do partial output of 24 bits
    // full 32-bit output would span entire cycle not allowing consecutive SETPT's
#pragma loop unroll
    for (int i = 0; i < I2S_SLAVE_NUM_OUT; i++) {
      signed x = 0;
      c_out :> x;
      partout_timed(dout[i],24,bitrev(x),(t + 33));
    }

    // input audio data
    // port will capture I2S MSb at t + 1 and LSb at t + 24
    // bits 0..7 are older than I2S MSb and hence discard them
    // compiler would insert SETC FULL on DIN input, because it doesn't know about inline SETPT above
    // hence we need inline IN too
#pragma loop unroll
    for (int i = 0; i < I2S_SLAVE_NUM_IN; i++) {
      signed x;
			asm("in %0, res[%1]" : "=r"(x)  : "r"(din[i]));
      c_in <: bitrev(x) << 8;
    }

    frame_counter++;
  }


User avatar
tuck1s
Active Member
Posts: 32
Joined: Thu Sep 25, 2014 1:19 am

Post by tuck1s »

The following now seems to work for a single channel. However it's not giving the expected result for two channels.

The setpt() call looks odd. It's iterating over the number of output channels, but it's applied to the input channels.

Code: Select all

void i2s_slave_loop(in buffered port:32 din[], out buffered port:32 dout[], streaming chanend c_in, streaming chanend c_out, in port wck)
{
    int lr = 0;
    while (1) {
        int t;

        // wait for WCK edge
        // timestamp this edge
        wck when pinsneq(lr) :> lr @ t;

        // set time for audio data input
        // split SETPT from IN using asm
        // basically a split transaction to allow multichannel timed input
        // input is always "up to" given time
        // I2S_SLAVE sample starts at t + 1, so capture "up to" t + 1 + 31 for full 32-bit input
#pragma loop unroll
        for (int i = 0; i < I2S_SLAVE_NUM_OUT; i++) {
          asm("setpt res[%0], %1" :: "r"(din[i]), "r"(t + 31));
        }
        // Output code removed

        // Read full 32-bit value and send to the channel
#pragma loop unroll
        for (int i = 0; i < I2S_SLAVE_NUM_IN; i++) {
          unsigned x;
                asm("in %0, res[%1]" : "=r"(x)  : "r"(din[i]));
                c_in <: bitrev(x);
        }
    }
}
User avatar
tuck1s
Active Member
Posts: 32
Joined: Thu Sep 25, 2014 1:19 am

Post by tuck1s »

I'd appreciate some help from you experienced XCorers please :-)
User avatar
tuck1s
Active Member
Posts: 32
Joined: Thu Sep 25, 2014 1:19 am

Post by tuck1s »

FYI - I've gone back to basics and just written my own I2S code in XC - here:
https://github.com/tuck1s/i2s-32bit-simple

If anyone thinks this is worth putting in the Xcore Github area, please let me know, for the moment it's work-in-progress.
dweeb4
Active Member
Posts: 52
Joined: Mon Jan 19, 2015 12:47 pm

Post by dweeb4 »

Thanks, tucks1, for updating & finalising your problem. I too am interested in similar modifications to I2S format

There don't seem to be many here willing to answer/help or maybe they are not that advanced (maybe the assembler code is the killer?) - I don't know which is correct?
User avatar
tuck1s
Active Member
Posts: 32
Joined: Thu Sep 25, 2014 1:19 am

Post by tuck1s »

dweeb4 wrote:Thanks, tucks1, for updating & finalising your problem. I too am interested in similar modifications to I2S format

There don't seem to be many here willing to answer/help or maybe they are not that advanced (maybe the assembler code is the killer?) - I don't know which is correct?
There are several people around who are very knowledgeable and have helped me .. but (as you'll see from some of my threads) I've often ended up finding my own answers and posting them back. I guess everyone's got a day-job here and sometimes it pays to have to struggle with a problem for a while in terms of knowledge gained.

I'm also trying to 'give back' in my own small way by posting HW and SW (even rough work in progress) on Github.

Regarding assembler - I was pretty surprised to find that I didn't need assembler for that part of my code. "Release mode" with optimisation level -O2 or -O3 gives good performance. A long way down my 'to do' list is to compare the compiler output (using the debugger) with the original i2s assembler code, to try and work out which bits are really needed and how to mod them.
Post Reply