« Close

Datasheets and User Guides

App Notes

Software & Driver

 

4.3.12 - Asynchronous Serial Communication

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:


LJ_ioASYNCH_COMMUNICATION

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.
ePut(lngHandle, LJ_ioASYNCH_COMMUNICATION, LJ_chASYNCH_ENABLE, 1, 0);

//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);

8 comments

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.