Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Задержки для COM порта под Win XP
Форум разработчиков электроники ELECTRONIX.ru > Цифровая обработка сигналов - ЦОС (DSP) > Алгоритмы ЦОС (DSP)
AKK
Доброго всем времени суток.
При иннициализации порта:
hCom = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE,0, NULL,OPEN_EXISTING, 0,NULL );
Устанавливаются следующие задержки на чтение:
COMMTIMEOUTS times;
...
times.ReadIntervalTimeout = MAXDWORD;
times.ReadTotalTimeoutMultiplier = MAXDWORD;
times.ReadTotalTimeoutConstant = 5;
...
Далее в программе происходит запись в порт 8 байт, и прием одного байта ответа:
WriteFile(hCom,Buffer,8,&b,NULL);
ReadFile (hCom,&i,1,&b,NULL);
И все это происходит в цикле.
Собственно проблема: на осциллографе видно, что передача 8 байт и ответный байт на скорости 9600 укладываются примерно в 10 мс, а следующая посылка данных происходит примерно только через 30 мс. Откуда берется это время - не понятно. При попытке читат 2 байта из порта (второго байта нет, т.е. должен происходить таймаут) картина полностью идентична описаной. При коде:
WriteFile(hCom,Buffer,8,&b,NULL);
ReadFile (hCom,&i,1,&b,NULL);
ReadFile (hCom,&i,1,&b,NULL);
задержка возрастает примерно до 100 мс. :-(.
При увеличении скорости порта до 19200 скорость передачи данных сократилась незначительно: задержка между посылками возросла на то же самое время, на какое сократилось время передачи данных.
Да, забыл: СОМ3 - это порт для преобразователя USB-RS485. Т.е. с компутера данные реально отправляются на через USB порт на преобразователь, и далее по линии RS485. Данные снимались осциллографом на преобразователе со стороны RS485, но преобразователь тут точно не при чем, он был испытан на самодельном устройстве - USB передатчике, никаких левых задержек не наблюдалось.
Кто знает в чем дело - помогите, плз. Кто не знает - может выдвигать версии, все будет внимательно рассмотрено, проверено.
TsAN
AKK, если хотите избежать таких вот лишних задержек - при передаче/приеме информации работайте с портами В/В (конкретно - с регистрами этого COM-порта) напрямую из своей программы, в обход драйверов и прочих наворотов ОС. При этом все возможные задержки будут под Вашим контролем.
Хотя м не все ОС это допускают, но, тем не менее, такая вот работа - наиболее кардинальное решение.
В ОС наподобие Windows пожно попробовать поиграть приоритетами заданий, хотя это будет и не столь эффективно.

Удачи!

добавлено
И лучше для наких целей использовать аппаратный COM-порт, ибо USB ориентирована прежде всего на обслуживание многих устройств по одному каналу. Возможно, уже одно это позволит получить нужные Вам параметры.
AKK
Цитата(TsAN @ Oct 7 2005, 09:53)
AKK, если хотите избежать таких вот лишних задержек - при передаче/приеме информации работайте с портами В/В (конкретно - с регистрами этого COM-порта) напрямую из своей программы, в обход драйверов и прочих наворотов ОС. При этом все возможные задержки будут под Вашим контролем.
*


К сожалению я не настолько знаю програмирование под Win XP, чтобы работать напрямую с виртуальным СОМ портом или напрямую с USB, может подскажите в каком направлении надо начинать двигаться?
Tech
У меня фунции работы с COM портом выделены в отдельный поток, запускаются по событиям и работают асинхронно. Задержек не наблюдаю даже при очень загруженной системе (кроме работы с FDD и т.п.). Хотя сначала делал синхронные прием и передачу и тоже задержек не видел.
Пробовал и аппаратный и эмулируемый (на PL2303) порты пока только под W2K.

Покажите, по возможности, значения всех полей структуры DCB, и кусок кода реализации цикла.
TsAN
Цитата(AKK @ Oct 7 2005, 07:19)
я не настолько знаю програмирование под Win XP, чтобы работать напрямую с виртуальным СОМ портом или напрямую с USB, может подскажите в каком направлении надо начинать двигаться?
*

Вообще-то в ОС типа NT для этого непосредственно взаимодействие с железом надо разрабатывать как драйвер, что само по себе требует значительного объема начальных знаний как в области структуры ОС, так и протокола работы железа. Поскольку драйвер Ваш - то и задержки под Вашим полным контролем, да и всю программу Вы полностью можете оформить как драйвер, хотя выигрыш от этого чисто теоретический: переключение на драйвер и обратно может выполняться достаточно быстро - за несколько машинных инструкций.
В эпоху NT4 был какой-то драйвер - названия, к сожалению, сразу вот так вспомнить не могу - который позволял работать напрямую с портами - так, как это было бы в DOS'е. Но, скорее всего, с виртуальными портами это работать не будет.
В данном случае, IMHO, резонно обратить внимание на совет ув. Tech - по крайней мере, в данном случае можно сделать, что ОС не будет пытаться оптимизировать обмен путем кэширования, ибо кэширование хорошо при больших объемах перекачимваемой информации. Плюс посмотреть, чтобы на USB при этом ничего не висело - по крайней мере, пока не будет получен положительный результат. Торможение при работе с FDD, которое отметил Tech, позникает по причине того, что, поскольку в FDD нет буферной памяти, то отложить обмен информацией с ним невозможно (точнее, при откладывание вознивает задержка на время оборота диска). Поэтому и такие процессы тоже надо исключить.

Удачи!
AKK
Цитата(Tech @ Oct 7 2005, 10:58)
Покажите, по возможности, значения всех полей структуры DCB, и кусок кода реализации цикла.
*


Собственно код иннициализации:
hCom = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0, NULL);
if (hCom == INVALID_HANDLE_VALUE)
{
Application->MessageBox...
return;
};
GetCommState (hCom, &dcb);
GetCommTimeouts (hCom, &times);

