I2S 2-channel mems microphone

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I2S 2-channel mems microphone

Jump to solution
16,340 Views
jcc273
Contributor III

Hello,

I have 2 I2S microphones (SPH0645LM4H) hooked up to an i.MX6 Solo.  These mic's transmit I2S audio data on either the low Frame Clock or the High Frame Clock of the I2S based on a select pin, i have one pulled either way so that i essentially have stereo microphones.  I have everything setup and working and i can capture audio data but i only get the left channel, the right channels i just silence with a little white noise.  I can't seem to figure out what the problem is, I can see the data on the scope and everything looks great, i see left channel data during the low frame clock and right channel during the high frame clock. 

They are connected as follows:

I2S_CLK -> CSI0_DAT4 -> AUD3_TXC

I2S_WS -> CSI0_DAT6 -> AUD3_TXFS

I2S_DATA -> CSI0_DAT7 -> AUD3_RXD

And here is how the device tree is setup:

pinctrl_micmux: micmuxgrp {
fsl,pins = <
MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0
MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0
MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0
>;
};

sound {
compatible = "fsl,imx-audio-sph0645",
"fsl,imx-mic-sph0645";
model = "sph0645-audio";
ssi-controller = <&ssi2>;
mux-int-port = <2>;
mux-ext-port = <3>;
};

&audmux {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_micmux>;
status = "okay";
};

&ssi2 {
fsl,mode = "i2s-master";
assigned-clocks = <&clks IMX6QDL_CLK_SSI2_SEL>,
<&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>;
assigned-clock-rates = <0>;
status = "okay";
};

And imx-audio-sph0645 is a small driver i wrote just to try and get this working, i have attached the whole file but here are the important parts:

static int imx_audmux_config(int slave, int master)
{
unsigned int ptcr, pdcr;
slave = slave - 1;
master = master - 1;

ptcr = IMX_AUDMUX_V2_PTCR_SYN |
IMX_AUDMUX_V2_PTCR_TFSDIR |
IMX_AUDMUX_V2_PTCR_TFSEL(slave) |
IMX_AUDMUX_V2_PTCR_TCLKDIR |
IMX_AUDMUX_V2_PTCR_TCSEL(slave);
pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(slave);
imx_audmux_v2_configure_port(master, ptcr, pdcr);

/*
* According to RM, RCLKDIR and SYN should not be changed at same time.
* So separate to two step for configuring this port.
*/
ptcr |= IMX_AUDMUX_V2_PTCR_RFSDIR |
IMX_AUDMUX_V2_PTCR_RFSEL(slave) |
IMX_AUDMUX_V2_PTCR_RCLKDIR |
IMX_AUDMUX_V2_PTCR_RCSEL(slave);
imx_audmux_v2_configure_port(master, ptcr, pdcr);

ptcr = IMX_AUDMUX_V2_PTCR_SYN;
pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(master);
imx_audmux_v2_configure_port(slave, ptcr, pdcr);

return 0;
}

static int imx_sph0645_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
u32 channels = 2; //ALWAYS 2 CHANNELS params_channels(params);
u32 rate = params_rate(params);
u32 bclk = rate * channels * 32;
int ret = 0;

/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
if (ret) {
dev_err(cpu_dai->dev, "failed to set dai fmt\n");
return ret;
}

ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 3, 2, 32);
if (ret) {
dev_err(cpu_dai->dev, "failed to set dai tdm slot\n");
return ret;
}

ret = snd_soc_dai_set_sysclk(cpu_dai, 0, bclk, SND_SOC_CLOCK_OUT);
if (ret)
dev_err(cpu_dai->dev, "failed to set cpu sysclk\n");

return ret;
}

Any idea what I am doing wrong??? Like i said on an oscilloscope the signals look great and i get great left channel audio, but nothing on the right : /.  Here is how I am recording:

arecord -c 2 -d 5 -f S32 -r 48000 -v /home/root/test.wav

Thanks,

Jarrod

Labels (4)
1 Solution
13,178 Views
jcc273
Contributor III

Alright figured this out, i had a couple problems.  The main was that it turned out they washed the boards with the microphones on there : /.  This damaged a lot of the microphones internally but the since they have I2S output it was still outputting data just not valid audio data, only white noise.

