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

How to implement i2s data loopback?

Hi engineers,

I want to implement function that input i2s data and then output it directly.

I find that i2s demo includes two buffers which are used for current buffer and the next buffer. This part I don't understand. Disappointed

static void data_handler(nrf_drv_i2s_buffers_t const * p_released,
                         uint32_t                      status)
{
    // 'nrf_drv_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))
    {
        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_rx_buffer)
    {
        nrf_drv_i2s_buffers_t const next_buffers = {
            .p_rx_buffer = m_buffer_rx[1],
            .p_tx_buffer = m_buffer_tx[1],
        };
        APP_ERROR_CHECK(nrf_drv_i2s_next_buffers_set(&next_buffers));

        mp_block_to_fill = m_buffer_tx[1];
    }
    else
    {
        mp_block_to_check = p_released->p_rx_buffer;
        // 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.
        APP_ERROR_CHECK(nrf_drv_i2s_next_buffers_set(p_released));

        // The pointer needs to be typecasted here, so that it is possible to
        // modify the content it is pointing to (it is marked in the structure
        // as pointing to constant data because the driver is not supposed to
        // modify the provided data).
        mp_block_to_fill = (uint32_t *)p_released->p_tx_buffer;
    }
}

And in the main function, if I want to loopback, it means that I need to transfer data what I receive. Confusing.. Please help~

void main(void)
{
    uint32_t err_code = NRF_SUCCESS;
    for (;;)
    {
        m_blocks_transferred = 0;
        mp_block_to_fill  = NULL;
        mp_block_to_check = NULL;

        prepare_tx_data(m_buffer_tx[0]);

        nrf_drv_i2s_buffers_t const initial_buffers = {
            .p_tx_buffer = m_buffer_tx[0],
            .p_rx_buffer = m_buffer_rx[0],
        };
        err_code = nrf_drv_i2s_start(&initial_buffers, I2S_DATA_BLOCK_WORDS, 0);
        APP_ERROR_CHECK(err_code);

        do {
            // Wait for an event.
            __WFE();
            // Clear the event register.
            __SEV();
            __WFE();

            if (mp_block_to_fill)
            {
                prepare_tx_data(mp_block_to_fill);
                mp_block_to_fill = NULL;
            }
            if (mp_block_to_check)
            {
                check_rx_data(mp_block_to_check);
                mp_block_to_check = NULL;
            }
        } while (m_blocks_transferred < BLOCKS_TO_TRANSFER);

        nrf_drv_i2s_stop();

        NRF_LOG_FLUSH();

        bsp_board_leds_off();
        nrf_delay_ms(PAUSE_TIME);
    }
}

Best Wishes,

Sean

Parents
  • Hi,

    The I2S peripheral supports double buffering, allowing you to prepare a new buffer while one is processed. This allows for continuous transfer without any interruptions, which may not be the case if the CPU had to update the buffer pointer at the exact time when one buffer was done transferring. You can read more about this in the EasyDMA chapter in the peripheral documentation.

    The I2S example in the SDK is already a loopback example. The SDIN and SDOUT pins are connected together and the data received is checked to be equal to the data transmitted.

    Or did you mean that you want to transmit back the data received? In that case, you need to store the received data (in check_rx_data() function) into the next tx_buffer, and configure this buffer for transmit as it is done in prepare_tx_data().

    Best regards,
    Jørgen

  • Hi Jørgen,

    Thanks! What a detailed answer! What i want to know is the latter you said. Slight smile

    Best regards,

    Sean

Reply Children
No Data
Related