dcb.BaudRate = CBR_9600;
dcb.ByteSize = 8;
dcb.fParity = true;
dcb.Parity = MARKPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommState(hCom, &dcb);

times.ReadIntervalTimeout = MAXDWORD;
times.ReadTotalTimeoutMultiplier = MAXDWORD;
times.ReadTotalTimeoutConstant = 5;
times.WriteTotalTimeoutMultiplier = MAXDWORD;
times.WriteTotalTimeoutConstant = 3;
SetCommTimeouts(hCom,&times);

PurgeComm(hCom,PURGE_TXCLEAR);
PurgeComm(hCom,PURGE_RXCLEAR);

Кусок цикла:
uchar buff[9];

for (b=0x200; b<0x020000;b+=8)
{
for (i=0;i<8;i++) buff[i] = buffer[b+i];
if ( !SetData(buff, 9) ) return;
addr += 8;
}

Функция SetData:
bool TFMain::SetData( uchar* Buffer, uchar Amount)
{
ulong b;
uchar i;

Buffer[Amount-1] = 0;
for (i=0; i<(Amount-1);i++) Buffer[Amount-1] ^= Buffer[i];

WriteFile(hCom,Buffer,Amount,&b,NULL);
PurgeComm(hCom,PURGE_RXCLEAR);

ReadFile (hCom,&i,1,&b,NULL);

if ( (i==Buffer[Amount-1]) && (b==1) ) return true;
else return false
}
andk
Вот кусок из доки
The COMMTIMEOUTS structure is used in the SetCommTimeouts and GetCommTimeouts functions to set and query the time-out parameters for a communications device. The parameters determine the behavior of ReadFile, WriteFile, ReadFileEx, and WriteFileEx operations on the device.

