Высокая задержка связи RS232 на PXA270

Я испытываю длительную задержку (1,5 мс - 9,5 мс) в RS232-связи на ПК /104 PXA270 RISC. Я хочу свести к минимуму длительную задержку, но я новичок со встроенными устройствами и С++, поэтому я думаю, что что-то не хватает.

Указанная задержка заключается в том, что плата PXA получает пакет от внешнего устройства через RS232 (115200 бод), пока он не отправит собственный пакет ACK обратно на внешнее устройство. Я измерил задержку на плате PXA с помощью осциллографа, один канал на Rx, а другой на Tx.

На плате PXA работает Arcom Embedded Linux (AEL). Я знаю, это не операционная система, но я все же думаю, что средняя задержка в 4,5 мс - это слишком высокая для извлечения полученного пакета, проверка CRC16, создание ACK-пакета (с CRC) и отправить его обратно в последовательную линию. Я также сознательно поставил CPU под большую нагрузку (некоторые параллельные операции gzip), но время задержки не увеличилось вообще. Максимальный размер полученного пакета составляет 30 байтов.

Приложение С++ (другой бывший сотрудник написал) обрабатывает прием пакетов и их подтверждение. Один поток отправляется, а другой принимает пакеты.

Я думал, что RTC на плате PXA имеет очень плохое разрешение, и AEL не может согласовать синхронизацию с внутренним разрешением RTC. Но частота RTC составляет 32,768 кГц. Разрешение достаточно, но не объясняет высокую задержку. Кстати, я думаю, что ОС использует внутренние часы PXA (которые также имеют достаточное разрешение) вместо RTC для синхронизации.

Поэтому проблема должна быть в приложении С++ или в настройке драйвера/ОС интерфейса RS232.

Для связи RS232 в приложении С++ используются следующие управляющие флаги в соответствии с Руководство по серийному программированию для 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);

Я думаю, что мне не хватает чего-то очень простого. Я думаю, что если процесс приложения работает под более высоким приоритетом, это не решит проблему. Должно быть что-то, что инструктирует драйвер RS232 обрабатывать запросы с более высоким приоритетом, чтобы свести к минимуму задержку.

Есть ли у кого-нибудь идеи? Заранее благодарю вас за помощь.

1 ответ

Большое спасибо за ваши комментарии.

Я смог уменьшить задержку до ~ 0,4 мс. Команда setserial (8) указана в руководстве AEL. И бинго, я нашел флаг low_latency со следующим описанием:

Минимизировать задержку приема последовательного устройства за счет увеличения Использование ЦП. (Обычно существует средняя задержка 5-10 мс до символы передаются на линию discpline, чтобы минимизировать накладные расходы.) Это отключен по умолчанию, но определенные приложения реального времени могут найти это полезно.

Затем я выполнил setserial /dev/ttyS1 low_latency, и задержка была уменьшена до ~ 0.4ms: -)

Но я хотел реализовать это поведение в приложении С++, не устанавливая этот флаг глобально с помощью seterial (эта команда по умолчанию не включена во все дистрибутивы).

Я добавил следующие строки кода, которые имели тот же эффект, что и флаг low_latency из 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);
</linux></sys>

licensed under cc by-sa 3.0 with attribution.