Audio I2S on 40 Pin Connector

Hello!

The u-boot command line is accessible via the serial console. Please see the following …

Regards,
Jon

My goal is to interface with an external codec, via I2S4 on the 40-pin header, which is converting four analog audio signals into a single time domain multiplexed (TDM) I2S data stream.

I am able to see appropriate MCLK, BCLK, and LRCLK operation on an oscilloscope. At this time I am capturing a null audio stream because I have not connected my external audio board.

I would like to take the TDM I2S data and route it to four separate files for analysis (1 per channel).

Current State:

  • Edited pinmux and rebuilt/flashed u-boot with I2S4 configuration:
    (NOTE: DAP4_DOUT_PJ6 is intentionally not muxed as SFIO, it is used as GPIO for my application.)
PINCFG(DAP4_FS_PJ4,          I2S4B,      NORMAL, NORMAL,   OUTPUT,  DISABLE, DEFAULT),
PINCFG(DAP4_DIN_PJ5,         I2S4B,      NORMAL, NORMAL,   INPUT,   DISABLE, DEFAULT),
PINCFG(DAP4_DOUT_PJ6,        DEFAULT,    NORMAL, NORMAL,   OUTPUT,  DISABLE, DEFAULT),
PINCFG(DAP4_SCLK_PJ7,        I2S4B,      NORMAL, NORMAL,   OUTPUT,  DISABLE, DEFAULT),

PINCFG(AUD_MCLK_PBB0,        AUD,        NORMAL, NORMAL,   OUTPUT,  DISABLE, DEFAULT),
  • Edited tegra210-porg-p3448-common.dtsi and generated/flashed updated DTB:
i2s_dai_link1: nvidia,dai-link-1 {
    linke-name = "spdif-dit-0";
    cpu-dai = <&tegra_i2s4>;
    codec-dai = <&spdif_dit0>;
    cpu-dai-name = "dit-hifi";
-   format = "i2s";
+   format = "dsp_a";
    bitclock-slave;
    frame-slave;
    bitclock-noninversion;
    frame-noninversion;
-   bit-format = "s16_le";
+   bit-format = "s24_le";
    bclk-ratio = <1>;
    srate = <48000>;
-   num-channel = <2>;
+   num-channel = <4>;
    ignore_suspend; 
    name-prefix = "x";
    status = "okay";
  }

Questions:

  • I’ve read about ADX, but have not found useful documentation. Is this the preferred method for routing TDM audio data to separate files?
  • I’ve also read about FFmpeg. The documentation is readily available. Is this an appropriate utility for routing the audio data?
  • Do I need to edit any other .dtsi files? (e.g. tegra210-audio.dtsi or tegra210-soc-base.dtsi)

Thank you in advance,
Kai

Hello!

To answer your questions …

  1. Yes the ADX capable of separating the TDM stream at runtime. So for doing this a runtime, it is the preferred method. However, you can also use tools like sox to separate a TDM stream capture into a single WAV file after the capture is complete. There is some documentation available for using the ADX in the online docs [0].

  2. I am not familiar with ffmpeg to know if it can do this, but sox certainly can as a post-processing step.

  3. For interfacing with a codec you will need to add the appropriate nodes for the codec to device-tree as well as update the dai-link node as well. Furthermore, it maybe necessary to update the Tegra machine driver. We are in the process of updating the documentation and so should have some references for you shortly.

Regards,
Jon

[0] https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%2520Linux%2520Driver%2520Package%2520Development%2520Guide%2Fasoc_driver.html%23wwpID0E0GC0HA

Thank you for the advice Jonathanh!

As I understand it I have configured the pinmux and dai-link correctly, but now need to add a node for the codec to the device tree.

I have been editing tegra210-porg-p3448-common.dtsi thus far. Is this an appropriate place to add the codec node as well? I searched for a “board_sound” node (as is used in the example at the link below), but did not find one in the device tree sources.

Is this an appropriate reference for me to follow? Eight channels audio on i.MX7 with PCM3168 - Bootlin's blog

Thanks again!
Kai

Hello,

I’ve been attempting to interface the Jetson Nano with an external ADC(PCM4204) via I2S4.

I’ve decided to attempt to capture data from 2 channels (Ch.1 & Ch.2) as an intermediate step in my development process. (Eventually I need input from 4 analog channels in TDM mode)

The external ADC is operating in master mode, and using arecord I can’t get my I2S bus to operate in slave mode. I’m using I2S4 and have altered the pinmux as well as the dtb file in an attempt to use the bus as a slave.

Adapted dai-link in tegra210-porg-p3448-common.dtsi:

i2s_dai_link1: nvidia,dai-link-1 {
  link-name = "spdif-dit-0";
  cpu-dai = <&tegra_i2s4>;
  cpu-dai-name = <&spdif_dit0>;
  cpu-dai-name = "IS24";
  codec-dai-name = "dit-hifi";
  format = "i2s";
  bitclock-master;
  frame-master;
  bitclock-noninversion;
  frame-noninversion;
  bit-format = "s24_le";
  bclk_ratio = <0>;
  srate = <48000>;
  num-channel =  <2>;
  name-prefix = "x";
}

NOTE: I have attempted to configure the Nano as a slave on the I2S4 bus by changing bitclock-master to bitclock-slave and frame-master to frame-slave; however, I saw no change in behavior.

Pinmux Configuration for DAP4:

PINCFG(DAP4_FS_PJ4,   I2S4B,   NORMAL, NORMAL, INPUT,  DISABLE, DEFAULT),
PINCFG(DAP4_DIN_PJ5,  I2S4B,   NORMAL, NORMAL, INPUT,  DISABLE, DEFAULT),
PINCFG(DAP4_DOUT_PJ6, DEFAULT, NORMAL, NORMAL, OUTPUT, DISABLE, DEFAULT),
PINCFG(DAP4_SCLK_PJ7, I2S4B,   NORMAL, NORMAL, INPUT,  DISABLE, DEFAULT),

PINCFG(AUD_MCLK_PBB, AUD, NORMAL, NORMAL, OUTPUT, DISABLE, DEFAULT),

NOTE: I am not using DAP4_DOUT for I2S, it is used as GPIO for my application.

Pin config verification:

sudo grep "Name:\|J:\|BB:" /sys/kernel/debug/tegra_gpio

Name:Bank:Port CNF OE OUT IN INT_STA INT_ENB INT_LVL
   J:   2: 1   40  40 00  00   00      00    000000
  BB:   6: 3   00  00 00  00   00      00    000000

My testing procedure is as follows:

/*Drive the PCM4204 enable gpio high*/

$arecord -D hw:tegrasndt210ref,0 -f s24_le -c 2 -r 48000 -d 10 /tmp/i2s4_test.wav

$hexdump /tmp/i2s4_test.wav

0000000 4952 4646 4c24 001d 4157 4556 6d66 2074
0000010 0010 0000 0001 0002 bb80 0000 dc00 0005
0000020 0008 0018 6164 6174 4c00 001d 0000 0000
0000030 0000 0000 0000 0000 0000 0000 0000 0000
*
01d4c2c

Any suggestions on where I’m going wrong configuring the Nano as an I2S slave on I2S4?

Thanks!
-Kai

Hello Kai,

I had a quick look at the PCM4204 and have a few questions …

  1. I see that it requires system input clock. What is driving this? It is the AUD_MCLK?
  2. How are the FS0, FS1 and FS2 pins on the PCM4204 configured?
  3. How are the FMT0, FMT1, and FMT2 pins on the PCM4204 configured?
  4. Do you see any errors when capturing with the PCM4204 in master mode? If not then this would indicate that the bitclock and frame-clock are active. However, if you can probe the data out of the PCM4204 that would be good to confirm there is data and it is not all zeros.

Regards,
Jon

Jon,

Yes, the system clock of the PCM4204 is supplied by the AUD_MCLK (12.288MHz).

Your questions guided me to finding my mistake. I was using arecord with -f s24_le which was causing the BCLK to oscillate at 48kHz48 = 2.304Mhz. The PCM4204 outputs data in 32bit words and thus the required clock frequency is 48kHz64=3.072MHz.

I had seen data output from the PCM4204 when I was testing in TDM mode. I had supplied the 12.288MHz signal to SysClk and BCLK and 48kHz to the LRCLK. This works, but only for TDM mode.

All I needed was to use arecord with -f s32_le and the BCLK frequency was fixed.

NOTE: The data should be reformatted because the samples are 24bits. If it is not converted the amplitude will be a fraction of the real signal because the upper byte is always zero. I believe the conversion is possible using FFmpeg.

Thanks!
-Kai

Hi Kai,

Just to let you know we have release JetPack 4.3 (L4T 32.3.1) and the update audio documentation is now available:

https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%2520Linux%2520Driver%2520Package%2520Development%2520Guide%2Fasoc_driver.17.1.html%23

Jon

Hello!

I also wanted to let you know that with JetPack 4.3 (L4T 32.3.1) and we now have a tool included to assist with the reconfiguration of the pins exposed by the 40-pin header so that you no longer need to rebuild and reflash. Please see the following:

https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%2520Linux%2520Driver%2520Package%2520Development%2520Guide%2Fhw_setup_jetson_io.html%23

Regards,
Jon

Just read the documentation, this looks awesome.
Will try it next week.
Thanks,

Thanks! There could be a delay in response over the next couple of weeks. However, I am interested in feedback or if any issues are found, so we can fix them.

Regards,
Jon

Hello!

Just to let you know that we have identified an issue with the Jetson.IO tool on Nano when updating Nano using SD card image. However, there is a simple fix availabe. Details are here:

Regards,
Jon

Works like a charm.
Thanks for making this tool available.

In future boards, would be awesome if the second I2S could also be routed to the 40 pin connector.

Using this stereo microphone https://www.mouser.com/pdfdocs/Infineon_S2GO_MEMSMIC_IM69D_QS.pdf

I get sound but the levels are very quiet.

I have to boost the levels to +25db to get a decent volume from it.

Also, one channel, the left channel, has a lot of hissing compared to the right which makes it unusable in stereo mode for my application.

Here’s a sample of stereo mode with hiss in one channel: - YouTube

These pins are connected:
Nano Pin 1 = Infineon Pin 7 (3V)
Nano Pin 6 = Infineon Pin 6 (GND)
Nano Pin 12 = Infineon Pin 15 (BCLK)
Nano Pin 35 = Infineon Pin 14 (CLK/WCLK)
Nano Pin 38 = Infineon Pin 17 (DATA)

Any thoughts?

Hello!

I see that this boards has two PDM mics connected to a ADAU7002 IC to convert the PDM to I2S. The connections that you have look fine to me. Have you configured these IOs on the 40-pin header to function as I2S as described in the following doc?

https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%2520Linux%2520Driver%2520Package%2520Development%2520Guide%2Fhw_setup_jetson_io.html%23

From a timing stand point, I don’t see any issues for supporting this module on Jetson, however, looking at the timing, it appears that the audio is 20-bit. Therefore, to capture audio from this device, we would capture as 32-bit samples (the data being in the upper MSBs) …

$ arecord -D hw:tegrasndt210ref,0 -c 2 -r 48000 -f S32_LE cap.wav

Regards,
Jon