The other issue was in the format, the SPH0645 microphone does 18-bit data and outputs it as 0 padded 24-bit data, but when i was recording as 24-bit it would pull the entire 32-bit value from the RX register (with 32-bit 0x00 padding) and put the whole thing into the resulting wave file.  So when i played back these files it was trying to play a 24-bit file that actually contained 32-bit data which resulted in a bunch of awful sounding garbage.  Changing the file format to 32-bit sample size corrects this issue.

So replaced the microphones and fixed the formatting (i actually am only using 16-bit instead which circumvents the non-aligned issue since the microphone only does 18-bit output anyway I'm only losing 2 bits).  Now i have perfect stereo audio recording! : )

View solution in original post

0 Kudos
Reply
22 Replies
12,910 Views
gordonsmith
Contributor II

Jarrod -

Are you using an ALSA config file for routing? If so, do you know what that looked like?

0 Kudos
Reply
12,904 Views
jcc273
Contributor III

Hello Gordon,

Here is my asound.conf file:

pcm.mic_mix {
   type dsnoop
   ipc_key 3025
   slave {
      pcm "hw:0,0"
      rate 48000
      channels 2
      format S16_LE
   }
   bindings {
      0 0
      1 1
   }
}

pcm.mic_sv {
   type softvol
   slave.pcm mic_mix
   control {
      name "Boost Capture Volume"
      card 0
   }
   min_dB -10.0
   max_dB 40.0
}

pcm.!default {
   type asym
   capture.pcm {
      type plug
      slave.pcm mic_sv
   }
}

I run it through softvol because the microphone volume is very low coming in.  Hope that helps : )

- Jarrod

12,887 Views
hitesh_kasera
Contributor III

Hi Jarrod,

i used the same config file as you suggested but i am getting error:

root@ccimx6ulsbc:~# arecord -l
**** List of CAPTURE Hardware Devices ****
ALSA lib ../../alsa-lib-1.1.4.1/src/conf.c:1876:(snd_config_load1) _toplevel_:1:123:Unexpected end of file
ALSA lib ../../alsa-lib-1.1.4.1/src/conf.c:3636:(config_file_open) /etc/asound.conf may be old or corrupted: consider to remove or fix it
ALSA lib ../../alsa-lib-1.1.4.1/src/conf.c:3558:(snd_config_hooks_call) function snd_config_hook_load returned error: Invalid argument
ALSA lib ../../alsa-lib-1.1.4.1/src/conf.c:4012:(snd_config_update_r) hooks failed, removing configuration
arecord: device_list:279: control open (0): Invalid argument

When i remove everything from asound.conf it shows :

root@ccimx6ulsbc:~# arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: imxaudiosph0645 [imx-audio-sph0645], device 0: imx-sph0645 snd-soc-dummy-dai-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Request you to please suggest what i might need to change.

Regards,

Hitesh

0 Kudos
Reply
12,887 Views
jcc273
Contributor III

Hmmm, it doesn't like something in your asound.conf file.  According to your arecord -l it is card #0 device #0 so hw:0,0 should be correct.  You could make sure you by:  ls /dev/snd  and you should see a pcmC0D0c  indicating you have pcm capture device hw:0,0.  If all is correct there you should be able to record from the device without using asound.conf at all:

arecord -c 2 -d 5 -f S32_LE -r 48000 -D hw:0,0 -v /home/root/test.wav

I think those should be all the correct settings, it is an 18-bit microphone so you'll need 32-bits, but you could also probably just use S16_LE and cut the least significant bits off.  Anyway play with the settings and see if you can get a recording from the the raw device first.  If you can then everything is good!  Then once that works just make your asound.conf settings match what you used for the raw recording.  Simplify it out by removing the soft volume first:

pcm.mic_mix {
   type dsnoop
   ipc_key 3025
   slave {
      pcm "hw:0,0"
      rate 48000
      channels 2
      format S32_LE
   }
   bindings {
      0 0
      1 1
   }
}

pcm.!default {
   type asym
   capture.pcm {
      type plug
      slave.pcm mic_mix
   }
}

