gpt4 book ai didi

c - 嵌入式 Linux : Reading bytes from serial port too slow for quicker transfer

转载 作者:太空宇宙 更新时间:2023-11-04 10:08:04 29 4
gpt4 key购买 nike

我有一个微 Controller 和一个嵌入式 PC。这两个通过串行连接进行通信,并且都在相互接收和发送数据。两者之间的波特率为38400。微 Controller 和PC具有相同的配置以确保通信(8个数据位,1个停止位,偶校验)。

在微 Controller 开始大约每 10 毫秒发送一次消息之前,通信工作正常。此时,微 Controller 的发送队列已满并溢出。然后他向 PC 发送一条错误消息(这就是我所知道的,微 Controller 的发送队列超限,而不是 PC 的发送队列。

在嵌入式 Linux 版本的 PC 程序之前,微 Controller 可以使用 DOS 版本的 PC 程序运行而不会导致错误。在 DOS 中,单个字节直接从串行端口读取和写入(没有像 Linux 中那样的内核缓冲区)由于大多数 C 代码都可以移植到 Linux,所以我尝试在 Linux 中复制串行端口读取和写入的 DOS 行为以保持其余部分处理这些单个字节。

我在PC上打开并初始化串口如下。

fd_mc = open("/dev/ttyS1", O_NOCTTY | O_RDWR /*| O_NONBLOCK*/ /*| O_SYNC*/);
if(fd_mc == -1)
{
perror("Could not open µc port.");
}
else
{
struct termios tty;
memset(&tty, 0, sizeof(tty));
if ( tcgetattr ( fd_mc, &tty ) != 0 )
{
perror("Error getting termios attributes");
}
cfsetospeed (&tty, B38400);
cfsetispeed (&tty, B38400);
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //raw input
tty.c_oflag &= ~OPOST; //raw output

tty.c_cflag |= PARENB; //even parity
tty.c_cflag &= ~PARODD;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;

tty.c_cflag |= (CLOCAL | CREAD);

tcsetattr(fd_mc, TCSANOW, &tty);
}

上面的代码是一个函数的片段,它初始化了两个串行端口(其中一个是微 Controller 的一个)。

编辑:这里是流量控制的设置,没有。

tty.c_cflag &= ~CRTSCTS;                            //No hardware based flow control
tty.i_cflag &= ~(IXON | IXOFF | IXANY); //no software based flow control

在环形缓冲区和 pollin 的帮助下,从串行端口读取发生在线程内。该线程在主循环中被调用。代码如下:

void *thread_read()
{

struct sched_param param;
param.sched_priority = 97;
int ret_par = 0;
ret_par = sched_setscheduler(3, SCHED_FIFO, &param);
if (ret_par == -1) {
perror("sched_setscheduler");
return 0;
}

struct pollfd poll_fd[2];
int ret;
extern struct fifo mc_fifo, serial_fifo;
ssize_t t;
char c;

poll_fd[0].fd = fd_mc;
poll_fd[0].events = POLLIN;

poll_fd[1].fd = fd_serial;
poll_fd[1].events = POLLIN;

while(1) {
ret = poll(poll_fd, 2, 10000);

if(ret == -1) {
perror("poll");
}

if(poll_fd[0].revents & POLLIN) {
t = read(fd_mc, &c, 1);
if(t>0) {
fifo_in(&mc_fifo, c);
}
}
if(poll_fd[1].revents & POLLIN) {
t = read(fd_serial, &c, 1);
if(t>0) {
fifo_in(&serial_fifo, c);
}
}
}
pthread_exit(NULL);
}

在主循环中调用。

pthread_t read;
pthread_create(&read, NULL, thread_read, NULL);

写入缓冲区(fifo_in)的函数是

int fifo_in(struct fifo *f, char data) 
{
if( (f->write + 1 == f->read) || (f->read == 0 && f->write + 1 == FIFO_SIZE) ) //checks if write one before read or at the end
{
printf("fifo in overflow\n");
return 0; //fifo full
}
else {
f->data[f->write] = data;
f->write++;
// printf("Byte in: Containing %4d\tData:\t%4d\n", BytesInReceiveBuffer(1), data); //Bytes contained in fifo of mc
if(f->write >= FIFO_SIZE) {
f->write = 0;
}
return 1; //success
}
}

这个函数基本上做的是检查读取和写入的位置,如果两个位置不重叠且大于+1,则将data写入缓冲区> 彼此远离。

当另一个函数需要环形缓冲区中的字节时,它调用 GetByte 从环形缓冲区中读取字节。

获取字节

int GetByte(int port)
{
char c;

switch(port) {
case 0: //COM1
fifo_out(&serial_fifo,&c);
break;
case 1: //COM2
fifo_out(&mc_fifo,&c);
break;
}
return (int)c;
}

fifo_out

int fifo_out(struct fifo *f, char *data) {
if(f->read == f->write) {
printf("fifo in overfwrite\n");
*data = 0;
return 0;
}
else {
*data = f->data[f->read];
f->read++;
// printf("Byte out: Containing %4d\tData:\t%4d\n", BytesInReceiveBuffer(1), *data);
if(f->read >= FIFO_SIZE) {
f->read = 0;
}
return 1;
}
}

在 Linux 移植之前,DOS 版本中的一切都是顺序的。

吃了那一刻,我最好的猜测是,read() 会减慢速度,并且在某个时候开始减慢缓冲区的读取速度,这再次阻止了线程的调用。也许我错了。目前我有点不知道这个错误到底是什么,甚至不知道如何解决这个问题。

感谢每一个好的建议。

最佳答案

您确定在应用程序中需要 fifo 吗?您的串行驱动程序很可能已经在内核中有相当大的缓冲区(通常是一页,通常为 4kB)。如果这就足够了,您可以通过让 GetByte 对串行设备执行非阻塞读取来从根本上简化实现。

如果您想坚持这种设计,请考虑修改您的读取循环以一次读取多个字节。现在,您需要为每个字节读取两次系统调用。

您总是在更改 PID 3 的调度类。这可能不是您想要的。此外,这仅意味着您的线程将在字节到达内核内部缓冲区后运行(即当 poll 返回时)。如果通过在工作队列上运行作业将字节从硬件 ​​FIFO 传输到缓冲区,并且该工作队列在 SCHED_OTHER 中运行(大多数情况下都是如此),更改线程的调度程序将不会想要的效果。经典的优先级倒置问题。您可能想要审核您的特定板使用的内核驱动程序。不过,如果您在每次 read 时清空整个缓冲区,这应该不是什么问题。

如果此代码曾经在 SMP 系统上使用过,您最想用锁来保护 readwrite 指针,因为它们不是原子更新。线程很难正确处理,您是否考虑过使用事件循环来代替?类似于 libev .

关于c - 嵌入式 Linux : Reading bytes from serial port too slow for quicker transfer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50930661/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com