nRF52840 I2S write failed -11

Hello,

I am using two nrf52840 DKs to test ble transmission and i2s output. The nRF Connect SDK I use is v2.6.0.

Both of them are ble connected. One sends data to the other through ble, and the other receives the data and outputs it to i2s.

The i2s is set to write data every 100ms.

During the test, I found that every time i2s writes 100ms of data, it must do an I2S_TRIGGER_STOP, otherwise an error will occur.

Just like the code below, I must first do I2S_TRIGGER_START in each round, then write data to i2s tx, and finally I must do I2S_TRIGGER_STOP.

void i2s_send(void){
	int ret;
	memset(mem_block, 0, BLOCK_SIZE);
	ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
	if (ret < 0) {
		LOG_ERR("Failed to write block %d", ret);
	}
	/* Put data into the tx buffer */
	for (int i = 0; i < 9600; i++) {
		((int16_t*)mem_block)[i] = (int16_t)data_buf_modify[i];
  	}
	ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, I2S_TRIGGER_START);
	if (ret < 0) {
		LOG_ERR("Failed to trigger command I2S_TRIGGER_START on TX: %d\n", ret);
	}
	ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
	if (ret < 0) {
		LOG_ERR("Failed to write data: %d", ret);
	}else{
		LOG_INF("Success to write data.");
	}
	ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, I2S_TRIGGER_STOP);
	if (ret < 0) {
		LOG_ERR("Failed to trigger command I2S_TRIGGER_DRAIN on TX: %d\n", ret);
	}
}

This causes my i2s output to be noisy, which I think is due to the pause during playback.

But if I only do I2S_TRIGGER_START at the beginning, and then do not do I2S_TRIGGER_STOP after i2s write, but directly do the next round of i2s write, I will get the following error:

[00:00:00.395,660] <inf> central_test: Success to write data.
[00:00:00.395,660] <inf> central_test: Success to write data.
[00:00:00.396,026] <inf> central_test: Success to write data.
[00:00:00.396,057] <inf> central_test: Success to write data.
[00:00:00.496,856] <inf> central_test: Success to write data.
[00:00:01.496,948] <err> central_test: Failed to write data: -11
[00:00:02.497,100] <err> central_test: Failed to write data: -11
[00:00:03.497,253] <err> central_test: Failed to write data: -11
[00:00:04.497,375] <err> central_test: Failed to write data: -11

I encountered a similar problem in this post, and it has solved by replacing i2s_write with i2s_buf_write.

But after joining ble communication, I encountered the same problem and used the same solution to no avail.

I'm confused as to why there is this difference. Is it because nrf52840 cannot continuously do i2s write while receiving ble data? Is it necessary to stop i2s first and then start to write continuously?

Parents
  • The I2S peripheral use double buffering for the Tx and Rx pointers, so interrupts or other things happening should not matter (as long as it does not take too long time compared to the buffer size). So it should definitely be possible to get this working. Can you help us reproduce this issue on the nrf52840 DK?

  • Sorry, I didn't express myself clearly.

    I am currently using one nrf52840DK to receive ble data from another nrf52840 DK. These ble data are a continuous piece of audio data.

    Then, I send the received data to i2s, which should theoretically output a continuous audio.

    I divide this data into many segments in units of 100ms, and then transmit it to i2s multiple times. Each time the data is transmitted, the following function will be called.

    void i2s_send(void){
    	int ret;
    	memset(mem_block, 0, BLOCK_SIZE);
    	ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
    	if (ret < 0) {
    		LOG_ERR("Failed to write block %d", ret);
    	}
    	/* Put data into the tx buffer */
    	for (int i = 0; i < 9600; i++) {
    		((int16_t*)mem_block)[i] = (int16_t)data_buf_modify[i];
      	}
    	ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, I2S_TRIGGER_START);
    	if (ret < 0) {
    		LOG_ERR("Failed to trigger command I2S_TRIGGER_START on TX: %d\n", ret);
    	}
    	ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
    	if (ret < 0) {
    		LOG_ERR("Failed to write data: %d", ret);
    	}else{
    		LOG_INF("Success to write data.");
    	}
    	ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, I2S_TRIGGER_STOP);
    	if (ret < 0) {
    		LOG_ERR("Failed to trigger command I2S_TRIGGER_DRAIN on TX: %d\n", ret);
    	}
    }

    The output result is noisy, and I think this is because there is an I2S_TIGGER_STOP every 100ms.

    I tried changing the function that writes i2s every 100ms to the following:

    void i2s_send(void){
    	int ret;
    	memset(mem_block, 0, BLOCK_SIZE);
    	ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
    	if (ret < 0) {
    		LOG_ERR("Failed to write block %d", ret);
    	}
    	/* Put data into the tx buffer */
    	for (int i = 0; i < 9600; i++) {
    		((int16_t*)mem_block)[i] = (int16_t)data_buf_modify[i];
      	}
      	//Only do this once
      	if(!has_started){
      	    ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, I2S_TRIGGER_START);
    	    if (ret < 0) {
    		    LOG_ERR("Failed to trigger command I2S_TRIGGER_START on TX: %d\n", ret);
    	    }
    	    has_started = 1;
      	}
    	ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
    	if (ret < 0) {
    		LOG_ERR("Failed to write data: %d", ret);
    	}else{
    		LOG_INF("Success to write data.");
    	}
    }

    The failed to write data error occurred.

  • Thanks for explaining that a bit clearer this time. Error code -11 corresponds to -EAGAIN, meaning the I2S buffer is full or unavailable. This happens because the I2S driver uses a double buffering mechanism. If you do fail to synchronize correctly, the buffer gets stuck in an unavailable state as this is a double buffered mechanism

    Monitor buffer availability something like below

    // Use i2s_buf_write() instead of i2s_write(), as it provides better handling for buffer availability and is non-blocking
    ret = i2s_buf_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
    if (ret == -EAGAIN) {
        LOG_ERR("I2S buffer full, retrying...");
        // add logic here to attempt few retires based on the acceptance of your application
    }
    

  • Thank you for your reply.

    After I used i2s_buf_write instead of i2s_write, the error I encountered changed.

    [00:00:25.157,379] <inf> central_test: Success to write data.
    [00:00:25.560,302] <err> i2s_nrfx: Next buffers not supplied on time
    [00:00:28.159,210] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:28.159,240] <err> central_test: Failed to write block -5
    [00:00:28.160,369] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:28.160,369] <err> central_test: Failed to write data: -5
    [00:00:29.164,764] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:29.164,794] <err> central_test: Failed to write block -5
    [00:00:29.165,832] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:29.165,863] <err> central_test: Failed to write data: -5
    [00:00:31.160,522] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.160,552] <err> central_test: Failed to write block -5
    [00:00:31.161,743] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.161,743] <err> central_test: Failed to write data: -5
    [00:00:31.336,212] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.336,212] <err> central_test: Failed to write block -5
    [00:00:31.337,280] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.337,280] <err> central_test: Failed to write data: -5
    [00:00:31.546,203] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.546,234] <err> central_test: Failed to write block -5