Then edit format, channels, pcm, etc. to match what you used in your raw arecord command to get a valid recording.  Then you should be able to use arecord without the -D hw:0,0 line and it will use your asound.conf file to find the device.  Then once you get that working you can add the soft volume back in to increase the volume of the obtained audio if desired (it is pretty quiet so you will likely want this).

Good Luck!

-Jarrod

12,910 Views
hitesh_kasera
Contributor III

Hi Jarrod,

I have started working with 1 I2S microphones (SPH0645LM4H) hooked up to an i.MX6UL. I want to record audio from mic to one file. I am using software environment Eclipse to implement the code in c. Request you to please guide me how should i go ahead. it would be really helpful.

Device Tree is:

/ {
    /*
     * Reference block.
     *
     * Add your sensor configuration.
     */
    //sound_max98089: sound-max98089 {
    //  compatible = "fsl,imx-audio-max98088";
    //  model = "imx-max98088";
    //  cpu-dai = <&sai1>;
    //  audio-codec = <&max98089>;
    //  asrc-controller = <&asrc>;
    //  gpr = <&gpr>;
    //  audio-routing =
    //      "Headphone Jack", "HPL",
    //      "Headphone Jack", "HPR",
    //      "Ext Spk", "SPKL",
    //      "Ext Spk", "SPKR",
    //      "LineOut", "RECL",
    //      "LineOut", "RECR",
    //      "Mic1", "MIC1",
    //      "Mic2", "MIC2",
    //      "LineInA", "INA1",
    //      "LineInA", "INA2",
    //      "LineInB", "INB1",
    //      "LineInB", "INB2";
    //  status = "okay";
    //};
};

/*
 * Reference block.
 *
 * Add your codec configuration to the corresponding I2C.
 */
//&i2c1 {
    //max98089: codec@10 {
    //  compatible = "maxim,max98089";
    //  reg = <0x10>;
    //  clocks = <&clks IMX6UL_CLK_SAI1>;
    //  clock-names = "mclk";
    //  interrupt-parent = <&gpio5>;
    //  interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
    //  status = "okay";
    //};
//};

&sai1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_sai1>;

    /*
     * Reference block.
     *
     * Codec dependent section.
     */
    //assigned-clocks = <&clks IMX6UL_CLK_SAI1_SEL>,
    //        <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>,
    //        <&clks IMX6UL_CLK_SAI1>;
    //assigned-clock-rates = <0>, <786432000>, <12288000>;
    //assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;

    status = "okay";
};

&iomuxc {
    imx6ul-ccimx6ul {
        pinctrl_sai1: sai1grp {
            fsl,pins = <
                MX6UL_PAD_LCD_DATA00__SAI1_MCLK        0x17088
                MX6UL_PAD_LCD_DATA03__SAI1_RX_DATA        0x11088
                MX6UL_PAD_LCD_DATA02__SAI1_TX_BCLK        0x17088
                MX6UL_PAD_CSI_DATA07__SAI1_TX_DATA        0x11088
                MX6UL_PAD_LCD_DATA01__SAI1_TX_SYNC        0x17088
            >;
        };
    };
};

Thanks,

Hitesh

0 Kudos
Reply
12,910 Views
jcc273
Contributor III

Hello Hitesh,

It has been awhile since i worked on this, but I'll try to describe everything the best I can : ).  I have attached a kernel patch that contains the driver i added for this microphone on the imx6.  I couldn't find a generic microphone driver that did what i wanted with the imx6 so i created one.  This patch is for the imx kernel (git.freescale.com/imx/linux-2.6-imx.git) version rel_imx_4.1.15_1.1.0_ga, BUT it is pretty generic and you should be able to fairly easily patch almost any similar kernel with it.

Apply this patch to your kernel then you will want to add the following entries in the appropriate sections in your device tree:

