This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

I2S handler always called an extra time

We have an I2S implementation that I based on the example code, but using the nrfx driver.  Audio plays fine, but after I call nrfx_i2s_stop, I first see that no next buffers are needed - same code as in the example, if (!(status & NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED)) - then I get another call into the handler, triggering the ASSERT(p_released) guard at the top of the handler because there is nothing to have been released.  I am not seeing how this can be the case since clearly the driver knows that I stopped it - I don't match against the next buffers needed flag.  What am I missing?

Here is my handler:

static void i2s_data_handler(nrfx_i2s_buffers_t const * p_released, uint32_t status)
{
    // 'nrfx_i2s_next_buffers_set' is called directly from the handler
    // each time next buffers are requested, so data corruption is not
    // expected.
    ASSERT(p_released);

    // When the handler is called after the transfer has been stopped
    // (no next buffers are needed, only the used buffers are to be
    // released), there is nothing to do.
    if (!(status & NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED))
    {
        m_state = AUDIO_COMPLETE; // Tells main loop that we should execute post-audio code
		return;
    }

    // First call of this handler occurs right after the transfer is started.
    // No data has been transferred yet at this point, so there is nothing to
    // check. Only the buffers for the next part of the transfer should be
    // provided.
    if (!p_released->p_tx_buffer)
    {
        nrfx_err_t err_code;
        nrfx_i2s_buffers_t const next_buffers = {
            .p_tx_buffer = (uint32_t *)m_file_drv.file_buffer[m_file_drv.current_buffer],
            .p_rx_buffer = NULL,
        };
        
        err_code = nrfx_i2s_next_buffers_set(&next_buffers);
        APP_ERROR_CHECK(err_code);

        err_code = file_driver_get_next_file_page(&m_file_drv);
        if (err_code == FILE_DRIVER_EOF)
        {
            m_state = AUDIO_ENDED; // Tells main loop audio has ended and we can stop I2S
        }
    }
    else
    {
        // The driver has just finished accessing the buffers pointed by
        // 'p_released'. They can be used for the next part of the transfer
        // that will be scheduled now.
        nrfx_err_t err_code;

        if (m_state == AUDIO_DRIVER_PLAYING)
        {
            err_code = nrfx_i2s_next_buffers_set(p_released);
            APP_ERROR_CHECK(err_code);

            err_code = file_driver_get_next_file_page(&m_file_drv);
            if (err_code == FILE_DRIVER_EOF)
            {
                m_state = AUDIO_ENDED; // Tells main loop audio has ended and we can stop I2S
            }
        }
    }
}

and main.c looks like:

while(1)
{
    ...
    if (m_state == AUDIO_ENDED)
    {
        nrfx_i2s_stop();
    }
    if (m_state == AUDIO_COMPLETE)
    {
        // Post audio tasks - these run before ASSERT is thrown
        ...
    }
    ...
}

**EDIT** I thought I should add that I have tried many different things to get this working, but I will mention one of the most obvious.  I have tried changing the final else block into

else
    {
        // The driver has just finished accessing the buffers pointed by
        // 'p_released'. They can be used for the next part of the transfer
        // that will be scheduled now.
        nrfx_err_t err_code;

        if (m_state == AUDIO_DRIVER_PLAYING)
        {
            err_code = file_driver_get_next_file_page(&m_file_drv);
            if (err_code == FILE_DRIVER_EOF)
            {
                m_state = AUDIO_ENDED; // Tells main loop audio has ended and we can stop I2S
                return;
            }
            
            err_code = nrfx_i2s_next_buffers_set(p_released);
            APP_ERROR_CHECK(err_code);
        }
    }

thinking that setting another set of buffers when I was about to stop might have caused the issue, but it still results in the ASSERT being thrown.  I should also add that the buffers for the audio are in their own RAM region to avoid bus collisions (something that we had happen here).

Parents Reply Children
No Data
Related