Reply
  • Thank you for your reply.

    After I used i2s_buf_write instead of i2s_write, the error I encountered changed.

    [00:00:25.157,379] <inf> central_test: Success to write data.
    [00:00:25.560,302] <err> i2s_nrfx: Next buffers not supplied on time
    [00:00:28.159,210] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:28.159,240] <err> central_test: Failed to write block -5
    [00:00:28.160,369] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:28.160,369] <err> central_test: Failed to write data: -5
    [00:00:29.164,764] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:29.164,794] <err> central_test: Failed to write block -5
    [00:00:29.165,832] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:29.165,863] <err> central_test: Failed to write data: -5
    [00:00:31.160,522] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.160,552] <err> central_test: Failed to write block -5
    [00:00:31.161,743] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.161,743] <err> central_test: Failed to write data: -5
    [00:00:31.336,212] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.336,212] <err> central_test: Failed to write block -5
    [00:00:31.337,280] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.337,280] <err> central_test: Failed to write data: -5
    [00:00:31.546,203] <err> i2s_nrfx: Cannot write in state: 4
    [00:00:31.546,234] <err> central_test: Failed to write block -5

Children
  • Hello,

    Susheel is away, so I am taking over in his absence.

    The errors you get now seems to originate from data_handler in the i2s_nrfx driver.

    The I2S state with value 4 is I2S_STATE_ERROR, and the return value of -5 is -EIO, which is returned from the i2s_buf_write if the I2S peripheral is not in the READY or RUNNING state.

    -EIO is returned when i2s_config_get returns NULL. So your I2S device is unconfigured after the first write.

    Could you please debug the application and see what happens after the successful write?

    Best regards,

    Maria

  • Thank you for your assistance.

    I added debug at the end of i2s_nrfx_write to output the state after successful writing.

    [00:00:38.656,372] <inf> i2s_nrfx: After Write state: 1
    [00:00:38.657,501] <inf> i2s_nrfx: After Write state: 2

    It seems that the state after successful writing is I2S_STATE_RUNNING, but the next write will change to I2S_STATE_ERROR.

    I don't know what happened to cause this state to change.

    In this post where I've asked the question, this problem does not occur. The difference between them is that this post uses i2s to play the same pcm data, so mem_block only needs to be written once and does not need to be changed subsequently. My current case is that mem_block needs to be changed every time before writing to i2s. Could this problem be caused by changes in mem_block?

    Let me restate my problem. As I said at the beginning, if I use i2s_write and add i2s_trigger (i2s_dev_tx, I2S_DIR_TX, I2S_TRIGGER_STOP) after each successful write, there will be no errors and continuous writes will be successful, but the sound will be intermittent.

    In fact, what I want to solve is the intermittent problem caused by I2S_TRIGGER_STOP, but removing I2S_TRIGGER_STOP will cause these problems. Is there any other way to solve this intermittent problem?

Related