/ {
   /*Use the sph0645 driver the patch adds
     On my board the microphone is connected to SSI2
     mux-int-port sets the internal audmux connection (2 = SSI2)
     mux-ext-port sets the external audmux connection (3 = AUD3)
     See Chapter 16 on reference manual for more on AUDMUX, but
     on my board I am using SSI2 and i have my mic connected to the
     AUD3 RXD, TXC, and TXFS lines, so just change the number below
     based on what you are using */
   sound {
      compatible = "fsl,imx-audio-sph0645",
                           "fsl,imx-mic-sph0645";
      model = "sph0645-audio";
      ssi-controller = <&ssi2>;
      mux-int-port = <2>;
      mux-ext-port = <3>;
   };
}

/* Pinmuxing for the AUDMUX lines my microphone is connected to */
&audmux {
   pinctrl-names = "default";
   pinctrl-0 = <&pinctrl_micmux>;
   status = "okay";
};

/* Enable the SSI2 as an I2S master */
&ssi2 {
   fsl,mode = "i2s-master";
   assigned-clocks = <&clks IMX6QDL_CLK_SSI2_SEL>,
                                 <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>;
   assigned-clock-rates = <0>;
   fsl,fifo-depth = <15>;
   status = "okay";
};

/* Define the pinmuxing for the lines your microphone is connected to,
mine is connected to AUD3 */
&iomuxc {
   pinctrl-names = "default";

   imx6qdl-sabresd {
      pinctrl_micmux: micmuxgrp {
         fsl,pins = <
            MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0
            MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0
            MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0
         >;
      };
   };
};

I put some comments in there to describe things, but basically I am using SSI2 internally so you should be able to leave that as is as long as you aren't using ssi2 for something else.  The only thing you might need to change is the AUDMUX stuff, as you can see i have my microphone's lines connected to CSI0_DAT7_)AUD3_RXD, CSI0_DAT4_)AUD3_TXC, and CSI0_DAT6__AUD3_TXFS.  If you aren't using the same pins then you will need to adjust the pinmuxing and then if you aren't using AUD3 you will need to change mux-ext-port in the sound module to the AUD you are using.

Anyways once you get that all setup and enable the new driver in your kernel and rebuild you should then have an audio device available in linux for use in capturing audio.  It will expose 2 channel audio in case you have 2 microphones attached, but it will still work just the same with 1 microphone just route mono audio in your asound.conf or whatever.

Hopefully this helps!  Let me know if you have any other questions and maybe i can point you in the right direction : )

-Jarrod

12,910 Views
hitesh_kasera
Contributor III

Hi jarrod,

Thanks a lot for your response. I can understand you have done this in past. Right now i am using connect core I.mx6ul not i.mx solo, from Digi which doesnt have audmux.

Device tree is :

&sai1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_sai1>;


    /*
     * Reference block.
     *
     * Codec dependent section.
     */
    assigned-clocks = <&clks IMX6UL_CLK_SAI1_SEL>,
            <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>,
            <&clks IMX6UL_CLK_SAI1>;
    assigned-clock-rates = <0>, <786432000>, <12288000>;
    assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;


    status = "okay";
};

Let me know what you think of this configuration. i didnt get purpose of assigning clock rates to 0 in your case.

I am hoping patch file which you have provided contains audiomux function but in i.mxul there is no such audio multiplexer. in this processor there is sai (serial audio interface) in place of ssi controller and no audio multiplexer. i will be using sai1. how i should i proceed with this. it will be really helpful if you can guide. what additional changes i need to do in patch file and in device true configuration?

let me know your suggestions!


Thanks & Regards,
Hitesh

0 Kudos
Reply
12,910 Views
jcc273
Contributor III

Hitesh,

Ah okay, i have never used the SAI before, but probably you just need to remove the audmux stuff from the driver and then tie the new driver and the SAI together with your device tree.  I have attached a new driver file for the microphone that shows what I mean.  Then probably use something similar to this in your device tree:

/ {
   sound {
      compatible = "fsl,imx-audio-sph0645",
                           "fsl,imx-mic-sph0645";
      model = "sph0645-audio";
      cpu-dai = <&sai1>;
   };
};

&sai1 {
   pinctrl-names = "default";
   pinctrl-0 = <&pinctrl_sai1>;

   /*
   * Reference block.
   *
   * Codec dependent section.
   */
   assigned-clocks = <&clks IMX6UL_CLK_SAI1_SEL>,
                        <&clks IMX6UL_CLK_SAI1>;
   assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
   assigned-clock-rates = <0>, <12288000>;

   status = "okay";
};

