PDM Microphone via DMIC Interface

I’d like some assistance bringing up the DMIC interface on a Jetson Nano production module.

I am looking at the PinMux spreadsheet “NV_Jetson_Nano_Module_Pinmux_Config_Template.xlsm”

I’m interested in using pins 224 and 222 for DMIC1_CLK and DMIC1_DAT. According to the spreadsheet, the default pinmux is I2S3_LRCK and I2S3_SDATA_IN for those pins.

Assuming I generate new device tree source files to change the pinmuxing to DMIC special function instead, I have two questions…

  1. How can I confirm the pinmuxing is correct (using DMIC) at runtime on the Linux system
  2. How can I use this interface from userspace Linux via tegrasndt210ref driver? An example arecord command or something equivalent would be helpful.

Thanks!

Hello!

To answer your questions …

  1. You can check the pinmux by
$ sudo cat /sys/kernel/debug/pinctrl/700008d4.pinmux/pinconf-groups
...
52 (dmic1_clk_pe0): 
        pull=0
        tristate=0
        enable-input=1
        open-drain=0
        lock=0
        schmitt=0
        pull-down-strength=16
        pull-up-strength=16
        lpdr=0
        pbias-buf=1
        preemp=1
        rfu-in=1
        special-function=1
        func=i2s3
53 (dmic1_dat_pe1): 
        pull=0
        tristate=0
        enable-input=1
        open-drain=0
        lock=0
        schmitt=0
        pull-down-strength=16
        pull-up-strength=16
        lpdr=0
        pbias-buf=1
        preemp=1
        rfu-in=1
        special-function=1
        func=i2s3

In the above you want to ensure that the function is set to “dmic1” and verify that input-enable and tristate are set accordingly.

The DMIC1 pins are shared with GPIOs E0 and E1 and so we also need to …

$ sudo cat /sys/kernel/debug/tegra_gpio | grep "Name\| E:"
Name:Bank:Port CNF OE OUT IN INT_STA INT_ENB INT_LVL
 E: 1:0 00 00 00 00 00 00 000000

That bits 0 and 1 of the CFG value for bank E above are 0. This means that they are not being used as GPIOs.

  1. To test audio record you can …
amixer -c tegrasndt210ref cset name="MVC1 Mux" DMIC1
amixer -c  tegrasndt210ref cset name="ADMAIF2 Mux" MVC1
amixer -c  tegrasndt210ref cset name="DMIC1 Boost Gain" 50
amixer -c  tegrasndt210ref cset name="MVC1 Vol" 12602
amixer -c  tegrasndt210ref cset name="MVC1 input bit format" 32
amixer -c  tegrasndt210ref cset name="DMIC1 output bit format" 32
arecord -D hw: tegrasndt210ref,1 -r 48000 -c 2 -f S32_LE -d 10 cap.wav

There are some more examples here: Welcome — Jetson Linux<br/>Developer Guide 34.1 documentation

Regards,
Jon

Hi Jonathan,

Thanks for the response, that was incredibly helpful!

I went ahead and patched the device tree and booted the system. When I run the command you show, the function still shows i2s3:

52 (dmic1_clk_pe0): 
	pull=0
	tristate=0
	enable-input=1
	open-drain=0
	lock=0
	schmitt=0
	pull-down-strength=16
	pull-up-strength=16
	lpdr=0
	pbias-buf=1
	preemp=1
	rfu-in=1
	special-function=1
	func=i2s3

53 (dmic1_dat_pe1): 
	pull=0
	tristate=0
	enable-input=1
	open-drain=0
	lock=0
	schmitt=0
	pull-down-strength=16
	pull-up-strength=16
	lpdr=0
	pbias-buf=1
	preemp=1
	rfu-in=1
	special-function=1
	func=i2s3

However, if I check here, I see dmic1…

cat /sys/firmware/devicetree/base/pinmux@700008d4/common/dmic1_dat_pe1/nvidia,function
dmic1

cat /sys/firmware/devicetree/base/pinmux@700008d4/common/dmic1_clk_pe0/nvidia,function
dmic1

On another Nano before my patch, the above commands show i2s3, so I feel more confident that it is actually configured. I will scope the signals and attempt the arecord commands.

Hi Jon,

Can you comment on the discrepancy I’m seeing between what this

/sys/kernel/debug/pinctrl/700008d4.pinmux/pinconf-groups

