czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

I2S clocks, GPCLK0

Tue Sep 19, 2017 7:21 am

Hi,

I'm trying to get my external audio codec to use PLLD, GPCLK0 on pin 7 as its MCLK. It seems like the best way to do this is in the dtoverlay for the soundcard. From this post viewtopic.php?f=107&t=136988 I've tried to enable the clocks in the same manner, but am still not getting MCLK. It seems like the overlay is loading:

Code: Select all

001856.839: dtdebug: Found fragment 0 (offset 36)
001859.774: dtdebug: merge_fragment(/soc/i2s@7e203000,/fragment@0/__overlay__)
001859.802: dtdebug:   +prop(status)
001861.588: dtdebug: merge_fragment() end
001861.647: dtdebug: Found fragment 1 (offset 112)
001867.893: dtdebug: merge_fragment(/soc/i2c@7e804000,/fragment@1/__overlay__)
001867.919: dtdebug:   +prop(#address-cells)
001869.350: dtdebug:   +prop(#size-cells)
001870.788: dtdebug:   +prop(status)
001875.890: dtdebug: merge_fragment(/soc/i2c@7e804000/cs42448@48,/fragment@1/__overlay__/cs42448@48)
001875.918: dtdebug:   +prop(#sound-dai-cells)
001877.392: dtdebug:   +prop(compatible)
001878.788: dtdebug:   +prop(clocks)
001880.255: dtdebug:   +prop(clock-names)
001881.762: dtdebug:   +prop(reg)
001883.230: dtdebug:   +prop(VA-supply)
001885.076: dtdebug:   +prop(VD-supply)
001886.937: dtdebug:   +prop(VLS-supply)
001888.815: dtdebug:   +prop(VLC-supply)
001890.710: dtdebug:   +prop(status)
001892.293: dtdebug:   +prop(linux,phandle)
001894.235: dtdebug:   +prop(phandle)
001895.804: dtdebug: merge_fragment() end
001899.688: dtdebug: merge_fragment(/soc/i2c@7e804000/codec-mclk,/fragment@1/__overlay__/codec-mclk)
001899.714: dtdebug:   +prop(compatible)
001901.130: dtdebug:   +prop(#clock-cells)
001902.611: dtdebug:   +prop(clock-frequency)
001904.165: dtdebug:   +prop(linux,phandle)
001906.042: dtdebug:   +prop(phandle)
001907.542: dtdebug: merge_fragment() end
001907.574: dtdebug: merge_fragment() end
001907.688: dtdebug: Found fragment 2 (offset 560)
001918.782: dtdebug: merge_fragment(/soc/sound,/fragment@2/__overlay__)
001918.810: dtdebug:   +prop(compatible)
001919.764: dtdebug:   +prop(mult-gpios)
001921.153: dtdebug:   +prop(reset-gpios)
001922.569: dtdebug:   +prop(i2s-controller)
001924.009: dtdebug:   +prop(codec)
001925.463: dtdebug:   +prop(status)
001926.460: dtdebug: merge_fragment() end
001941.564: dtdebug: /aliases:serial0=uart0
001946.659: dtdebug: /aliases:serial1=uart1
002983.382: dtparam: arm_freq=900000000
002986.790: dtdebug: Found override arm_freq
002986.840: dtdebug:   override arm_freq: cell target clock-frequency @ offset 0 (size 4)
002995.232: dtdebug:   override arm_freq: cell target clock-frequency @ offset 0 (size 4)
003003.698: dtdebug:   override arm_freq: cell target clock-frequency @ offset 0 (size 4)
003012.247: dtdebug:   override arm_freq: cell target clock-frequency @ offset 0 (size 4)
My overlay is below. Does anyone have any suggestions for where I might be going wrong?

Many thanks!

Code: Select all

// Definitions for raspberryberet.net audio add on soundcard
/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2708";

        fragment@0 {
                target = <&i2s>;
                __overlay__ {
                        status = "okay";
                };
        };

	fragment@1 {
                target-path = "/clocks";
                __overlay__ {
                clock_routing{
                        vco@PLLD{freq = <500000000>;};
                        chan@APER{div=<4>;};
                        clock@GPCLK0{pll="PLLA";chan="APER";};
                };
                clock_setup{
                        clock@GPCLK0{freq=<11289600>;};
        	        };
        	};
	};

 	/* set GPIO4 to ALT0 (GPCLK0) */
        fragment@2 {
                target = <&gpio>;
                __overlay__ {
                can_clk_pin: can_clk_pin {
                        brcm,pins = <4>;
                        brcm,function = <4>;
                        brcm,pull = <1>;
                        };
                };
        };

        fragment@3 {
                target = <&i2c1>;
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        cs42448: cs42448@48 {
                                #sound-dai-cells = <0>;
                                compatible = "cirrus,cs42448";
                                clocks = <&clocks 38>;
                                clock-names = "mclk";
                                reg = <0x48>;
                                VA-supply = <&vdd_5v0_reg>;
                                VD-supply = <&vdd_3v3_reg>;
                                VLS-supply = <&vdd_3v3_reg>;
                                VLC-supply = <&vdd_3v3_reg>;
				pinctrl-names = "default";
                                pinctrl-0 = <&can_clk_pin>;
				status = "okay";
                        };
                };
        };
       fragment@4 {
                target = <&sound>;
                __overlay__ {
                        compatible = "raspberry-beret,raspberry-beret-soundcard";
                        mult-gpios = <&gpio 27 0>, <&gpio 22 0>, <&gpio 23 0>,
                                     <&gpio 24 0>;
                        reset-gpios = <&gpio 5 0>;
                        i2s-controller = <&i2s>;
                        codec = <&cs42448>;
                        status = "okay";
                };
        };
};


PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Tue Sep 19, 2017 9:21 am

Most of that looks OK, except for the clock setup. The content of fragment 1 does compile, but it isn't really Device Tree - it's the proprietary format used by the firmware to configure the pins and clocks.

If you want the firmware to set up the clock then you'll need to create a custom dt-blob.bin and copy it into the boot partitions for all users. I wouldn't recommend this approach because it becomes a maintenance headache whenever the source dt-blob changes, which it does from time to time.

It should be possible to get the soundcard driver to configure the clock just like any other. However, 11289600 is not an integer divisor of 500MHz - the result is 44.289. Fractional divisors are possible, but the answer is only correct on average: sometimes you will get a pulse 44 cycles long and sometimes it will be 45 cycles long. Audio hardware designers work hard to eliminate jitter and yet you seem to be designing it in from the start - you're better off using external crystals.

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Tue Sep 19, 2017 7:51 pm

Hi Phil,

Thanks for getting back to me. I guess the DT isn't the right solution. I have tried for weeks to provide the clocks by setting the DIVI / DIVF registers and sending the PLLD clock to GPIO4 with patches to the bcm2835-i2s.c file, but to no avail - there seems to incredibly little documentation on how to go about making the necessary changes to the actual drivers in order to get this to happen. It seems like this approach would make more sense if I could manage to get it to work. Do you know where I could find documentation on how to do this? I've scoured the I2S threads, but no one seems to have done it with the 2835, and no one has responded to any of my posts regarding this (Thanks for being the first person to actually respond!).

Anyway, if you have any suggestions, I'd be really grateful.

Thanks.

piras77
Posts: 138
Joined: Mon Jun 13, 2016 11:39 am

Re: I2S clocks, GPCLK0

Tue Sep 19, 2017 8:50 pm

I'm not sure about what you are actually want to achieve...

...a description of the GPIO clocks is available in the peripheral datasheet https://www.raspberrypi.org/app/uploads ... herals.pdf

...all register for the clock manager are described on the eLinux project http://elinux.org/BCM2835_registers#CM

..also the Raspbian source may be of some help https://github.com/raspberrypi/linux/bl ... -bcm2835.c

So you can "simply" set up the peripheral as you want by writing directly to these registers.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Wed Sep 20, 2017 8:51 am

Nooo, don't write directly to the hardware - you can get all sorts of atomicity problems, and it's not the Linux way.

You should be able to use Device Tree to select the clock. You've tried to do with the codec, but that is the wrong place since the details of clocks are board-specific not codec specific. So you'll need a sound card driver, even if it's a very simple one; there are plenty of examples in sound/soc/bcm. The driver's probe function will use devm_clk_get() to locate the clock device using its DT properties, then you can use clk_set_rate() to change the frequency. All peripheral clocks should be using PLLD_PER as a clock source as a matter of course, unless the 19.2MHz oscillator gives a better frequency match. The PCM/I2S clock gets special treatment because it is marked as low_jitter - deviation from the required frequency is considered as well as the average. This isn't the case for GPCLK0, and making it so would require a modified clock driver.

piras77
Posts: 138
Joined: Mon Jun 13, 2016 11:39 am

Re: I2S clocks, GPCLK0

Wed Sep 20, 2017 9:09 am

PhilE wrote:
Wed Sep 20, 2017 8:51 am
Nooo, don't write directly to the hardware - you can get all sorts of atomicity problems, and it's not the Linux way.
In general I would agree. However, we're talking here about a Pi were the TS want's to tap a certain pin for a configurable clock pulse (that is at least what I understand he wants to achieve).
PhilE wrote:
Wed Sep 20, 2017 8:51 am
You should be able to use Device Tree to select the clock...So you'll need a sound card driver, even if it's a very simple one;
A sound card driver for the clock-manager peripheral? Maybe you can provide an example since this would probably be also interesting for others.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Wed Sep 20, 2017 9:13 am

However, we're talking here about a Pi were the TS want's to tap a certain pin for a configurable clock pulse (that is at least what I understand he wants to achieve).
I don't see why that makes a difference.
A sound card driver for the clock-manager peripheral?
No, a sound card driver for the sound card he is building - read the original post.

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Wed Sep 20, 2017 7:22 pm

Thanks for the input on this.

I've gotten clocks to work, but I need them to be sent to GPIO4, which I think my originally posted overlay was doing (or trying to do). I spent a ton of time looking at the drivers, including the simple-card. I'm using the CS42448 codec, so I've taken the audioinjector-octo driver and overlay and changed them. The octo uses an external ocsillator, but I need to use one of the clocks in the Pi sent to GPIO4. This is really the only difference. I just haven't found a way to switch the clock source and direct to the pin 7. Is this still best done in the overlay, or is this something that set_sysclk() in the driver would handle?

https://github.com/raspberrypi/linux/bl ... oundcard.c
https://github.com/raspberrypi/linux/bl ... verlay.dts


Again, thank you for the help!

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Thu Sep 21, 2017 9:43 am

Fragment 2 of your original overlay looks like it should do the job (*), provided the DT node for your soundcard references it. Just move the pinctrl-names and pinctrl-0 properties to the soundcard node and it should work.

(*) I don't think you really need the pull to be enabled, but it shouldn't do any harm.

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Sun Sep 24, 2017 7:23 am

I'm sorry, but I'm still confused. I think I now have the clocks set properly in the overlay. Can you let me know if this is correct? I'm still not getting clock signals when I do speaker-test, so obviously the codec doesn't know to look at pin 7 as the MCLK.

Thank you yet again.

Code: Select all

// Definitions for raspberryberet soundcard
/dts-v1/;
/plugin/;

/ {
	compatible = "brcm,bcm2708";

	fragment@0 {
		target = <&i2s>;
		__overlay__ {
			status = "okay";
		};
	};

	fragment@1 {
                target-path = "/clocks";
                __overlay__ {
                clock_routing{
                        vco@PLLA{freq = <1966080000>;};
                        chan@APER{div=<4>;};
                        clock@GPCLK0{pll="PLLA";chan="APER";};
	                };
        	};
	};

	/* set GPIO4 to ALT0 (GPCLK0) */
        fragment@2 {
                target = <&gpio>;
                __overlay__ {
                rb_clk_pin: rb_clk_pin {
                        brcm,pins = <4>;
                        brcm,function = <4>;
                        brcm,pull = <1>;
                        };
                };
        };

	fragment@3 {
		target = <&i2c1>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			cs42448: cs42448@48 {
				#sound-dai-cells = <0>;
				compatible = "cirrus,cs42448";
				clocks = <&cs42448_mclk>;
				clock-names = "mclk";
				pinctrl-names = "default";
				pinctrl-0 = <&rb_clk_pin>;
				reg = <0x48>;
				VA-supply = <&vdd_5v0_reg>;
				VD-supply = <&vdd_3v3_reg>;
				VLS-supply = <&vdd_3v3_reg>;
				VLC-supply = <&vdd_3v3_reg>;
				status = "okay";
			};

			cs42448_mclk: codec-mclk {
				compatible = "fixed-clock";
				#clock-cells = <0>;
				clock-frequency = <49152000>;
			};
		};
	};

	fragment@4 {
		target = <&sound>;
		__overlay__ {
			compatible = "raspberry-beret,raspberry-beret-soundcard";
			reset-gpios = <&gpio 5 0>;
			i2s-controller = <&i2s>;
			codec = <&cs42448>;
			status = "okay";
		};
	};
};

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Sun Sep 24, 2017 2:58 pm

You seem to have gone backwards with this version:
  1. Fragment 1 is still completely bogus and should be deleted.
  2. Declaring a fixed-clock doesn't cause anything to happen except that anything querying the clock frequency will be given the specified value. You need to ask the clock manager to return a clock - use "clocks = <&clocks 38>" which equates to "clocks = <&clocks BCM2835_CLOCK_GP0>". Note that since you need to be able to set the clock rate using "clk_set_rate" you'll need some board-specific code to do that for you. That has to go in your sound card driver, so the "clocks" property has to go with the other sound card properties in fragment 4 (as it is numbered below).
  3. The knowledge that there is an MCLK on pin 7 has to go in the hardware in the form of a wire.

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Mon Sep 25, 2017 7:25 am

I think I have the overlay correct, but I'm not sure what I'm doing wrong in the driver. Is this the proper way to address the clock in the probe function?

Code: Select all

static int raspberry_beret_probe(struct platform_device *pdev)
{
	struct snd_soc_card *card = &snd_soc_raspberry_beret;
	int ret;
	struct clk *mclk;

	card->dev = &pdev->dev;

	mclk = devm_clk_get(&pdev->dev, "clk");
	
	clk_set_rate(mclk, 49152000);

	if (pdev->dev.of_node) {
		struct snd_soc_dai_link *dai = &raspberry_beret_dai[0];
		struct device_node *i2s_node =
					of_parse_phandle(pdev->dev.of_node,
							"i2s-controller", 0);
		struct device_node *codec_node =
					of_parse_phandle(pdev->dev.of_node,
								"codec", 0);


The code compiles, but I get pointer errors on boot with dmesg.

Code: Select all

// Definitions for raspberryberet soundcard
/dts-v1/;
/plugin/;

/ {
	compatible = "brcm,bcm2708";

	fragment@0 {
		target = <&i2s>;
		__overlay__ {
			status = "okay";
		};
	};

	/* set GPIO4 to ALT0 (GPCLK0) */
        fragment@1 {
                target = <&gpio>;
                __overlay__ {
                rb_clk_pin: rb_clk_pin {
                        brcm,pins = <4>;
                        brcm,function = <4>;
                        brcm,pull = <1>;
                        };
                };
        };

	fragment@2 {
		target = <&i2c1>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			cs42448: cs42448@48 {
				#sound-dai-cells = <0>;
				compatible = "cirrus,cs42448";
				clocks = <&clocks 38>;
				clock-names = "mclk";
				pinctrl-names = "default";
				pinctrl-0 = <&rb_clk_pin>;
				reg = <0x48>;
				VA-supply = <&vdd_5v0_reg>;
				VD-supply = <&vdd_3v3_reg>;
				VLS-supply = <&vdd_3v3_reg>;
				VLC-supply = <&vdd_3v3_reg>;
				status = "okay";
			};
		};
	};

	fragment@3 {
		target = <&sound>;
		__overlay__ {
			compatible = "raspberry-beret,raspberry-beret-soundcard";
			reset-gpios = <&gpio 5 0>;
			i2s-controller = <&i2s>;
			codec = <&cs42448>;
			clk = <&clocks>;
			status = "okay";
		};
	};
};

As always, thank you yet again.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Mon Sep 25, 2017 8:27 am

I think there are two problems with the clock declaration in the overlay: the first is that in order for the standard devm_clk_get to work you have to use the correct property name - "clocks", and the second is that although the clock provider is specified ("&clocks"), it is missing the clock identifier ("BCM2835_CLOCK_GP0" or 38). It should look like this:

Code: Select all

clocks = <&clocks, 38>;

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Tue Sep 26, 2017 11:24 pm

When I try to use <&clocks, 38> (with a comma), it won't compile. The other examples I've seen all use <&clocks 38> (no comma). Also, In looking at the cs42xx8.c file, it seems that the driver requests the clock frequency:

Code: Select all

cs42xx8->clk = devm_clk_get(dev, "mclk");
	if (IS_ERR(cs42xx8->clk)) {
		dev_err(dev, "failed to get the clock: %ld\n",
				PTR_ERR(cs42xx8->clk));
		return -EINVAL;
	}

	cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
	
That suggests I need the compatible = "fixed-clock" node, no?

Code: Select all

cs42448: cs42448@48 {
				#sound-dai-cells = <0>;
				compatible = "cirrus,cs42448";
				clocks = <&clocks 38>;
				clock-names = "mclk";
				pinctrl-names = "default";
				pinctrl-0 = <&rb_clk_pin>;
				reg = <0x48>;
				VA-supply = <&vdd_5v0_reg>;
				VD-supply = <&vdd_3v3_reg>;
				VLS-supply = <&vdd_3v3_reg>;
				VLC-supply = <&vdd_3v3_reg>;
				status = "okay";
			};
			clocks: codec-mclk {
				compatible = "fixed-clock";
				#clock-cells = <0>;
				clock-frequency = <49152000>;
			};
		};
	};

	fragment@3 {
		target = <&sound>;
		__overlay__ {
			compatible = "raspberry-beret,raspberry-beret-soundcard";
			reset-gpios = <&gpio 5 0>;
			i2s-controller = <&i2s>;
			codec = <&cs42448>;
			status = "okay";
		};
	};
};
I'm still trying to call clk_set_rate() in the init section of the soundcard driver, but am not getting any clocks on my scope and now I'm getting I2S sync error and "DMA transfer could not terminated." I've been looking for drivers that manage and start clocks in the same way I'm trying to do, but can't seem to find any. Do you have any suggestions?