typedef struct _COMMTIMEOUTS { // ctmo
DWORD ReadIntervalTimeout;
DWORD ReadTotalTimeoutMultiplier;
DWORD ReadTotalTimeoutConstant;
DWORD WriteTotalTimeoutMultiplier;
DWORD WriteTotalTimeoutConstant;
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;


Members

ReadIntervalTimeout

Specifies the maximum time, in milliseconds, allowed to elapse between the arrival of two characters on the communications line. During a ReadFile operation, the time period begins when the first character is received. If the interval between the arrival of any two characters exceeds this amount, the ReadFile operation is completed and any buffered data is returned. A value of zero indicates that interval time-outs are not used.
A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the characters that have already been received, even if no characters have been received.

ReadTotalTimeoutMultiplier

Specifies the multiplier, in milliseconds, used to calculate the total time-out period for read operations. For each read operation, this value is multiplied by the requested number of bytes to be read.

ReadTotalTimeoutConstant

Specifies the constant, in milliseconds, used to calculate the total time-out period for read operations. For each read operation, this value is added to the product of the ReadTotalTimeoutMultiplier member and the requested number of bytes.
A value of zero for both the ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant members indicates that total time-outs are not used for read operations.

WriteTotalTimeoutMultiplier

Specifies the multiplier, in milliseconds, used to calculate the total time-out period for write operations. For each write operation, this value is multiplied by the number of bytes to be written.

WriteTotalTimeoutConstant

Specifies the constant, in milliseconds, used to calculate the total time-out period for write operations. For each write operation, this value is added to the product of the WriteTotalTimeoutMultiplier member and the number of bytes to be written.
A value of zero for both the WriteTotalTimeoutMultiplier and WriteTotalTimeoutConstant members indicates that total time-outs are not used for write operations.



Remarks

If an application sets ReadIntervalTimeout and ReadTotalTimeoutMultiplier to MAXDWORD and sets ReadTotalTimeoutConstant to a value greater than zero and less than MAXDWORD, one of the following occurs when the ReadFile function is called:

· If there are any characters in the input buffer, ReadFile returns immediately with the characters in the buffer.
· If there are no characters in the input buffer, ReadFile waits until a character arrives and then returns immediately.
· If no character arrives within the time specified by ReadTotalTimeoutConstant, ReadFile times out.



See Also

GetCommTimeouts, ReadFile, ReadFileEx, SetCommTimeouts, WriteFile, WriteFileEx
Tech
Ничего плохого в коде не вижу.
Попробуйте
dcb.fOutxCtsFlow=FALSE;
dcb.fOutxDsrFlow=FALSE;

И можно еще попытаться оформить цикл как критическую секцию.
Ну и по-русски:
http://bcb.net.ru/article/hard/index003.htm
AKK
[
Цитата(Tech @ Oct 7 2005, 14:11)
И можно еще попытаться оформить цикл как критическую секцию.
Ну и по-русски:
http://bcb.net.ru/article/hard/index003.htm
*


К сожалению ссылки уже не существует.

Спасибо всем кто откликнулся, будем рыть дальше.
Tech
Эта статья есть и здесь http://www.rs232.ru/doc002.html
SM
На мой взгляд описанная проблема вытекает исключительно из диспетчера самой винды. Указанные 30 мс + 10 мс это примерно (36 мс) время двух тиков таймера диспетчера. То есть два переключения задач. Сначала выясните, с какой стороны это мешает. Для этого, как сказали, вынесите все в отдельный тред, всадите процессу реалтайм приоритет и треду - тайм критикал. Если задержки исчесзли, значит проблема была тут. Оставляйте тред на тайм-критикале, и осторожно и качественно работайте с объектами синхронизации. Если проблема осталась, то это переключалово в нулевом кольце, в данном случае другого выхода, кроме как юзанье недокументированных ф-ций прямого доступа к портам или написания своего драйвера поверх системного не будет.
xelos
как уже было сказано, выносите операции чтения/записи в отдельный поток.

а для WinNT(XP,2k) на www.beyondlogic.org есть porttalk утилитка, открывающая прямой доступ к физическим портам из приложений 3-го кольца (пользовательские приложения)
starter48
Цитата(AKK @ Oct 7 2005, 10:23)
...
Далее в программе происходит запись в порт 8 байт, и прием одного байта
ответа:
WriteFile(hCom,Buffer,8,&b,NULL);
ReadFile (hCom,&i,1,&b,NULL);
И все это происходит в цикле.
Собственно проблема: на осциллографе видно, что передача 8 байт и ответный байт на скорости 9600 укладываются примерно в 10 мс, а следующая посылка данных происходит примерно только через 30 мс. Откуда берется это время - не понятно. При попытке читат 2 байта из порта (второго байта нет, т.е. должен происходить таймаут) картина полностью идентична описаной. При коде:
WriteFile(hCom,Buffer,8,&b,NULL);
ReadFile (hCom,&i,1,&b,NULL);
ReadFile (hCom,&i,1,&b,NULL);
задержка возрастает примерно до 100 мс. :-(.
*

Может это эффект от FIFO компорта?
AKK
Буфера FIFO отключены.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2016 Invision Power Services, Inc.