is showing, and what this

/sys/firmware/devicetree/base/pinmux@700008d4/common/dmic1_dat_pe1/nvidia,function

is showing?

I’m probing the DMIC data / clock signals and not seeing any activity.

So here are my current set of questions:

  1. What is the reason for the discrepancy in pin function between /sys/kerne/debug and /sys/firmware/devicetree
  2. In your example, was your choice of ADMAIF2 arbitrary or is there some significance to using ADMAIF2 over the other ones?
  3. Can you confirm there would be no other device tree changes on top of pinmux changes to be able to use DMIC (device tree is based on hardware/nvidia/platform/t210/porg/kernel-dts/tegra210-p3448-0002-p3449-0000-b00.dts)

Hello!

To answer your questions …

  1. The /sys/kernel/debug/pinctrl is showing the actual configuration of the pins, whereas the /sys/firmware/devicetree is showing what the devicetree blob (DTB) file contains. So we need to see the pin configuration reflected in /sys/kernel/debug/pinctrl to indicate that the changes to the DTB have taken effect.

  2. I choose ADMAIF2 because by default ADMAIF1 is used for I2S (check the output from 'amixer -c tegrasndt210ref cget name=“ADMAIF1 Mux”). It is possible to use ADMAIF1 but I know that ADMAIF2 is not used by default.

  3. Correct it should only be necessary to configure the pinmux. What do you see under …

$ cat /sys/firmware/devicetree/base/pinmux@700008d4/pinctrl-names

Regards
Jon

Hi Jon,

Thanks again for another helpful response.

The big question for me now is, what are the reasons that the actual configuration of the pins won’t match the DTB that is loaded?

As for the pinctrl-names file, I don’t actually see one in that location. This is all I have

$ sudo find /sys/firmware/devicetree  -iname pinctrl-names
/sys/firmware/devicetree/base/sdhci@700b0400/pinctrl-names
/sys/firmware/devicetree/base/sdhci@700b0000/pinctrl-names
/sys/firmware/devicetree/base/aconnect@702c0000/ahub/i2s@702d1000/pinctrl-names
/sys/firmware/devicetree/base/aconnect@702c0000/ahub/i2s@702d1300/pinctrl-names
/sys/firmware/devicetree/base/aconnect@702c0000/ahub/i2s@702d1200/pinctrl-names
/sys/firmware/devicetree/base/aconnect@702c0000/ahub/i2s@702d1100/pinctrl-names
/sys/firmware/devicetree/base/aconnect@702c0000/ahub/i2s@702d1400/pinctrl-names
/sys/firmware/devicetree/base/clock@70110000/pinctrl-names
/sys/firmware/devicetree/base/host1x/dc@54200000/pinctrl-names
/sys/firmware/devicetree/base/host1x/dc@54240000/pinctrl-names
/sys/firmware/devicetree/base/pcie@1003000/pinctrl-names
/sys/firmware/devicetree/base/pwm@70110000/pinctrl-names
/sys/firmware/devicetree/base/i2c@7000d000/max77620@3c/pinctrl-names
/sys/firmware/devicetree/base/pmc@7000e400/pinctrl-names

Under that pinmux directory this is what I see:

$ ls -l /sys/firmware/devicetree/base/pinmux@700008d4
total 0
-r--r--r--   1 root root  4 Jan 28 16:01 '#gpio-range-cells'
drwxr-xr-x   3 root root  0 Jan 28 16:01  clkreq_0_bi_dir
drwxr-xr-x   3 root root  0 Jan 28 16:01  clkreq_0_in_dir
drwxr-xr-x   3 root root  0 Jan 28 16:01  clkreq_1_bi_dir
drwxr-xr-x   3 root root  0 Jan 28 16:01  clkreq_1_in_dir
drwxr-xr-x 103 root root  0 Jan 28 16:01  common
-r--r--r--   1 root root 23 Jan 28 16:01  compatible
drwxr-xr-x   2 root root  0 Jan 28 16:01  drive
drwxr-xr-x   3 root root  0 Jan 28 16:01  dvfs_pwm_active
drwxr-xr-x   3 root root  0 Jan 28 16:01  dvfs_pwm_inactive
-r--r--r--   1 root root  4 Jan 28 16:01  linux,phandle
-r--r--r--   1 root root  7 Jan 28 16:01  name
-r--r--r--   1 root root  4 Jan 28 16:01  phandle
-r--r--r--   1 root root  4 Jan 28 16:01  pinctrl-0
-r--r--r--   1 root root  4 Jan 28 16:01  pinctrl-1
-r--r--r--   1 root root  4 Jan 28 16:01  pinctrl-2
drwxr-xr-x  16 root root  0 Jan 28 16:01  prod-settings
-r--r--r--   1 root root 32 Jan 28 16:01  reg
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc1_clk_schmitt_disable
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc1_clk_schmitt_enable
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc1_default_drv_code
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc1_drv_code
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc1_schmitt_disable
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc1_schmitt_enable
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc3_clk_schmitt_disable
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc3_clk_schmitt_enable
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc3_default_drv_code
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc3_drv_code
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc3_schmitt_disable
drwxr-xr-x   3 root root  0 Jan 28 16:01  sdmmc3_schmitt_enable
-r--r--r--   1 root root  5 Jan 28 16:01  status
drwxr-xr-x  62 root root  0 Jan 28 16:01  unused_lowpower

Thanks!

Just to follow up, here’s what the DTS looks like for the pinmux:

    pinmux: pinmux@700008d4 {
            status = "okay";
            pinctrl-names = "default", "drive", "unused";
            pinctrl-0 = <&pinmux_default>;
            pinctrl-1 = <&drive_default>;
            pinctrl-2 = <&pinmux_unused_lowpower>;

            pinmux_default: common {
                    /* SFIO Pin Configuration */
                    dvfs_pwm_pbb1 {
                            nvidia,pins = "dvfs_pwm_pbb1";
                            nvidia,function = "cldvfs";
                            nvidia,pull = <TEGRA_PIN_PULL_NONE>;
                            nvidia,tristate = <TEGRA_PIN_ENABLE>;
                            nvidia,enable-input = <TEGRA_PIN_DISABLE>;
                    };

                    dmic1_clk_pe0 {
                            nvidia,pins = "dmic1_clk_pe0";
                            nvidia,function = "dmic1";
                            nvidia,pull = <TEGRA_PIN_PULL_NONE>;
                            nvidia,tristate = <TEGRA_PIN_DISABLE>;
                            nvidia,enable-input = <TEGRA_PIN_DISABLE>;
                    };

                    dmic1_dat_pe1 {
                            nvidia,pins = "dmic1_dat_pe1";
                            nvidia,function = "dmic1";
                            nvidia,pull = <TEGRA_PIN_PULL_NONE>;
                            nvidia,tristate = <TEGRA_PIN_DISABLE>;
                            nvidia,enable-input = <TEGRA_PIN_ENABLE>;
                    };
...

You can see the nvidia,function = “dmic1”; line for the clk and dat pins.

I even decompiled the active dtb like so and can see the pin function is set

$ dtc -I fs -O dts /sys/firmware/devicetree/base | grep 'nvidia,function = "dmic1"' -B4 -A2
			dmic1_dat_pe1 {
				nvidia,enable-input = <0x1>;
				nvidia,pins = "dmic1_dat_pe1";
				nvidia,tristate = <0x0>;
				nvidia,function = "dmic1";
				nvidia,pull = <0x0>;
			};
--
			dmic1_clk_pe0 {
				nvidia,enable-input = <0x0>;
				nvidia,pins = "dmic1_clk_pe0";
				nvidia,tristate = <0x0>;
				nvidia,function = "dmic1";
				nvidia,pull = <0x0>;
			};

However if I run this command it still shows i2s3…

$ sudo cat /sys/kernel/debug/pinctrl/700008d4.pinmux/pinconf-groups | grep "dmic1_" -A 14
52 (dmic1_clk_pe0): 
     pull=0
     tristate=0
     enable-input=1
     open-drain=0
     lock=0
     schmitt=0
     pull-down-strength=16
     pull-up-strength=16
     lpdr=0
     pbias-buf=1
     preemp=1
     rfu-in=1
     special-function=1
     func=i2s3
53 (dmic1_dat_pe1): 
     pull=0
     tristate=0
     enable-input=1
     open-drain=0
     lock=0
     schmitt=0
     pull-down-strength=16
     pull-up-strength=16
     lpdr=0
     pbias-buf=1
     preemp=1
     rfu-in=1
     special-function=1
     func=i2s3

Hello!

The pinmux is programmed by the bootloader and so the DTB needs to be flash to the DTB partition on eMMC. You can do this using the flash.sh script provide in the L4T release.

$ sudo ./flash.sh -k DTB -d <path-to-dtb-file> jetson-nano-qspi-sd internal mmcblk0p1

For more details on using flash.sh please see:
https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%2520Linux%2520Driver%2520Package%2520Development%2520Guide%2Fflashing.html%23

Regards,
Jon

Hi Jon,

Thanks for the tip about the bootloader…

The solution that worked for us ended up being to patch u-boot to remove the pin configuration lines. Our patch looks like this:

 --- u-boot/board/nvidia/p3450-porg/pinmux-config-p3450-porg.h	2020-05-21 13:49:07.009782793 -0700
+++ u-boot/board/nvidia/p3450-porg/pinmux-config-p3450-porg_dmic1.h.patch	2020-05-21 14:59:51.455531212 -0700
@@ -110,10 +110,6 @@
 	PINCFG(UART3_RX_PD2,         UARTC,      NORMAL, NORMAL,   INPUT,   DISABLE, DEFAULT),
 	PINCFG(UART3_RTS_PD3,        UARTC,      UP,     NORMAL,   OUTPUT,  DISABLE, DEFAULT),
 	PINCFG(UART3_CTS_PD4,        UARTC,      UP,     NORMAL,   INPUT,   DISABLE, DEFAULT),
-	PINCFG(DMIC1_CLK_PE0,        I2S3,       NORMAL, NORMAL,   INPUT,   DISABLE, DEFAULT),
-	PINCFG(DMIC1_DAT_PE1,        I2S3,       NORMAL, NORMAL,   INPUT,   DISABLE, DEFAULT),
-	PINCFG(DMIC2_CLK_PE2,        I2S3,       NORMAL, NORMAL,   INPUT,   DISABLE, DEFAULT),
-	PINCFG(DMIC2_DAT_PE3,        I2S3,       NORMAL, NORMAL,   INPUT,   DISABLE, DEFAULT),
 	PINCFG(DMIC3_CLK_PE4,        RSVD2,      DOWN,   TRISTATE, OUTPUT,  DISABLE, DEFAULT),
 	PINCFG(DMIC3_DAT_PE5,        RSVD2,      DOWN,   TRISTATE, OUTPUT,  DISABLE, DEFAULT),
 	PINCFG(PE6,                  DEFAULT,    DOWN,   NORMAL,   INPUT,   DISABLE, DEFAULT),

After applying this patch and reflashing, the pinfunc-groups is showing dmic1 and we were successfully able to record audio from our microphone!

Hello!

Thanks for letting me know. Please note that on recent Jetpack/L4T releases, the pinmux configuration in u-boot has been removed and is handled purely by the DTB which the CBoot bootloader programs.

Regards,
Jon

Hi,

Is there any PDM based microphones tested already on Jetson Nano ? If so, can you mention those?

@jonathanh @Trumany @sharadg

Thanks,
Sakthi

Hello Sakthi,

We have used these …

https://in.element14.com/stmicroelectronics/mp34dt01tr-m/mems-microphone-1-ch-61db-hclga/dp/2462799

Regards,
Jon

1 Like

Hi,

I have some doubts regarding DMIC interface.

  1. When we connect a PDM based microphone on DMIC, What are changes need to be done software wise? Is pinmux changes enough? Are the drivers for PDM related already present?

  2. The mic mentioned, is no longer manufactured.

Can I use the following mic? Any ideas on this.

@jonathanh

Thanks,
Sakthi

Hello!

  1. Yes you need to configure the pinmux and following the instructions in the examples to use the DMIC interface [0].
  2. This is the mic we have on an audio card that we have been using for validation purposes. We have been using this card for years and so yes I see now that this is no longer manufacturer. Unfortunately, I am not aware of any other PDM MEMS mic we have tested. However, we do test with the Adafruit I2S MEMS mic [1].

Regards,
Jon

[0] Welcome — Jetson Linux<br/>Developer Guide 34.1 documentation
[1] Adafruit I2S MEMS Microphone Breakout - SPH0645LM4H : ID 3421 : $6.95 : Adafruit Industries, Unique & fun DIY electronics and kits

1 Like