Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I2S: Wrong return codes for partial data transfers to/from DMA memory (IDFGH-6464) #8121

Closed
miketeachman opened this issue Dec 21, 2021 · 4 comments
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally

Comments

@miketeachman
Copy link

miketeachman commented Dec 21, 2021

Environment

  • Development Kit: Lolin D32 Pro
  • Kit version: 2.0
  • Module or chip used: ESP32-WROVER
  • IDF version: v4.4-beta1
  • Build System: CMake
  • Compiler version: 8.4.0
  • Operating System: Windows 10
  • (Windows only) environment type: WSL2/Ubuntu
  • Using an IDE?: No
  • Power Supply: USB

Problem Description

A bug has been introduced in ESP-IDF v4.4-beta1 release that changes the behaviour of some I2S functions. The i2s_write() routine now returns an ESP_ERR_TIMEOUT error when the transmit buffer has become full, after a portion of the supplied data has been written. Here is the problem: a partial data transfer is NOT an error situation and should return ESP_OK -- partial data transfers are expected behaviour and are described in the I2S API documentation. Similar problems exist in functions i2s_write_expand() and i2s_read().

Expected Behavior

i2s_write() returns ERR_OK when any amount of data (even 0 bytes) has been copied to the transmit buffer. This is the API behaviour prior to ESP-IDF v4.4-beta1.

Actual Behavior

i2s_write() returns ESP_ERR_TIMEOUT. This behaviour is introduced in ESP-IDF v4.4-beta1.

Steps to reproduce

  1. call i2s_write() providing more data than can be copied into the transmit buffer during the timeout period provided. ESP_ERR_TIMEOUT is returned.

Code to reproduce this issue

rather than show code to reproduce the issue it's easiest to identify the code that was added which produces this bug.
By inspecting this code I think the bug will be obvious. The bug is found in the I2S driver file i2s.c in the functions i2s_write, i2s_write_expand(), and i2s_read(). The bug was introduced in commits b26da6f (for the write functions) and
commit 3c57a6a (for i2s_read())

Here is a code sample from i2s_write(), showing the problem line:

    while (size > 0) {
        if (p_i2s[i2s_num]->tx->rw_pos == p_i2s[i2s_num]->tx->buf_size || p_i2s[i2s_num]->tx->curr_ptr == NULL) {
            if (xQueueReceive(p_i2s[i2s_num]->tx->queue, &p_i2s[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) {
                ret = ESP_ERR_TIMEOUT;   // <==== the bug was introduced by adding this line.  Removing this line fixes the bug.
                break;
            }
            p_i2s[i2s_num]->tx->rw_pos = 0;

Debug Logs

Debug information comes from MicroPython

Traceback (most recent call last):
  File "uasyncio/core.py", line 1, in run_until_complete
  File "<stdin>", line 120, in continuous_play
  File "uasyncio/stream.py", line 1, in drain
OSError: [Errno 116] ETIMEDOUT: ESP_ERR_TIMEOUT

Other items if possible

@espressif-bot espressif-bot added the Status: Opened Issue is new label Dec 21, 2021
@github-actions github-actions bot changed the title I2S: Three functions return ESP_ERR_TIMEOUT error for partial data write I2S: Three functions return ESP_ERR_TIMEOUT error for partial data write (IDFGH-6464) Dec 21, 2021
@miketeachman miketeachman changed the title I2S: Three functions return ESP_ERR_TIMEOUT error for partial data write (IDFGH-6464) I2S: Three functions return ESP_ERR_TIMEOUT error for partial data transfers (IDFGH-6464) Dec 21, 2021
@miketeachman miketeachman changed the title I2S: Three functions return ESP_ERR_TIMEOUT error for partial data transfers (IDFGH-6464) I2S: Wrong return codes for partial data transfers to/from DMA memory (IDFGH-6464) Dec 21, 2021
@L-KAYA
Copy link
Collaborator

L-KAYA commented Dec 27, 2021

Hi @miketeachman , thank you for your feedback!

We add this error code because i2s reading and writing functions could never return an error code before, it means even the operation failed (i.e. 0 byte is read or written), it would still return ESP_OK. We think it can not indicate the exact result of reading or writing.

But yes, in the case you mentioned, we can't just return timeout since sometimes incomplete reading or writing is allowed, so we might better to change the error line into ret = (*bytes_written) == 0 ? ESP_ERR_TIMEOUT : ESP_OK;

@espressif-bot espressif-bot added Status: In Progress Work is in progress and removed Status: Opened Issue is new labels Dec 27, 2021
@miketeachman
Copy link
Author

Hi @L-KAYA, thank you for looking at this issue.

I looked at the proposed change you suggested. I have some concerns with this change. 0 bytes written or read does not seem like a failure - it just means that all DMA buffers were full (i2s_write) or empty (i2s_read) during the specified timeout period. This will be a normal situation with I2S. The write and read functions return with either bytes_written or bytes_read - these return values can be used by the calling applications to determine that 0 bytes were copied.

Why do you consider 0 bytes written or read to be a failed operation? I'm struggling to understand this.

@L-KAYA
Copy link
Collaborator

L-KAYA commented Dec 28, 2021

Hi @miketeachman , from my consideration, if 0 byte is not a failure, how do users know their configuration is not working? For the case that no data to receive or write, just set the timeout ticks to the maximum value, it will be blocked here. And if the app needs to work in non-block mode (i.e. a short timeout period), the app needs to be able to know that there is a timeout event while receiving message from DMA queue, but the app can also choose to ignore this error code if it doesn't need this.

Therefore, instead of only receiving ESP_OK, the app now can receive the timeout event and decide whether to use this information. Looking forward to your reply!

@miketeachman
Copy link
Author

I'm curious on the motivation to change the existing I2S API -- was this user driven? There must be a really good reason given that this is a breaking change (now returns an error code when previously ESP_OK was returned). I wonder how many other existing implementations will be affected by this breaking change.

dpgeorge pushed a commit to micropython/micropython that referenced this issue Jan 6, 2022
- Add default values for I2S features added in ESP-IDF 4.4.
- Add workaround for bug introduced in ESP-IDF 4.4
  (espressif/esp-idf#8121).
Jason2866 added a commit to tasmota/esp-idf that referenced this issue Jan 8, 2022
Jason2866 added a commit to tasmota/esp-idf that referenced this issue Jan 8, 2022
Jason2866 added a commit to tasmota/esp-idf that referenced this issue Jan 8, 2022
Jason2866 added a commit to tasmota/esp-idf that referenced this issue Jan 8, 2022
@espressif-bot espressif-bot added Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Resolution: Done Issue is done internally and removed Status: In Progress Work is in progress Resolution: NA Issue resolution is unavailable labels Jan 11, 2022
espressif-bot pushed a commit that referenced this issue Jan 21, 2022
Closes #8121

Revert reading/writing return ESP_ERR_TIMEOUT introduced in commit b26da6f
dskulina pushed a commit to playable-tech/esp-idf that referenced this issue Feb 4, 2022
Closes espressif#8121

Revert reading/writing return ESP_ERR_TIMEOUT introduced in commit b26da6f
dskulina pushed a commit to playable-tech/esp-idf that referenced this issue Feb 5, 2022
Closes espressif#8121

Revert reading/writing return ESP_ERR_TIMEOUT introduced in commit b26da6f
leifbirger pushed a commit to leifbirger/micropython that referenced this issue Jun 14, 2023
- Add default values for I2S features added in ESP-IDF 4.4.
- Add workaround for bug introduced in ESP-IDF 4.4
  (espressif/esp-idf#8121).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally
Projects
None yet
Development

No branches or pull requests

3 participants