This is my first post on the Raspberry pi forum. Please let me know if this post should be made in a different group.
I am struggling for quite some time to get rid of audio glitches when playback a 4 channel TDM audio signal at 352.8 kHz sample rate via the RP1 i2s GPIO output pins of a Raspberry pi 5 (4GB), running kernel version 6.6.34. The glitches occur when the RPi is heavily loaded. I am not an experienced programmer, but I can make simple changes in modules and compile the kernel and its modules.
To get the higher sample rates, the following kernel modules have been adapted:
- /sound/soc/codecs/spdif_transmitter.c : maximum sample rate 192000 => 384000
- /sound/soc/codecs/spdif_receiver.c : maximum sample rate 192000 => 384000
- /sound/soc/dwc/dwc-i2s.c : maximum sample rate 192000 => 384000 in struct “i2s_platform_data jh7110_i2stx1_data” and “i2s_platform_data jh7110_i2srx1_data”
The soundcard in use is a simple-audio-card based on the dtoverlay code of AkiyukiOkayasu, adapted for the RPi 5 as clock master, with the following code:
For playback, it uses the codec spdif_transmitter.c with its maximum sample rate increased to 384 kHz. To get four i2s output channels via the GPIOs, the following dtoverlay code it used:
When the TDM audio signal is send with aplay to the soundcard “i2smasterrpi5”, this works well except for the audio glitches. These glitches occur rather erratically but always at multiples of the period-time, which for this device is 725 us. The hardware parameter limits for the soundcard “i2smasterrpi5” are:
HW Params of device "hw:i2smasterrpi5":
--------------------
ACCESS: MMAP_INTERLEAVED RW_INTERLEAVED
FORMAT: S16_LE S24_LE S32_LE
SUBFORMAT: STD
SAMPLE_BITS: [16 32]
FRAME_BITS: [32 256]
CHANNELS: [2 8]
RATE: [8000 384000]
PERIOD_TIME: (10 128000]
PERIOD_SIZE: [4 1024]
PERIOD_BYTES: [128 4096]
PERIODS: [2 32768]
BUFFER_TIME: (20 16384000]
BUFFER_SIZE: [8 131072]
BUFFER_BYTES: [128 524288]
TICK_TIME: ALL
--------------------
Available formats: S16_LE, S24_LE, S32_LE
When the soundcard is in use, /proc/asound/card0/pcm0p/sub0/hw_params shows:
ACCESS: RW_INTERLEAVED
FORMAT: S32_LE
SUBFORMAT: STD
CHANNELS: 4
RATE: 352800
PERIOD_SIZE: 256
BUFFER_SIZE: 32768
The period_size is given in frames and a single frame is 16 bytes (4 channels * 4 bytes). So 256 frames cover period_bytes = 4096 bytes, i.e. 1024 bytes per channel. At a sample rate of 352.8 kHz and with 4 bytes per sample, this results in a period time of 1024/(4 * 352800) = 725.6 us. The occurrence of a glitch, which is about 10 us long and happens at multiples of 725 us, means that at the start of a new period, the buffer is empty. To reduce the probability of this happening, I want to increase the period_time to create more buffering. In aplay, with --period-size, I can reduce the period_size, resulting in an even shorter period_time , but I cannot increase it beyond a period_size of 256 because the period_bytes is limited to a maximum of 4096.
Where and how can the period_size be increase, and if needed the buffer_size? What parameters determine the limits found with --dump-hw-params and where are these specified?
Thank you very much for any helpful information!
I am struggling for quite some time to get rid of audio glitches when playback a 4 channel TDM audio signal at 352.8 kHz sample rate via the RP1 i2s GPIO output pins of a Raspberry pi 5 (4GB), running kernel version 6.6.34. The glitches occur when the RPi is heavily loaded. I am not an experienced programmer, but I can make simple changes in modules and compile the kernel and its modules.
To get the higher sample rates, the following kernel modules have been adapted:
- /sound/soc/codecs/spdif_transmitter.c : maximum sample rate 192000 => 384000
- /sound/soc/codecs/spdif_receiver.c : maximum sample rate 192000 => 384000
- /sound/soc/dwc/dwc-i2s.c : maximum sample rate 192000 => 384000 in struct “i2s_platform_data jh7110_i2stx1_data” and “i2s_platform_data jh7110_i2srx1_data”
The soundcard in use is a simple-audio-card based on the dtoverlay code of AkiyukiOkayasu, adapted for the RPi 5 as clock master, with the following code:
Code:
//Device tree overlay for generic I2S audio codec. ex) Asahi kasei AK4558//Raspi: I2S master//Codec: I2S slave/dts-v1/;/plugin/;/ { compatible = "brcm,bcm2708"; fragment@0 { target = <&sound>; __overlay__ { compatible = "simple-audio-card"; simple-audio-card,name = "i2smaster_rpi5"; status="okay"; capture_link: simple-audio-card,dai-link@0 { format = "i2s"; r_cpu_dai: cpu { sound-dai = <&i2s_clk_producer>; // TDM slot configuration for stereo dai-tdm-slot-num = <2>; dai-tdm-slot-width = <32>; }; r_codec_dai: codec { sound-dai = <&codec_in>; }; }; playback_link: simple-audio-card,dai-link@1 { format = "i2s"; p_cpu_dai: cpu { sound-dai = <&i2s_clk_producer>; // TDM slot configuration for stereo dai-tdm-slot-num = <2>; dai-tdm-slot-width = <32>; }; p_codec_dai: codec { sound-dai = <&codec_out>; }; }; }; }; fragment@1 { target-path = "/"; __overlay__ { codec_out: spdif-transmitter { #address-cells = <0>; #size-cells = <0>; #sound-dai-cells = <0>; /* "linux,spdif-dit" is used in generic I2S(transmitter) driver. You can see details "linux,spdif-dit" by bellow command modinfo snd_soc_spdif_tx */ compatible = "linux,spdif-dit"; status = "okay"; }; codec_in: spdif-receiver { #address-cells = <0>; #size-cells = <0>; #sound-dai-cells = <0>; /* "linux,spdif-dir" is used in generic I2S(receiver) driver. You can see details "linux,spdif-dir" by bellow command modinfo snd_soc_spdif_rx */ compatible = "linux,spdif-dir"; status = "okay"; }; }; }; fragment@2 { target = <&i2s_clk_producer>; __overlay__ { #sound-dai-cells = <0>; status = "okay"; }; };};/* Compile with: dtc -@ -H epapr -O dtb -o i2smaster.dtbo -Wno-unit_address_vs_reg i2smaster.dtsCopy i2smaster.dtbo to /boot/overlays sudo cp i2smaster.dtbo /boot/overlaysEdit /boot/config.txt sudo nano /boot/config.txtEdit and add to this line # Uncomment some or all of these to enable the optional hardware interface #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on to # Uncomment some or all of these to enable the optional hardware interface #dtparam=i2c_arm=on dtparam=i2s=on #dtparam=spi=on dtoverlay=i2smasterIf you don't need HDMI audio output and RasPi's headphone output, comment out "dtparam=audio=on" by hash.like this. dtparam=audio=on to #dtparam=audio=on*/
Code:
//Device tree overlay for 4ch RP1/dts-v1/;/plugin/;/ { fragment@0 { target = <&rp1_i2s0_18_21>; __overlay__ { pins = "gpio18", "gpio19", "gpio20", "gpio22", "gpio21", "gpio23"; }; }; fragment@1 { target = <&rp1_i2s1_18_21>; __overlay__ { pins = "gpio18", "gpio19", "gpio20", "gpio22", "gpio21", "gpio23"; }; };};
Code:
aplay -D hw:i2smasterrpi5 --dump-hw-params /dev/zero
--------------------
ACCESS: MMAP_INTERLEAVED RW_INTERLEAVED
FORMAT: S16_LE S24_LE S32_LE
SUBFORMAT: STD
SAMPLE_BITS: [16 32]
FRAME_BITS: [32 256]
CHANNELS: [2 8]
RATE: [8000 384000]
PERIOD_TIME: (10 128000]
PERIOD_SIZE: [4 1024]
PERIOD_BYTES: [128 4096]
PERIODS: [2 32768]
BUFFER_TIME: (20 16384000]
BUFFER_SIZE: [8 131072]
BUFFER_BYTES: [128 524288]
TICK_TIME: ALL
--------------------
Available formats: S16_LE, S24_LE, S32_LE
When the soundcard is in use, /proc/asound/card0/pcm0p/sub0/hw_params shows:
ACCESS: RW_INTERLEAVED
FORMAT: S32_LE
SUBFORMAT: STD
CHANNELS: 4
RATE: 352800
PERIOD_SIZE: 256
BUFFER_SIZE: 32768
The period_size is given in frames and a single frame is 16 bytes (4 channels * 4 bytes). So 256 frames cover period_bytes = 4096 bytes, i.e. 1024 bytes per channel. At a sample rate of 352.8 kHz and with 4 bytes per sample, this results in a period time of 1024/(4 * 352800) = 725.6 us. The occurrence of a glitch, which is about 10 us long and happens at multiples of 725 us, means that at the start of a new period, the buffer is empty. To reduce the probability of this happening, I want to increase the period_time to create more buffering. In aplay, with --period-size, I can reduce the period_size, resulting in an even shorter period_time , but I cannot increase it beyond a period_size of 256 because the period_bytes is limited to a maximum of 4096.
Where and how can the period_size be increase, and if needed the buffer_size? What parameters determine the limits found with --dump-hw-params and where are these specified?
Thank you very much for any helpful information!
Statistics: Posted by GerardJ — Wed Jul 17, 2024 11:07 am