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

Send data continuously over i2s for speaker

Hi all,

I am trying to control a speaker using the i2s output of the nrf52832 mapped into a TAS2505 from TI. I am able to play sounds in the speaker but my issue is that as I am sending the audio data blocks after blocks, the sounds is also played blocks after blocks with little time gaps between the blocks. As I have limited RAM size I cannot send the sound I want to play in only one block!

So my question is how can I send continuously data through I2S?

Below you will find the code I am using right now where test is a tab of bytes with the sound I want to play :

// This is the I2S data handler - all data exchange related to the I2S transfers // is done here.

static void data_handler(uint32_t const * p_data_received,
	uint32_t       * p_data_to_send,
	uint16_t         number_of_words)
{
	// Non-NULL value in 'p_data_to_send' indicates that the driver needs
	// a new portion of data to send.
	if (p_data_to_send != NULL)
	{
		// Here we write the provided buffer with consecutive 16-bit values
		// in order to be able to check later if they were transmitted properly.
		//prepare_tx_data(p_data_to_send, number_of_words);

		++m_blocks_transferred;

		uint16_t i;
		for(i=0;i<I2S_BUFFER_SIZE;i++){
			m_buffer_tx[i]=(uint32_t)(test[I2S_BUFFER_SIZE*m_blocks_transferred+i*4]<<24)+(uint32_t)(test[I2S_BUFFER_SIZE*m_blocks_transferred+i*4+1]<<16)+(uint32_t)(test[I2S_BUFFER_SIZE*m_blocks_transferred+i*4+2]<<8)+(uint32_t)(test[I2S_BUFFER_SIZE*m_blocks_transferred+i*4+3]<<0);
		}	
	}
}

void main()
{ 
	uint32_t err_code = NRF_SUCCESS;

	NRF_LOG_INFO("I2S loopback example\r\n");

	nrf_drv_i2s_config_t config = NRF_DRV_I2S_DEFAULT_CONFIG;
	config.sdin_pin  = 3;//TAS2505_DATA_PIN;
	config.sdout_pin = TAS2505_DATA_PIN;
	config.mck_setup = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV63;
	config.ratio     = I2S_CONFIG_RATIO_RATIO_32X;
	config.channels  = I2S_CONFIG_CHANNELS_CHANNELS_Left;//NRF_I2S_CHANNELS_STEREO;
	err_code = nrf_drv_i2s_init(&config, data_handler);
	APP_ERROR_CHECK(err_code);

	m_blocks_transferred = 0;

	err_code = nrf_drv_i2s_start(NULL, m_buffer_tx,
		I2S_BUFFER_SIZE, 0);
	APP_ERROR_CHECK(err_code);

	while (m_blocks_transferred < BLOCKS_TO_TRANSFER)
	{
	}
	nrf_drv_i2s_stop();
}

Thanks in advance,

Sylvain

  • You should use properties of EasyDMA incorporated into I2S peripheral HW block of nRF52 and simply create two RAM buffers where one is being plaid (this is action done autonomously on MCU once you set the registers, prepare data in RAM buffer and start the transfer) and second is being "prepared" (= filled with next block of valid audio data). Once the playback is finished then you just start another with second buffer and outside the interrupt handler you start preparation of next block. Until your MCU isn't blocked for whole time of playback of one block this works without problems. This kind of construction is usually called "swing" (because you just jungle with two buffers here and there) and you should be able to find some general examples all over the internet if necessary. I've thought this is also in I2S example in nRF5 SDK but it seems just basic read/write loop-back program so it's on you.

Related