4.3.12 - Asynchronous Serial Communication [U3 Datasheet] | LabJack
« Close

Datasheets and User Guides

App Notes

Software & Driver


4.3.12 - Asynchronous Serial Communication [U3 Datasheet]

The U3 (hardware version 1.21+ only) has a UART available that supports asynchronous serial communication. On hardware version 1.30 the TX (transmit) and RX (receive) lines appear on FIO/EIO after any timers and counters, so with no timers/counters enabled, and pin offset set to 4, TX=FIO4 and RX=FIO5. On hardware version 1.21, the UART uses SDA for TX and SCL for RX.

Communication is in the common 8/n/1 format. Similar to RS-232, except that the logic is normal CMOS/TTL. Connection to an RS-232 device will require a converter chip such as the MAX233, which inverts the logic and shifts the voltage levels.

This serial link is not an alternative to the USB connection. Rather, the host application will write/read data to/from the U3 over USB, and the U3 communicates with some other device using the serial protocol. Using this serial protocol is considered an advanced topic. A good knowledge of the protocol is recommended, and a logic analyzer or oscilloscope might be needed for troubleshooting. Also consider that a better way to do RS-232 (or RS-485 or RS-422) communication is with a standard USB<=>RS-232 adapter/converter/dongle, so the user should have a particular reason to not use that and use a U3 instead.

There is one IOType used to write/read asynchronous data:


The following are special channels used with the asynch IOType above:

LJ_chASYNCH_ENABLE  // Enables UART to begin buffering RX data.
LJ_chASYNCH_RX      // Value= returns pre-read buffer size. x1= array.
LJ_chASYNCH_TX      // Value= number to send (0-56), number in RX buffer. x1= array.
LJ_chASYNCH_FLUSH   // Flushes the RX buffer.  All data discarded. Value ignored.

When using LJ_chASYNCH_RX, the Value parameter returns the size of the Asynch buffer before the read. If the size is 32 bytes or less, that is how many bytes were read. If the size is more than 32 bytes, then the call read 32 this time and there are still bytes left in the buffer.

When using LJ_chASYNCH_TX, specify the number of bytes to send in the Value parameter. The Value parameter returns the size of the Asynch read buffer.

The following is a special channel, used with the get/put config IOTypes, to specify the baud rate for the asynchronous communication:

LJ_chASYNCH_BAUDFACTOR  // 16-bit value for hardware V1.30.  8-bit for V1.21.

With hardware revision 1.30 this is a 16-bit value that sets the baud rate according the following formula: BaudFactor16 = 2^16 – 48000000/(2 * Desired Baud). For example, a BaudFactor16 = 63036 provides a baud rate of 9600 bps. With hardware revision 1.21, the value is only 8-bit and the formula is BaudFactor8 = 2^8 – TimerClockBase/(Desired Baud).

Following is example pseudocode for asynchronous communication:

//Set data rate for 9600 bps communication.
ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chASYNCH_BAUDFACTOR, 63036, 0);

//Enable UART.

//Write data.
eGetPtr(lngHandle, LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_TX, &numBytes, array);

//Read data.  Always initialize array to 32 bytes.
eGetPtr(lngHandle, LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_RX, &numBytes, array);


Why is says describing ePut in Class LabJackPython "for windows only"?

Snippets showing UART access highly appreciated (hope 1.21 will support)

The ePut function is provided by the UD high-level driver, which is only available on Windows.  The function is not cross-platform.  On Linux and Mac OS X we provide low-level drivers that only have basic USB communication functionality (open, write, read, close).  With the low-level driver users need to set up their own low-level commands to send to the U3 and read back the responses.  Low-level functions are documented here: http://labjack.com/support/u3/users-guide/5

Fortunately the Python library provides high-level functions that are cross-platform.  In the U3 class for UART use the asynchConfig (configures UART), asynchTX (send bytes to UART) and asynchRX (read bytes from UART).  These three functions handle the command/response packets for the AsynchConfig, AsynchTX and AsynchRX low-level functions.  If you look in the u3.py source code you'll find documentation for the functions which should explain things. 

Hardware version 1.21 can do UART, though you need to read timer configuration first and set the olderHardware parameter to true when using asynchConfig.  Also, on hardware 1.21 UART uses SDA for TX and SCL for RX.   Here's a quick Python example which is hardware 1.21 specific:

import u3

d=u3.U3() #opens first found U3
d.configTimerClock() #reads timer configuration for U3 object d
d.asynchConfig(olderHardware=True, DesiredBaud=9600) #9600 bits per second
txBytes = [116, 101, 115, 116, 13, 10] #"test\r\n" in ASCII
d.asynchTX(txBytes)  #send UART bytes
rxResponse = d.asynchRX() #read UART bytes
print rxResponse

Asynchronus serial communications is very useful; though you recommend using a separate USB/RS-232 interface, using the labjack simplifies hardware and software considerably in my application. It would be really useful if there was function to see how many bytes of data are in the RX buffer WITHOUT pulling the data out. This would allow me to poll the RX buffer count at intervals, and when it hits the anticipated number of bytes, then read it out using the current Receive function. 

Is this something you could add? Thanks.

We can't support that on the U3, so your software will have to buffer the bytes.  Typical operation is to read the RX buffer at some interval, or as fast as possible even.  Each time you read you add any new bytes to a buffer (array) in your software, and you keep reading until you get the desired number of bytes or a termination character.

On the T7 you can read how many RX bytes have received without reading those bytes.  See the Asynch section of the T7 Datasheet.

A typical read looks similar either way.  The difference is that on the T7 you can let the T7 buffer or buffer in your software, whereas with the U3/U6/UE9 you are forced to buffer in your software.

