Splitting from the huge Async FIFO thread https://www.diyaudio.com/forums/dig...mate-weapon-fight-jitter-721.html#post6773534
The clock arrangement of RPi Master I2S has been discussed here many times. One of the best posts is Henrik's https://www.diyaudio.com/forums/vendor-s-bazaar/355137-symphonic-mpd-24.html#post6250795
RPi4, I2S master (i.e. clocked internally), list of clocks:
The configuration DTS files of the PCM (I2S) peripheral assign clock 54MHz osc -> PLL_D (3,000,000,091Hz) -> divider PLLD_PER (div by 4 i.e. 750,000,023Hz) -> MASH divider to PCM 3,071,997Hz average frequency (I2S 32bit slot => 3071997/64 = 47,999.95 Hz).
Clearly 3000000091/4/(48000*64) = 244.141 division ratio from PLL_D to the I2S bitclock. That's where the MASH kicks in (page 80 of https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf ). In my case
ctl -> MASH 1, source PLL_D
DIVI: 0x0f4= 244
DIVF: 0x241 = 577
3,000,000,091/4/(244 + 577/4,096) = 3,071,997.02Hz
Clearly the division produces something close to the correct bitclock.
But the MASH does the fractional division by changing the divider 244 to 245 (for MASH 1) in some iterations. IMO it's simply 577-times dividing by 245 and 4096-577=3519-times dividing by 244. So the frequency flips between 3,073,770.58 and 3,061,224.582, which makes a difference in period 1.3ns, as clearly seen in Ian's earlier measurement:
If the fractional part were always set to zero, the output frequency would slightly deviate from the requested value, but only clean integer divison would be used and no jitter from the MASH. A trivial patch does so:
The resultant frequency differs from the requested one because the fractional part is missing. The code could be improved with rounding instead of flooring the int part.
My scope is only 100MHz, max. resolution 5ns/div.
Scope traces in the same order:
768000Hz vs. 781250Hz diff 1.8%
705600Hz vs. 732421Hz diff 4%
384000Hz vs. 390625Hz diff 1.7%
352800Hz vs. 355113Hz diff 0.7%
192000Hz vs. 192110Hz diff 0.06%
96000Hz vs. 96055Hz diff 0.06%
No scope traces:
88200Hz vs. 88778Hz diff 0.7%
48000Hz vs. 48027Hz diff 0.06%
44100Hz vs. 44221Hz diff 0.3%
If someone is willing to accept the playback speed error, the above patch vastly improves the jitter of I2S master on RPi. Or an on-the-fly fractional resampling could be used, e.g. the efficient and precise resampler in CamillaDSP.
Of course the correct way is avoiding the I2S master mode and slaving the I2S controller to a proper external clock located by the DAC.
The clock arrangement of RPi Master I2S has been discussed here many times. One of the best posts is Henrik's https://www.diyaudio.com/forums/vendor-s-bazaar/355137-symphonic-mpd-24.html#post6250795
RPi4, I2S master (i.e. clocked internally), list of clocks:
Code:
cat /sys/kernel/debug/clk/clk_summary
enable prepare protect duty hardware
clock count count count rate accuracy phase cycle enable
-------------------------------------------------------------------------------------------------------
...............
osc 4 4 1 54000000 0 0 50000 Y
tsens 0 0 0 3375000 0 0 50000 Y
otp 0 0 0 13500000 0 0 50000 Y
timer 0 0 0 1000000 0 0 50000 Y
plld 5 5 0 3000000091 0 0 50000 Y
plld_dsi1 1 1 0 11718751 0 0 50000 Y
plld_dsi0 1 1 0 11718751 0 0 50000 Y
plld_per 4 4 0 750000023 0 0 50000 Y
pcm 1 1 0 3071997 0 0 50000 Y
emmc2 1 1 0 100000003 0 0 50000 Y
emmc 0 0 0 250000007 0 0 50000 Y
uart 1 1 0 48000001 0 0 50000 Y
plld_core 1 1 0 600000019 0 0 50000 Y
pllc 3 3 1 2999999988 0 0 50000 Y
pllc_per 1 1 0 599999998 0 0 50000 Y
pllc_core2 0 0 0 11718750 0 0 50000 Y
pllc_core1 0 0 0 11718750 0 0 50000 Y
pllc_core0 2 2 1 999999996 0 0 50000 Y
vpu 3 3 1 500000000 0 0 50000 Y
fe804000.i2c_div 1 1 1 100000 0 0 50000 Y
aux_spi2 0 0 0 500000000 0 0 50000 N
aux_spi1 0 0 0 500000000 0 0 50000 N
aux_uart 0 0 0 500000000 0 0 50000 N
peri_image 0 0 0 500000000 0 0 50000 Y
pllb 2 2 0 1200000005 0 0 50000 Y
pllb_arm 1 1 0 600000003 0 0 50000 Y
plla 2 2 0 2999999988 0 0 50000 Y
plla_ccp2 0 0 0 11718750 0 0 50000 Y
plla_dsi0 0 0 0 11718750 0 0 50000 Y
plla_core 1 1 0 499999998 0 0 50000 Y
h264 0 0 0 499999998 0 0 50000 Y
isp 0 0 0 499999998 0 0 50000 Y
The configuration DTS files of the PCM (I2S) peripheral assign clock 54MHz osc -> PLL_D (3,000,000,091Hz) -> divider PLLD_PER (div by 4 i.e. 750,000,023Hz) -> MASH divider to PCM 3,071,997Hz average frequency (I2S 32bit slot => 3071997/64 = 47,999.95 Hz).
Clearly 3000000091/4/(48000*64) = 244.141 division ratio from PLL_D to the I2S bitclock. That's where the MASH kicks in (page 80 of https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf ). In my case
Code:
cat /sys/kernel/debug/clk/pcm/regdump
ctl = 0x00000296
div = 0x000f4241
ctl -> MASH 1, source PLL_D
DIVI: 0x0f4= 244
DIVF: 0x241 = 577
3,000,000,091/4/(244 + 577/4,096) = 3,071,997.02Hz
Clearly the division produces something close to the correct bitclock.
But the MASH does the fractional division by changing the divider 244 to 245 (for MASH 1) in some iterations. IMO it's simply 577-times dividing by 245 and 4096-577=3519-times dividing by 244. So the frequency flips between 3,073,770.58 and 3,061,224.582, which makes a difference in period 1.3ns, as clearly seen in Ian's earlier measurement:
An externally hosted image should be here but it was not working when we last tested it.
If the fractional part were always set to zero, the output frequency would slightly deviate from the requested value, but only clean integer divison would be used and no jitter from the MASH. A trivial patch does so:
Code:
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 39fabced602a..e0dd36137135 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1134,6 +1134,11 @@ static int bcm2835_clock_set_rate_and_parent(struct clk_hw *hw,
ctl |= parent << CM_SRC_SHIFT;
}
+ if (data->div_reg == CM_PCMDIV) {
+ // PCM clock, clearing fractional divider
+ div &= ~CM_DIV_FRAC_MASK;
+ }
+
ctl &= ~CM_FRAC;
ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
cprman_write(cprman, data->ctl_reg, ctl);
The resultant frequency differs from the requested one because the fractional part is missing. The code could be improved with rounding instead of flooring the int part.
My scope is only 100MHz, max. resolution 5ns/div.
Scope traces in the same order:
768000Hz vs. 781250Hz diff 1.8%
705600Hz vs. 732421Hz diff 4%
384000Hz vs. 390625Hz diff 1.7%
352800Hz vs. 355113Hz diff 0.7%
192000Hz vs. 192110Hz diff 0.06%
96000Hz vs. 96055Hz diff 0.06%
No scope traces:
88200Hz vs. 88778Hz diff 0.7%
48000Hz vs. 48027Hz diff 0.06%
44100Hz vs. 44221Hz diff 0.3%
If someone is willing to accept the playback speed error, the above patch vastly improves the jitter of I2S master on RPi. Or an on-the-fly fractional resampling could be used, e.g. the efficient and precise resampler in CamillaDSP.
Of course the correct way is avoiding the I2S master mode and slaving the I2S controller to a proper external clock located by the DAC.
Attachments
-
768000-fract.png53.9 KB · Views: 272
-
192000-int.png36.3 KB · Views: 128
-
192000-fract.png39.4 KB · Views: 130
-
352800-int.png37.8 KB · Views: 127
-
352800-fract.png43.6 KB · Views: 126
-
384000-int.png38.6 KB · Views: 121
-
384000-fract.png44.8 KB · Views: 161
-
705600-int.png44 KB · Views: 278
-
705600-fract.png53 KB · Views: 279
-
768000-int.png43.6 KB · Views: 275
Last edited: