PXA270 上 RS232 通信的高延迟

发布于 2024-10-11 17:58:26 字数 2100 浏览 3 评论 0原文

我在 PXA270 RISC PC/104 上的 RS232 通信中遇到长时间延迟(1.5 毫秒 - 9.5 毫秒)。我想尽量减少长时间的延迟,但我是嵌入式设备和 C++ 的初学者,所以我认为我错过了一些东西。

上述延迟是指 PXA 板通过 RS232(115200 波特)从外部设备接收数据包时,直到将 ACK 自定义数据包发送回外部设备为止。 我使用示波器测量了 PXA 板上的延迟,一个通道位于 Rx,另一个通道位于 Tx。

PXA 板运行 Arcom 嵌入式 Linux (AEL)。我知道,这不是一个实时操作系统,但我仍然认为,4.5ms 的平均延迟对于提取接收到的数据包、验证它的 CRC16、构造一个 ACK​​ 数据包来说太高 CRC)并将其发送回串行线。 我还故意让CPU承受重负载(一些并行的gzip操作),但延迟时间根本没有增加。 接收数据包的最大大小为 30 字节。

一个 C++ 应用程序(另一个前同事编写的)正在处理数据包的接收及其确认。 一个线程正在发送,另一个线程正在接收数据包。

我认为 PXA 板上的 RTC 分辨率非常差,AEL 无法将时序与内部 RTC 分辨率对齐。但 RTC 的频率为 32.768 kHz。分辨率足够了,还是不解释延迟高。顺便说一句,我认为操作系统使用内部 PXA 时钟(也有足够的分辨率)而不是 RTC 进行计时。

因此,问题必定出在 C++ 应用程序中或 RS232 接口的驱动程序/操作系统设置中。

根据串行编程指南,以下控制标志用于 C++ 应用程序中的 RS232 通信对于 POSIX 操作系统

// Open RS232 on COM1
mPhysicalComPort = open(aPort, O_RDWR | O_NOCTTY | O_NDELAY);
// Force read call to block if no data available
int f = fcntl(mPhysicalComPort, F_GETFL, 0);
f &= ~O_NONBLOCK;
fcntl(mPhysicalComPort, F_SETFL, f);
// Get the current options for the port...
tcgetattr(mPhysicalComPort, &options);
// ... and set them to the desired values
cfsetispeed(&options, baudRate);
cfsetospeed(&options, baudRate);
// no parity (8N1)
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// disable hardware flow control
options.c_cflag &= ~CRTSCTS;
// raw input
options.c_lflag = 0;
// disable software flow control
options.c_iflag = 0;
// raw output
options.c_oflag = 0;
// Set byte times
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
// Set the new options for the port
tcsetattr(mPhysicalComPort, TCSAFLUSH, &options);
// Flush to put settings to work
tcflush(mPhysicalComPort, TCIOFLUSH);

我认为我错过了一些非常简单的东西。我认为,如果应用程序的进程在更高的优先级下运行,这并不能解决问题。必须有某种东西指示 RS232 驱动程序以更高的优先级处理请求,以最大限度地减少延迟。

有人有什么想法吗?预先非常感谢您的帮助。

I'm experiencing a long delay (1.5ms - 9.5ms) in a RS232 communication on a PXA270 RISC PC/104. I want to minimize the long delay but I'm a beginner with embedded devices and C++ so I think I'm missing something.

The mentioned delay is at the time when the PXA board receives a packet from the external device via RS232 (115200 baud) until it sends an ACK custom packet back to the external device.
I measured the delay on the PXA board with an oscilloscope, one channel at the Rx and the other on the Tx.

The PXA board is running an Arcom Embedded Linux (AEL). I know, it's not a real-time OS, but I still think, that an average delay of 4.5ms is way too high for extracting the received packet, verify it's CRC16, construct an ACK packet (with CRC) and send it back the serial line.
I also deliberately put the CPU under heavy load (some parallel gzip operations) but the delay time didn't increase at all.
The maximum size of a received packet is 30 bytes.

A C++ application (another former co-worker wrote it) is handling the reception of the packets and their acknowledgement.
One thread is sending and the other is receiving the packets.

I thought that the RTC on the PXA board has a very bad resolution and the AEL can not align the timing to the internal RTC resolution. But the RTC has a frequency of 32.768 kHz. The resolution is sufficient, still don't explain the high delay. Btw, I think the OS is using the internal PXA clock (which has also a sufficient resolution) instead of the RTC for the timing.

Therefore the problem must be in the C++ app or in a driver/OS setting of the RS232 interface.

The following control flags are used for the RS232 communication in the C++ application according to the Serial Programming Guide for POSIX Operating Systems:

// Open RS232 on COM1
mPhysicalComPort = open(aPort, O_RDWR | O_NOCTTY | O_NDELAY);
// Force read call to block if no data available
int f = fcntl(mPhysicalComPort, F_GETFL, 0);
f &= ~O_NONBLOCK;
fcntl(mPhysicalComPort, F_SETFL, f);
// Get the current options for the port...
tcgetattr(mPhysicalComPort, &options);
// ... and set them to the desired values
cfsetispeed(&options, baudRate);
cfsetospeed(&options, baudRate);
// no parity (8N1)
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// disable hardware flow control
options.c_cflag &= ~CRTSCTS;
// raw input
options.c_lflag = 0;
// disable software flow control
options.c_iflag = 0;
// raw output
options.c_oflag = 0;
// Set byte times
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
// Set the new options for the port
tcsetattr(mPhysicalComPort, TCSAFLUSH, &options);
// Flush to put settings to work
tcflush(mPhysicalComPort, TCIOFLUSH);

I think I'm missing something very simple. I think, that if the process of the app is running under a higher priority, this will not solve the problem. There must be something, which instructs the RS232 driver to handle the requests with a higher priority to minimize the latency.

Does anyone have any ideas? Thank you very much in advance for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

给妤﹃绝世温柔 2024-10-18 17:58:26

非常感谢您的评论。

我能够将延迟减少到约 0.4 毫秒。 AEL 手册中引用了命令 setserial(8)。宾果游戏,我在那里找到了 low_latency 标志,并具有以下描述:

最大限度地减少接收延迟
串行设备的成本更大
CPU 利用率。 (通常有一个
之前平均延迟 5-10 毫秒
字符被传递给线路
纪律以尽量减少开销。)
默认情况下关闭,但某些情况下
实时应用程序可能会发现这个
有用。

然后我执行了setserial /dev/ttyS1 low_latency,延迟减少到~0.4ms:-)

但是我想在C++应用程序中实现这个行为,而不用setserial全局设置这个标志(这个命令默认情况下不包含在所有发行版中)。

我添加了以下代码行,其与 setserial 中的 low_latency 标志具有相同的效果:

#include <sys/ioctl.h> 
#include <linux/serial.h>
// Open RS232 on COM1
mPhysicalComPort = open(aPort, O_RDWR | O_NOCTTY | O_NDELAY);
struct serial_struct serial;
ioctl(mPhysicalComPort, TIOCGSERIAL, &serial); 
serial.flags |= ASYNC_LOW_LATENCY; // (0x2000)
ioctl(mPhysicalComPort, TIOCSSERIAL, &serial);

Thank you very much for your comments.

I was able to reduce the delay to ~0.4ms. The command setserial(8) was referenced in the AEL manual. And bingo, I found the low_latency flag there with the following description:

Minimize the receive latency of the
serial device at the cost of greater
CPU utilization. (Normally there is an
average of 5-10ms latency before
characters are handed off to the line
discpline to minimize overhead.) This
is off by default, but certain
real-time applications may find this
useful.

I then executed setserial /dev/ttyS1 low_latency and the delay was reduced to ~0.4ms :-)

But I wanted to implement this behaviour in the C++ app, without setting this flag globally with setserial (this command is by default not included in all distros).

I've added the following code lines, which had the same effect as the low_latency flag from setserial:

#include <sys/ioctl.h> 
#include <linux/serial.h>
// Open RS232 on COM1
mPhysicalComPort = open(aPort, O_RDWR | O_NOCTTY | O_NDELAY);
struct serial_struct serial;
ioctl(mPhysicalComPort, TIOCGSERIAL, &serial); 
serial.flags |= ASYNC_LOW_LATENCY; // (0x2000)
ioctl(mPhysicalComPort, TIOCSSERIAL, &serial);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文