Getting up and running with I2S Audio on Zero 3E

Greetings, everyone!

I wanted to reach out and try to get some help with setting up I2S audio on the Zero 3E using a device tree overlay. It mostly works already, but I’m having some issues with corruption on the receiving device. I’m hoping that someone who is smarter than me could help me work out what might be going on.

I’ve done some preliminary work here:

/dts-v1/; 
/plugin/;

/ {
	compatible = "rockchip,rk3568";

	fragment@0 {
		target = <&i2s3_2ch>;
		__overlay__ {
			rockchip,clk-trcm = <1>;
			pinctrl-names = "default";
			pinctrl-0 = <&i2s3m0_sclk
				     &i2s3m0_lrck
				     &i2s3m0_sdi
				     &i2s3m0_sdo>;
			status = "okay";
		};
	};

	fragment@1 {
		target-path = "/";
		__overlay__ {
			sound {
				status = "okay";
				compatible = "simple-audio-card";
				simple-audio-card,name = "test";
				simple-audio-card,format="i2s";

				simple-audio-card,bitclock-master = <&cpu_dai>;
				simple-audio-card,frame-master = <&cpu_dai>;
				simple-audio-card,mclk-fs = <256>;

				cpu_dai: simple-audio-card,cpu {
					sound-dai = <&i2s3_2ch>;
				};

				codec_dai: simple-audio-card,codec {
					sound-dai = <&i2s3_out>;
				};

			};

			i2s3_out: i2s3-out {
				#sound-dai-cells = <0>;
				compatible = "rockchip,dummy-codec";
				status = "okay";
			};
		};
	};
	fragment@2 {
                target = <&hdmi_sound>;
                __overlay__ {
                        status = "disabled";
                };
        };
};

And here is my PulseAudio daemon config:

# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# PulseAudio is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.

## Configuration file for the PulseAudio daemon. See pulse-daemon.conf(5) for
## more information. Default values are commented out.  Use either ; or # for
## commenting.

; daemonize = no
; fail = yes
; allow-module-loading = yes
; allow-exit = yes
; use-pid-file = yes
; system-instance = no
; local-server-type = user
; enable-shm = yes
; enable-memfd = yes
; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
; lock-memory = no
; cpu-limit = no

; high-priority = yes
; nice-level = -11

; realtime-scheduling = yes
; realtime-priority = 5

; exit-idle-time = 20
; scache-idle-time = 20

; dl-search-path = (depends on architecture)

; load-default-script-file = yes
; default-script-file = /etc/pulse/default.pa

; log-target = auto
; log-level = notice
; log-meta = no
; log-time = no
; log-backtrace = 0

; resample-method = speex-float-1
; avoid-resampling = false
; enable-remixing = yes
; remixing-use-all-sink-channels = yes
; remixing-produce-lfe = no
; remixing-consume-lfe = no
; lfe-crossover-freq = 0

; flat-volumes = no

; rescue-streams = yes

; rlimit-fsize = -1
; rlimit-data = -1
; rlimit-stack = -1
; rlimit-core = -1
; rlimit-as = -1
; rlimit-rss = -1
; rlimit-nproc = -1
; rlimit-nofile = 256
; rlimit-memlock = -1
; rlimit-locks = -1
; rlimit-sigpending = -1
; rlimit-msgqueue = -1
; rlimit-nice = 31
; rlimit-rtprio = 9
; rlimit-rttime = 200000

; default-sample-format = s16le
default-sample-rate = 192000
alternate-sample-rate = 192000
; default-sample-channels = 2
; default-channel-map = front-left,front-right

; default-fragments = 4
; default-fragment-size-msec = 25

; enable-deferred-volume = yes
; deferred-volume-safety-margin-usec = 8000
; deferred-volume-extra-delay-usec = 0

This device tree overlay is more or less stitched together from a few different posts on this forum. I’ve gotten out my scope and seen that the bit clock runs a bit above 12 MHz, as one would expect for 192k@32 bits stereo. This is connected to a DAC which has been configured for I2S operation at that rate. When monitoring on my oscilloscope, sometimes the data comes across perfectly, but many times the DAC either transmits nothing, or transmits very corrupted data. I’m using aplay to transmit a pure 1kHz sine wave.

I’ve been chipping away at this for a while, and so far I’ve tried:

  • Using the rk3566’s MCLK as a reference for the DAC
  • Lowering the sample rate to 96kHz
  • Adding 50Ω resistors in series

I’m a little lost with where to go from here. I’m a little suspicious of the <&cpu_dai> in the dt overlay. Is there a better way to source the clock on these boards?

Thank you,
Brodie