I'm not sure if it actually works, but it looks like you can query the number of bytes in the RX buffer by sending an empty list using asynchTX(). For example (in Python):

lj = u3.U3()

rx_buf_size = lj.asynchTX([])['NumAsynchBytesInRXBuffer']


Using the AsynchTX low-level function, which the asynchTX U3 Python method is a wrapper for, you can check how many bytes are currently in the RX buffer like you are doing. It looks like our previous response was in regards to the UD driver and the high-level interface described on this page, but using LabJackPython's U3 asynchTX method or the UD driver's raw output/input functionality with the AsynchTX command/response you can check the number of bytes in the RX buffer without reading the buffer.

To follow up on this issue, in the next update of the UD driver we are changing the returned/result Value of LJ_chASYNCH_TX to the number of bytes in the RX buffer. It looks like we documented it like that on this page ("Value= number to send (0-56), number in rx buffer. x1= array.") but it was unimplemented. So a call like this will return the number of bytes in the RX buffer without reading from it:

numBytes = 0;
eGet(lngHandle, LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_TX, &numBytes, array);
printf("# of bytes in RX buffer = %f\n", numBytes);

I have been able to determine the number of bytes in the RX buffer by calling asynchTX() with empty data (see http://labjack.com/support/u3/users-guide/5.2.17). The return value from asynchTX() will contain the number of bytes in the RX buffer. I have used this to implement the inWaiting() method for a PySerial-like interface wrapper around the Labjack Asynch feature.

ElectroLund's picture

Hello, I'm trying to verify Asynch operation and having difficulty.

I attempted to sanity check my settings with:


This indeed returns my set baud factor (63036).



This doesn't return the enable.  data is still set to previous value.

My 232-USB dongle doens't see any traffic in/out from the Labjack FIO 4/5 pins with an offset of 4.

There isn't a LJControlPanel option to enable serial comms, so I'm not sure what else I can do to verify.  

labjack support's picture

For sanity, I recommend a loop-back test. Most of our example packages have an ASYNCH example to look at. For C++ it is VC6_LJUD.zip\VC6_LJUD\U3 Specific\U3_Asynch
I am told that the LJ_chASYNCH_ENABLE does not work for sanity checking. Something about the way the driver tracks things.
Once the loop-back test works we can move onto your dongle. My best guess atm is that either we have a logic level or handshaking issue. RS232 usually runs on a ±9-12V logic. To talk to the U3's 3.3V logic we either need something like a FTDI cable or a MAX232 translation chip.
So first step is the loop-back test. Then we need to look into what the USB-232 dongle is expecting for logic levels.
ElectroLund's picture

Ok, I have the RX side working.  I can send ASCII characters from my terminal app via low voltage RS232 USB dongle directly into my LabJack FIO5 RX pin.  I get all data perfectly.

Now for transmit.  I get nothing from the Labjack and my CVI program.  Using the example above (eGetPtr method):

int size = 3; char buffer[3] = {"0", "1", "3"); eGetPtr(handle, LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_TX, &size, buffer);


Nothing comes over to my terminal app. I tried replacing my wires, no change.

The U3 Asynch example code uses eGet instead.  I tried that method, same results.

labjack support's picture

I would test by connecting the Tx pin of the U3 to the Rx. If you get data then we know something is going out on the Tx line and we need look upstream. If we do not get data the problem is with the U3 or host application.

If you have an oscilloscope available we can use that to check whether there is anything coming out of the U3.

Also, I ran a quick test using the "Asynch Simple U3 U6.vi" example. I connected FIO5 to FIO4 and the data transmitted was read back. Did you ever try a loopback test?

We should also consider the possibility of a damaged IO. Make sure that without anything other than a DMM connected, the IO will toggle as expected.


ElectroLund's picture

Very curiously, if I do the transmit nothing trick mentioned by someone else in the forums, I get back the correct number of bytes in the receive buffer.  So at least that much of the transmit attempt is working.

Meanwhile, I hooked up a scope.  I can trigger nicely on my receiver and see characters come from my PC.  But on the TX out of the U3, it's all quiet.

labjack support's picture

Oh man, what are we missing.

Are you using C++? Have you tried the C example?

I tested the C++ example "U3_Asynch" on my U3 and it worked as expected.


C++ examples:


ElectroLund's picture

I finally got this working with a clear head.  :)  Turned out to be that I wasn't sending the number of outgoing bytes correctly.  ePut takes a double and my casting was killing the value apparently.  Thanks for your help!

ElectroLund's picture

Good thought.  Ok, I connected RX (FIO5) to TX (FIO4), no other hardware.  I transmit out a packet and nothing comings in.

I then tried a different set of IO by changing my timer offset from 4 to 6 and then change pins to FIO7/5.  Still nothing.  I then connected out to my RS232 terminal and continue to see transmit out of the PC receive correctly into the U3. 

I'll get a scope next, but there's something wrong with the transmit side of this setup, across IO pins.

ElectroLund's picture

Is there a way I could use the LJ_chASYNCH_RX but only request N bytes?  The manual makes it pretty clear there is not.

the Value parameter returns the size of the Asynch buffer before the read. If the size is 32 bytes or less, that is how many bytes were read. If the size is more than 32 bytes, then the call read 32 this time and there are still bytes left in the buffer.

And I could set up my own memory FIFO but that's a pain.  Wondering if there's some undocumented trick to do this.  

labjack support's picture

There is not any way to request less than 32 bytes if there are 32 bytes or more in the buffer. Firmware will always return the oldest 32 bytes in the buffer.