Thank you as always!

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Wed Sep 27, 2017 8:54 am

The spurious comma is a mistake/typo on my part - I still find it unnatural to write any kind of array without commas.

Using a fixed clock is not going to help when the sample rate varies between audio streams, particularly the switch between 44.1KHz and 48KHz.

I don't think the codec driver's querying of the clock rate should be a problem. The driver also implements the set_sysclk method which is plumbed into the bottom end of snd_soc_codec_set_sysclk, a function called by several of the Pi soundcard drivers. I think your soundcard driver needs to use this method, along with snd_soc_dai_set_sysclk and clk_set_rate.

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Wed Sep 27, 2017 5:09 pm

It seems like I'm getting some sort of clock when I do a speaker-test or aplay..., but it looks more like jitter than an actual signal:

Image

I'm calling clk_set_rate in the codec driver:

Code: Select all

cs42xx8->clk = devm_clk_get(dev, "mclk");
	if (IS_ERR(cs42xx8->clk)) {
		dev_err(dev, "failed to get the clock: %ld\n",
				PTR_ERR(cs42xx8->clk));
		return -EINVAL;
	}

	clk_set_rate(cs42xx8->clk, 49152000);

	cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
and setting sysclk in the platform driver:

Code: Select all

raspberry_beret_rate = params_rate(params);

	// Set the correct sysclock for the codec
	switch (raspberry_beret_rate) {
	
	case 96000:
	case 48000:
		return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 49152000,
									0);
		break;
	case 24000:
		return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 49152000/2,
									0);
		break;
	case 88200:
	case 44100:
		return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 45185400,
									0);
		break;
	case 22050:
		return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 45185400/2,
									0);
		break;
	default:
		return -EINVAL;
	}
