9 months, 1 week ago.

Behavior of Serial pc.readable() on NUCLEO-F446RE

I don’t know if it’s a fault or a feature on NUCLEO-F446RE, but I’m intrigued with the behavior of pc.readable() of Serial API, because it returns true only if one and only one byte was received and it returns false if more than one byte was received.

Other boards behave differently, with pc.readable() returning true if one or more bytes were received.

For example,

#include "mbed.h"
Serial pc(USBTX, USBRX);

int main()
{
    while(1) {
        if(pc.readable()) {
            pc.getc();
            pc.printf("Data received\r\n");
        }
        wait(0.5);
    }
}

On NUCLEO-F446RE, the previous code prints “Data received” if one and only one byte was received on serial port. It prints nothing if two or more bytes were received on serial port (except if I remove the wait(0.5), thus syncing readable() with bytes reception).

In contrast, on NUCLEO-L4R5ZI and FRDM-KL25Z, the same code prints “Data received” if one or more bytes were received, which is a more advantageous behavior.

I can get around using callbacks, but is this the expected behavior?

Another question, is there a function to return number of bytes available to read on serial buffer?

Thank you.

Question relating to:

Affordable and flexible platform to ease prototyping using a STM32F446RET6 microcontroller.
Comment on this question

3 Answers

9 months, 1 week ago.

Hello Fabio,

  • I think this is an intended behavior. The NUCLEO-F446RE does not have a serial Rx buffer (in contrary to NUCLEO-L4R5ZI, FRDM-KL25Z and others) so when the first received byte is overwritten by the following one without a read from the data register this prevents working with corrupted data. To handle such situations try to setup an Rx buffer in your code to store the whole packet. For example:

#include "mbed.h"
Serial  pc(USBTX, USBRX);
char    rxBuf[64];
int     i = 0;

int main()
{
    while (1) {
        i = 0;
        while (pc.readable())
            rxBuf[i++] = pc.getc();
        if (i > 0) {
            pc.printf("Data received\r\n");
            if (i < 64) {
                // process the data received
                pc.printf("Data processed\r\n");
            }
            else
                pc.printf("Error: Receive buffer overrun\r\n)");
        }
        wait(0.5);
    }
}
  • I'm afraid there is no such built-in function available. But if you setup your own Rx buffer (as in the example above) then you'll know the number of bytes received.

Hello Zoltan,

Thanks for the answer.

Unfortunately, this code doesn’t work either for the same reason. But, your solution inside RX serial interrupt works well:

#include "mbed.h"
RawSerial pc(USBTX, USBRX);
char      rxBuf[64];
int       i = 0;

void pc_recv()
{
    rxBuf[i++] = pc.getc();
}

int main()
{
    pc.attach(&pc_recv, Serial::RxIrq);

    while (1) {
        if (i > 0) {
            pc.printf("Data received\r\n");
            if (i < 64) {
                // Process the data received
                pc.printf("Data processed\r\n");
            } else
                pc.printf("Error: Receive buffer overrun\r\n");
                
            i = 0;
        }
        
        wait(0.5);
    }
}

My goal was to find if this pc.readable() behavior is intended or if it is a bug…

posted by Fabio Faria 08 Mar 2019
9 months, 1 week ago.

Great thought you had shared here. In my experiences I even have forever used variable length packets with indicators for begin and end like brackets. In some ways in which this can be comforting to grasp others have seen my issue... but you probably did not say you found a solutions in order that additionally makes American state worry. Dissertation writing services

9 months, 1 week ago.

While polling for characters in a loop like this any calls to printf are going to mess up your timing. It's easy to imagine more characters arriving as you sit there printing out 20 or 30 characters.

Serial transmissions usually have some notion of data frames. If you are sending data as strings (which is often the easiest way) you can use a newline to indicate the end of the frame. Then you can sit in the while loop like Zoltan suggests, filling your buffer and checking for newline. When newline is received you break the loop and process the data frame. You can also enforce a request/response protocol on both ends, so after the pc sends a request string it waits for a response rather than continuing to throw more requests at the micro.

As you mention, receiving characters via interrupt is usually the best way to do this since you can handle it immediately. Class RawSerial seems to be the right choice here as regular Serial has issues with mutexes inside ISR last time I checked.