8 years, 6 months ago.

Using multiple BufferedSerial on Nucleo F091RC

Hello,

I have a problem using multiple BufferedSerial on the USARTs of NUCLEO F091RC. I picked this board because it has 8 USARTs. The PC is used for debug via USB. USART4 and USART5 are connected to a sensor that sends data every 10 seconds (82 bytes each sensor). USART8 is connected to a communication device.

To be specific when more than one USART is receiving data the program stop running (freeze).

If I comment one of the sensors the code works fine. If I use the Buffered Library only in one USART (per example only in USART4) the code works but I'm not capable to receive all the 82 bytes in the normal (non Buffered) Serial USART.

Main.cpp

#include "mbed.h"
#include "BufferedSerial.h"
#include "custom_f.h"

Serial pc(USBTX, USBRX);
BufferedSerial sensor1(PC_10, PC_11);
BufferedSerial sensor2(PC_12, PD_2);  
Serial comDevice(PC_8, PC_9); // Not used yet 
DigitalOut myled(LED1);

int main()
{
    pc.baud(9600);
    sensor1.baud(19200);
    sensor2.baud(19200);
    comDevice.baud(115200);

while(1) {

            if (sensor1.readable()) {
            pc.printf("SENSOR1: ");
            while(sensor1.readable()) {
                char incoming = sensor1.getc();
                pc.putc(incoming);
            }
            pc.printf("\r\n");
        }
        myled = !myled;
        wait_ms(500);


        if (sensor2.readable()) {
            pc.printf("SENSOR2: ");
            while(sensor2.readable()) {
                char incoming = sensor2.getc();
                pc.putc(incoming);
            }
            pc.printf("\r\n");
        }
        myled = !myled;
        wait_ms(500);
}
}

NOTE: To simplify the debugging process, I'm not using the real function that process the data sent by the sensor. The previous code work, is a simplified version for debug. This version freeze in the same way than the complex function, I mean when more than one USART receive data; eventually the LED1 stop "blinking" and the PC USB stop showing new data.

Can you please help ?

Thank you !

2 Answers

8 years, 6 months ago.

Hello Felícito,
Since you are receiving constant size (82 bytes) packets every ten seconds, another alternative is to use your own buffers:

#include "mbed.h"

const int   PACKET_SIZE = 82;       // Data packet size
const float RX_MAXTIME  = 3.0f;     // Maximum time gap between two serial bytes
                                    // (must be < time gap between two packets)
char sensor1RxBuf[PACKET_SIZE];
char sensor2RxBuf[PACKET_SIZE];

volatile int sensor1RxLen = 0;
volatile int sensor2RxLen = 0;

Serial      pc(USBTX, USBRX);
Serial      sensor1(PC_10, PC_11);
Serial      sensor2(PC_12, PD_2);
Serial      comDevice(PC_8, PC_9); // Not used yet
DigitalOut  myled(LED1);
Timer       rx1Timer;
Timer       rx2Timer;


// Sensor1 serial received interrupt handler: Reads data into a buffer
void onSensor1Rx(void)
{
    if(sensor1RxLen < PACKET_SIZE) {
        sensor1RxBuf[sensor1RxLen++] = sensor1.getc();
        rx1Timer.reset();
    }
    else
        sensor1.getc();
}

// Sensor2 serial received interrupt handler: Reads data into a buffer
void onSensor2Rx(void)
{
    if(sensor2RxLen < PACKET_SIZE) {
        sensor2RxBuf[sensor2RxLen++] = sensor2.getc();
        rx2Timer.reset();
    }
    else
        sensor2.getc();
}

int main()
{
    pc.baud(9600);
    sensor1.baud(19200);
    sensor2.baud(19200);
    comDevice.baud(115200);

    sensor1.attach(&onSensor1Rx);
    sensor2.attach(&onSensor2Rx);
    
    rx1Timer.start();
    rx2Timer.start();

    while(1) {
        // Discard incomplete/corrupted packets
        if (rx1Timer.read() > RX_MAXTIME)
            sensor1RxLen = 0;
            
        if (rx2Timer.read() > RX_MAXTIME)
            sensor2RxLen = 0;
            
        //  Process complete packets            
        if (sensor1RxLen == PACKET_SIZE) {
            sensor1RxLen = 0;
            pc.printf("SENSOR1: ");
            for(int i = 0; i < PACKET_SIZE; i++)
                pc.printf(" %x", sensor1RxBuf[i]);
            pc.printf("\r\n");
         }

        if (sensor2RxLen == PACKET_SIZE) {
            sensor2RxLen = 0;
            pc.printf("SENSOR2: ");
            for(int i = 0; i < PACKET_SIZE; i++)
                pc.printf(" %x", sensor2RxBuf[i]);
            pc.printf("\r\n");
        }
        myled = !myled;
        wait_ms(500);
    }
}

Accepted Answer

Thank you Zoltan for your code, it is really interesting. I will read it and study it, to completely understand it and how to deal with interrupts.

Best regards. :)

posted by Felícito Manzano 01 Jun 2016
8 years, 6 months ago.

For a start increase the baud rate on the pc connection and take out the waits.

Each time around your loop takes about 1.15 seconds (1s of waits plus the time it takes to send 2x 84 bytes at 9600 baud from a uart with a 16 byte tx buffer.) If you sensors are sending data at 1Hz then you aren't going to keep up with them.

There is no reason at all to have those waits in there.

For every 82 bytes that show up on a sensor you are outputting 84 bytes to the PC. Since you have two sensors that means that you should set the PC uart baud rate to at a very minimum twice the sensor baud rate, ideally faster.

Thanks for your reply Andy.

I have tried changing the pc baudrate to 38400. But it does not work, the program keep freezing when both USART receive data from the sensor1 and sensor2.I kept digging and found this table. Link: http://www.st.com/content/ccc/resource/technical/document/datasheet/95/3c/2e/5b/21/09/45/a6/DM00115237.pdf/files/DM00115237.pdf/jcr:content/translations/en.DM00115237.pdf

Table 10. STM32F091xB/xC USART implementation:

USART modes/featuresUSART1, 2, 3USART 4USART 5, 6, 7, 8
Hardware flow control for modemXX-
Continuous communication using DMAXXX
Multiprocessor communicationXXX
Synchronous modeXXX
Smartcard modeX--
Single-wire half-duplex communicationXXX
IrDA SIR ENDEC blockX--
LIN modeX--
Dual clock domain and wakeup from Stop modeX--
Receiver timeout interruptX--
Modbus communicationX--
Auto baud rate detectionX--
Driver EnableXXX

Where: X mean supported.

I kept the pc baudrate in 38400; but move the sensor1 to USART1 and sensor2 to USART3 (by factory the USART2 is the PC, could be change moving some jumpers in the board); keep using BufferedSerial and everything work fine :) . Also modify the wait_ms - this to gave time for the buffer to be polled, not so sure... but this allow that the entery 82 bytes recived get in a single char array.

The new code is this one:

include the mbed library with this snippet

#include "mbed.h"
#include "BufferedSerial.h"

// all these are optional
const int   BUFF_SIZE = 64; 
const int   TX_MULTIP = 8;
const char*  SEN1 = "S1";
const char*  SEN2 = "S2";

Serial pc(USBTX, USBRX); // USART2
BufferedSerial fuelR1(PA_9, PA_10, BUFF_SIZE, TX_MULTIP, SEN2);  // USART1
BufferedSerial fuelR2(PB_10, PB_11, BUFF_SIZE, TX_MULTIP, SEN2);   // USART3
DigitalOut myled(LED1);

int main()
{
    pc.baud(38400);
    fuelR1.baud(19200);
    fuelR2.baud(19200);

    while(1) {
      
        if (fuelR1.readable()) {
            wait_ms(10);
            pc.printf("SENSOR1: ");
            while(fuelR1.readable()) {
                char incoming = fuelR1.getc();
                pc.putc(incoming);
            }
            pc.printf("\r\n");
        }


        if (fuelR2.readable()) {
            wait_ms(10);
            pc.printf("SENSOR2: ");
            while(fuelR2.readable()) {
                char incoming = fuelR2.getc();
                pc.putc(incoming);
            }
            pc.printf("\r\n");
        }
        myled = !myled;
        wait_ms(10);
    }
}

At my point of view (read: guessing), the Issue could be that the USART4, 5, 6, 7, 8 does not support Timeout Interrupt. It would be great to have another point of view to confirm.

Best regards.

posted by Felícito Manzano 01 Jun 2016