Persist Alsa configuration (I2S4) in Jetson Nano doesn't apply upon reboot

When setting up the Alsa configuration the settings work but upon reboot the settings are not applying and are effectively not working.

Is there something specific we should do to persist the Alsa configuration and to initiate even after reboot?

Have you checked NVIDIA Jetson Linux Developer Guide : Audio Setup and Development | NVIDIA Docs to see if can help?

Hi @kayccc thanks for the reply. In reviewing the documentation we are not finding the solution to our issue. Can you help direct us to where in the documentation that information could be found?
Do you know what the issue is and can perhaps suggest something?

Hi xtianus,
Please refer Forgetting audio output presets (4/4) - Jetson & Embedded Systems / Jetson Orin Nano - NVIDIA Developer Forums forum query which has solution for similar issue. Let us know if you still face any issue after following the steps provided in the link.

thanks @mkumard we will let you know as soon as possible!

Hi @mkumard

Perhaps there was a misunderstanding
Let me try to explain the problem.
Our device must use the I2S bus to work with audio.
For testing, we took the devkit and activated I2S4 in jetson-io.
Next I configured alsa, here is an example of my configuration:

amixer -c tegrasndt210ref sset 'I2S4 Mux' 'ADMAIF1'
amixer -c tegrasndt210ref sset 'ADMAIF1 Mux' 'I2S4'
amixer -c tegrasndt210ref sset 'I2S4 codec bit format' '16'
amixer -c tegrasndt210ref sset 'I2S4 codec master mode' 'cbm-cfm'
amixer -c tegrasndt210ref sset 'I2S4 BCLK ratio' '64'
amixer -c tegrasndt210ref sset 'I2S4 codec frame mode' 'i2s'
amixer -c tegrasndt210ref sset 'I2S4 fsync width' 15
amixer -c tegrasndt210ref sset "I2S4 Loopback" off
amixer -c tegrasndt210ref sset "I2S4 Sample Rate" 44100
amixer -c tegrasndt210ref sset "I2S4 Channels" 1

after that I used the arecord and aplay commands, and also wrote a small test in С++ using the <alsa/asoundlib.h> library. Everything worked, I saw I2S4 sync packets on the line and even connected a speaker to record audio.
testAlsa.mp4.zip (32.3 MB)

But after rebooting the device, I2S4 stopped working. I don’t see any sync packets.
I tried to configure Alsa again, because I thought that the settings were not saved after a reboot, but it did not help.
The log I received by posting it in this thread Alsa configuration (I2S4) Jetson Nano - #5 by georgiy.lutsenko
I also noticed that periodically some lines of the I2S4 bus change their logical level and this happens at a random moment.