The blue signal on the scope should be mclk, but the I2S clocks don't seem to be syncing to that signal (maybe because it's just jitter?). The overlay, as far as I can tell is exactly what you recommended:

Code: Select all

/* set GPIO4 to ALT0 (GPCLK0) */ 
        fragment@1 {
                target = <&gpio>;
                __overlay__ {
                rb_clk_pin: rb_clk_pin {
                        brcm,pins = <4>;
                        brcm,function = <4>;
                        };
                };
        };

	fragment@2 {
		target = <&i2c1>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			cs42448: cs42448@48 {
				#sound-dai-cells = <0>;
				compatible = "cirrus,cs42448";
				clocks = <&clocks 38>;
				clock-names = "mclk";
				pinctrl-names = "default";
				pinctrl-0 = <&rb_clk_pin>;
				reg = <0x48>;
				VA-supply = <&vdd_5v0_reg>;
				VD-supply = <&vdd_3v3_reg>;
				VLS-supply = <&vdd_3v3_reg>;
				VLC-supply = <&vdd_3v3_reg>;
				status = "okay";
			};
		};
	};

	fragment@3 {
		target = <&sound>;
		__overlay__ {
			compatible = "raspberry-beret,raspberry-beret-soundcard";
			reset-gpios = <&gpio 5 0>;
			i2s-controller = <&i2s>;
			codec = <&cs42448>;
			status = "okay";
		};
	};
};
Can you think of anything I might be doing wrong? This is driving me absolutely crazy.

