Skip to main content
Sebastian K.
Associate III
May 26, 2017
Question

Nucleo F767 - Serial com. over virtual com port on Linux

  • May 26, 2017
  • 3 replies
  • 6526 views
Posted on May 26, 2017 at 16:25

Hello,

I am having problems communicating with my NUCLEO-F767ZI board over the virtual COM port on Linux. The board uses USART3 to communicate via the ST-Link USB port with the PC.

The ST-Link connects fine to the PC on device /dev/ttyACM0 and I can program it fine. I can even mount its disk partition as a mass storage device.

I am using the re-routing of printf() to the USART interface to output debug text, as proposed in the ST examples, and this works fine on a Windows PC. On a Linux machine however, I don't get the output.

I have tried 'screen' to open a serial console, as well as an Arduino IDE serial console, no luck. I have added udev rules for the ST-Link device in /etc/udev to be able to access the device without being root. I can work with other, Arduino-compatible boards over the same /dev/ttyACM0 device just fine.

Does anyone have experience with these boards under Linux and can help me out? What am I missing here?

#serial-interface #nucleo-f767zi #linux

Note: this post was migrated and contained many threaded conversations, some content may be missing.
This topic has been closed for replies.

3 replies

AvaTar
Senior III
May 26, 2017
Posted on May 26, 2017 at 16:41

Serial ports under Linux are opened in a terminal emulation mode, i.e. character are filtered and lines are buffered.

You need to switch it to 'raw' mode, to get every character directly, and unmodified.

I need to look up some older example code I have.

Perhaps you find some example elswhere in the meantime...

Sebastian K.
Associate III
May 27, 2017
Posted on May 27, 2017 at 13:49

Thanks for the hint. I tried playing around with setting the serial port to 'raw' but still can't get anything out of the board.

I looked a little closer at what the Arduino boards do in terms of serial communication, and apparently it's much more complex than the simple code I use on the F767 that just retargets the printf function to the USART. I guess that simple solution just does not work on Linux.

So if anyone has any working code that allows printing strings over the USB serial port, that would be really helpful.

AvaTar
Senior III
May 27, 2017
Posted on May 27, 2017 at 20:00

Something like this, incomplete example, error checking and other stuff skipped:

(Seems the 'Formatting as Souce Code' option is pretty useless)

♯ include <unistd.h>

♯ include <stdio.h>         // Standard input/output definitions

♯ include <stdlib.h>        // standard library functions

♯ include <fcntl.h>         // File control definitions

♯ include <termios.h>       // POSIX terminal control definitions

♯ include <string.h>        // String function definitions

♯ include <errno.h>         // Error number definitions

your_function_here ()

{

    ...

    struct termios  options, oldoptions;

    ...

    iFD = openLine (iSerLine, devtype);

    ...

    // Configure port reading; block read(), until data arrive

    fcntl (iFD, F_SETFL, 0);

    // Get the current options for the port, and copy for restoration

    tcgetattr (iFD, &oldoptions);

    memcpy (&options, &oldoptions, sizeof (struct termios));

    // Set the baud rates to the defined value

    cfsetispeed (&options, iBaudRate);

    cfsetospeed (&options, iBaudRate);

    // Enable the receiver and set local mode

    options.c_cflag |= (CLOCAL | CREAD);

    options.c_cflag &= ~PARENB;                 // Mask the character size to 8 bits, no parity

    options.c_cflag &= ~CSTOPB;

    options.c_cflag &= ~CSIZE;

    options.c_cflag |=  CS8;                    // Select 8 data bits

    if (hwFCntl)

        options.c_cflag |= CRTSCTS;             // enable hardware flow control

    else

        options.c_cflag &= ~CRTSCTS;            // Disable hardware flow control

    // Enable data to be processed as raw input

    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    options.c_iflag &= ~(ICRNL | INLCR | IXON | IXOFF);

    options.c_oflag &= ~OPOST;

    options.c_cc[VTIME] = 0;                    // no inter-character timer

    options.c_cc[VMIN]  = 1;                    // number of characters expected

    // options.c_cc[VEOF] = 4;

    // enable the new options for the port

    tcsetattr (iFD, TCSANOW, &options);

}

static int  openLine (int iSerLine, int devtype)

{

    if (devtype == DEVTYPE_SERIAL)

        sprintf (devName, '/dev/ttyS%d', iSerLine);

    else

        sprintf (devName, '/dev/ttyUSB%d', iSerLine);

    // (fd == -1) -> Could not open the port

    return (iFD = open (devName, O_RDONLY | O_NOCTTY | O_NDELAY));

}

Works for me, at least (Linux Mint 17 Distro).

nichtgedacht
Associate III
May 29, 2017
Posted on May 29, 2017 at 12:43

stty is your friend.

Sebastian K.
Associate III
May 31, 2017
Posted on May 31, 2017 at 20:12

Okay, I found out what the problem was. I had to include a file syscalls.c that declares an extern function that is used by printf(). I had it in my first project, but somehow forgot to carry it over to the new project. The code compiles and runs fine without it, it just doesn't work correctly. So it's actually not a Linux problem. With that compiled in I can see the outputs fine at least when I 'cat /dev/ttyACM0'.

Thanks again for everybody's suggestions!

AvaTar
Senior III
June 1, 2017
Posted on June 01, 2017 at 08:29

Just to understand this correctly - this probably resulted in no serial output from the target at all.

In other words, the sender (your STM32 target) was mute.

Sebastian K.
Associate III
June 1, 2017
Posted on June 01, 2017 at 13:56

Yes, that's what I figure. Somewhere in the code the string to be printed did not get carried through and thus did never reach the USART. It is the 'UART_printf' example that I used for this, but the one important additional file is somewhat hidden in a separate directory.