3
\$\begingroup\$

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.

\$\endgroup\$
22
  • \$\begingroup\$ might be an encoding issue \$\endgroup\$ Feb 13, 2021 at 1:44
  • \$\begingroup\$ @EdwinFairchild, please be kind enough to expand? How does TeraTerm or Putty automatically convert & display? Im sending over characters and not raw bytes. \$\endgroup\$
    – cyber101
    Feb 13, 2021 at 1:48
  • \$\begingroup\$ Maybe the clocks of the two devices are too imprecise relative to each other. Try a slower baud rate and if that works then you may need more precise clock sources. \$\endgroup\$
    – kkrambo
    Feb 13, 2021 at 2:35
  • 1
    \$\begingroup\$ Not sure this line is correct: "HAL_UART_Transmit(huart, (uint8_t*) str, sizeof(str), 1000);" sizeof(str) will always be the length of the array. I think you would be better of using strlen(str) instead of sizeof(str). Also you would be better off using snprintf() instead of sprintf(). Just to make sure you don't overrun your buffer. \$\endgroup\$
    – mkeith
    Feb 13, 2021 at 4:28
  • 1
    \$\begingroup\$ Hi. Have you tried the script for the loopback test at the end of the blog? you should connect a wire from RX to TX on the RPi and test that script or minicom. If you still get garbage on the loopback test I don't know what to tell you other than changing the power supply on the Pi for another one less noisy and/or more powerful. If that does not work either then I think you might need a new board. But I would be very surprised to see a serial port go bad like that, I've tested and tortured many boards; sometimes some things really break down completely... Do you have a spare board to try? \$\endgroup\$
    – Marcos G.
    Apr 3, 2021 at 7:13

1 Answer 1

1
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ appreciate the input all the things you mentioned I had already tried in the original post. I have already posted the solution. The problem as 1) faulty Pi UART 2) small bug in the C's console print logic. \$\endgroup\$
    – cyber101
    Apr 6, 2021 at 3:07
  • \$\begingroup\$ 1) The definitive answer was MarcosG's loopback test that identified a faulty UART on my Pi. When Swiped my Pi with another Pi everything worked. Another smaller issue was extra "\n" in C's console output. However, I still appreciate the wisdom. Any thoughts on how STM to Pi communication over UART may go wrong in the production system (mission-critical) application? Strictly focusing on the UART aspect. \$\endgroup\$
    – cyber101
    Apr 6, 2021 at 3:13
  • \$\begingroup\$ minicom...will auto adjust the baud rate...; are you sure you are not confusing it with something else? The one I have does not have any auto baud rate detection. \$\endgroup\$
    – Marcos G.
    Apr 11, 2021 at 6:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.