Yet again, thank you.
Attachments
CaptureClocks.PNG
CaptureClocks.PNG (60.91 KiB) Viewed 763 times
CaptureClocks.PNG
CaptureClocks.PNG (60.91 KiB) Viewed 763 times

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Wed Sep 27, 2017 6:10 pm

Your clock speed (49MHz) is a bit close to the scope´s sampling rate for my liking. Can you try with a higher scope speed or a slower clock? I'm also not sure how fast we can reliably drive a GPIO pin...

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Wed Sep 27, 2017 10:44 pm

Here is what I get with a 1/2 speed clock (24.576MHz):

Image

So it looks like mclk is working, but for some reason the I2S clocks aren't syncing to it for some reason.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Thu Sep 28, 2017 8:37 am

The yellow trace is looking plausible - I'd still like a higher time resolution to be happy that the waveforms are good but the mid-point crossings are clear and nicely regular and I'm guessing you've hit the limits of your 'scope.

What is the cyan trace? That isn't looking so healthy.

You could try halving the clock again - some of the more audiophile Pi soundcards use separate crystals for 44.1- and 48-based sample rates, and they tend to be 11.2896 and 12.288 MHz.

I presume you have configured the codec to be the I2S clock master and the Pi to be the slave?

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Fri Sep 29, 2017 3:07 am

