5 years, 3 months ago.

serial getc() not working properly

Hi, I just ran into a very frustrating problem, I am not able to simply get a character from one serial port and send it out to another with some modifications.

example:

this works!

#include <mbed.h>
Serial pc(USBTX, USBRX, 9600);    // tx, rx
Serial device(PA_9, PA_10, 9600); // tx, rx
int main() {

  

  while(1) {
    while(device.readable())
    {
      const char x = device.getc();
     // pc.putc('['); <--
      pc.putc(x);
      //pc.putc(']');<--
    }
  }
}

when i run this code, I get the expected output: ..RING.. (input was "\r\nRING\r\n" ) now, if i uncomment the two marked lines, one would expect following; [][][R][I][N][G][][] BUT instead i get following: [][][R][G]

adding to that, if only uncomment the open bracket, I get something like: [[[R[I[G[

If have run out of ideas now. I tried compiling with MBED online compiler and gnu++, same result. chip is a Nucleo L432KC. It is easily reproducable.

1 Answer

5 years, 3 months ago.

Hello Jonas,

When the two lines are uncommented the program spends more time transmitting data than receiving. However, the external device keeps sending new data to the program. That could result in data loss. Try to increase the transmission bitrate in your program. For example:

//...
Serial device(PA_9, PA_10, 9600); 
Serial pc(USBTX, USBRX, 115200);
//...

If the external device is sending data in packets and there is enough time between two packets to send it (+ the modifications) to the pc then you can try to setup a buffer and transmit after a complete packet has been received. For example:

#include <mbed.h>

#define MAX_LEN  512

char   buf[MAX_LEN];
Serial pc(USBTX, USBRX, 9600);    // tx, rx
Serial device(PA_9, PA_10, 9600); // tx, rx

int main() {

    while (1) {
        int     i = 0;

        while (device.readable()) {
            if (i < MAX_LEN)
                buf[i++] = device.getc();
        }

        while (i > 0) {
            pc.putc('[');
            pc.putc(buf[--i]);
            pc.putc(']');
        }
    }

}

One other solution that's probably not practical - Use a processor with a buffers on the UART.

The STM32L432KC that you are using only has a single byte buffer in each direction. If you don't read the UART before the next byte is received then you will lose data.

So your code reads a byte, transmits a byte ([), puts a second byte into the transmit buffer and then has to wait for the first byte to finish before it can put the 3rd (]) into the transmit buffer. Only then can it read the next byte from the receive buffer. It then has to wait for space in the transmit buffer to start sending that second set of 3 bytes.

Some processors include buffers on the transmit and receive for the UARTs, typically 16 bytes but there is some variation. This gives a massive speed up when sending messages that are under the transmit buffer size since (assuming the buffer has space left) the processor can put the whole message in the buffer without waiting. The hardware then handles sending it out as fast as possible. Similarly a buffer on the receive means that multiple bytes can queue up waiting to be read by the processor, as long as the buffer doesn't get full no data is lost.

Which processors have these buffers normally takes some digging to find out, it looks like few STM parts include them while a lot of the LPC family do.

Alternatively you can use software triggered off the serial port transmit and receive interrupts to emulate this behavior in software. The software queues up the receive and transmit data in the background. This adds software complexity and depending on the buffer size can eat up a fair amount of RAM but helps in situations like yours. Searching for buffered serial on this site gives a lot of libraries and examples of how to do this.

posted by Andy A 08 Jan 2019