Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

I2S issue - last sample in memory always replaced with 0x0001

I'm using the nRF52 DK and attempting to use I2S to send data to a DAC. I'm using the nRF5 SDK, version 17.0.2. The last sample in the data I'm sending is always replaced with 0x0001. I've set up a simple example where the audio data I'm sending is only 4 16-bit samples, but I've seen the same thing in all my tests.

Here's the data I'm trying to send:

static int16_t audio_data[4] = {
    0,
    10,
    0,
    -10
};

And here's my I2S initalization:

// Enable transmission
NRF_I2S->CONFIG.TXEN = I2S_CONFIG_TXEN_TXEN_ENABLE << I2S_CONFIG_TXEN_TXEN_Pos;

// Enable MCK generator, set MCK to 1 MHz
NRF_I2S->CONFIG.MCKEN = I2S_CONFIG_MCKEN_MCKEN_ENABLE << I2S_CONFIG_MCKEN_MCKEN_Pos;
NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV32  << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos;

// Set MCK/LRCK ratio to 64
NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_64X << I2S_CONFIG_RATIO_RATIO_Pos;

// Master mode, 16-bit, left-aligned
NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_MASTER << I2S_CONFIG_MODE_MODE_Pos;
NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16BIT << I2S_CONFIG_SWIDTH_SWIDTH_Pos;
NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_LEFT << I2S_CONFIG_ALIGN_ALIGN_Pos;

// I2S format
NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos;

// Left channel only
//NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_LEFT << I2S_CONFIG_CHANNELS_CHANNELS_Pos;
NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_STEREO << I2S_CONFIG_CHANNELS_CHANNELS_Pos;

// Configure pins
NRF_I2S->PSEL.MCK = PIN_MCK << I2S_PSEL_MCK_PIN_Pos;
NRF_I2S->PSEL.SCK = PIN_SCK << I2S_PSEL_SCK_PIN_Pos;
NRF_I2S->PSEL.LRCK = PIN_LRCK << I2S_PSEL_LRCK_PIN_Pos;
NRF_I2S->PSEL.SDOUT = PIN_SDOUT << I2S_PSEL_SDOUT_PIN_Pos;

NRF_I2S->ENABLE = 1;

NRF_I2S->TXD.PTR = (uint32_t)&audio_data[0];
NRF_I2S->RXTXD.MAXCNT = sizeof(audio_data) / sizeof(uint32_t);
NRF_LOG_INFO("TXDPTR: %ul", NRF_I2S->TXD.PTR);

NRF_I2S->TASKS_START = 1;

When I run the code and look at the location of NRF_I2S->TXD.PTR in memory, I see the 4 samples as expected (0x0000, 0x000A, 0x0000, 0xF6FF):

But when the data is actually being transmitted, the last sample (-10 or 0xF6FF in this case) is always replaced with 1 (see logic analyzer capture).

I see the same thing when I used different sized arrays for the audio data, as well as when I use a single channel instead of stereo. Some help would be much appreciated.

Parents
  • Hi,

     I believe what you are seeing here might be a limitation in hardware. To avoid this, try doing zero-padding on your data. In the I2S example in the nRF5-SDK, we have e.g. this "m_zero_samples_to_ignore" variable, and this comment:

            // Normally a couple of initial samples sent by the I2S peripheral
            // will have zero values, because it starts to output the clock
            // before the actual data is fetched by EasyDMA. As we are dealing
            // with streaming the initial zero samples can be simply ignored.

    PS:  I would recommend using our drivers in the SDK. Have a look at the I2S example in the nRF5-SDK on how to use it.

  • Thanks for the response.

    What I'm doing here is transmitting this data on a loop, it's meant to be a tone that's repeated, not just a one-shot transfer. The I2S module does this automatically (i.e. after the last sample it cycles back to the first one). So it's meant to send a periodic signal as follows:

    0, 10, 0, -10, 0, 10, 0, -10, 0, 10, 0, -10, ...

    And what I'm actually seeing is:

    0, 10, 0, 1, 0, 10, 0, 1, 0, 10, 0, 1, ...

    The actual tone I'm sending has more than 4 samples, but I'm seeing the same thing, the last sample is always replaced with 1.

    I'm not clear on how zero padding would solve this issue. I wouldn't want extra zeros in the actual data, and having padding between periods of the waveform would mess with the timing given that this is sound data used to drive an audio DAC.

  • Hi,

    Sigurd is currently out on vacation and will not be back before August 2nd. Are you still having issues with this? We are a bit short on staffing at the moment so responses can be slow.

    tmurias said:
    I'm not clear on how zero padding would solve this issue. I wouldn't want extra zeros in the actual data, and having padding between periods of the waveform would mess with the timing given that this is sound data used to drive an audio DAC.

    From what Sigurd wrote in his last post I would guess that zero-padding will help if you are sending packets with different lengths. Have you tried to run the I2S example on the nRF5 SDK with any luck?

    Best regards,

    Marjeris

Reply
  • Hi,

    Sigurd is currently out on vacation and will not be back before August 2nd. Are you still having issues with this? We are a bit short on staffing at the moment so responses can be slow.

    tmurias said:
    I'm not clear on how zero padding would solve this issue. I wouldn't want extra zeros in the actual data, and having padding between periods of the waveform would mess with the timing given that this is sound data used to drive an audio DAC.

    From what Sigurd wrote in his last post I would guess that zero-padding will help if you are sending packets with different lengths. Have you tried to run the I2S example on the nRF5 SDK with any luck?

    Best regards,

    Marjeris

Children
  • Hi Marjeris,

    I have run the I2S example from the nRF5 SDK and that seems to work fine. But that's a little different from what I'm trying to do because it sends one-shot transfers instead of looping. I run into issues when I point the I2S module to my waveform data and let it repeat, that's when the last sample is being replaced with 1. I've tried using the SDK functions from the example as well, but I see the same issue.

    Taylor

Related