Electronic – Unable to display UART character data sent from STM32F407G Discovery Board (TX) to Ubuntu(or Raspian) on Rasperry Pi 3 Model B (RX)

embeddedserialstm32uart

Solved. The problem was a bad board & then appending extra "\n" in the output after reading from via "C".


I'm trying to send data via UART from STM32F407G Discovery Board micro-controller to RasperryPi 3 Model B running Ubuntu.

I was able to send data using STM32F407G Discovery Board "C" libraries & display that output on TeraTerm & Putty apps on Windows via serial-usb interface wire.

My goal is to create my own simple serial port reader/writer program that displays the UART character data thaw which will come from STM32F407G.

Below is the relevant snippet of the transmission code on the STM32F407G side:

void print_mpu_values_to_uart(mpu6050_device *dev, UART_HandleTypeDef* huart, long print_delay_millisecs) {

    if (NULL != dev) {
        char str[120];
        char *pStr = str;
        clear_uart_message(pStr, sizeof(str));
        /* Format data */
        sprintf(str,
                "dev=%.2X,Ax=%2.4f,Ay=%2.4f,Az=%2.4f,Gx=%2.4f,Gy=%2.4f,Gz=%2.4f\r\n",
                dev->address, dev->pMpu_6050_data.Ax, dev->pMpu_6050_data.Ay,
                dev->pMpu_6050_data.Az, dev->pMpu_6050_data.Gx,
                dev->pMpu_6050_data.Gy, dev->pMpu_6050_data.Gz);
        //send label
        HAL_UART_Transmit(huart, (uint8_t*) str, sizeof(str), 1000);
        HAL_Delay(print_delay_millisecs);
    }

}

I connected STM32F407G Discovery Board via Serial-USB wire & configured TeraTerm to listen to com port (COM9):

See snap of configured serial port values & correct output:

enter image description here

So far all is as expected & good.

I have confirmed the STM32F407G board, MPU sensors are integrated, and transmission code on STM32F407G is correct, as expected output is displayed.

I would like to create my own custom serial receiver on RasperryPi (other linux embedded boards) to further process my data.

Based on these online resources:

https://www.cmrr.umn.edu/~strupp/serial.html
http://www.ing.iac.es/~docs/external/serial/serial.pdf
https://www.raspberrypi.org/documentation/configuration/uart.md

These are my steps:

  1. I disconnected the usb-serial that was sending data to TeraTerm on Windows and connect my STM32F407G Discovery Board UART to RasperryPi UART pins, like this:

STM UART RX (PA3) to Rasperry UART TX (GPIO 14 PIN 8)
STM UART TX (PA2) to Rasperry UART RX (GPIO 15 PIN 10)

  1. UART Receive code on RasperryPi side (Im made sure my buadrate, parity bit, etc are same as TeraTerm settings):

       #include <iostream>
         #include <stdio.h> /* Standard input/output definitions */
         #include <string.h> /* String function definitions */
         #include <unistd.h> /* UNIX standard function definitions */
         #include <fcntl.h> /* File control definitions */
         #include <errno.h> /* Error number definitions */
         #include <termios.h> /* POSIX terminal control definitions */
    
         using namespace std;
    
         int open_port(char * port);
         void read_port(int file_descriptor, int buffer_size);
         struct termios SerialPortOptions;
         int main() {
             char * port = "/dev/ttyS0";
             std::cout << "Serial comm..." << port << std::endl;
    
             /*this program must executed via SUDO*/
             int fd = open_port(port);
             if (fd!=-1) {
                 std::cout << port << ", Opened successfully " << std::endl;
                 /*
                  * Set the baud rates to 115200...
                  */
                 cfsetispeed( & SerialPortOptions, B115200);
                 cfsetospeed( & SerialPortOptions, B115200);
    
                 /*
                  *Turn off hardware based flow control (RTS/CTS).
                  */
                 SerialPortOptions.c_cflag &= ~CRTSCTS;
    
                 /*
                  * Enable the receiver and set local mode...
                  */
                 SerialPortOptions.c_cflag |= (CLOCAL | CREAD);
    
                 /*For Serial communications with outside devices like serial modems,mice etc NON Cannonical mode is recommended.*/
                 SerialPortOptions.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
                 /*setting character size bits*/
                 SerialPortOptions.c_cflag &= ~CSIZE; /* Mask the character size bits */
                 SerialPortOptions.c_cflag |= CS8; /* Select 8 data bits */
    
                 /* No parity*/
                 SerialPortOptions.c_cflag &= ~PARENB;
                 SerialPortOptions.c_cflag &= ~CSTOPB;
                 SerialPortOptions.c_cflag &= ~CSIZE;
                 SerialPortOptions.c_cflag |= CS8;
                 tcsetattr(fd, TCSANOW, & SerialPortOptions);
                 //read from serial port
    
                     read_port(fd, 128);
    
                 close(fd);
    
    
             }
             return 0;
         }
    
         /*References: http://www.ing.iac.es/~docs/external/serial/serial.pdf
          * Page 8-10*/
         int open_port(char * port) {
    
             int fd; /* File descriptor for the port */
             /*
              * O_RDWR  - read write mode
              * O_NOCTTY -  this program doesn't want to be the "controlling terminal" for that port
              * O_NDELAY -  this program doesn't care what state the DCD signal line is in − whether
                         the other end of the port is up and running.
              */
             fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
             cout << "open_port(),fd:" << fd<< endl;
             if (fd == -1) {
                 /*
                  * Could not open the port.
                  */
                 perror("open_port: Unable to open ");
                 perror(port);
             } else {
                 fcntl(fd, F_SETFL, 0);
             }
             return fd;
         }
    
    
     void read_port(int file_descriptor, int buffer_size) {
         char serial_buffer[buffer_size];
         //cout << "read_port(),file_descriptor:" << file_descriptor << endl;
         int total_read= 0;
         int r=0;
         while (true) {
         r = read(file_descriptor, serial_buffer, sizeof(serial_buffer));
         if (r>0) {
             total_read = total_read + r;
         }
         if (total_read >= buffer_size) {
             serial_buffer[buffer_size] = '\0';
             printf("%s\n", serial_buffer);
             fflush(stdout);
             cout << "total_read:" << total_read << endl;
             total_read = 0;
    
         }
     }
    

    }