Both the device tree and the attached driver file are untested, this is just my assumption about what you probably need to do.  I have no way to try any of it out now, but they will hopefully point you in the correct direction to figure it out!

Since the Microphone requires no setup you should only need to define the cpu-dai property in your sound node, you do not need a codec node, so as long as your sai is setup correctly you just bind them and hopefully everything will work well.

Wish i knew more, but hopefully this information helps you a little! : )  Best of luck!

Thanks,

Jarrod

12,910 Views
hitesh_kasera
Contributor III

Hi Jarrod,

Thanks a lot for helping me out and sharing driver file. Surely i will try it out. Now i have also edited patch file which i have attached according to SAI and removed audmux stuff. I am not sure whether i need to generate the patch or directly use it. Can you suggest how to generate patch file like you did, or should i directly use it? also it will be great if you can provide some reference on how to apply this patch file to i.mx6 ul kernel.

Regards,

Hitesh

0 Kudos
Reply
12,910 Views
jcc273
Contributor III

Hitesh,

To apply a patch file to the kernel you can just:

- Change directory into the base of the kernel source

- run the following:  patch -p1 < $LOCATION_OF_PATCH_FILE

- just replace $LOCATION_OF_PATCH_FILE with the location of your patch (linux-imx-4.1.15_1.1.0_ga-sph0645.patch)

Your edited patch file may not apply properly because it is not straightforward editing a patch file as it contains line indicators and such that can get messed up.  Probably what i would do if i were you is either apply the original patch and then go edit the files as necessary OR using your patch and what you want it to do just go make the changes manually to the files instead of using the patch command.

Whatever way you choose once you get the changes made to files like you want make sure you add the new CONFIG_SND_SOC_IMX_SPH0645 to the kernel config and then rebuild the kernel and install on your board and put in your new device tree.  Then if everything goes well you will hopefully have a new audio capture device.  If things don't work then you will have to debug and see where the problem occurs.  As long as it is setup in the device tree and built into the kernel then at least the "probe" function in the driver should be called, so if not working a good first step is to make sure you are getting there with a print or something and also to check dmesg for errors : ).

Thanks,

Jarrod

12,910 Views
hitesh_kasera
Contributor III

Hi Jarrod,

Thanks a lot for your guidance. i tried to generate the patch for both device tree (added new custom machine) and driver patch. Both i have attached for your reference. i build the kernel and updated the same. i have attached both patches for your reference. the output which i get by running arecord -c 2 -d 5 -f S32 -r 48000 -v /home/root/test.wav is:

root@ccimx6ulsbc:~# arecord -c 2 -d 5 -f S32 -r 48000 -v /home/root/test.wav
ALSA lib ../../alsa-lib-1.1.4.1/src/confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib ../../alsa-lib-1.1.4.1/src/conf.c:4554:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib ../../alsa-lib-1.1.4.1/src/confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib ../../alsa-lib-1.1.4.1/src/conf.c:4554:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib ../../alsa-lib-1.1.4.1/src/confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib ../../alsa-lib-1.1.4.1/src/conf.c:4554:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib ../../alsa-lib-1.1.4.1/src/conf.c:5033:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib ../../../alsa-lib-1.1.4.1/src/pcm/pcm.c:2501:(snd_pcm_open_noupdate) Unknown PCM default
arecord: main:807: audio open error: No such file or directory

it cannot find the card, i checked in dmesg also there was nothing mentioned related to sai1 or imx-spho645. Can you help out what i am missing?

Thanks,

Hitesh

0 Kudos
Reply
12,910 Views
gordonsmith
Contributor II

I also add output to fsl_sai.c:

fsl_sai_probe+
fsl-sai 40031000.sai: failed to get mclk[2] clock: -2
fsl-sai 40031000.sai: failed to get mclk[3] clock: -2
fsl-sai 40031000.sai: failed to get mclk[4] clock: -2
fsl_sai_probe: exit final: result=0
0 Kudos
Reply
12,910 Views
gordonsmith
Contributor II

Do you have any audio cards?

