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

Issues with USB-JTAG/serial console on ESP32-S3 (IDFGH-12951) #13907

Closed
3 tasks done
eriksl opened this issue Jun 4, 2024 · 9 comments
Closed
3 tasks done

Issues with USB-JTAG/serial console on ESP32-S3 (IDFGH-12951) #13907

eriksl opened this issue Jun 4, 2024 · 9 comments
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Doc issue pertains to documentation of IDF

Comments

@eriksl
Copy link

eriksl commented Jun 4, 2024

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

v5.2.1

Espressif SoC revision.

ESP32-S3 v0.1

Operating System used.

Linux

How did you build your project?

Command line with idf.py

If you are using Windows, please specify command line type.

None

Development Kit.

Not relevant here.

Power Supply used.

USB

What is the expected behavior?

I was using liblinenoise for command line editing, but it didn't work. From the liblinenoise source I could not determine the cause, so I started experimenting with own code. It appears that a read() call from the stdin (0) file descriptor, very often returns "0 bytes". In POSIX this means: end-of-file. EOF on a USB console input is meaningless. I got it to work by completely ignoring any zero byte reads and if it happens, I add a short RTOS delay before trying again, because this condition appears to happen in bursts. I also tried setting the input (O_)NONBLOCK and clearing this status, but interestingly, that does not matter at all.

What is the actual behavior?

It appears that a read() call from the stdin (0) file descriptor, very often returns "0 bytes". In POSIX this means: end-of-file. EOF on a USB console input is meaningless. I got it to work by completely ignoring any zero byte reads and if it happens, I add a short RTOS delay before trying again, because this condition appears to happen in bursts. I also tried setting the input (O_)NONBLOCK and clearing this status, but interestingly, that does not matter at all.

Steps to reproduce.

  1. Create a loop that reads to a buffer from fd 0 using read() function
  2. Show acquired strings and amount of bytes read
  3. Confirm that many times read() returns with 0 bytes read

Debug Logs.

No response

More Information.

No response

@eriksl eriksl added the Type: Bug bugs in IDF label Jun 4, 2024
@github-actions github-actions bot changed the title Issues with USB-JTAG/serial console on ESP32-S3 Issues with USB-JTAG/serial console on ESP32-S3 (IDFGH-12951) Jun 4, 2024
@espressif-bot espressif-bot added the Status: Opened Issue is new label Jun 4, 2024
@igrr
Copy link
Member

igrr commented Jun 4, 2024

@eriksl My guess is that in your test, some of the steps required to enable blocking reads from usb_serial_jtag console might be missing, resulting in the behavior you have observed.

Could you please show how you are initializing the usb_serial_jtag driver before step 1? Could you please also attach your sdkconfig file?

If you can attach the complete code which reproduces the issue, it would make it much faster for us to solve this problem.

@eriksl
Copy link
Author

eriksl commented Jun 4, 2024

I am not doing anything at all with "usb_serial_jtag console". I am just reading from VFS fd 0, just like liblinenoise does.

The only thing I did with the USB JTAG/serial console is to select it in menuconfig as "primary console" and disabled the "secondary console" there.

I am not sure what would have needed to be configure about a USB console. It's just emulating an UART. Baud rate, start/stop/parity are meaningless here. Especially because it already works, the logging is shown just fine, just as writing to fd 1. The linenoise library doesn't do anything in that area as well, so if there is some configuration required, I guess Espressif "forgot" to add it there too.

But for now, it looks like a simple bug in the USB JTAG console driver to me.

BTW you're referring to the USB-CDC driver in your link, which I am not using. I have no PHY connected to it, so it can't work.

fcntl(fileno(stdout), F_SETFL, 0);
fcntl(fileno(stdin), F_SETFL, 0);

These two I already tried (as more or less described), they do not have any effect. Also if you change '0' to 'O_NONBLOCK. And BTW fileno(stdout) is always '1', fileno(stdin) is always '0'.

@igrr
Copy link
Member

igrr commented Jun 4, 2024

I see, thanks for explaining.

When you select "USB JTAG/serial console" as primary console, by default, for code size reasons, we use a simple VFS device implementation which is always doing blocking writes and non-blocking reads, regardless of O_NONBLOCK setting. This works for the most common use cases, where the console is used for output only. Because of this, as you noticed, "the logging is shown just fine, just as writing to fd 1".

Enabling more standard behavior — where both reads and writes can be either blocking or non-blocking — requires extra steps. (This section of the docs describes the process for UART VFS, but it's similar for USB_SERIAL_JTAG VFS.) Essentially, you need to:

  1. Install the USB_SERIAL_JTAG driver — in this case, call usb_serial_jtag_driver_install
  2. Tell the VFS layer to use driver instead of the simple implementation — by calling usb_serial_jtag_vfs_use_driver.

After this, F_SETFL should work the way you expect.

@eriksl
Copy link
Author

eriksl commented Jun 4, 2024

Ah ok, that's new to me, is this documented?

@igrr
Copy link
Member

igrr commented Jun 4, 2024

It is only documented for the specific case of UART console, that's the link I posted in the previous comment. I think this section was written before we had any chip with USB_OTG or USB_SERIAL_JTAG peripherals, so it was written in a UART-specific way, and we didn't notice that it should be updated.

I'll update the docs to describe this also for USB_SERIAL_JTAG. Sorry for the trouble!

Here is the code snippet which works with IDF v5.2.x:

#include <stdio.h>
#include "esp_err.h"
#include "driver/usb_serial_jtag.h"
#include "esp_vfs_dev.h"

void app_main(void)
{
    usb_serial_jtag_driver_config_t usb_serial_jtag_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();

    ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&usb_serial_jtag_config));

    esp_vfs_usb_serial_jtag_use_driver();

    printf("Enter a line and press Enter:\n");
    char line[128];
    fgets(line, sizeof(line), stdin);
    printf("Read: %s", line);
}

@eriksl
Copy link
Author

eriksl commented Jun 4, 2024

Thanks, with your help I got it working.

As ever I was stubborn and I ditched the VFS layer for the console altogether (don't need it anyway). So I included the call to usb_serial_jtag_driver_install, with tiny buffers of 128 bytes (apparently they must be > 64) and just used usb_serial_jtag_write_bytes and usb_serial_jtag_read_bytes and then it works as expected.

There is just one thing that may be correction in ESP-IDF: the output is never flushed. I added calls to fsync(1) which worked, but it's just not appropriate to mix low-level and VFS functions. I now used the (private) hal function use_serial_jtag_ll_txfifo_flush, and that works too, but I don't think it's really designed that way ;-)

@eriksl
Copy link
Author

eriksl commented Jun 4, 2024

Upgrading from v5.2.1 to v5.2.2 seems to have solved this last issue (explicit flush).

@igrr
Copy link
Member

igrr commented Jun 4, 2024

Glad to hear you got it working!

We'll close this issue when the documentation update explaining what I wrote above is done.

@espressif-bot espressif-bot added Type: Doc issue pertains to documentation of IDF Status: Reviewing Issue is being reviewed and removed Type: Bug bugs in IDF Status: Opened Issue is new labels Jun 5, 2024
@espressif-bot espressif-bot added Status: Done Issue is done internally Resolution: NA Issue resolution is unavailable and removed Status: Reviewing Issue is being reviewed labels Jun 13, 2024
@eriksl
Copy link
Author

eriksl commented Jun 17, 2024

Thumbs up and thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Doc issue pertains to documentation of IDF
Projects
None yet
Development

No branches or pull requests

3 participants