philpoole
Posts: 69
Joined: Mon Oct 29, 2012 5:09 pm

Re: I2S: Anyone got it running?

Thu Nov 08, 2012 9:52 am

That's not the bug, that's a typo in the post it's normally one, I had tried both states.
When trying all options, the code is often quite dynamic. As I mentioned, the PCM side seems to be okay (when that bit is set) I can see INTSTC_A changing.

I originally had static handlers (I basically copied the function declaration from spi-bcm2708.c), but tried reversing this to see if it made any difference (it shouldn't because request_irq() is sent a pointer to a function with known parameters). Again, I was at the 'trying anything' stage.

I think I'll go away and have a look at the irq stuff again in the kernel. I may be some time...

andrewg
Posts: 2
Joined: Fri Nov 09, 2012 9:45 am

Re: I2S: Anyone got it running?

Fri Nov 09, 2012 9:58 am

Thanks everyone for your efforts so far as this is something I'd like to use. I am a hardware not software guy so I'm not sure if this is helpful or not. Some modern DAC chips (e.g. PCM5102) can generate (derive) the master clock from one of the slower clocks. The goal of this is to reduce the EMC issues in a design (caused by routing fast clocks around the circuit).

However it occurred to me that it might take less system resources, or make your lives easier in general not to drive this line? I have no idea if this helps or not with what your trying to do, just thought I'd raise the possibility.

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Fri Nov 09, 2012 5:04 pm

PCM51xx chips do have the internal SCLK->MCLK PLL but it degrades still performance when compared to using clean MCLK. Old DAC's like TDA1541A and TDA1543 don't need system clock at all, they are synced to SCLK. Also the (obsolete but still available) Wavefront DAC AL1201G has internal PLL and syncs to LRCLK (http://www.wavefrontsemi.com/index.php?products). Anyway, sonically best option is to use local master clock to sync codec / DAC+ADC and run RPi in slave mode. No need for routing the MCLK to RPi.

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Fri Nov 16, 2012 9:19 pm

It starts looking unlikely that the I2S FIFO IRQ's can be fired, don't know why. For some reason the TXW bit ("TXW: TX Write Interrupt Status / Clear: This bit indicates an interrupt occurred on TX Write. Writing 1 to this bit clears it. Writing 0 has no effect.") is stuck, it can not be cleared, neither the interrupt handler will be called. I don't have DAC or codec connected, but the interface should be working fine in master mode. So it seems better to try the DMA alternative next.

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Sun Nov 18, 2012 9:38 pm

Haven't got enough time to study the problem with I2S FIFO interrupts further, but I can see from /proc/interrupts that IRQ 81 (which is the I2S IRQ defined in modules below) is triggered every time I run (insmod) the kernel module (from the code in this thread).

Code: Select all

./arch/arm/mach-bcm2708/include/mach/irqs.h:#define IRQ_I2SPCM            (IRQ_ARMCTRL_START + INTERRUPT_I2SPCM)
./arch/arm/mach-bcm2708/include/mach/irqs.h:#define FIQ_I2SPCM            (FIQ_START+INTERRUPT_I2SPCM)
./arch/arm/mach-bcm2708/include/mach/platform.h:#define INTERRUPT_I2SPCM               (ARM_IRQ0_BASE + 17)

It seems that there are some problems mapping the IRQ 81 to the IRQ 55 in ARMCTRL module in ./arch/arm/mach-bcm2708/armctrl.c , maybe someone who maintains this code could tell where's the problem. I think the case is similar to GPIO interrupt handling, so maybe the I2S interrupt should be set similar way to the GPIO driver at arch/arm/mach-bcm2708/bcm2708_gpio.c, right?

philpoole
Posts: 69
Joined: Mon Oct 29, 2012 5:09 pm

Re: I2S: Anyone got it running?

Mon Nov 19, 2012 1:20 pm

Interesting.
I had taken a break from this when I discovered it should've been irq 81, and discovered that enabling that IRQ forced the machine to hang.
How are you finding IRQ 81 firing from /proc/interrupts - unless you're successfully enabling it?

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Mon Nov 19, 2012 2:59 pm

I guess it's armctrl's own IRQ handler and kind of dynamic one and comes visible after you have enabled the interrupts for IRQ 55 (in the interrupt controller registers) and receives an IRQ after FIFO is emptied enough (don't have anything connected though). I'm just wondering if it was possible to register your own handler to that IRQ number using setup_irq function instead of request_irq. It seems that armctrl is no willing to share the interrupt and hangs, but if I reconfigured just the irqaction it might work (just a theory so far). The arch/arm/mach-bcm2708/bcm2708.c is also missing I2S_BASE and related information from iotables config.

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Mon Nov 19, 2012 8:40 pm

Couldn't get the thing working, guess it's my turn leave now. Hopefully the RPi kernel hackers get it (the I2S/PCM interface) working some day.

philpoole
Posts: 69
Joined: Mon Oct 29, 2012 5:09 pm

Re: I2S: Anyone got it running?

Tue Nov 20, 2012 7:37 am

Not just me then.
I tried using setup_irq() yesterday - as per gpio code (and using stubs for the mask and unmask functions). No luck. The only positive was that I could use any IRQ number, 17, 55, 81, etc, and none of them crashed the box! So either that's a good thing or it's not working at all.
Sorry, I need a break from this too.

Here's what I currently have. Enjoy!

Code: Select all

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");



#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/hrtimer.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>

#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <mach/platform.h>
#include <mach/gpio.h>



//IO stuff
#include <linux/ioport.h>
#include <asm/io.h>

#define BCM2708_PERI_BASE        0x20000000

#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#define I2S_BASE                (BCM2708_PERI_BASE + 0x203000) /* GPIO controller */
#define CLOCK_BASE               (BCM2708_PERI_BASE + 0x101000) /* Clocks */
#define INT_BASE                (BCM2708_PERI_BASE + 0x00B200) //not actually the base, but heh!


#define CS_A     0
#define FIFO_A   1
#define MODE_A   2
#define RXC_A    3
#define TXC_A    4
#define DREQ_A   5
#define INTEN_A  6
#define INTSTC_A 7
#define GRAY     8

const char *i2s_register_name[] = {"CS_A", "FIFO_A", "MODE_A", "RXC_A", "TXC_A", "DREQ_A", "INTEN_A", "INTSTC_A", "GRAY"};

unsigned int *i2s_registers;
unsigned int *gpio;
unsigned int *clock_registers;
unsigned int *int_registers;

static int isr_count =0;

static irqreturn_t i2s_interrupt_handler(int irq, void *dev_id)
{
   printk(KERN_EMERG "ISR!\n");
   isr_count++;
   *(i2s_registers+INTSTC_A)=0x0f; //set the bit to clear the interrupt
    generic_handle_irq(irq);
    return IRQ_HANDLED;
}

static void bcm2708_i2s_irq_unmask(struct irq_data *d)
{
    printk(KERN_EMERG "IRQ UNMASK\n");
}
static void bcm2708_i2s_irq_mask(struct irq_data *d)
{
    printk(KERN_EMERG "IRQ MASK\n");
}

static int bcm2708_i2s_irq_set_type(struct irq_data *d, unsigned type)
{
    printk(KERN_EMERG "SET TYPE\n");   
    return 0;
}

static struct irq_chip bcm2708_i2s_irqchip = {
	.name = "I2S",
	.irq_enable = bcm2708_i2s_irq_unmask,
	.irq_disable = bcm2708_i2s_irq_mask,
	.irq_unmask = bcm2708_i2s_irq_unmask,
	.irq_mask = bcm2708_i2s_irq_mask,
	.irq_set_type = bcm2708_i2s_irq_set_type,
};

#define IRQ_TO_USE 55  
//81

static struct irqaction bcm2708_i2s_irq = {
	.name = "BCM2708 I2S handler",
	//.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
       // .flags = IRQF_TRIGGER_HIGH,  IRQF_VALID | 
        .flags = IRQF_TRIGGER_HIGH|IRQF_SHARED,
	.handler = i2s_interrupt_handler,
};


static int hello_init(void)
{

        int i=0, err=0;
	int pin;
        unsigned int temp;
        printk(KERN_EMERG "Hello, world\n");

        irq_set_chip(IRQ_TO_USE, &bcm2708_i2s_irqchip);

        err = setup_irq(IRQ_TO_USE, &bcm2708_i2s_irq);
        if(err)
           printk(KERN_EMERG "COMPUTER SAYS NO INTS\n");
        else
           printk(KERN_EMERG "INTERRUPTS AHOY!\n");


#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

	gpio = ioremap(GPIO_BASE, SZ_16K);

	/* SPI is on GPIO 7..11 */
	for (pin = 28; pin <= 31; pin++) {
		INP_GPIO(pin);		/* set mode to GPIO input first */
		SET_GPIO_ALT(pin, 2);	/* set mode to ALT 0 */
	}

#undef INP_GPIO
#undef SET_GPIO_ALT

    i2s_registers = ioremap(I2S_BASE, 128);
    clock_registers = ioremap(CLOCK_BASE, 32);
    //currently, I don't believe we need to enable the interrupt line, but try it anyway
    int_registers = ioremap(INT_BASE, 128);
    *(int_registers+5) |= 1<<23;
      iounmap(int_registers);  
    printk(KERN_EMERG "Disabling I2S clock\n");
    *(clock_registers+0x26) = 0x5A000000;
    *(clock_registers+0x27) = 0x5A000000;
     
    udelay(10);

    printk(KERN_EMERG "Configure I2S clock\n");
    *(clock_registers+0x26) = 0x5A000001;

    *(clock_registers+0x27) = 0x5A006CD7; //a calculated guess, hopefully about 6.8, but seems out somewhat (I want 64*44100 = 2822400 Hz)
    udelay(10);
    printk(KERN_EMERG "Enabling I2S clock\n");
    *(clock_registers+0x26) = 0x5A000011;

    // disable I2S so we can modify the regs
    printk(KERN_EMERG "Disable I2S\n");
   // *(i2s_registers+CS_A) &= ~(1<<24);
    udelay(100);
    //*(i2s_registers+CS_A) = 0;
    udelay(100);

    *(i2s_registers+INTSTC_A) = 0x000f;// clear status bits

   
    printk(KERN_EMERG "Clearing FIFOs\n");
    *(i2s_registers+CS_A) |= 1<<3 | 1<<4 | 3<<5; // clear TX FIFO
    udelay(100);
//en able interrupts

   *(i2s_registers+INTEN_A) = 0x01;
   
    *(i2s_registers+INTSTC_A) = 0x000f;// clear status bits
 
    udelay(100);
    // set register settings
    // --> enable Channel1 with 32bit width
    // For 16 bit I2S, Channel width should be 16, possible positions should be 1 and 17?
    //(e.g. look for 1<<29 and 17<<4
    printk(KERN_EMERG "Setting TX channel settings\n");
    *(i2s_registers+TXC_A) = 0<<31 | 1<<30 | 1 << 20  | 8<<16   |   0<<15 | 1<<14 | 33<<4 | 8 ;

    //Set frame length and frame sync length (32 and 16), and set FTXP=1 so I can inject 2 channels into a single 32 bit word
    *(i2s_registers+MODE_A) = 1 << 24 | 63<<10 | 32;

    // --> disable STBY
    printk(KERN_EMERG "disabling standby\n");
    *(i2s_registers+CS_A) |= 1<<25;
    udelay(50);

//*(i2s_registers+CS_A) |= 2 <<5;

   // for(i = 0; i < 64; i++)
   //   (*(i2s_registers+FIFO_A)) = 0;
   //might be triggering here...
    
    for(i=0; i<9;i++) {
       printk(KERN_EMERG "I2S memory address=0x%08x: 0x%08x    %s\n", (unsigned int)i2s_registers+i, *(i2s_registers+i), i2s_register_name[i]);
    }
    // enable I2S
    *(i2s_registers+CS_A) |= 0x01;
       
    // enable transmission
    *(i2s_registers+CS_A) |= 0x04;
    
    // --> ENABLE SYNC bit
    printk(KERN_EMERG "setting sync bit high\n");
    *(i2s_registers+CS_A) |= 1<<24;

    if (*(i2s_registers+CS_A) & 1<<24) {
        printk(KERN_EMERG "SYNC bit high, strange.\n");
    } else {
        printk(KERN_EMERG "SYNC bit low, as expected.\n");
    }

    udelay(1);

    if (*(i2s_registers+CS_A) & 1<<24) {
        printk(KERN_EMERG "SYNC bit high, as expected.\n");
    } else {
        printk(KERN_EMERG "SYNC bit low, strange.\n");
    }
    printk(KERN_EMERG "Memory dump\n");

    for(i=0; i<9;i++) {
        printk(KERN_EMERG "I2S memory address=0x%08x: 0x%08x    %s\n", (unsigned int)i2s_registers+i, *(i2s_registers+i), i2s_register_name[i]);
    }

    msleep(300);
    //Let's fill up the FIFO, let it overflow, and then sleep, so it must surely underflow. Surely that'll trigger something??!

    printk(KERN_EMERG "WRITING...");
    for(i = 0; i < 640; i++)
      (*(i2s_registers+FIFO_A)) = 0;
    printk(KERN_EMERG "WRITTEN\n");
    msleep(300);

    printk(KERN_EMERG "WRITING...");
    for(i = 0; i < 640; i++)
      (*(i2s_registers+FIFO_A)) = 0;
    printk(KERN_EMERG "WRITTEN\n");
    msleep(300);

    printk(KERN_EMERG "WRITING...");
    for(i = 0; i < 640; i++)
      (*(i2s_registers+FIFO_A)) = 0;
    printk(KERN_EMERG "WRITTEN\n");
 
    return 0;
}

static void hello_exit(void)
{
    int i=0;
    remove_irq(IRQ_TO_USE, &bcm2708_i2s_irq);
 
    printk(KERN_EMERG "Disable I2S\n");

    for(i=0; i<9;i++) {
        printk(KERN_EMERG "I2S memory address=0x%08x: 0x%08x    %s\n", (unsigned int)i2s_registers+i, *(i2s_registers+i), i2s_register_name[i]);
    }  
  *(i2s_registers+CS_A) &= ~(1<<24);
    udelay(100);
    *(i2s_registers+CS_A) = 0;
    udelay(100);
    *(i2s_registers+INTSTC_A) = 0xf;
    *(i2s_registers+INTEN_A) = 0;
    for(i=0; i<9;i++) {
        printk(KERN_EMERG "I2S memory address=0x%08x: 0x%08x    %s\n", (unsigned int)i2s_registers+i, *(i2s_registers+i), i2s_register_name[i]);
    }
    iounmap(i2s_registers);
    iounmap(gpio);
    iounmap(clock_registers);

    printk(KERN_EMERG "Goodbye, cruel world ISR COUNT %d\n", isr_count);
}
module_init(hello_init);
module_exit(hello_exit);







mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Thu Nov 22, 2012 12:18 pm

Maybe we should connect the word clock (LRCLK) output to some GPIO pin and implement a GPIO interrupt handler instead. If we first fill the FIFO with 64 samples (or 32 x2 channels in case of >16 bit ones) and enable the GPIO IRQ we can get exact sample position and can calculate FIFO state just by counting the interrupts. Then allowing for some safety margin we can fill TX FIFO and pull data from RX FIFO either in user space application (we could signal the process which has registered through some IOCTL in kernel module) or in the kernel module itself (the user mode application then writes or reads data using character device API). ALSA is obviously one alternative, though bare JACK support would be enough for most applications. DMA with larger block size buffers might be still needed if USB or ethernet (guess it uses USB in RPi) are used heavily. On the other hand if you can control your application via simple UART interface you could disable USB and GUI and have maybe a little better and more stable performance (no drop outs).

philpoole
Posts: 69
Joined: Mon Oct 29, 2012 5:09 pm

Re: I2S: Anyone got it running?

Thu Nov 22, 2012 8:55 pm

Well, that would work, but you'd get 44k interrupts a second.
Maybe shove the word clock into a divider (ideally divide by 64 or 128) first?

When I used the userspace code, I was just SSHing into the pi, no gui or anything, and there were the occasional dropouts (and huge processor usage reported by top).

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Fri Nov 23, 2012 12:25 pm

The divider is a good idea, but because FIFO is only 64 words deep meaning 32 stereo samples in 24 bit words can be stored when it's full I think a divider like 8 or 16 (can be implemented using single 175 type flip-flop) might be a better choice. Even then you might want to use a FIQ interrupt (seems USB now uses FIQ).

philpoole
Posts: 69
Joined: Mon Oct 29, 2012 5:09 pm

Re: I2S: Anyone got it running?

Fri Nov 23, 2012 6:50 pm

Sorry, forever thinking 16 bit samples!
Don't forget the divider to lower the output back down to 3.3v.

Mind you, it'd be wise to see if GPIO IRQs work first.

bossesand
Posts: 2
Joined: Thu Nov 29, 2012 3:00 pm

Re: I2S: Anyone got it running?

Thu Nov 29, 2012 3:07 pm

Have you seen this, it seems to be very relevant info on this issue.

http://www.diyaudio.com/forums/digital- ... hub-8.html

Bosse

philpoole
Posts: 69
Joined: Mon Oct 29, 2012 5:09 pm

Re: I2S: Anyone got it running?

Fri Nov 30, 2012 8:08 am

Yes, I've posted on that thread too. I think this is where it's (not) happening though.
mhelin, I noticed you submitted an issue on github for this, let's hope something happens.
I'm a bit too distracted to look at this (christmas looms) but might eventually try putting some debug in the kernel to see if anything's going on. Problem is I don't have anything suitably fast with linux to rebuild kernels on at the moment, so it's a slow process that I've been trying to avoid - the initial one off took 50 minutes. I shall dig out a faster PC over the christmas break and set it up.

bossesand
Posts: 2
Joined: Thu Nov 29, 2012 3:00 pm

Re: I2S: Anyone got it running?

Fri Nov 30, 2012 12:32 pm

Interesting.
I am interested in finding information and pointers on how to use I2S interfaces on RPi.
According to information there is a possibility to configure for 3 I2S interfaces.
My hope is to find or inspire some one to describe and implement linux JACK drivers for at least a 4 channel 24bit 48kHz (eventually 96KHz ) ADC interface using 2 I2S interfaces as Input.
This would be a great step forward to us a RPi as a mobile multichannel digital recorder.

Sadly for me, most I2S use cases I have found via google for I2S concentrate on DAC circuits.

- Bosse

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Fri Nov 30, 2012 7:52 pm

I don't think there are more than single PCM input, and it can be accessed either via GPIO18-GPIO21 or GPIO28-GPIO31 pins (http://elinux.org/RPi_BCM2835_GPIOs ).

However, if you must use the PCM/I2S input then I think it would be possible to hack a single input to support four channels. That is possible if you have two A/D converters where the other uses left justified and the other right justified mode and both are 16-bit ADC's with 64fs BCLK and you just OR (sum the bits of) the SDATA outputs of the two ADC's. In the kernel module or in your application you then separate the two 32-bit channels into four 16-bit ones.

Yes I raised the issue on github but so far no one has commented it. I think if someone wants it to be corrected would add a comment and a link to this thread with the example (forgot to do it). I think that after all it may be firmware issue, so it should maybe reported to the firmware issues instead.

I may later start playing with the DMA's. I have setup Eclipse C/C++ to compile on my Ubuntu PC but haven't set it up for compiling kernel modules yet (I think it's better use the cross compiling tools for kernel modules from command line). Haven't cross-compiled the kernel either. Here are some instructions but it looks like there are some errors:
https://www.grendelman.net/wp/cross-com ... -raspbian/

philpoole
Posts: 69
Joined: Mon Oct 29, 2012 5:09 pm

Re: I2S: Anyone got it running?

Fri Nov 30, 2012 8:14 pm

I can't remember how I built the kernel source last time. I used a webpage as reference. I'll look at the history on that machine and post what I did (might be tomorrow though).

I built it once ages ago, purely so I could have source to compile my driver against that would be the same version as the kernel.

P1000
Posts: 6
Joined: Sat Dec 01, 2012 8:44 am

Re: I2S: Anyone got it running?

Sun Dec 02, 2012 8:45 am

I am very interested in this, in fact, this was on the top of my toDo list when I got my pi. I just have had no time to play with it at all. So, I will make this my project for over the holidays. Honestly, I thought somebody would have got it working by now, but I guess there was just not enough people with this need?

Anyway, my plan is to make a good sound source with a Pi as the core. The rest of the system will be quite a bit more expensive than the Pi, but I think it will be worth it in the end. Maybe we can call it project soundPi

What I am planning on doing is: clock generated from DAC board - probably will need 2 crystals with a PLL (to generate oversampling clocks) in order to support both 48kHz and 44.1kHz (if that is working we can look at higher rates.) This will also likely mean a micro to control things. For the first iteration, I plan on using a PCM1792 or 1796(they are pin-compatible) as the DAC, a PLL1705 or similar, I just need to check what I have in stock, and some small micro to control it all - which also means we will need the I2C from the GPIO for control, like volume, clock rate etc.

But first things first, we need to sort out the software. This might be quite a hurdle, as I haven't done much low-level Linux, but I have been meaning to for a couple of years, so it will be a good experience. (I have quite a bit of embedded development experience, otherwise). I have just started looking into this, and my time is VERY limited for now, but hopefully I will get bored in the holidays and work on this.

philpoole
Posts: 69
Joined: Mon Oct 29, 2012 5:09 pm

Re: I2S: Anyone got it running?

Sun Dec 02, 2012 11:19 am

Hi mhelin,
I think I used this for inspiration on compiling the kernel.
http://mitchtech.net/raspberry-pi-kernel-compile/

P1000, the more the merrier. Wouldn't you be better off with a higher frequency clock that you divide down than use PLLs?

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Sun Dec 02, 2012 3:17 pm

I was wondering this setting but now I understand it is used as prefix and concatenated to usual command:

CROSS_COMPILE=/usr/bin/arm-linux-gnueabi-

jij3
Posts: 2
Joined: Sun Dec 02, 2012 4:59 pm

Re: I2S: Anyone got it running?

Sun Dec 02, 2012 5:17 pm

P1000: I have the same goal. There is a very nice player I have running on my RPi now called Squeezelite, http://forums.slimdevices.com/showthrea ... alsa-only), that does everything you mention but output to I2S. With an I2S driver and this nice app, all that would be required are external clocks (and a DAC).

I would recommend using two high qualtity clocks located at the DAC of 22.5792 MHz (for 44.1, 88.2 and 176.4K) and 24.5760 MHz (for 48, 96, and 192K), and using logic hardware to select one of these clocks and to divide them down as needed for the required sampling rate. Squeezelite can determine the sampling rate from the datastream, so I suppose there is a way to output the necessary control signals on 1 or 2 GPIO ports on the RPi. This would not add nearly as much jitter to the clocks as using a PLL. On my current DAC I use Tent Lab clock modules (available at both frequencies) and have successfully injected these into a modified Squeezebox Touch player.

I am not a programmer, so have no idea what would be involved in developing an I2S driver that would work with Squeezelite. It is open source and its author has been extremely generous in assisting folks in the Squeezebox community.

Best of luck with your project.

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Mon Dec 03, 2012 4:14 pm

Regarding the hardware and master clock generation you can you BCM2835 general purpose clocks which can be output from GPIO pins (see the data sheet).

Actually it would be nice is someone designed a codec (meaning ADC+DAC in this case, not some software codec) for raspberry like this:

http://ebrombaugh.studionebula.com/synt ... index.html

Above would work but it would be nice if the pinout was compatible with raspberry directly. Also there are many better quality codec's available. Cirrus CS4271 would be much better, but then you would need extra analog power source for handling the differential outputs using opamps. WM8731 and CS4270 are otherwise fine but their THD is really bad. They are maybe select because of the SNR is decent though I don't get it why people just look at SNR figures when they select converters.

jij3
Posts: 2
Joined: Sun Dec 02, 2012 4:59 pm

Re: I2S: Anyone got it running?

Tue Dec 04, 2012 12:45 am

I would want the master clock to be generated at the DAC and inputted to the BCM2835 at the I2S connection. I will recheck the BCM2835 spec sheet, but I believe the PCM master clock can be set as an input. This is to reduce jitter. With a crystal controlled clock at the DAC, the data, bit clock and word clocks from the BCM2835 can all be reclocked by the master clock at the DAC, so any jitter introduced by the RPi is eliminated.

mhelin
Posts: 115
Joined: Wed Oct 17, 2012 7:18 pm

Re: I2S: Anyone got it running?

Tue Dec 04, 2012 9:02 am

The PCM block of BCM2835 can input bit clock (SCK using naming convention from NXP I2S specifications) and generate word clock (WS) from it (not exactly any of the I2S master or slave modes), or in frame sync mode input WS and synchronize the PCM block to it. Latter should work fine if you want to have local clocks (to converters) but then you have to reserve some GPIO pins also for the clock selection (well guess one is enough if you have I2C control for the DAC/ADC clock generator). If the RPi works as clock master you have software control right in your driver - just use some GPIO clock and program the desired system (master) clock frequency in the driver. Yes this will increase jitter but on the other hand keeps the hardware simpler.

Problem with PCM / I2S interface is that even though the relations between clocks (SCK,WS) and data framing is well defined there is no standard interface to clock mode (master/slave) and sample rate selection. Linux kernel though have support for a number of codecs, for an example the CS4271 I'm interested has such driver in sound/soc/codecs/cs4271.c . To get it working in ALSA SoC system you have to write ALSA SoC driver for BCM2835 SoC, obviously. One example is sound/soc/ep93xx/ep93xx-i2s.c.

Return to “Interfacing (DSI, CSI, I2C, etc.)”

Who is online

Users browsing this forum: No registered users and 16 guests