zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.98k stars 6.68k forks source link

UART: uart_poll_in() not working in Shell application #43972

Closed oscarbaselga closed 2 years ago

oscarbaselga commented 2 years ago

Describe the bug When running a Shell application, UART interface is not working.

I am using the Shell feature in Zephyr and would like to add a custom command to allow users enter data via UART. Function uart_poll_out() works, but uart_poll_in() does not.

uart

CONFIG_SERIAL=y

shell

CONFIG_SHELL=y CONFIG_KERNEL_SHELL=y CONFIG_DEVICE_SHELL=y

- involved code

static int subcmd_uart_in_handler(const struct shell *shell, size_t argc, char **argv) { ARG_UNUSED(argc); ARG_UNUSED(argv);

const struct device *uart_dev = DEVICE_DT_GET(DT_NODELABEL(uart0));
if (!device_is_ready(uart_dev)) {
    LOG_ERR("UART device not ready\n");
    return 0;
}

unsigned char recv_char;
uart_poll_out(uart_dev, '>');

while (uart_poll_in(uart_dev, &recv_char) < 0) {
    k_yield();
}

uart_poll_out(uart_dev, recv_char);

return 0;

}

void main(void) { / UART shell / SHELL_STATIC_SUBCMD_SET_CREATE(sub_demo, // root subcommand SHELL_CMD(uart_in, NULL, "UART in command", subcmd_uart_in_handler), SHELL_SUBCMD_SET_END // array ending ); SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL); // root command

const struct device *dev;
uint32_t dtr = 0;

dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart));
if (!device_is_ready(dev)) {
    return;
}

while (!dtr) {
    uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr);
    k_sleep(K_MSEC(100));
}

}

- devicetree (.dts file)

... chosen { zephyr,sram = &sram0; zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; }; ... &uart0 { status = "okay"; current-speed = <115200>; tx-pin = <1>; rx-pin = <3>; rts-pin = <22>; cts-pin = <19>; }; ...

- `minicom v2.7.1`

**Expected behavior**
From `minicom`, previous code prints:

uart:~$ demo uart_in

However, when a key is pressed, nothing happens. I expected the key pressed to be printed, e.g. if 'a':

uart:~$ demo uart_in a

Impact This is blocking the progress of my project. The goal is to implement XMODEM protocol.

Additional context I am thinking that the code is not working because it might be necessary to disable Shell while UART calls. If this is the problem, I do not know how to do it.

sylvioalves commented 2 years ago

@oscarbaselga Would you be able to test in v3.0 instead of v2.7.0?

oscarbaselga commented 2 years ago

@sylvioalves I will keep this in mind. The code in samples/subsys/shell/shell_module/src/uart_reinit.c solves the problem of calling uart_poll_in() within the Shell context. They use a timer that is started when shell_uninit() is called and whose timeout callback executes uart_poll_in(). The need to uninitialize the Shell for every call to the UART is a bit strange.

oscarbaselga commented 2 years ago

UPDATE: I have reached a solution. It is as simple as stopping and then starting the shell during the handler:

static int subcmd_uart_in_handler(const struct shell *shell, size_t argc, char **argv) {
    ARG_UNUSED(argc);
    ARG_UNUSED(argv);

    shell_print(shell, "Example UART input (send one character)");

    shell_stop(shell);

    const struct device *uart_dev = DEVICE_DT_GET(DT_NODELABEL(uart0));
    if (!device_is_ready(uart_dev)) {
        LOG_ERR("UART device not ready\n");
        return 0;
    }

    char c;
    while (uart_poll_in(uart_dev, &c) < 0)
        ;
    uart_poll_out(uart_dev, c);

    shell_start(shell);

    return 0;
}
twaclaw commented 2 years ago

I am having the same issue: the shell doesn't seem to work on an ESP32. The same examples work on different platforms (e.g., on nucleo boards). Zephyr version v3.1.0-rc2, ESP-IDF release/v4.3-162-ga7dc3c722. I see the shell prompt uart $ but the characters I type are not echoed. This is for instance the output after flashing west build -b esp32 samples/subsys/shell/fs/;west flash

I (29) boot: ESP-IDF release/v4.3-162-ga7dc3c722 2nd stage bootloader
I (29) boot: compile time 20:44:59
I (30) boot: chip revision: 0
I (33) boot.esp32: SPI Speed      : 40MHz
I (38) boot.esp32: SPI Mode       : DIO
I (43) boot.esp32: SPI Flash Size : 4MB
I (47) boot: Enabling RNG early entropy source...
I (53) boot: Partition Table:
I (56) boot: ## Label            Usage          Type ST Offset   Length
I (63) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (71) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (78) boot:  2 factory          factory app      00 00 00010000 00100000
I (86) boot: End of partition table
I (90) esp_image: segment 0: paddr=00010020 vaddr=00000020 size=0001ch (    28) 
I (98) esp_image: segment 1: paddr=00010044 vaddr=3ffb0000 size=009c4h (  2500) load
I (108) esp_image: segment 2: paddr=00010a10 vaddr=3ffb09c4 size=0028ch (   652) load
I (115) esp_image: segment 3: paddr=00010ca4 vaddr=40080000 size=06518h ( 25880) load
I (135) esp_image: segment 4: paddr=000171c4 vaddr=00000000 size=08e74h ( 36468) 
I (149) esp_image: segment 5: paddr=00020040 vaddr=3f400040 size=0396ch ( 14700) map
I (154) esp_image: segment 6: paddr=000239b4 vaddr=00000000 size=0c664h ( 50788) 
I (174) esp_image: segment 7: paddr=00030020 vaddr=400d0020 size=0dfe0h ( 57312) map
I (199) boot: Loaded app from partition at offset 0x10000
I (199) boot: Disabling RNG early entropy source...
�*** Booting Zephyr OS build v3.1.0-rc2  ***

uart:~$

I am using Minicom 2.8. The ESP32 is connected via ttyUSB with 115200 8N1.

sylvioalves commented 2 years ago

@twaclaw Hi, I have just tested the samples/subsys/shell/fs and it does read input and echoes back.
Can you check whether your minicom is configured with HW flow control disabled?
I tested with minicom, miniterm and west espressif monitor, all working in here.

twaclaw commented 2 years ago

Thanks @sylvioalves, that was it, Hardware Flow Control was enabled :face_exhaling: