Sending rs485 message on dbus9 connector from my qt5 app on verdin dev board

I’ve been trying to get rs485 working on my verdin through the dedicated rs485 dbus9 connector on the dev board for a few days now. Some of this is definitely down to my confusion and inexperience but if anyone can offer some guidance it would be greatly appreciated.

I’ve added the device to my dockerfile:

version: "3.9"
services:
  qttemp-debug:
    build:
      context: .
      dockerfile: Dockerfile.debug
    image: ${LOCAL_REGISTRY}:5002/qttemp-debug:${TAG}
    ports:
      # SSH debug
      - 2231:2231
      # gdbserver
      - 2232:2232
      # qml debug
      - 2233:2233
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
    device_cgroup_rules:
      # ... for tty0
      - "c 4:0 rmw"
      # ... for tty7
      - "c 4:7 rmw"
      # ... for /dev/input devices
      - "c 13:* rmw"
      - "c 199:* rmw"
      # ... for /dev/dri devices
      - "c 226:* rmw"
    depends_on: [
      weston
    ]
    devices:
       - "/dev/verdin-uart1:/dev/verdin-uart1"
       - "/dev/video0:/dev/video0"
       - "/dev/video1:/dev/video1"
    restart: on-failure
       

  qttemp:
    build:
      context: .
      dockerfile: Dockerfile
    image: ${DOCKER_LOGIN}/qttemp:${TAG}
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
    device_cgroup_rules:
      # ... for tty0
      - "c 4:0 rmw"
      # ... for tty7
      - "c 4:7 rmw"
      # ... for /dev/input devices
      - "c 13:* rmw"
      - "c 199:* rmw"
      # ... for /dev/dri devices
      - "c 226:* rmw"
    depends_on: [
      weston
    ]
    devices:
       - "/dev/verdin-uart1:/dev/verdin-uart1"
       - "/dev/video0:/dev/video0"
       - "/dev/video1:/dev/video1"
    restart: on-failure

  weston:
    image: torizon/weston${GPU}:2
    environment:
      - ACCEPT_FSL_EULA=1
    # Required to get udev events from host udevd via netlink
    network_mode: host
    volumes:
      - type: bind
        source: /tmp
        target: /tmp
      - type: bind
        source: /dev
        target: /dev
      - type: bind
        source: /run/udev
        target: /run/udev
    cap_add:
      - CAP_SYS_TTY_CONFIG
    # Add device access rights through cgroup...
    device_cgroup_rules:
      # ... for tty0
      - "c 4:0 rmw"
      # ... for tty1
      - "c 4:1 rmw"
      # ... for tty7
      - "c 4:7 rmw"
      # ... for /dev/input devices
      - "c 13:* rmw"
      - "c 199:* rmw"
      # ... for /dev/dri devices
      - "c 226:* rmw"

I’m pretty sure this actually works because when I “open” the serial device in qt5 now it doesn’t throw an error.

Here is the relevant qt5 code. It’s a bit of a mess but you’ll see what I’m trying to accomplish:

    int fd;
    fd = open("/dev/verdin-uart1", O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);
    qDebug() << fd;
    
    struct serial_rs485 rs485conf;

    rs485conf.flags |= SER_RS485_ENABLED;
    rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
    rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
    rs485conf.flags |= SER_RS485_RX_DURING_TX;

    ioctl(fd, TIOCSRS485, &rs485conf);

    serialDevice = new QSerialPort(this);
    qDebug() << "Number of serial ports: " << QSerialPortInfo::availablePorts().length() << "\n";
    foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
        qDebug() << "Description: " << serialPortInfo.description() << "\n";
        qDebug() << "Has vendor id?: " << serialPortInfo.hasVendorIdentifier() << "\n";
        qDebug() << "Vendor ID: " << serialPortInfo.vendorIdentifier() << "\n";
        qDebug() << "Has product id?: " << serialPortInfo.hasProductIdentifier() << "\n";
        qDebug() << "Product ID: " << serialPortInfo.productIdentifier() << "\n";
    }

    QString portName;
    foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts())
    {
        if(serialPortInfo.hasProductIdentifier() && serialPortInfo.hasVendorIdentifier())
        {
            qDebug() << serialPortInfo.vendorIdentifier();
            qDebug() << serialPortInfo.productIdentifier();
            if((serialPortInfo.productIdentifier() == product_id) && (serialPortInfo.vendorIdentifier() == vendor_id))
            {
                portName = serialPortInfo.portName();
            }
        }
    }
    qDebug() << portName;
    qDebug() << vendor_id;
    qDebug() << product_id;

    qDebug() << serialDevice->error();
    //serialDevice->setPortName(portName);
    serialDevice->setPortName("/dev/verdin-uart1");
    qDebug() << serialDevice->open(QSerialPort::ReadWrite);
    qDebug() << serialDevice->error();
    serialDevice->setBaudRate(QSerialPort::Baud9600);
    serialDevice->setDataBits(QSerialPort::Data8);
    serialDevice->setFlowControl(QSerialPort::NoFlowControl);
    serialDevice->setParity(QSerialPort::NoParity);
    serialDevice->setStopBits(QSerialPort::OneStop);
    QObject::connect(serialDevice, SIGNAL(readyRead()), this, SLOT(readSerial()));

void MainWindow::openLock(int lockNumber, int boardNumber)
{
    qDebug() << lockNumber;
    qDebug() << boardNumber;

    QByteArray myHexArray = QByteArray::fromHex("8A0100119A");
    qDebug() << myHexArray;
    qDebug() << serialDevice->error();
    qDebug() << serialDevice->write(myHexArray);
    qDebug() << serialDevice->error();
}

Firstly I had set this up just using the qt serial control code. It worked fine using a usb to rs485 adapter or using gpio pins on a raspberry pi. However, the toradex verdin does not appear to send any message at all when I invoke openLock. I know this because I am looking at the rs485 debug that I have running from the usbc port which shows output while the verdin is booting up but nothing when I runt he function.

I added the ioctl code after reading this doc on torizon-core:

From what I can tell from those docs the flags I’m setting are the only ones that are necessary. I couldn’t figure out a way to do that from the qt serial lib, but perhaps one does exist. And help or direction on this would be much appreciated.

Could you try connecting an oscilloscope or logic analyzer to the X17/28 pin (UART_1_TXD) and check if you have any signals there when you invoke the openLock() function? If not, could you check for a signal there when simply copying some data to /dev/verdin-uart1 using the Linux console?

Have you tried to just get simple rs485 running without the qt overhead? Might be a good way to start out. There are some utilities out there that are pretty simple to use. A quick google: GitHub - cbrake/linux-serial-test: Linux Serial Test Application

I don’t have any hardware like that. I have a python app I wrote which will send the appropriate signal, but I don’t know how to install the pip dependencies inside the container for my app.

For anyone engaged in hardware development or debugging, a logic analyzer and/or oscilloscope is essential. You could use a simple one like this https://www.amazon.com/HiLetgo-Analyzer-Ferrite-Channel-Arduino/dp/B077LSG5P2

Yes, I’ve been putting off those purchases. However, shouldn’t I be able to see the same thing (or close enough) on the debug usbc port on my development board? If not then I can probably just listen in to the rs485 line on a breadboard attached to the usb/rs485 adapter I have.

Hello @munderwoods,
sorry for the delay in answering this. I just did a quick test on my setup with a Verdin Development Board and a Verdin iMX8MP module running Torizon Core 5.7.2 and I could see the RS485 working. For the other side of the serial link I used a Waveshare TS485 to ethernet converter (https://www.waveshare.com/product/iot-communication/wired-comm-converter/ethernet-to-uart-rs232-rs485/rs485-to-eth.htm).

My quick test consisted of a small C program to setup the RS485 flags and then using microcom to setup and use the serial port. Here’s the sequence of what I did:

  • First, I copied the binaries of the two test programs I wrote to the module, the files are attached here.
    get (13.9 KB)
    setup (13.9 KB)

  • run the commands

torizon@verdin-imx8mp-07330987:~$ ./setup /dev/verdin-uart1
torizon@verdin-imx8mp-07330987:~$ ./get /dev/verdin-uart1 
flags: 40089d
SER_RS485_ENABLED: enabled
SER_RS485_RTS_ON_SEND: disabled
SER_RS485_RTS_AFTER_SEND: enabled
SER_RS485_RX_DURING_TX: enabled
  • run microcom to setup and use the serial port (I did this part on a second console connected through ssh)
torizon@verdin-imx8mp-07330987:~$ microcom -s 115200 /dev/verdin-uart1

With microcom running like this, everything typed on this console goes via serial link to the waveshare. Everything coming from the waveshare is displayed there.

In my case, I had some difficulties first because of these problems:

  • I had the jumpers for SODIMM_129 and SODIMM_131 on X16 removed on my devboard because of a previous test and forgot to put them back

  • Initially, I had the A and B signals connected the wrong way. After switching them the communication started to work.

The RS485 transceiver on the devboard has some power gating logic going on, so it would also be interesting to check if the LED32 is ON (with our default software images it should).

If you run the quick test like I did and it works, we can focus on why you can’t get the same result inside the container running the QT app. Maybe you could run it with one end of the serial link on the Verdin dev board and the other end on the RS485 to USB converter that you have connected on your PC (where you can also run any serial program to see the communication working.

Please let me know if you need more help,
Rafael

Awesome, I’ll try this out when I’m in the office on Tuesday. Thanks.