Page 1 of 1

I2S interfacing with DSP4You DG

Posted: Mon May 09, 2016 8:33 am
by tonsmets
Hi all,

I'm currently working on a project where I want to connect the Raspberry Pi I2S bus to the DSP4YOU DG hardware. Additional info found here: http://www.dsp4you.com/products/avb-oem-series/avb-dg

I've tried a lot of different things but I'm unable to get the Raspberry Pi to use the external clock signals as the DG is only capable of being master (default config on this hardware). I hooked it up as follows:
Image

I then configured the CLKM and FSM bits in the MODE_A registers to be "slave" by setting them to 1. The code I used is based upon the code I found in this topic: viewtopic.php?f=44&t=8496&p=104359

The default config of the DSP4YOU DG should be sufficient for this connection. 24.576MHz clock and 48kHz sample rate is pretty common. MCLK = 512* Fs (LRCLK). There is also a System Clock available from the DSP4YOU DG hardware that runs at 3Mhz but I don't think I need to use it.

Some things I'm uncertain about:
- The clock settings of the Raspberry Pi itself (*clk+0x26 and *clk+0x27)
- The FLEN and FSLEN (now configured on 32bit (FLEN) and 16 bit (FSLEN) with FTXP set to 1 to get 2 16 bit channels in 1 32 bit word
- The SYNC bit, as this gives the word "strange" in the first if-statement in the code after setting the SYNC bit high

Do I overlook certain things or does anybody have an idea to help me further? I used my logic analyzer (with the Salae Logic software) to verify some things but since it's only able to sample at a max rate of 24MHz I can't confirm the clock as it gives me about 571.4kHz (with a +/- 3% variation). (see picture)
Image

Thanks in advance!

Re: I2S interfacing with DSP4You DG

Posted: Mon May 09, 2016 3:59 pm
by chuckkh
Hi there.

I'm not sure if this will solve your problem, but GPIO 18 input should be bit clock, not 24.576 MHz master clock. The master clock seems to be something that many audio chips need for their internal audio processing, but it is not considered part of the I2S standard; it doesn't need to be communicated to the Pi. There should be a bit clock, though, which, if FLEN is 32, will be 1.536 MHz, if i'm not mistaken.
I'm also seeing very bizarre behavior with I2S timing. I've verified my connections and the settings of my audio codec at least 50 times. It does output sound, but around 2.6666 times too fast, and I can't figure out any explanation. I believe there is also some arbitrary or empty info being passed to fill in, because I hear periodic crackling that changes regularly. I have attempted to dive into the ALSA drivers, but they were written by many different people over a long time and with very little documentation, and I think everyone else who was having problems like mine has either fixed them or given up.

You linked to the big I2S thread, but not the particular post. You can link to a particular post with the "permalink" button. Did you use, by any chance, the my_loader.c solution, with the generic simple card? That's what I'm using.

I don't know if it'll solve your problem completely, but you definitely do not need to send any 24.576 clock to the Pi in slave mode. Oh, and I also had problems with current consumption while trying to use an external crystal oscillator for master clock; my 2.1 amp power source couldn't run that and Wifi at the same time.

-Chuckk

Re: I2S interfacing with DSP4You DG

Posted: Tue May 10, 2016 6:27 am
by tonsmets
Hi Chuckkh!

Thanks for your reply, could you explain the calculation you did for the clock speed? :) I didn't know the master clock wasn't needed in this case. I will try some other clock signal today. I'm also starting to wonder now if the Pi needs to be clock slave at all, or that only syncing on the LRCLK would be enough.

The post I used as a base for my code is this one: viewtopic.php?p=103325#p103325

The fact that I2S on the Pi is often unpredictable also occured to me. I will work on this info today and keep this topic up to date. Any other thoughts on this are still welcome!

Re: I2S interfacing with DSP4You DG

Posted: Tue May 10, 2016 7:55 am
by chuckkh
I found it much simpler to use RPi as a timing slave, as long as your codec can do that. It's not hard to output a 9.6 MHz or lower clock from GPIO using wiringpi or pigpio. I can't find my code right now as my Pi is on the shelf, but you only have to set the mode of the one GPIO pin that can be used as GCLOCK or some such, and set its frequency. That, for me, is the master clock input for my codec. Then I set the codec to divide the 1. bit clock and 2. LR (frame) clock from the 0. master clock, and send them back to the Pi.
I tried using an external crystal oscillator of 12.288 MHz, because this would be more accurate timing for 48000 samples/second, but it draws too much current and it didn't fix the major timing problem I have, so I went back. Either way, then, for 44100 samples at 16 bits, you would set the frame clock (also LR clock) to 44100 Hz. When it's low, it sends one channel, high, the other channel. And the bit clock goes at divisions of that small enough to fit in enough bits. For 16 bits per channel, most likely you'd use 32x the frame clock. So, e.g., bit clock could be 1,411,200 (44100*32) per second and frame clock 44100 per second.
If you want 24-bit sound, I think most people use bit clock = 64* frame clock, e.g. 2,822,400 (44100*64) per second, frame clock still 44100. Essentially, 44100 times per second (or 48000 if you prefer), the sender sends 16/24/32 bits of info for left and 16/24/32 for right, and the frame/LR clock and bit clock are used to tell the receiver when to check the value of the incoming data.
For whatever reason, some prefer to use 64 bit clocks per frame clock to send the 48 bits of 24-bit stereo, and the remaining bits as zeroes. There are also different methods, then, of aligning the bits inside that setup, but only really a couple.
I hope I'm not just telling you what you already know.

What I'm having trouble with is that ALSA has an ambitious System-on-Chip section intended to generalize all of this for any different audio chip and any different controller; but applying it is pretty complicated if those drivers don't all exist already, something I would want to do if I were preparing to sell DACs by the hundreds. I have come to the conclusion that I must skip ALSA completely and program the RPi hardware on a lower level just to send my bits in the format I want them, nothing else. I don't know if or when I'll succeed.....

-Chuckk

Re: I2S interfacing with DSP4You DG

Posted: Tue May 10, 2016 8:05 am
by tonsmets
Thanks again for your reply!

I have been thinking what to do now. The DSP4YOU hardware is master and outputs a 3.072MHz System Clock that I could use. It accepts 16 or 24 bit data input per channel. When using 24 bits, this corresponds to the 64 * Fs calculation you provided. 64 * 48KHz = 3.072MHz. Maybe the PDF of this hardware (page 7) gives you some more background info on my problem.

If I'm correct, I could use the 3.072MHz System Clock from my DSP hardware I2S bus as the bitclock for the Pi, right?

Could you explain what you meant with using the Raspberry as a timing slave?

Re: I2S interfacing with DSP4You DG

Posted: Tue May 10, 2016 9:34 pm
by chuckkh
Yup, that's what the sheet says. What they call system clock is what I was calling bit clock, and it looks like it's fixed to 64 x the sampling frequency. You can probably change the sample rate and other settings, it mentions that but I didn't see instructions.

By slave, I meant that the RPi can be set up to follow external system and frame clocks (slave), or to output them based on one clock or another (master). It's a moot point for your hardware, because it can only work as master, so if you're trying to communicate between it and a RPi, the RPi will be set as timing slave. That shouldn't be a problem. I'm trying to do the same thing.
I can't, however, tell you how to work the software side of it as I haven't worked it out myself yet. I'm forcing myself to slowly read through this whole thread and gradually picking up a lot of the theory behind what's been done. Sloooowly!


-Chuckk

Re: I2S interfacing with DSP4You DG

Posted: Wed May 11, 2016 6:40 am
by tonsmets
Hi chuckkh,