Ubuntu on RasperryPi, console output snippet:

Serial comm.../dev/ttyS0
open_port(),fd:3
/dev/ttyS0, Opened successfully 
W��k
total_read:128
��k
total_read:128
Y��k
total_read:128
��k
total_read:128

total_read:128
7��k
total_read:128
��k
total_read:128

As you can see I cant display the characters correctly but data is being sent to /dev/ttyS0.

Troubleshooting:

  1. For sanity check, to see if that was actually coming from STM32F407G, I physically disconnect TX (line from STM32F407G) to RX in RasperryPi, data stops flowing & stops printing on console.

  2. For further sanity check, I also tried "minicom" on Ubuntu's shell:

sudo minicom -D "/dev/ttyS0" -b 115200

Minicom output:

CTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.7.1 | VT102 | Offline | ttyS0
5…Y{‚A‚A‚A‚A‚ˆžaÊBœ"WWñö‹]ÁIÈœ"7WšÔä†Q2”UgÛV5F[uIœ"wSË€@‚A‚‚Aþˆžaœ"YM÷‹\ÁÅYÈ5…Qêœ"7[ì†S*ŠZZŸQ:”[

As you can see Minicom also gets data its not formatted correctly & garbage.

  1. I though this might have to do with endianess, the STM32 has ARM Cortex M4 which according to the document (PM0214 Programming manual STM32 Cortex®-M4 MCUs and MPUs programming manual) is by default little-endian, also running the command "lscpu" on the RasperryPi 3 model B, shows the Cortex-A53 which is also Little Endian based (https://en.wikipedia.org/wiki/ARM_architecture#64/32-bit_architecture), so I highly doubt the issue is endianess.

Based on user comments I tried different baud rates here are the results:

BAUDRATE:   OUTPUT TERMINAL & ENVIRONMENT:      RESULT:
115,200     TeraTerm/Putty (Windows)        Good (can see correct data)
115,200     C Program (Linux Ubuntu of Pi)      Garbage & Bad format

57,600          TeraTerm/Putty (Windows)        Good (can see correct data)
57,600          C Program (Linux Ubuntu of Pi)      Garbage & Bad format

38,400          TeraTerm/Putty (Windows)        Good (can see correct data)
38,400          C Program (Linux Ubuntu of Pi)      Garbage & Bad format

19200       TeraTerm/Putty (Windows)        Good (can see correct data)
19200       C Program (Linux Ubuntu of Pi)      Garbage & Bad format & also stops after few lines

14400       TeraTerm/Putty (Windows)        Good (can see correct data) 
14400       C Program (Linux Ubuntu of Pi)      Not supported & constant not present in termios.h 

9600        TeraTerm/Putty (Windows)        Good (can see correct data) 
9600        C Program (Linux Ubuntu of Pi)      Garbage & Bad format

4800        TeraTerm/Putty (Windows)        Good (can see correct data) 
4800        C Program (Linux Ubuntu of Pi)      Garbage & Bad format

Another attempt:, i changed the OS to Raspian & followed this blog (https://www.circuits.dk/setup-raspberry-pi-3-gpio-uart/). I wrote this small Python script:

import serial

serialport = serial.Serial("/dev/ttyS0", baudrate=4800, timeout=3.0)

while True:
    rcv = port.read(120)
    print(rcv)

Still getting garbage output!

How can I alter my C code on the RasperryPi to display the incoming UART characters properly?

PARTIAL-SOLUTION: Based on user input I tried UART from my original Pi board to actual PC & also UART loop, I was not able to get output. At this point I suspect the board, therefore I switched my board with another Pi 3 Model version B. After instaling minicom & disabking shell over UART. I can see meaningful minicom output:

enter image description here

I wrote a simpler version of C program above:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

int main(int argc, char* argv[]) {

    struct termios serial;
    char buffer[120];

    if (argc == 1) {
        printf("Usage: %s [device]\n\n", argv[0]);
        return -1;
    }

    printf("Opening %s\n", argv[1]);

    int fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);

    if (fd == -1) {
        perror(argv[1]);
        return -1;
    }

    if (tcgetattr(fd, &serial) < 0) {
        perror("Getting configuration");
        return -1;
    }

    // Set up Serial Configuration
    serial.c_iflag = 0;
    serial.c_oflag = 0;
    serial.c_lflag = 0;
    serial.c_cflag = 0;

    serial.c_cc[VMIN] = 0;
    serial.c_cc[VTIME] = 0;

    serial.c_cflag = B115200 | CS8 | CREAD;

    tcsetattr(fd, TCSANOW, &serial); // Apply configuration
    int flag =0;
    int read_count = 0; 
    while (flag!=-1)
    {
            int rcount = read(fd, buffer, sizeof(buffer));
            if (rcount < 0) {
                perror("Read");
                flag= -1;
            break;
            }
        else if (rcount>0)
        {
            //printf("Received %d characters\n", rcount);
                buffer[rcount] = '\0';
                printf("%s", buffer);
        }
            else {
                //read nothing, do nothing.
            }   


    }

    close(fd);
}

Im getting expected output:

dev=D2,Ax=-0.9922,Ay=0.0566,Az=0.8118,Gx=-0.2672,Gy=-1.0611,Gz=0.7634
dev=D0,Ax=-0.0664,Ay=0.0955,Az=0.8772,Gx=-0.6947,Gy=-0.9924,Gz=-1.4351
dev=D2,Ax=-0.9958,Ay=0.0535,Az=0.8113,Gx=-0.2824,Gy=-1.0687,Gz=0.7328
dev=D0,Ax=-0.0664,Ay=0.0962,Az=0.8818,Gx=-0.4656,Gy=-0.8397,Gz=-1.5420
dev=D2,Ax=-0.9961,Ay=0.0554,Az=0.8169,Gx=0.0305,Gy=-0.9771,Gz=0.6870
dev=D0,Ax=-0.0566,Ay=0.0999,Az=0.8813,Gx=-0.4809,Gy=-0.9466,Gz=-1.7023
dev=D2,Ax=-0.9858,Ay=0.0571,Az=0.8225,Gx=-0.3359,Gy=-0.9084,Gz=0.7023
dev=D0,Ax=-0.0657,Ay=0.0896,Az=0.8850,Gx=-0.7939,Gy=-1.0916,Gz=-1.5191
dev=D2,Ax=-0.9956,Ay=0.0623,Az=0.8191,Gx=-0.1756,Gy=-0.9542,Gz=0.8626
dev=D0,Ax=-0.0632,Ay=0.1025,Az=0.8782,Gx=-0.9008,Gy=-1.0076,Gz=-1.3893
dev=D2,Ax=-0.9985,Ay=0.0576,Az=0.8252,Gx=-0.1221,Gy=-0.7252,Gz=0.8702

Solved. The problem was a bad board & then appending extra "\n" in the output after reading from via "C".

Really apprecaite the community support.

Best Answer

This should work (I did this on the RP4 just 2 days ago at the same baudrate and an STM32F405 and it worked fine after a 'gotcha') these are some things to check:

  1. Make sure you have a ground between boards (TX and RX is not enough)

  2. Check the TX voltage level of the output (with an oscilloscope or logic analyzer) and make sure it's 3.3V for the Pi (which it should be coming from the STM32F407G, but you never know sometimes ports get blown out.

  3. Check the clock rate on the STM32F, I don't have my code with me but I do know there was a problem with one of the clocks that generated the baud rate wrong (there was a multiplier somewhere in the HAL code that was supposed to be 8Mhz higher and was generating an incorrect baud rate (the baud rate was 8x lower, if I remember right). (this is also why it's good to check the baud rate with a scope or logic analyzer). I'll find the error when I get a chance and update.

Also Minicom is not a good way to check sometimes because it will auto adjust the baud rate, whatever COM program you use, make sure you force the baud rate to a fixed known value.

Related Topic