Dear NXP team,
Please check below,
imx8mp-evk + PDM mic(SPG08P4HM4H-1 * 2ea)
1. When I check other case of PDM mic on NXP community & NXP's mic board, PDM_CLK 1MHz is ok. But 'SPG08P4HM4H' needs minimum 1.2MHz.
So, I want to change PDM_CLK, But I can't understand the algorithm of assigned-clock-rates = <196608000>
Could you explain the calculate algorithm using example real-use-case?
196608000 means?
MICFIL_CLK_ROOT = ? (code location)
PDM_CLK = ? (code location)
2. When I use memtool for reading PDM register, I does not work. (bus error? sorry, I have no captures now)
command : memtool -32 0x30ca0000 1
How I read the PDM register in this case?
Environment)
HW :
SW : using imx8mp-evk.dts (imx_5.10.72-2.2.0)
BR,
Thanks.
Regarding the access with memtool the bus error it is caused because the MICFIL module is not clocked until you exercise it. You can first check which is the card assigned to the imxaudiomicfil
root@imx8mp-lpddr4-evk:/unit_tests# arecord -l
**** List of CAPTURE Hardware Devices ****
...
card 1: imxaudiomicfil [imx-audio-micfil], device 0: micfil hifi snd-soc-dummy-dai-0 [micfil hifi snd-soc-dummy-dai-0]
Subdevices: 1/1
Subdevice #0: subdevice #0
...
Do a record on the background and now the MICFIL registers should be accesible
root@imx8mp-lpddr4-evk:/unit_tests# arecord -Dhw:1,0 -fS32_LE -r48000 -c4 test.wav &
Recording WAVE 'test.wav' : Signed 32 bit Little Endian, Rate 48000 Hz, Channels 4
root@imx8mp-lpddr4-evk:/unit_tests# ./memtool -32 0x30ca0000 1
Reading 0x1 count starting at address 0x30CA0000
0x30CA0000: 2100000F
root@imx8mp-lpddr4-evk:/unit_tests# pkill arecord
Dont forget to kill the arecord application.
The assigned-clocks -rate property on the mifcil node set the initial rate of the corresponding clk under the assigned-clocks. This is the IMX8MM_CLK_PDM is set to 196608000Hz at boot up.
&micfil {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pdm>;
assigned-clocks = <&clk IMX8MM_CLK_PDM>;
assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
assigned-clock-rates = <196608000>;
status = "okay";
};
If you dump the clk_summary just after booting linux
cat /sys/kernel/debug/clk/clk_summary
enable prepare protect duty clock count count count rate accuracy phase cycle
----------------------------------------------------------------------------------------
audio_pll1_ref_sel 0 0 0 24000000 0 0 50000
audio_pll1 0 0 0 393216000 0 0 50000
audio_pll1_bypass 0 0 0 393216000 0 0 50000
audio_pll1_out 0 0 0 393216000 0 0 50000
pdm 0 0 0 196608000 0 0 50000
pdm_root 0 0 0 196608000 0 0 50000
pdm_sel 0 0 0 196608000 0 0 50000
pdm_root_clk 0 0 0 196608000 0 0 50000
As you can see the pdm_root_clk (IMX8MM_CLK_PDM) is set at 196608000Hz
However, once you record something using arecord (The micfil driver is exercised)
arecord -Dhw:1,0 -fS32_LE -r48000 -c4 test.wav
You will notice the pdm_root_clk changes its value to 24576000 Hz
cat /sys/kernel/debug/clk/clk_summary
audio_pll1_ref_sel 1 1 0 24000000 0 0 50000
audio_pll1 1 1 0 393216000 0 0 50000
audio_pll1_bypass 1 1 0 393216000 0 0 50000
audio_pll1_out 1 1 0 393216000 0 0 50000
pdm 1 1 0 24576000 0 0 50000
pdm_root 1 1 0 24576000 0 0 50000
pdm_sel 1 1 0 24576000 0 0 50000
pdm_root_clk 1 1 0 24576000 0 0 50000
This is because the output rate 48KHz is requested by the application. The fsl_micfil_set_mclk_rate function at the kernel driver will be called with parameter freq = 48000 and the mclk (pdm_root_clk) will be set the accordingly
If freq is interger multiple of 8K then pdm_root_clk = 24576000 (CLK_8K_FREQ)
if freq NOT integer multiple of 8K then use 22579200 (CLK_11K_FREQ)
For the freq = 48Khz mclk = 24576000
This can be seen at the sound/soc/fsl/fsl_micfil.c file on kernel driver
#define CLK_8K_FREQ 24576000
#define CLK_11K_FREQ 22579200
static int fsl_micfil_set_mclk_rate(struct fsl_micfil *micfil, int clk_id,
unsigned int freq)
{
. . .
clk_disable_unprepare(micfil->mclk);
. . .
clk_rate = freq % 8000 == 0 ? CLK_8K_FREQ : CLK_11K_FREQ;
ret = clk_set_rate(micfil->mclk, clk_rate);
. . .
clk_prepare_enable(micfil->mclk);
. . .
}
The mclk is not the actual bitclk. This is computed based from the following table on the RM
which correspond to the calculations on the get_pdm_clk function (plus the k factor)
where rate = output rate 48KHz and cicosr = osr =16
For High quality -> bclk = 48KHz * 8 * 16 /2 = 3072000 Hz
static inline int get_pdm_clk(struct fsl_micfil *micfil,
unsigned int rate)
{
. . .
switch (qsel) {
case MICFIL_HIGH_QUALITY:
bclk = rate * 8 * osr / 2; /* kfactor = 0.5 */
break;
case MICFIL_MEDIUM_QUALITY:
case MICFIL_VLOW0_QUALITY:
bclk = rate * 4 * osr * 1; /* kfactor = 1 */
break;
case MICFIL_LOW_QUALITY:
case MICFIL_VLOW1_QUALITY:
bclk = rate * 2 * osr * 2; /* kfactor = 2 */
break;
case MICFIL_VLOW2_QUALITY:
bclk = rate * osr * 4; /* kfactor = 4 */
break;
. . .
}
The OSR is always set to the default value of MICFIL_CTRL2_OSR_DEFAULT (0) hence cicosr = 16
static int fsl_set_clock_params(struct device *dev, unsigned int rate)
{
.. .
/* set CICOSR */
ret |= regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
MICFIL_CTRL2_CICOSR_MASK,
MICFIL_CTRL2_OSR_DEFAULT);
. . .
}
Finally the clk_div is computed as follows
clk_div = mclk / (pdm_clk *2)
clkdiv = 24576000/(3072000 * 2) = 4
clk__div = 4
static inline int get_clk_div(struct fsl_micfil *micfil,
unsigned int rate)
{
. . .
mclk_rate = clk_get_rate(micfil->mclk);
clk_div = mclk_rate / (get_pdm_clk(micfil, rate) * 2);
. . .
}
So, translated to the nomenclature on RM for the output rate = 48KHz example:
MICFIL_CLK_ROOT = mclk_rate = = 24576000
PDM_CLK = mclk_rate/ clk_div = 6144000
So actual clk on the pdm microphone will be 6.1 MHz for High Quality
First of all, thank you for the detail information.
I have one more question.
=============================================================
So, translated to the nomenclature on RM for the output rate = 48KHz example:
MICFIL_CLK_ROOT = mclk_rate = = 24576000
PDM_CLK = mclk_rate/ clk_div = 6144000
So actual clk on the pdm microphone will be 6.1 MHz for High Quality
=============================================================
When I check "amixer -c 1 cget name='MICFIL Quality Select'"
I already know, the Mic-fil set 'High Quality' using register set.
But amixer set values=6 'VLow0' as a default. Is it need to modify?
Yes, need.
When I change that using "amixer -c 1 cset name='MICFIL Quality Select' 1" for test,
PDM mic does not work......
How do I fix it?
Does it work well for the other values? Or it only fail with value=1?
What is the failure? Does it throw you an error?
We did a test and it is working on all the levels on our side.
How are you recording, which command are you using to record?
Dear NXP team,
Sorry, I can't attach files because of our security program.
working invironment : imx8mp-evk + PDM mic(SPG08P4HM4H-1 * 2ea)
test command : arecord -f S16_LE -D plughw:1,0 -t wav -r 48000 -c 2 -d 10 -vvv ./sample.wav
case1) "MICFIL Quality Select" "VLow0"(default) : working good (no noise)
case2) set "MICFIL Quality Select" to "HIGH" : NG (high noise)
I got the expert AE reply:
===============
I tried on 8Mplus but not able to reproduce the noise issue. Noticed you are using format S16_LE, micfil on 8Mplus outputs S32_LE, so maybe try to do the arecord bypassing the plug element on your pipeline. The plug element will perform format convertion from S16_LE to S32_LE and this extra process might be adding some artifacts, maybe not as severe as the noise you are observing but I will advise to try without the plug.
Try something like:
arecord -f S32_LE -D hw:1,0 -t wav -r 48000 -c 2 -d 10 -vvv
===============
Best regards,
Jimmy
Hello,
We see this same issue on i.MX8MN SoC. Setting quality "High" introduces tons of more noise.
Br
August