2011-01-12 4 views
7

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

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

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

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

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

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

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

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

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

+0

Есть ли у вас эти задержки для каждого полукокса, или же ваш вход приходят, когда есть \ n на входе или буфер заполнен? В дополнение к серийному драйверу есть некоторые связанные с терминалом материалы, которые могут вывести ваше время. – Rudi

+0

Задержка не возникает для каждого символа. Это происходит, когда весь пакет (~ 30 байт) принимается, пока пакет ACK не будет отправлен обратно. – saxos

+1

1.Пожалуйста, покажите нам код, где вы ждете и читаете из порта. 2.Показать нам вывод 'uptime' (возможно, ваша система перегружена?) 3. У вашего Linux есть Fast Context Switch Extension (lwn.net/images/conf/rtlws11/papers/proc/p01.pdf)? PXA270 может иметь задержку переключения контекста ~ 0,5 мс без него. – atzz

ответ

8

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

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

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

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

Но я хотел реализовать это поведение в приложении C++, не устанавливая этот флаг глобально с помощью 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); 
+0

более низкая латентность за счет увеличения использования ЦП: это означает, что ОС должна каким-то образом опросить последовательный порт? – stijn

+0

Я не знаю точных внутренних деталей. Я читал что-то, что с флагом low_latency данные вставляются в слой tty в режиме жесткого прерывания, который имеет гораздо более высокий приоритет, чем мягкое прерывание. Я вообще не замечаю увеличения использования ЦП (для моего сценария). – saxos