Sunday, March 22, 2009

Receive Latency Tip in Serial Programming

In some serial applications, you need good receive latency. It means you need to get input RS232/422/485 data from UART ASAP becuase  you want to response to the device in time.

Although Windows is not real time OS, you still can good latency by change serial FIFO settings. FIFO is a small buffer in UART including Tx/Rx 2 differnet directions. To optimize the performance, Rx FIFO has a Rx trigger design including 1/4/8/14 bytes options.  "Trigger" means when the UART needs to issue interrupt to CPU/driver the rx data is ready. In default value 14, driver will get interrupt each time the RX FIFO has 14 bytes in it. But if the data lentgh in FIFO is smaller 14, when the UART will issue interrupt? The answer is timeout. This is depend on UART design. But this will cause the bad latency if your input data is always smaller than trigger level.

To avoid this problem, disable FIFO or set the Rx FIFO size to 1 - this means driver will get interrupt for each input byte. Your program can get input data ASAP. 

In old Age, this is also very useful for old UART in Xon/Xoff flow control setting. As you know, driver needs to get Xoff character ASAP to know when it should stop tx if the connected device Rx buffer is almost full. If UART has FIFO, this will delay the Xoff action and cause the connected device overrun. But for modern UARTs, they have on-chip Xon/Xoff flow control and it will immedately stop tx while Xoff is received. The xoff latency is not problem any more. For example, Moxa Serial Device Connectivity Products use the Moxa powered UART - MU860/MU150 with on-chip Xon/Xoff flow control can avoid the Xoff latency problem.

To change FIFO setting, you need to open the serial port's Property Page in Device Manager. Uncheck the "Use FIFO" and click OK. My suggestion is to reboot system to acivate this setting. In my lab test, this can decrease several ms latency. 

Tuesday, February 17, 2009

Industrial USB HUB with USB-IF certification


Moxa new USB HUB product line - UPort HUB 404/407 is launched. 
UPort HUB is good USB extenstion solution for industrial environment. If you always have USB compatibility/stability problem such as "Unknown Device", you can take a look at it. It has USB-IF certification with USB 2.0 high speed (480Mbps), including self power and bus power mode. This can eliminate USB compatibility problem. With IEC-61000-4-2 level 4 protection, plug/un-plug frequently will never be a problem and it is very suitable for mobile device manufacturing. For harsh environment, the rugged metal case design, DIN rail mountable and wide range operating temperature support (-40~+85) can fulfil your industrail USB connection requirement. 

Thursday, February 05, 2009

Win32 DCB Trap

In Win32 serial communication functions, the DCB is very important struct (which is similar to termios struct in *UIX). There are several Win32 functions can change the struct - SetCommState, GetCommState and BuildCommDCB. When you want to use them, you have to notice some traps:

Trap 1:
DCB dcbSerial = {0};
dcbSerial.DCBlength = sizeof(dcbSerial);
dcbSerial.BaudRate = CBR_19200;
dcbSerial.ByteSize = 8;
dcbSerial.StopBits = ONESTOPBIT;
dcbSerial.Parity = NOPARITY;
if(!SetCommState(hSerial, &dcbSerial)){
//error setting serial port state
}
In above code, you clear all fields first and set some basic parameters. Please DON'T set DCB in this way.  That will set zero to important fields such as XonLim and XoffLim and cause some serial adapter driver to return fail. XonLim can not be the same as XoffLim if any flow control is enabled. 


Trap 2:
DCB dcbSerial = {0};
dcbSerial.DCBlength = sizeof(dcbSerial);
BuildCommDCB(“baud=1200 parity=N data=8 stop=1”, &dcbSerial);
if(!SetCommState(hSerial, &dcbSerial)){
//error setting serial port state
}  
This is very similar to trap 1. BuildCommDCB is just for compatbility and only few people will use it in Win32. It use the "mode" (one DOS program) style to describe serial parameter. 

The best way to set DCB is to get previous setting by calling GetCommState. This is also verys similer to *UIX termios - you should get old termios setting before setting new termios. That means: Get all old settings, change the field which you really want to change and set the new settings.

Correct way:
DCB dcbSerial = {0};
dcbSerial.DCBlength = sizeof(dcbSerial);
GetCommDCB(hSerial, &dcbSerial);
dcbSerial.BaudRate = CBR_19200;
dcbSerial.ByteSize = 8;
dcbSerial.StopBits = ONESTOPBIT;
dcbSerial.Parity = NOPARITY;
if(!SetCommState(hSerial, &dcbSerial)){
//error setting serial port state

Change the specific field only and don't touch others if and only if you know what you are doing. This way can keep the previous settings.

Friday, January 23, 2009

Industrial serial-to-fiber converters


ICF-1150/1150I:
This is Moxa first IA form factor serial to fiber converter with rugged design. Support up to 921.6k baud rate and ADDC for RS-485 connection. With 3-way communication for easy troubleshooting and galvanic isolation, it is suitable for industrail environment.

Tuesday, January 20, 2009

Win32 TransmitCommChar trap

Sometimes my customers tell me they get trouble with TransmitCommChar. I try to tell you the story from driver side.

When you want to write data into COM port in Windows with C/C++, you will get 2 functions in SDK document: WriteFile and TransmitCommChar. If you only want to write one byte, most people will choose TransmitCommChar. Yes, it's easier than WriteFile. But I think this choice is not correct. 

TransmitCommChar is only "urgent" data and the char will be sent ahead of any pending data. In driver, it will only allocate one byte buffer for this function. When driver want to send any data, it will check urgent data buffer. If any, send it first. If there is any pending "urgent" data while calling this function, driver will return fail. That is, if you really want to use this function (just becuase WriteFile is too complicated...), you have to check the return value. If failed, you need to try again.

The "urgent" data concept is from UNIX. Sometimes you want to send "stop" or Xoff char to another side, you may this kind of function. So if you are not trying to send "urgent" data, don't use TransmitCommChar or you will get in trouble.