# cat /proc/asound/cards
 0 [imxaudioinmp441]: imx-audio-inmp4 - imx-audio-inmp441
                      imx-audio-inmp441

Is the microphone driver loading OK?

I'm using SAI2 on Vybrid using part inmp441 instead of sph0645.

I get the following message when the microphone driver loads successfully.

# modprobe dm-mic-inmp441

dm-mic-inmp441 sound.3: snd-soc-dummy-dai <-> 40031000.sai mapping ok

I add output of my own in the microphone driver to help understand what's happening. The output actually looks like this:

# modprobe dm-mic-inmp441

dm-mic-inmp441 sound.3: probe+
dm-mic-inmp441 sound.3: snd-soc-dummy-dai <-> 40031000.sai mapping ok
dm-mic-inmp441 sound.3: register card OK
0 Kudos
Reply
12,910 Views
hitesh_kasera
Contributor III

Hi gordon,

i am not able to register the card. when i run the following command get the output of no sound card found.

root@ccimx6ulsbc:~# cat /proc/asound/cards                                      
--- no soundcards ---

i am not able to get what am i missing or doing wrong.

Thanks,

Hitesh

0 Kudos
Reply
12,910 Views
jcc273
Contributor III

Hitesh,

If i were you i would do like Gordon did in his below comment and add prints to the drivers.  That way you can see what is happening on boot.  Start by adding prints to the function: imx_sph0645_probe  in the file:  sound/soc/fsl/imx-sph0645.c   The probe function is what will get called if you have properly registered the driver and device in your device tree.  If a print at the top of the probe function never prints then something is probably wrong with your device tree specification OR something like the names in your device tree don't match the names in imx_sph0645_dt_ids or something like that, that makes the kernel unable to find the driver.

If the print does print out then the easiest thing to do is to keep putting more prints down through the probe function to display different information and find out where the error is occuring.  If the probe function succeeded it would register the card on this line:  ret = snd_soc_register_card(card); and you would see that card be available.

I usually use kernel prints like this that will show up in dmesg:

printk(KERN_ERR "SPH- Got here\r\n");

Thanks,

Jarrod

12,910 Views
hitesh_kasera
Contributor III

Hi Jarrod,

Thanks a lot for providing your inputs. After debugging i got the card registered. Here is the output.

cat /proc/asound/cards                                      
 0 [imxaudiosph0645]: imx-audio-sph06 - imx-audio-sph0645                       
                      imx-audio-sph0645       

But when i run the command arecord got this error:

 

arecord -c 2 -d 5 -f S32 -r 48000 -v /home/root/test.wav    


Recording WAVE '/home/root/test.wav' : Signed 32 bit Little Endian, Rate 48000 o
fsl-sai 2028000.sai: failed to derive required Rx rate: 2304000                 
fsl-sai 2028000.sai: ASoC: can't set 2028000.sai hw params: -22                 
arecord: set_params:1382: Unable to install hw params:                          
ACCESS:  RW_INTERLEAVED                                                         
FORMAT:  S32_LE                                                                 
SUBFORMAT:  STD                                                                 
SAMPLE_BITS: 32                                                                 
FRAME_BITS: 64                                                                  
CHANNELS: 2                                                                     
RATE: 48000                                                                     
PERIOD_TIME: (42666 42667)                                                      
PERIOD_SIZE: 2048                                                               
PERIOD_BYTES: 16384                                                             
PERIODS: 4                                                                      
BUFFER_TIME: (170666 170667)                                                    
BUFFER_SIZE: 8192                                                               
BUFFER_BYTES: 65536                                                             
TICK_TIME: 0                    

"failed to derive required Rx rate:" - This device print i have found in fsl_sai.c but we havent called that function in our driver code. Function which i am using is "snd_soc_dai_set_sysclk(cpu_dai, 0, bclk, SND_SOC_CLOCK_OUT)". As i am passing parameter 48000 then bclk should be 48000*32*2 but its taking 48000*24*2 = 2304000, that part also i am not able to get. Can you share some thoughts on this and any comments for hardware installation error.

Thanks,

Hitesh

0 Kudos
Reply
12,910 Views
hitesh_kasera
Contributor III

Hi Jarrod,

