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

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

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

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

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

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

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

Следующие управляющие флаги используются для связи RS232 в приложении C++ в соответствии с Руководством по последовательному программированию для операционных систем 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 обрабатывать запросы с более высоким приоритетом, чтобы минимизировать задержку.

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

1 ответ

Решение

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

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

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

Я тогда казнил setserial /dev/ttyS1 low_latency и задержка была уменьшена до ~0,4 мс:-)

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

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