UART3 Access on Custom Board based on IMX8MPlus

I have a custom board where I am trying to test/use /dev/verdin-uart3 to send/receive commands/responses with an external board connected to it. I struggle to have it working properly and I am not sure why.

Custom device-tree:

#include "imx8mp-verdin.dtsi"
#include "imx8mp-verdin-wifi.dtsi"

/* ... */

/* Verdin UART_3 */
&uart3 {
	status = "okay";
	linux,rs485-enabled-at-boot-time;
	rs485-rts-active-low;
	rs485-rx-during-tx;
};

/* ... */

Relevant schematic parts:

Docker compose (application) snippet:

# ...

  my-server:
    container_name: "my-server"
    restart: always
    restart: unless-stopped
    image: gitlab.org.ch:5050/my-server:0000-arm64
    depends_on:
      mariadb:
        condition: service_healthy
    entrypoint: "./app/my-server"
    environment:
      - MEAS_UNIT_DEV=/dev/verdin-uart3
    devices:
      # SODIMM_220, SODIMM_222 are on gpiochip3 (lines 3 and 1 respectively). Correspond to
      # X4_BOOT_SOM and X4_READY_SOM respectively
      - /dev/gpiochip3:/dev/gpiochip3
      - /dev/verdin-uart3:/dev/verdin-uart3
    group_add:
      - dialout
      - gpio
    # The server needs to be on the same network as the DB to access it
    networks:
      - dbhostnet
    ports:
      - "50051:50051"
    healthcheck:
      test: ["CMD", "nc", "-z", "localhost", "50051"]
      retries: 10
      timeout: 5s
      interval: 2s
      start_period: 10s

# ...

Serial port code

// ...

#include <termios.h>

// ...

ErrorCode SerialPort::open(const std::string& device)
{
    if (device.empty())
    {
        spdlog::error("Name cannot be empty");
        return ERR_DRIVERS_SERIAL_INVALID_DEVICE;
    }

    _fd = ::open(device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (_fd < 0)
    {
        spdlog::error("Error opening device {}, errno={}, {}.",
                      device,
                      errno,
                      Poco::Error::Error::getMessage(errno));
        return ERR_DRIVERS_SERIAL_IO_ERROR;
    }

    termios options {};
    memset(&options, 0, sizeof(options));
    options.c_cflag = (options.c_cflag & static_cast<tcflag_t>(~CSIZE)) | CS8;
    options.c_cflag |= B115200;// | CLOCAL | CREAD;
    options.c_iflag = IGNPAR;
    options.c_oflag = 0;
    options.c_lflag = 0;
    if (tcsetattr(_fd, TCSANOW, &options) != 0)
    {
        spdlog::error("tcsetattr errno={} ({}).", errno, Poco::Error::Error::getMessage(errno));
        return ERR_DRIVERS_SERIAL_IO_ERROR;
    }

    return ERR_SUCCESS;
}

Testing (with or without RS485 in device tree):

  • From the external board, I see that the proper commands are coming and responded to. Example:
COMMAND (From imx8mp):  0x01 0x04 0xCE 0x99 0x88 0x02 0xC8 0xD9 0x01 0x01 0xCB 0x3B 0xDB
RESPONSE (To imx8mp):  0x07 0xCE 0x00 0x00 0x00 0xA5 0x47
  • From the board itself, my docker application receives nothing.
  • Same thing if I manually use stty and hexdump. Once again, from my external board, I see a response being sent:
root@verdin-imx8mp-14772918:~# stty -F /dev/verdin-uart3 115200
root@verdin-imx8mp-14772918:~# echo -e '\x01\x01\xcb\x3b\xdb' > /dev/verdin-uart3
root@verdin-imx8mp-14772918:~# hexdump -C < /dev/verdin-uart3
# <- Nothing here even though the external board answered.
root@verdin-imx8mp-14772918:~#

Testing (connecting the External board to a PC via an adapter)

Everything works as intended

Hi, I’m the Toradex AI Assistant. The Toradex Support team will follow up with you shortly!

Did you like my answer?

:+1: :-1:


Hello,

To address the UART3 communication issue on your custom board based on the Verdin iMX8M Plus, here are some steps you can follow:

  1. Device Tree Configuration:

    • Double-check your device tree settings for UART3. If RS485 is not required, consider commenting out the RS485-related properties to see if this resolves the issue.
    • Ensure that the pin multiplexing is correctly set for UART3, confirming that the appropriate pins are assigned.
  2. Hardware Connections:

    • Verify the physical connections between the Verdin iMX8M Plus and the external board. Ensure that the TX and RX lines are correctly connected and not reversed.
    • Check the ground connection, as a poor ground can disrupt communication.
  3. Testing with stty and hexdump:

    • Confirm that the UART settings (baud rate, parity, stop bits) match those expected by the external board.
    • Perform a loopback test by connecting the TX and RX pins on the Verdin iMX8M Plus to ensure data sent is received correctly.
  4. Docker Configuration:

    • Ensure your Docker container has the necessary permissions to access /dev/verdin-uart3. The group_add directive should include the dialout group, which typically has access to serial ports.
    • Verify that the device is correctly mapped into the container using the devices directive.
  5. Software Debugging:

    • Add logging in your application to confirm that the serial port opens successfully and that data is being written to it.
    • Check for any error messages or logs that might indicate issues with the serial port configuration or access.
  6. External Board Testing:

    • Since the external board works when connected to a PC, ensure that the same settings and conditions are replicated when connected to the Verdin iMX8M Plus.

By following these steps, you should be able to identify and resolve the issue with UART3 communication on your custom board. If the problem persists, consider testing with a different UART port or using a logic analyzer to monitor the signals on the UART lines.

Best regards,
Toradex AI Assistant

Please, also check if these links can help you solve your problem:

Opening one of the 3 uarts on verdin 8MPlus.

I now notice that UART_3 on the verdin imx8mp seems to be used by u-boot in some way. I noticed that my external board was receiving the following for example:

U-Boot SPL 2022.04-6.8.0-devel+git.a1eb18d157f4 (Jan 01 1970 - 00:00:00 +0000)
DDRINFO: start DRAM init
DDRINFO: DRAM rate 4000MTS
Training FAILED
DDRINFO: start DR

How do I configure the UART_3 correctly?

We modified the board a little to use UART_2 instead. But, I get the same issue.

/* Verdin UART_2 */
&uart2 {
	status = "okay";
	linux,rs485-enabled-at-boot-time;
	rs485-rts-active-low;
	rs485-rx-during-tx;
};

Seems like I can get an initial transmit from my external board but then nothing seems to be received, even if the external board transmit continuously:

root@verdin-imx8mp-15133370:~# stty -F /dev/verdin-uart2 115200 cs8 -cstopb -parenb
root@verdin-imx8mp-15133370:~# hexdump -C < /dev/verdin-uart2
00000000  00 00 00 00 00 00 58 34  20 52 65 61 64 79 0a 0a  |......X4 Ready..|

Edit:
Seems like it might work with: stty -F /dev/verdin-uart2 115200 -echo -icanon -onlcr. How to configure that in the serial port C code ?

Hi @mnao

You can set the terminal configuration with:
https://linux.die.net/man/3/tcsetattr

Here an example:
https://www.cs.uleth.ca/~holzmann/C/system/ttyraw.c

Normally configure the tty in raw mode might be a good idea (see example). It would be the same as:

stty -F /dev/verdin-uart2 raw

Regards,
Stefan