I tried adding a default sink (Forgetting audio output presets (4/4) - #6 by DO_Ray), but that didn’t help either.

I also found a topic with a similar problem, but there was no solution there; more precisely, the person who wrote the topic wrote that he started using a USB audio card instead of I2S4.

Regards,
Georgiy

Hi Georgily,
Thanks for your detailed explanation about the issue.

From the log you posted
[ 19.058532] tegra210-i2s tegra210-i2s.3: ASoC: can’t set DAP hw params: -22
[ 19.065536] tegra-asoc: sound: ASoC: PRE_PMU: x Capture-I2S4 DAP Receive event failed: -22

The above points, there is definitely some issue with the configuration.

Couple of clarification needed from your end before we can suggest any fix.

  1. Is Tegra I2S4 in slave mode is a must have requirement?.
  2. why BCLK ratio is set to 64?

Can you provide the log dump for below commands in a file

cat /sys/kernel/debug/clk/clk_summary
amixer -c APE contents → provide this for working and non-working case

Hello @mkumard
Thanks for the answer

Tegra I2S4 should work in master mode.
I set the BCLK ratio to 64 so that there was some margin, although 32 is enough for 1 channel.

Here are the files containing the log dump:
clk_summary.txt (56.5 KB)
contents.txt (143.4 KB)

Regards,
Georgiy

Hi georgiy,

I believe the clock log was taken when no audio playback. Can you dump during audio playback active.

on “Tegra I2S4 should work in master mode.” below command you have used sets Tegra I2S4 as Slave (i.e codec drives the bclk,fs clocks).

amixer -c tegrasndt210ref sset ‘I2S4 codec master mode’ ‘cbm-cfm’

Please use cbs-cfs for Tegra I2S master and try again

Hello @mkumard
Thanks for the answer

This is quite strange since cbm-cfm stands for bit master and frame master. Although maybe I’m confusing something. But there is also no playback or activity on the pins of the i2s4 line with the cbs-cfs setting.

I collected a log with both settings during playback:
clk_cbm-cfm.txt (56.5 KB)
clk_cbs_cfs.txt (56.5 KB)

Regards,
Georgiy

Hi georgily,
cbm-cfm is standard terminology used in ALSA. cbm is codec bitclock master, so external codec will be master which provides clock.

One question, did you tried playback on GUI or aplay tool in commandline?. I don’t get the comment no playback or activity on the i2s4 pin. If you tried playback and pinmux is set as your previous comment for I2S4 then am expecting clock on I2S4.

Provide the below dump during the active playback session.
cat /sys/kernel/debug/clk/clk_summary

Hi @mkumard

I collected a new log
I used aplay to playback:
aplay_clk_cbm.txt (56.5 KB)
aplay_clk_cbs.txt (56.5 KB)

Hi @mkumard did the logs help or is something else we can provide?

Hi xtianus,
I don’t see I2S4 clock enabled on both the log file. This points something wrong on the mixer control path and initialization of the usecase with I2S4. Assuming the log dump was during the playback session active.

Can you provide me the steps or command how u started the playback session?.

Hi @mkumard I will get that information for you. May you share what you should see in the log for reference?

If I2S4 is running, we should be seeing the second column or enable_cnt column set to 1

i2s4 0 0 45158334 11289600 0 0
*[ default_freq 0]

@mkumard thanks so much. get back to you soon.

Hello @mkumard

Thanks for the answer

I’m a little puzzled by the fact that the clk don’t change during playback. Setting up the i2s4 bus was done using the jetson-io.py script, here is the command I use to playback
aplay -D plughw:CARD=tegrasndt210ref,DEV=0 test.wav

I also attached here a piece of code that I used to use exclusively for tests:

#include <alsa/asoundlib.h>
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <thread>
#include <mutex>
#include <cmath>
#include <vector>
#include <chrono>

enum Note {
    C4 = 261,
    CSharp4 = 277,
    D4 = 293,
    DSharp4 = 311,
    E4 = 329,
    F4 = 349,
    FSharp4 = 370,
    G4 = 392,
    GSharp4 = 415,
    A4 = 440,
    ASharp4 = 466,
    B4 = 493,
    silence = 0
};

const int TEMPO = 300;

const std::vector<std::pair<Note, int>> imperialMarch = {
        {A4, 500},
        {A4, 500},
        {F4, 350},
        {C4, 150},
        {A4, 500},
        {F4, 350},
        {C4, 150},
        {A4, 1000},
        {E4, 500},
        {E4, 500},
        {E4, 500},
        {F4, 350},
        {C4, 150},
        {G4, 500},
        {F4, 350},
        {C4, 150},
        {A4, 1000},
        {ASharp4, 500},
        {A4, 350},
        {A4, 150},
        {A4, 500},
        {G4, 250},
        {F4, 250},
        {E4, 125},
        {F4, 125},
        {A4, 1000}
};


int main() {
    snd_pcm_t *pHandle;

    int err = snd_pcm_open(&pHandle, "hw:tegrasndt210ref,0", SND_PCM_STREAM_PLAYBACK, 0);
    if (err < 0) {
        std::cerr << "Error initialization device: " << snd_strerror(err) << std::endl;
        return 1;
    }

    snd_pcm_hw_params_t *pParams;
    snd_pcm_hw_params_alloca(&pParams);
    snd_pcm_hw_params_any(pHandle, pParams);
    snd_pcm_hw_params_set_access(pHandle, pParams, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(pHandle, pParams, SND_PCM_FORMAT_S16_LE);
    snd_pcm_hw_params_set_channels(pHandle, pParams, 1);

    unsigned int tempRate = 44100;
    snd_pcm_hw_params_set_rate_near(pHandle, pParams, &tempRate, 0);

    snd_pcm_uframes_t buffer_size = 44100;
    snd_pcm_uframes_t period_size = buffer_size / 4;
    snd_pcm_hw_params_set_buffer_size_near(pHandle, pParams, &buffer_size);
    snd_pcm_hw_params_set_period_size_near(pHandle, pParams, &period_size, nullptr);

    snd_pcm_hw_params(pHandle, pParams);

    auto playNote = [&](Note note, int duration) {
        int numSamples = tempRate * duration / 1000;
        short *pBuf = new short[numSamples];
        short *tmpBuf = pBuf;

        for (int i = 0; i < numSamples; i++) {
            pBuf[i] = (short)(32767.0 * sin(2.0 * M_PI * note * i / tempRate));
        }

        int frames = numSamples;
        while (frames > 0) {
            int err = snd_pcm_writei(pHandle, tmpBuf, frames);
            if (err == -EPIPE) {
                snd_pcm_prepare(pHandle);
            } else if (err < 0) {
                std::cerr << "Error write to audiodevice: " << snd_strerror(err) << std::endl;
                break;
            } else {
                tmpBuf += err;
                frames -= err;
            }
        }
        delete[] pBuf;
    };

    while(true) {

        for (const auto &[note, duration]: imperialMarch) {
            playNote(note, duration);
            std::this_thread::sleep_for(std::chrono::milliseconds(TEMPO));
        }

    }
    snd_pcm_drain(pHandle);
    snd_pcm_close(pHandle);

    return 0;
}

This code definitely works, as I have already tested it before.
I would like to ask again, is it possible that some kind of internal error occurred during the work process, which was cached and now is not reset? I just don’t understand the reason why playback and recording worked before, but now they don’t.

Regards,
Georgiy

Hi georgiy,
Let us try few things to cross check. Please perform the below steps after boot and check the clock on I2S4(avoid your mixer controls configs)

amixer -c tegrasndt210ref sset ‘I2S4 Mux’ ‘ADMAIF5’
amixer -c tegrasndt210ref sset ‘ADMAIF5 Mux’ ‘I2S4’
amixer -c tegrasndt210ref sset ‘I2S4 codec master mode’ ‘cbs-cfs’

aplay -D plughw:CARD=tegrasndt210ref,DEV=4 test.wav &

During the playback check the clk_summary. Also, for e.g test.wav on your side is 10sec of duration, the aplay command should execute for same period.

Please provide the kernel uart log and clock summary dump

Hi

Here are the files containing the log when the configuration was changed.
clk.txt (56.5 KB)
uart-log.txt (42.6 KB)

Unfortunately, it didn’t work, but maybe these files will help in some way

Regards,
Georgiy