Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.arch.embedded > #30658
| From | pozz <pozzugno@gmail.com> |
|---|---|
| Newsgroups | comp.arch.embedded |
| Subject | Embedded linux serial port |
| Date | 2021-05-26 13:53 +0200 |
| Organization | A noiseless patient Spider |
| Message-ID | <s8lcsm$56b$1@dont-email.me> (permalink) |
I used a simple driver for serial port in Linux with success in many
projects, but recently I found an issue with it.
The scenario is an embedded Linux (running on iMX6) that runs a QT
application (that creates a GUI on a touch display) and a C application
that communicates over a serial port.
When QT application starts some complex graphics (I see its CPU load
reaching 70-80%), the serial port application stops working correctly.
After some debugging, I noticed that the bytes really transmitted on the
wire aren't correct. It seems one or two bytes are re-transmitted and
one-two bytes aren't completely transmitted.
I suspect my serial port driver has some errors that are triggered only
when the CPU is loaded by other processes, but I don't know how to fix them.
I use O_NONBLOCK flag when opening serial port, but write() always
returns a positive number, so I think the byte is correctly moved to the
low-level serial port driver and really transmitted... but it isn't
always the case.
If I enable debugging messagin (with DEBUG_SERIAL macro), I always see
correct data on stdout, but wrong data on the wire.
Any hint?
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <time.h>
#include "serial.h"
//#define DEBUG_SERIAL
#ifdef DEBUG_SERIAL
static bool debug_tx;
#endif
SERIAL_HANDLE
serial_open(const char *serial_name, int baudrate)
{
if (serial_name == NULL) return INVALID_SERIAL_HANDLE_VALUE;
speed_t speed;
if (baudrate == 57600)
{
speed = B57600;
}
else if (baudrate == 115200)
{
speed = B115200;
}
else
{
return INVALID_SERIAL_HANDLE_VALUE;
}
int hSerial;
hSerial = open(serial_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (hSerial != -1)
{
int oldflags = fcntl (hSerial, F_GETFL, 0);
if (oldflags == -1) return -1;
oldflags &= ~O_NONBLOCK;
if (fcntl(hSerial, F_SETFL, oldflags) == -1)
{
return INVALID_SERIAL_HANDLE_VALUE;
}
struct termios options;
tcgetattr(hSerial, &options);
cfsetispeed(&options, speed);
cfsetospeed(&options, speed);
/* Input mode flags */
options.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF |
IXON | INPCK );
options.c_iflag |= IGNBRK;
/* Output mode flags */
options.c_oflag &= ~OPOST;
/* Control mode flags */
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~( CSTOPB | PARENB);
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
/* Local mode flags */
options.c_lflag &= ~(ICANON | ECHO | ISIG);
options.c_lflag = NOFLSH;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 1;
tcsetattr(hSerial, TCSANOW, &options);
#ifdef DEBUG_SERIAL
debug_tx = 1;
printf("-> ");
#endif
}
return (SERIAL_HANDLE)hSerial;
}
void
serial_close(SERIAL_HANDLE hSerial)
{
close(hSerial);
}
int
serial_getdata(SERIAL_HANDLE hSerial, void *data, size_t data_len,
unsigned int timeout_sec)
{
size_t bytes_read = 0;
uint8_t *d = data;
time_t t_begin = time(NULL);
while(bytes_read != data_len)
{
if ((timeout_sec > 0) && (time(NULL) - t_begin > timeout_sec)) {
break;
}
int ret;
ret = read(hSerial, d, data_len - bytes_read);
if (ret < 0) return -1; // Error
if (ret > 0) {
#ifdef DEBUG_SERIAL
if (debug_tx) {
printf("\n<- ");
fflush(stdout);
debug_tx = 0;
}
for (unsigned int i = 0; i < ret; i++) {
printf("%02X", ((unsigned char * ) d)[i]);
fflush(stdout);
}
#endif
d += ret;
bytes_read += ret;
}
}
return bytes_read;
}
int
serial_putchar(SERIAL_HANDLE hSerial, unsigned char c)
{
#ifdef DEBUG_SERIAL
if (!debug_tx) {
printf("\n-> ");
debug_tx = 1;
}
printf("%02X", c);
#endif
int bytes_written;
bytes_written = write(hSerial, &c, 1);
if (bytes_written != 1) return -1;
return 0;
}
int
serial_putdata(SERIAL_HANDLE hSerial, const void *data, size_t size)
{
const unsigned char *d = data;
while(size--) {
int ret;
ret = serial_putchar(hSerial, *d++);
if (ret < 0) return -1;
}
return 0;
}
int
serial_putstr(SERIAL_HANDLE hSerial, const char *s)
{
if (s == NULL) return -1;
return serial_putdata(hSerial, s, strlen(s));
}
#endif
Back to comp.arch.embedded | Previous | Next — Next in thread | Find similar | Unroll thread
Embedded linux serial port pozz <pozzugno@gmail.com> - 2021-05-26 13:53 +0200 Re: Embedded linux serial port Johann Klammer <klammerj@NOSPAM.a1.net> - 2021-05-26 23:52 +0200
csiph-web