'Uncommon baud rate on serial port - Linux
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");
};
Solution 1:[1]
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.
Solution 2:[2]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Ole-Egil Hvitmyren |