Thanks again for your reply! I'm going to implement all the new information into my software today. What I didn't know was that the I2S protocol handles a lot of stuff itself. I can only have 16 to 24 bits of data (firmware limitation of DSP4YOU DG) but since the bitclock runs at 3.072MHz (32 bits per channel because 32 * 2 * 48kHz = 3.072MHz) I can just fill the first 16 to 24 bits of a 32 bit word with my data and pad the remaining bits with zeros. The I2S interface on the DSP4YOU DG handles all the rest.

Again, thanks for your help and I'll keep this topic up to date!

Re: I2S interfacing with DSP4You DG

Posted: Thu May 12, 2016 11:44 am
by tonsmets
Okay, I fixed it... After wasting about 3 days trying to find the mistakes I made, I read something in chuckkh's topic here about bad timings on the Pi 3. I grabbed a Pi B+ and everything magically started working! The Pi now uses the 3.072MHz clock and the 48kHz LRCLOCK from the DSP4YOU DG unit without any problems. Below is the code for all the settings.

I don't know exactly what the issue was with the Pi 3 but using an older version fixed it and I don't feel like investigating the exact cause of the problems.

Code: Select all

    setup_io();
    printf("Setting GPIO regs to alt0\n");
    for (int g=18; g<=21; g++)
    {
        INP_GPIO(g);
        SET_GPIO_ALT(g,0);
    }
 
    printf("Disabling I2S clock\n");
    *(clk+0x26) = 0x5A000000;
    *(clk+0x27) = 0x5A000000;
    usleep(10);

    printf("Configure I2S clock\n");
    *(clk+0x26) = 0x5A000001;
    *(clk+0x27) = 0x5A000000 | 3<<12 | 1<<9 | 1<<8;

    usleep(10);
    printf("Enabling I2S clock\n");
    *(clk+0x26) = 0x5A000011;

    // disable I2S so we can modify the regs
    printf("Disable I2S\n");
    *(i2s+0) &= ~(1 << 24);
    usleep(100);
    *(i2s+0) = 0;
    usleep(100);

    clear_fifo();

    // set register settings
    // --> enable Channel1 & Channel2 with 32bit width
    printf("Setting TX channel settings\n");
    *(i2s+4) = 1 << 31 | 1<<30 | 0<<16 | 1 << 15 | 1<<14 | 0;
    printf("%32x\n", (unsigned int)*(i2s+4));
    // --> frame width 63+1 bit
    *(i2s+2) = 63<<10;

    // Frame sync length to 32 clocks
    *(i2s+2) |= 32<<0;

    // Set FSM to 1 (slave)
    *(i2s+2) |= (1<<21);

    // Set FSI to 0
    *(i2s+2) &= ~(1<<20);

    // Set CLKM to 1 (slave)
    *(i2s+2) |= (1<<23);

    // Set CLKI to 0
    *(i2s+2) &= ~(1<<22);

    // Set FTXP to 0
    *(i2s+2) &= ~(1<<24);

    // Set FRXP to 0
    *(i2s+2) &= ~(1<<25);

    // --> disable STBY 
    printf("disabling standby\n");
    *(i2s+0) |= 1<<25;
    usleep(50);

    // enable I2S
    *(i2s+0) |= 0x01;

    // enable transmission
    *(i2s+0) |= 0x04;

    // --> ENABLE SYNC bit
    printf("setting sync bit high\n");
    *(i2s+0) |= 1<<24;

    if (*(i2s+0) & 1<<24) {
        printf("SYNC bit high, strange.\n");
    } else {
        printf("SYNC bit low, as expected.\n");
    }

    usleep(3);

    if (*(i2s+0) & 1<<24) {
        printf("SYNC bit high, as expected.\n");
    } else {
        printf("SYNC bit low, strange.\n");
    }

Re: I2S interfacing with DSP4You DG

Posted: Mon May 16, 2016 4:36 am
by chuckkh
Unbelievable. That is infuriating. I've wasted far more than 3 days with this piece of junk. Congrats on getting it to work!
Chuckk