Clocks are looking good!

The codec (cs42448) actually needs to be in slave mode to operate in TDM mode, so my FMT settings are:

Code: Select all

// set codec DAI configuration
	int ret = snd_soc_dai_set_fmt(rtd->codec_dai,
			SND_SOC_DAIFMT_CBS_CFS|SND_SOC_DAIFMT_DSP_A|
			SND_SOC_DAIFMT_NB_NF);
	if (ret < 0)
		return ret;

	// set cpu DAI configuration
	ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
			SND_SOC_DAIFMT_CBS_CFS|SND_SOC_DAIFMT_I2S|
			SND_SOC_DAIFMT_NB_NF);
Here are my clocks:

Image

Image

I'm still having an issue where files are playing at something like 1/4 speed. I'm pretty sure that has something to do with the functional mode and bclk ratio settings in the codec driver, though, so I'll figure that out.

Phil, you are a king among men, and I owe you a couple dozen beers. Cheers and thank you for all your help!!!

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Wed Oct 04, 2017 12:52 am

Hi again,

So it seems like I'm still having an issue. As I mentioned above, I was designating both the codec and the CPU as CBS and CFS:

Code: Select all

// set codec DAI configuration
	int ret = snd_soc_dai_set_fmt(rtd->codec_dai,
			SND_SOC_DAIFMT_CBS_CFS|SND_SOC_DAIFMT_DSP_A|
			SND_SOC_DAIFMT_NB_NF);
	if (ret < 0)
		return ret;

	// set cpu DAI configuration
	ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
			SND_SOC_DAIFMT_CBS_CFS|SND_SOC_DAIFMT_I2S|
			SND_SOC_DAIFMT_NB_NF);
I was doing this because it was the only way I was getting any audio at all.
When I have them set this way, though, I get audio, but no matter how I set the MCLK or the sysclk, I get audio out at 1/4 speed. I've checked all the clocks and they are exactly what they are supposed to be for the format that I'm using - TDM (DSP_A). They are the exact same clocks that I get when I use the Audioinjector Octo board, which, again, uses the same codec.
When I change the CPU to CBM/CFM, (as the Octo does) I get a MCLK, but no BCLK or LRCK. This makes me think that the I2S stream just isn't syncing to my MCLK - GPCLK0 as set up in the overlay. I can't seem to find anything about locking the I2S stream to this clock. Do you know how this is done?

Thank you yet again.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1317
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: I2S clocks, GPCLK0

Wed Oct 04, 2017 10:55 am

If both ends are slaves to both the bit clock and the frame clock, who is generating those clocks? My understanding was that you would feed GPCLK0 to the codec as an MCLK (the I2S interface on the host doesn't need an MCLK). The codec can then divide down the MCLK to generate BCLK and LRCLK, which makes it clock master for both clocks. The DAI (host I2S interface) must then be slaves for them.

Ah - you said earlier (and the datasheet agrees) that the codec must be in slave mode to use TDM. The implications of that didn't hit me then, but Something has to generate BCLK and LRCLK synchronised to MCLK - it can't be the codec because of the TDM requirement, and it also can't be the host because the host has no input for MCLK. That means you will need an external device to perform clock generation - a tiny FPGA, for example - or you need to rethink the requirement for TDM.

Are you sure you need TDM? Are you sure the I2S driver and the rest of the host software has been/can be configured to generate samples in TDM format?

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Wed Oct 04, 2017 4:35 pm

What's driving me absolutely crazy, though, is that when both CPU and codec are in CBS/CFS mode, I get the right clocks - 11.2896MHz for MCLK and BCLK, and 44.1K for LRCK - but then the audio plays at 1/4 speed. This lead me to believe that somehow the TDM format wasn't being set on the codec properly, but I've read the Functional Mode and Interface Format registers and they're exactly what they should be. I do need TDM because I need 8 channels of output. I've tested my clocks against two other soundcards that use the same codec (the Octo and a board for the Teensy) and they have the exact same clock speeds. I've tried different bclk ratios as well, but only get audio at 256 or above, and again, at 1/4 speed. It seems like I should be able to have the CPU as CBM/CFM, but it isn't starting the BCLK or LRCK - only the MCLK. I'm losing my mind over this.

Thank you again.

-As an aside -
The Teensy soundcard has a really simple setup, since it doesn't have to deal with any OS or DAI linkage:

Code: Select all

static const uint8_t default_config[] = {
	0xF4, // CS42448_Functional_Mode = slave mode, MCLK 25.6 MHz max
	0x76, // CS42448_Interface_Formats = TDM mode
	0x1C, // CS42448_ADC_Control_DAC_DeEmphasis = single ended ADC
	0x63, // CS42448_Transition_Control = soft vol control
	0xFF  // CS42448_DAC_Channel_Mute = all outputs mute
};

bool AudioControlCS42448::enable(void)
{
	Wire.begin();
	// TODO: wait for reset signal high??
	if (!write(CS42448_Power_Control, 0xFF)) return false; // power down
	if (!write(CS42448_Functional_Mode, default_config, sizeof(default_config))) return false;
	if (!write(CS42448_Power_Control, 0)) return false; // power up
	return true;
}
I've rewritten the cs42xx8.c driver in linux/raspberry pi repository so that it just writes directly to these registers with these values and loaded it on my Pi. I've checked the registers and they're what they should be. Still no joy. No joy at all.

HiassofT
Posts: 22
Joined: Fri Jun 30, 2017 10:07 pm

Re: I2S clocks, GPCLK0

Wed Oct 04, 2017 10:06 pm

A few comments: the CS42448 requires MCLK to run at 256x-1024x fs, depending on it's configuration - see the "MCLK Frequency Settings" tables on page 46/47 of the datasheet.

Also you'll need to configure the CS42448 to drive BCLK (usually at 64x fs) and LRCLK.

I have to add that the audioinjector octo driver is a really bad example to use as a reference. Directly writing to internal data structures (td->cpu_dai->driver->playback.channels_min/max etc in startup and shutdown) is a no-go and is prone to stop working any time some (upstream) driver changes - one should only use the official API functions. Also the modelling of the driver is wrong, you can't set both the CPU and the CODEC as a slave and have no active clock master - some component has to set up the clocks. In ASoC terminology that's usually modelled as a codec-codec link: the first one providing the clocks and the CPU and the "real" codec being the clock slaves of that - this is missing in the octo driver.

so long,

Hias

czyskows
Posts: 33
Joined: Sun Oct 07, 2012 5:42 am

Re: I2S clocks, GPCLK0

Wed Oct 04, 2017 11:19 pm

Thanks, Hias,

I do have the MCLK running at 256XFS - 11.289600 = 44.1K * 256.

As for the CS42448 driving the BCLK - How is this done if the CS42448 is the slave? My understanding was that the master provides the clocks to which the slave syncs.

The issues are still:
1. Why I get no LRCK or BCLK when the CPU is designated as master.
2. Why I get proper MCLK, BCLK and LRCK when both codec and CPU are CBS/CFS, but get audio out at 1/4 speed.

As for the upstream driver changes, I feel like I can cross that bridge when I come to it - right now I'm just pulling my hair out trying to get it to work.

Return to “Device Tree”

Who is online

Users browsing this forum: No registered users and 1 guest