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

How do I use the I2S interface on the 9160

I want to realize audio playing function in 9160, according to the specification, there are 9160 I2S interface. However, the specification only describe the definition of some registers in the book, I didn't find related sample code in ncs1.2, and I don't know how to define it in overlay file, I can't get the I2S device binding, is the I2S device name "I2S" or "I2S_0" string?

my code:

#define I2S_DEV_NAME "I2S"
#define NUM_BLOCKS 20
#define SAMPLE_NO 64
#define TIMEOUT          2000
#define FRAME_CLK_FREQ   44000

static void test_i2s_tx_transfer_configure(void)
{
	struct device *dev_i2s;
	struct i2s_config i2s_cfg;
	int ret;

	dev_i2s = device_get_binding(I2S_DEV_NAME);
	if(!dev_i2s)
	{
		LOG_INF("ERROR SETTING UP I2S\n");
		return;
	}

	/* Configure */
	i2s_cfg.word_size = 16U;
	i2s_cfg.channels = 2U;
	i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
	i2s_cfg.options = I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE;
	i2s_cfg.frame_clk_freq = FRAME_CLK_FREQ;
	i2s_cfg.block_size = BLOCK_SIZE;
	i2s_cfg.mem_slab = &tx_0_mem_slab;
	i2s_cfg.timeout = TIMEOUT;
	i2s_cfg.options = I2S_OPT_LOOPBACK;

	ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg);
}

 

Parents
  • Hello,

    There is no nrf i2s driver support available for zephyr yet (zephyr/drivers/i2s does not contain any 'nrf' implementation). So you would need to use nrfx directly, however I can't find any example for it, but I can find some have been looking into it here:
    https://devzone.nordicsemi.com/f/nordic-q-a/60256/i2s-on-nrf9160

    If possible I highly recommend to update to newer ncs version.

    Kenneth



  • Now I'm using nrfx directly can initialize I2s, but I find that when I start I2s, the program crashes.I tracked it down and it crashed here, I can't see what's wrong with it.like this:

    NRF_STATIC_INLINE void nrf_i2s_task_trigger(NRF_I2S_Type * p_reg,
                                                nrf_i2s_task_t task)
    {
        *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
    }
    

    This is my code:

    void test_i2s(void)
    {
    	uint32_t err_code = NRFX_SUCCESS;
    	
    	nrfx_i2s_config_t config = NRFX_I2S_DEFAULT_CONFIG(I2S_BCK,I2S_LRCK,I2S_MCK,I2S_DO,I2S_DI);
    	// In Master mode the MCK frequency and the MCK/LRCK ratio should be
    	// set properly in order to achieve desired audio sample rate (which
    	// is equivalent to the LRCK frequency).
    	// For the following settings we'll get the LRCK frequency equal to
    	// 15873 Hz (the closest one to 16 kHz that is possible to achieve).
    	config.mode         = NRF_I2S_MODE_MASTER;
    	config.format       = NRF_I2S_FORMAT_I2S;
    	config.alignment    = NRF_I2S_ALIGN_LEFT;
    	config.sample_width = NRF_I2S_SWIDTH_16BIT;
    	config.channels     = NRF_I2S_CHANNELS_LEFT;
    	config.mck_setup    = NRF_I2S_MCK_32MDIV8;
    	config.ratio        = NRF_I2S_RATIO_32X;
    
    	err_code = nrfx_i2s_init(&config, data_handler);
    	__ASSERT(err_code == NRFX_SUCCESS, "i2s init error");
    
    	for (;;)
    	{
    		m_blocks_transferred = 0;
    		mp_block_to_fill  = NULL;
    		mp_block_to_check = NULL;
    
    		prepare_tx_data(m_buffer_tx[0]);
    
    		nrfx_i2s_buffers_t const initial_buffers = {
    		    .p_tx_buffer = m_buffer_tx[0],
    		    .p_rx_buffer = m_buffer_rx[0],
    		};
    		err_code = nrfx_i2s_start(&initial_buffers, I2S_DATA_BLOCK_WORDS, 0);
    		__ASSERT(err_code == NRFX_SUCCESS, "i2s start error!");
    
    		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);
    
    		nrfx_i2s_stop();
    
    		k_sleep(K_MSEC(PAUSE_TIME));
        }
    }
    

  • I suggest to put the '(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)' into a variable, so you can see what memory/pointer address you are actually trying to write to.

    Kenneth

Reply Children
  • yes, I used the variable to look at the actual address, and found a problem, When the program goes here, I see reg_addr=0x40028104, and the program is work well, like this:

    NRF_STATIC_INLINE void nrf_i2s_event_clear(NRF_I2S_Type * p_reg,
    nrf_i2s_event_t event)
    {
    reg_addr = ((uint8_t *)p_reg + (uint32_t)event);
    *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
    #if __CORTEX_M == 0x04
    volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
    (void)dummy;
    #endif
    }
    
    

    when the program goes here, I see reg_addr=0x40028000, and the program crashes, like this:

    NRF_STATIC_INLINE void nrf_i2s_task_trigger(NRF_I2S_Type * p_reg,
                                                nrf_i2s_task_t task)
    {
    	reg_addr = ((uint8_t *)p_reg + (uint32_t)task);
        *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL;
    }
    

    So, what's the reason? The two addresses may not seem very different, but they lead to completely different results.

Related