0
votes

I'm currently trying to make a programm to read a serial port. On this port I receive data with a baud rate of 875000. It's really uncommon and I don't succeed to modified it. I've make a little C programm to do that but it didn't work with 875000... Here some part of the code with the programmation of the serial port :

    #include <stdio.h>
    #include <stdlib.h>
    #include <asm/termios.h>
    #include <sys/fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include "test.h"

    void read_Serial_Port(const char* DEVICE_PORT)
    {
        int file;
        struct ktermios options;
        unsigned int nCountMax = 60;
        bool b;

        file = open(DEVICE_PORT, O_RDONLY | O_NOCTTY | O_NDELAY);

        if(file == -1){perror("Unable to open the serial port\n");}
        //printf("Serial port open successful !\n");
        int speed = atoi("875000");

        ioctl(file, TCGETS2, &options);     


        options.c_ispeed = speed;
        options.c_ospeed = speed;

        options.c_cflag |= (CLOCAL | CREAD);              
        options.c_cflag |= PARENB;                  
        options.c_cflag |= PARODD; 
        options.c_cflag &= ~CBAUD;

        options.c_cflag |= BOTHER;                                          
        options.c_cflag &= ~CSIZE;                      
        options.c_cflag |= CS8;     

        ioctl(file, TCSETS2, &options); 


        //printf("Reading serial port ...\n\n"); 
        b = readMessage(file, nCountMax);

        if (b == 0){printf("Error while reading serial port\n");}
        //else printf("\nSerial port read successful\n");

        close(file);
        //printf("Serial port closed\n");
    };
2
Have you checked that the UART hardware in your PC even supports that baudrate? Otherwise it is mission impossible.Lundin
I think that if you set your receiver's baudrate to the next higher baudrate and assuming the same modulation technique (and manchester encoding) is used, the receiver will be able to receive the lower baudrate due to the self-clocking nature of the Manchester encoding (see en.wikipedia.org/wiki/Self-clocking_signal and stackoverflow.com/questions/25834577/…)Paul Ogilvie
I've tried with a baudrate of 921600 and it didn't work properly... I think this baudrate is just a crazy thing !Landry Leblanc
@PaulOgilvie Plain old UART is neither Manchester encoded nor self-clocking. The baud rate setting must match (to within some margin of error, say 3%) on both ends.unwind
What was the result with options.c_ispeed = options.c_ospeed = 875000; instead of int speed = atoi("115200"); ...chux - Reinstate Monica

2 Answers

0
votes

Unfortunately, for custom baudrates, you sometimes need custom hardware, or at least custom driver. The standard baudrates handled by Linux are VERY limited, but a modern UART can typically reach many more due to the fact that the baud rate generators are clocked at much higher frequencies than 30-40 years ago, in addition to often supporting fractional dividers. An example: https://assets.maxlinear.com/web/documents/xr17v358.pdf

It can use 125MHz or 62.5MHz as reference, and at 125MHz, a baudrate of 875000 would need a divider of 8 and 15/16ths. To get there, you must use a custom exar_serial driver instead of the usual Linux serial subsystem.

On older hardware, it was common to find a different crystal to get the frequency you wanted, and even having variable or selectable oscillators was often used.

-1
votes

Finally i've found another topic on stackoverflow wich is complete and solve my problem : How to set baud rate to 307200 on Linux?

Here is my code with the modification :

static int rate_to_constant(int baudrate) {
#define B(x) case x: return B##x
switch(baudrate) {
    B(50);     B(75);     B(110);    B(134);    B(150);
    B(200);    B(300);    B(600);    B(1200);   B(1800);
    B(2400);   B(4800);   B(9600);   B(19200);  B(38400);
    B(57600);  B(115200); B(230400); B(460800); B(500000); 
    B(576000); B(921600); B(1000000);B(1152000);B(1500000);
    B(2000000);B(2500000);B(3000000);B(3500000);B(4000000); 
default: return 0;
}
#undef B
}    


int Custom_Baudrate(const char* Device, int rate)
  {

/*Declaration of all the variables needed*/
struct termios2 options;
struct serial_struct serinfo;
int file=-1;
int speed = 0;
int r=rate;



/* Open and configure serial port */
file = open(Device,O_RDWR|O_NOCTTY);

if(file==-1){printf("\nERROR : Unable to open the serial port\n\n");return 1;}

speed = rate_to_constant(r);



/*Find best Baudrate*/
if (speed == 0) {

    /* Custom divisor */
    serinfo.reserved_char[0] = 0;
    if (ioctl(file, TIOCGSERIAL, &serinfo) < 0) file=-1;
    serinfo.flags &= ~ASYNC_SPD_MASK;
    serinfo.flags |= ASYNC_SPD_CUST;

    serinfo.custom_divisor = ((serinfo.baud_base + (r / 2)) / r);

    if (serinfo.custom_divisor < 1) 
        serinfo.custom_divisor = 1;
    if (ioctl(file, TIOCSSERIAL, &serinfo) < 0) file=-1;
    if (ioctl(file, TIOCGSERIAL, &serinfo) < 0) file=-1;
    if (serinfo.custom_divisor * r != serinfo.baud_base) {
        warnx("actual baudrate is %d / %d = %f",
              serinfo.baud_base, serinfo.custom_divisor,
              (float)
              serinfo.baud_base / serinfo.custom_divisor);
    }
}



/*Set the best Baudrate (if desired baudrate is unvailable, it's set automatically at 38400)*/
fcntl(file, F_SETFL, 0);
tcgetattr(file, &options);
cfsetispeed(&options, speed ?: B38400);
cfsetospeed(&options, speed ?: B38400);
cfmakeraw(&options);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CRTSCTS;
if (tcsetattr(file, TCSANOW, &options) != 0) file=-1;


/*Read the serial port*/
communicate_Serial_Port(file);

close(file);
return 1;
}

In this code you just have to precise wich baudrate you want and it find the nearest value that you can use. This value is based on the "base baudrate" of your device and it search a divisor to set the best baudrate. However, some baudrate should always being unavailable so this program will put the 38400 as a base (it's a choice). I've test it with several baudrate and it always work.

I'm new on stackoverflow, i hope this post will complete correctly the question.