2 years, 5 months ago.

UART missing values being sent over serial

I am sending a list of values over serial terminal program to my Nucleo F401RE. But it only picks up every alternate value. Can someone point out what might be the reason for this.

Serial Transfer

#include "mbed.h"
#define SAMPLE_SIZE (5)
 
Serial pc(USBTX, USBRX);
DigitalOut led(LED1);

float received_value[SAMPLE_SIZE];
volatile static int index = 0;
char buffer[15];
volatile int counter = 0;
volatile int read_complete = 0;


void read_data() 
{
    char c;
    float temp_val;
    while(pc.readable())
    {
        c = pc.getc();
        buffer[index++] = c;
        if(c == '\n' || c == '\r')
        {
            buffer[index - 1] = '\0';
            //temp_val = atof(buffer);
            sscanf(buffer, "%f", &temp_val);
            if(counter < SAMPLE_SIZE)
            {
                received_value[counter] = temp_val;
                counter++;
                pc.printf("\n\r%f",temp_val);
            }
            else
            {
                read_complete = 1;
            }
            index = 0;
        }
    }
}

int main() 
{
    pc.baud(9600);
    pc.attach(read_data, Serial::RxIrq);
    while (read_complete == 0) 
    {
        led=1;
        wait_ms(200);
        
    }
    printf("\n\rDone");
    for(int i = 0; i<1000;i++)
    {
        printf("\n\rIn loop");
        pc.printf("\n\r %f",received_value[i]);   
    }
}

2 Answers

2 years, 5 months ago.

You can't guarantee operation when you put printf inside of an ISR. Rethink your code to capture the Rx data to a buffer only and then process the buffer as it reaches a certain value. You need to use a circular buffer or dual buffer typically to prevent overflow....

2 years, 5 months ago.

Immediate observation is that you are trying to do too much inside the ISR. Get in and get out ASAP. Any work that needs to be done, do it later. If a second character arrives while you are in ISR you will miss it and your program may crash.

Also mutexes are not allowed inside mbed-os ISR, so you should not call printf. A printf at 9600 baud is also super slow.

Also once read_complete equals true you are exiting your main function. You should never exit main.

This works for me. Doesn’t handle condition when received string overflows buffer. And available flag is only polled every 1ms which means you need to leave a gap between sending floats to allow them to be processed.

#include "mbed.h"
#define SAMPLE_SIZE (5)
 
Serial pc(USBTX, USBRX);
 
float received_value[SAMPLE_SIZE];
volatile int index = 0;
char buffer[15];
volatile bool available = false;
 
void read_data() 
{
    char c;
    while(pc.readable())
    {
        c = pc.getc();
       
        buffer[index] = c;
        index ++;
        if(c == '\n' || c== '\r')
        {
            buffer[index] = '\0';
            available = true;
            index = 0;         
        }     
    }
}
 
int main() 
{
    pc.baud(9600);
    pc.attach(read_data);
    
    float temp;
    
    while(true) {
        while (available == false) {
            wait_ms(1);            
        }
        available = false;
        printf("Available\n");
        
        sscanf(buffer, "%f", &temp);
        pc.printf("%.3f\n",temp);
    }     
}