I tried using different sampling rate and it was working. For an example:

when i used this below mentioned command it was working

arecord -c 2 -d 5 -f S32 -r 64000 -v /home/root/test.wav 

i just changed the sampling rate 48000 to 64000. but on oscilloscope i was getting bit clock frequency around 11.086Mhz and Frame sync clock was about 230.41Khz. In this case i have not attached the microphone sensor because it could get damaged due to higher frequency. As for sph0645 microphone frame sync should be bclk/64 but its here not the case and also am not able to get desired bclk. Request you to please guide me for the same.

Thanks,

Hitesh

0 Kudos
Reply
12,910 Views
jcc273
Contributor III

Hitesh,

Very strange : /.  It is calculating the wrong clocks.  Like you stated above this is your driver code:

u32 channels = 2; //ALWAYS 2 CHANNELS params_channels(params);
u32 rate = params_rate(params);
u32 bclk = rate * channels * 32;

......
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 3, 2, 24);

......

ret = snd_soc_dai_set_sysclk(cpu_dai, 0, bclk, SND_SOC_CLOCK_OUT);

The set_tdm_slot and set_sysclk calls should call functions within:  sound/soc/fsl/fsl_sai.c because that is what should be assigned to cpu_dai using your device tree.  In the tdm_slot call the last parameter is the slot width and the mic only has 24 valid so we set it to that instead of 32, that might be where your 24 is coming from in the 48KHz attempt above.  if you look at the function fsl_sai_hw_params in fsl_sai.c you will see if it is NOT in slave mode it calculates the bclk itself using slot_width, so that is probably hitting and setting the bclk after your imx-sph0645 code causing the issues with 48KHz.

The set_sysclk function in imx_sph0645.c should call the fsl_sai_set_bclk function within the fsl_sai.c file as well using the bclk you calculated above, but i think the hw_params in fsl_sai.c calls it after as described above using slot_width and changes it.

You could try changing the 24 in the call to snd_soc_dai_set_tdm_slot to 32 and see how that affects trying to record at 48K.

As for why you are seeing such a crazy clock rate on your output with 64KHz i have no idea there other than the clock, pll assignment is not correct so it is not making the clock rate it thinks it is.

I have not used the sai at all in this part so sorry i don't have more info on setting it up.  What i would do in your situation is put prints all through the hw_params functions in both your imx-sph0645.c and fsl_sai.c and also in the fsl_sai_set_bclk and fsl_sai_set_dai_tdm_slot functions in fsl_sai.c and print out the values of rates and such and just try and sort out where things are going wrong.  You'll probably just need to use prints to trace where these faulty rates are coming from and then get it sorted out from there.  You will then be able to at least see what rate it thinks it is setting bclk too and you can keep going deeper to find the pll it is using and such and hopefully it will point out the problem why the clock it puts out doesn't match.

-Jarrod

0 Kudos
Reply
13,179 Views
jcc273
Contributor III

Alright figured this out, i had a couple problems.  The main was that it turned out they washed the boards with the microphones on there : /.  This damaged a lot of the microphones internally but the since they have I2S output it was still outputting data just not valid audio data, only white noise.

The other issue was in the format, the SPH0645 microphone does 18-bit data and outputs it as 0 padded 24-bit data, but when i was recording as 24-bit it would pull the entire 32-bit value from the RX register (with 32-bit 0x00 padding) and put the whole thing into the resulting wave file.  So when i played back these files it was trying to play a 24-bit file that actually contained 32-bit data which resulted in a bunch of awful sounding garbage.  Changing the file format to 32-bit sample size corrects this issue.

So replaced the microphones and fixed the formatting (i actually am only using 16-bit instead which circumvents the non-aligned issue since the microphone only does 18-bit output anyway I'm only losing 2 bits).  Now i have perfect stereo audio recording! : )

0 Kudos
Reply
12,909 Views
igorpadykov
NXP Employee
NXP Employee

Hi Jarrod

to narrow down problem if this is related to AUDMUX/SSI settings or linux,

one can test configuration with baremetal sdk

Github SDK
https://github.com/backenklee/swp-report/tree/master/iMX6_Platform_SDK 

Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply