[[PageOutline]] = UART Communication = This page gives some tips and tricks regarding serial communcation. Gateworks boards often have connectors available for either RS232 or TTL level UART with and without hardware handshaking. Refer to the board specific hardware manual for pinout details. Cables are available from Gateworks in the online shop: * [http://shop.gateworks.com/index.php?route=product/product&path=70_75&product_id=27 GW10001 10 pin IDC header to DB9] * [http://shop.gateworks.com/index.php?route=product/product&path=70_75&product_id=30 GW10019 DB9 Gender Changer] * [http://shop.gateworks.com/index.php?route=product/product&path=70_75&product_id=28 GW10005 DB9 male to DB9 female 6ft cable] [=#mapping] == Linux serial port devices == Serial UARTS will be represented as /dev/tty* devices depending on the CPU architecture. For avila/cambria/laguna product families the first UART is /dev/ttyS0 and for Ventana product families the UARTs are /dev/ttymxc*. The following table describes the various on-board UARTs for standard Gateworks products. Please consult the board specific hardware user manual for additional details: ||= Family =||= Board =||= Device =||= Function =|| || Avila || GW2347 || ttyS0 || console: 3.3V TTL JTAG J2 / RS232 J5 || || || || ttyS1 || UART: RS232 J3 || || || GW2348 || ttyS0 || console: 3.3V TTL JTAG J7 / RS232 J13 || || || || ttyS1 || UART: RS232 J6 || || || GW2355 || ttyS0 || console: 3.3V TTL JTAG J3 / RS232 J5 || || || || ttyS1 || GPS || || || GW2357 || ttyS0 || console: 3.3V TTL JTAG J2 / RS232 J6 || || || || ttyS1 || UART: RS232 J36 || || Cambria || GW2350 || ttyS0 || console: 3.3V TTL JTAG J1/J10 || || || || ttyS1 || GPS || || || || ttyS2 || RS485 J6 || || || GW2358 || ttyS0 || console: 3.3V TTL JTAG J10 / RS232 J17 || || || || ttyS1 || GPS || || || || ttyS2 || RS485 J3 || || Rincon || GW2361 || ttyS0 || console: 3.3V TTL JTAG J2 || || || || ttyS1 || RS232 J7 || || || || ttyS2 || RS485 J6 || || Laguna || GW2380/2/3 || ttyS0 || console: 3.3V TTL JTAG J2 / 3.3V TTL J4 || || || || ttyS1 || GPS || || || || ttyS2 || UART: 3.3V TTL J8 || || || GW2387 || ttyS0 || console: 3.3V TTL JTAG J3/J7 / RS232 J13 || || || || ttyS1 || RS232 J13 / 3.3V TTL J7 || || || || ttyS2 || GPS || || || GW2388 || ttyS0 || console: 3.3V TTL JTAG J8 / RS232 J21 || || || || ttyS1 || RS232 J21 || || || || ttyS2 || GPS || || || GW2391 || ttyS0 || console: 3.3V TTL JTAG J1 / RS232 J15 || || || || ttyS1 || RS232 J15 || || || || ttyS2 || GPS || || Ventana || GW51xx || ttymxc0 || GPS || || || || ttymxc1 || console: 3.3V TTL JTAG J10/J11 || || || || ttymxc4 || TTL J11 || || || GW52xx || ttymxc0 || RS485/CAN/TTL J12 / RS232 J10 || || || || ttymxc1 || console: 3.3V TTL JTAG J14 / RS232 J10 || || || || ttymxc4 || GPS || || || GW53xx || ttymxc0 || RS485/CAN/TTL J11 / RS232 J12 || || || || ttymxc1 || console: 3.3V TTL JTAG J14 / RS232 J12 || || || || ttymxc4 || GPS || || || GW54xx || ttymxc0 || RS485 J13 || || || || ttymxc1 || console: 3.3V TTL JTAG J17 / RS232 J15 || || || || ttymxc4 || GPS || || || GW551x || ttymxc1 || console: exp 3.3V TTL J3 || || || || ttymxc2 || exp 3.3V TTL J3 || || || GW552x || ttymxc1 || console: 3.3V TTL JTAG J7 || || || || ttymxc2 || exp 3.3V TTL J5 || || || || ttymxc4 || exp 3.3V TTL J5 || || || GW553x || ttymxc1 || console: 3.3V TTL JTAG J11 || || || || ttymxc2 || exp 3.3V TTL JTAG J10 || || || || ttymxc3 || GPS || || || || ttymxc4 || exp 3.3V TTL JTAG J10 || || || GW16111 || ttymxc1 || console: 3.3V TTL JTAG J8 / RS232 J16 / RS485 J20 || || || || ttymxc2 || RS232 J16 || [=#baud] == Baudrates == The maximum baudrate supported depends on the product family and sometimes whether or not you are using TTL or RS232 as at times a transceiver may limit the stream to below 250000 (consult the hardware manual). A safe and typical baudrate is 115200. [=#flowcontrol] == Flow control == Flow control refers to hardware or software handshaking that can tell a transmitter when its ok to send more data. Hardware flow control is typically via RTS/CTS (request-to-send / clear-to-send) or via DTR/DSR (data-terminal-ready / data-set-ready). Depending on the board and port used you may be able to use hardware flow control. Software flow control uses a specific character for start and stop and therefore cannot be used in binary data transfer. Take care to set flow control properly. Typically this is done in Linux with the stty application. For example to disable the first UART's flow control on an IMX6 based Ventana product: {{{ stty -crtscts -F /dev/ttymxc0 }}} == Serial Port Types (DCE vs DTE) == The Data Communication Equipment (DCE) (Typically used on a Gateworks board) pin assignments permit direct connection to a standard Data Terminal Equipment (DTE) PC running terminal emulation software. In certain scenarios, a null modem cable may be needed [http://en.wikipedia.org/wiki/Null_modem Null Modem Information] Please read more about the RS232 Specification [http://en.wikipedia.org/wiki/RS-232 here] [=#console] == Linux serial Console == There are times when one may not care about serial Linux console because the serial port is desired for other uses. By default the Gateworks bootloader's configure one of the board's UARTs for serial console. This can be disabled by changing the bootargs in the bootloader: * Example: Laguna uboot {{{ setenv bootargs console= root=/dev/mtdblock3 rootfstype=squashfs,jffs2 noinitrd saveenv }}} * Example: Ventana uboot: {{{ setenv console null saveenv }}} If using Yocto or a more traditional Linux based OS, you may need to take additional steps to disable the OS enabling the serial port for a Login terminal by removing the line with that serial port from /etc/inittab. The bootloader will still output data upon power up - see below. [=#bootloader] == Bootloader Serial Console == If you wish to disable the bootloader's use of the serial port, you will need to recompile the bootloader. Notes: * For Lagunu u-boot-2008.10 modify CONFIG_CONS_INDEX in include/configs/cavium_cns3000*.h setting it to a non-existent port. * Define CONFIG_SILENT_CONSOLE to enable support for silent mode (must custom compile bootloader as discussed on the wiki [wiki:laguna/bootloader here]) * Set the u-boot envvar silent to disable some u-boot output * One should probably tweak the bootdelay to 1 second (or turn it off) * One can still interrupt u-boot by pressing the specified key (you won't see output, but your input will be processed) [=#rs323] == RS232 == [https://en.wikipedia.org/wiki/RS-232 RS-232] is a standard for serial communication transmission of data. The most important aspects of the spec are: * defines electical signal characteristics such as voltage levels, signalling rate, timing and slew-rate of signals * mechanical characteristics such as pinouts Many Gateworks boards have RS232 support (not to be confused with TTL level UART support which has different voltage and signalling specifications). === Example usage: RS232 connection to a PC === 1. Connect all hardware / cables {{{ #!html

Note: A NULL MODEM adapter / cable may need to be used between the Gateworks board and a PC!

}}} [[Image(serial2391.jpg,400px)]] 2. The serial port must be configured on the Gateworks board using the stty command for the baud rate: {{{#!bash # stty --help BusyBox v1.19.4 (2013-06-26 04:34:22 PDT) multi-call binary. Usage: stty [-a|g] [-F DEVICE] [SETTING]... Without arguments, prints baud rate, line discipline, and deviations from stty sane -F DEVICE Open device instead of stdin -a Print all current settings in human-readable form -g Print in stty-readable form [SETTING] See manpage root@OpenWrt:/# stty -F /dev/ttyS1 115200 }}} 3. Configure PC: * On the receiving PC, a terminal program can be used. For example: - Windows: putty, hyperterm - Linux: screen, minicom - Example (adjust as necessary) {{{ screen /dev/ttyS1 115200,cs8 }}} * Be sure to select the same baud rate, format (ie 8 data bits, no parity, 1 stop bit - aka 8N1 or cs8) and flow control as configured on the Gateworks board. 4. Test Connection: * A quick way to test this is to use an echo statement from the console of the Gateworks board like so: {{{#!bash # echo "0" > /dev/ttyS1 }}} The character '0' should appear on the serial console on the PC. Troubleshooting: * make sure you are either not using hardware/software flow control, or in the case that you do have hardware flow control (CTS/RTS or DTR/DSR) they are properly connected. * use a null-modem if needed (DTE vs DCE) * make sure both ends are RS232 compliant (as opposed to TTL level logic) == Specific Model Notes == === GW2382 === J8 is an expansion header and is by default mapped to /dev/ttyS2. J2 and J4 are connected to /dev/ttyS0. The GPS is hooked to /dev/ttyS1. === Laguna: Baud Rate === The Laguna Family has the option of 2 clocks for the serial port, 24MHz and 14.7456MHz. By default the 24MHz clock is loaded. This clock creates drift for some baud rates as seen below. Because this drift is consistent on Laguna boards, Laguna to Laguna serial will work at all baud rates. Therefore, we suggest using rates below 115200. Please contact support at Gateworks if higher baud rates are required. [[Image(baudrates.jpg)]] [=#rs485] == RS485 == Some Gateworks boards have RS485 transceivers connected to host CPU UART's. This often is an optional feature that must be loaded at the factory. Please contact support@gateworks.com via email for more information. RS485 uses a differential pair and is typically half-duplex such that the TX and RX share a differential pair on a multi-master bus and the TX and an enable that is controlled via one of: 1. always enabled (only useful if there is only a single transmitter on the bus) 2. connected to UART RTS line 3. connected to host CPU GPIO Because of the half-duplex nature, typically custom software needs to be written to: * control the enabling of the transmit driver (sometimes this is done for you in the driver) * receive the data you sent directly after sending (unless the driver does this for you) * implement a protocol such that multiple masters know when it is there turn to transmit RS485 Networks also require termination. Most Gateworks boards which have RS485 have on-board 4.75Kohm pulls and an optional on-board 121ohm load termination resistor. In a typical scenario you may have two devices on an RS485 half-duplex bus, NodeA and NodeB and a conversation would look like this: 1. NodeA enables its transmitter, sends out a request packet, then disables its transmitter and waits for a response 2. NodeB waits for a request packet and until it sees one its transmitter is not enabled. When it receives the request it enables its transmitter, sends a response, then disables its transmitter. 3. NodeA knows the exact nature of the response so it can wait until the message is complete then knows that it can transmit again The following table and sections below provides per-board details of RS485: ||= Family =||= Board =||= TXEN =||= Termination =||= Notes =|| || Cambria || GW235x || DTR || optional || use tcdrain() and TIOCMBIC/TIOCMBIS ioctl || || || || Rincon || GW2361 || RTS || off-board || use tcdrain() and TIOCMBIC/TIOCMBIS ioctl || || || || Laguna || GW2380+GW16067 || gpio3 || optional || use tcdrain() and userspace /sys/class/gpio/gpio3 || || || || Ventana || GW551x+GW16111 || gpio19 || optional || see [#ventana-rs485 below] || || Ventana || GW52xx '''(optional)''' || gpio193 || optional || TIOCSRS485 support || || Ventana || GW53xx '''(optional)''' || gpio193 || optional || TIOCSRS485 support || || Ventana || GW54xx '''(optional)''' || gpio193 || optional || TIOCSRS485 support || Note that if a driver supports TIOCSRS485 (in other words it handles the assertion/de-assertion of TXEN in the driver) this is preferred over using tcdrain() to determine when the FIFO is empty as tcdrain() can have considerable latency at small transmit sizes. References: * [http://www.ti.com/lit/an/slla272b/slla272b.pdf TI RS-485 Design Guide] - excellent source of info regarding termination, multi-master transmission, line length etc * https://en.wikipedia.org/wiki/RS-485 [=#cambria-rs485] === Cambria === The Cambria GW2350 and GW2358 optionally supports half-duplex, multi-drop RS485: * TL16C752B UART * MAX3485 transceiver * TXEN connected to DTR * '''optional termination By 'optional' this means the baseboard design supports this, but it is not loaded on standard product therefore would be a Gateworks Special. Contact sales@gateworks.com if interested to see if a configuration already exists. Your software must assert/de-assert DTR manually (see [#rs485-example] example code) or the uart driver would need to be modified to add TIOCSRS485 ioctl support. [=#rincon-rs485] === Rincon === The Rincon GW2361 supports half-duplex, multi-drop RS485: * DM6446 (CPU) UART2 (/dev/ttyS2) * MAX3485 transceiver * TXEN connected to RTS Your software must assert/de-assert RTS manually (see [#rs485-example] example code) or the uart driver would need to be modified to add TIOCSRS485 ioctl support. [=#laguna-rs485] === Laguna === The GW16067 IO Expansion module for the GW2380/2/3 supports half-duplex, multi-drop RS485: * CNS3xxx UART2 (/dev/ttyS2) * MAX3485 transceiver * TXEN connected to gpio3 * '''optional termination (R5) * 4.75k pull-up on D+, 4.75k pull-down on D- (bus defaults to logic 1 - never idle) By 'optional' this means the baseboard design supports this, but it is not loaded on standard product therefore would be a Gateworks Special. Contact sales@gateworks.com if interested to see if a configuration already exists. Your software must assert/de-assert gpio3 manually (see [#rs485-example] example code) or the uart driver would need to be modified to add TIOCSRS485 ioctl support. [=#ventana-rs485] === Ventana === The GW52xx/GW53xx/GW54xx support optional half-duplex, multi-drop RS485: * IMX6 UART1 (/dev/ttymxc0) * MAX14840 transceiver * TXEN connected to gpio193 * '''optional termination * '''optional D+ pull-up and D- pull-down By 'optional' this means the baseboard design supports this, but it is not loaded on standard product therefore would be a Gateworks Special. Contact sales@gateworks.com if interested to see if a configuration already exists. Your software must use the TIOCSRS485 ioctl to configure TXEN (see [#rs485-example] example code). The GW551x + GW16111 breakout module support half-duplex, multi-drop RS485: * IMX6 UART2 (/dev/ttymxc1) - Note that a jumper must be placed on '''J10:2-3''' to enable RS485 RX (routes UART2 RX to RS485 vs RS232 transceiver) - Note that a jumper must be placed on '''J10:1-2''' to enable RS232 (routes UART2 to RS232 transceiver) * MAX14840 transceiver * TXEN connected to gpio19, or always enabled, or enable on transmit (selected via J10 jumper) - '''always drive mode''' - jumpers placed on '''J10:2-3''' and '''J10:4-5''' will cause the transceiver to always have its transmit enabled. This is useful for fast signal switching (fast/large bus) if you are using a single master and one or more receivers. - '''TXD drive mode''' - jumpers placed on '''J10:2-3''' and '''J10:7-8''' will cause the transceiver to be enabled only when TX is asserted. Because there are 4.75k pull's on D+/D- the bus is never 'idle'. This is useful for multi-master scenarios but could pose issues with fast/large busses if the 4.75pull's are not strong enough to switch the signals quick enough. - '''DIO-drive mode''' - jumpers placed on '''J10:2-3''' and '''J10:7-8''' will cause the transceiver to be enabled only when IMX_DIO1 (gpio19) is asserted high. This is useful for fast/large busses where the TXD drive mode doesn't provide fast enough switching. If using this mode you either need to manage the assertion/de-assertion of gpio19 in usersapce or modify the GW551x device-tree to configure rs485-txen for TIOCSRS485 support by adding '''fsl,rs485-gpio-txen = <&gpio1 19 GPIO_ACTIVE_HIGH>;''' to the uart2 device-tree node in arch/arm/boot/dts/imx6qdl-gw551x.dtsi * 121ohm termination can be enabled by placing a jumper on '''J10:9-10''' * 4.75k pull-up on D+, 4.75k pull-down on D- (bus defaults to logic 1 - never idle) [=#rs485-example] === Example Application === Here is an example application that uses the TIOCSRS485 ioctl to configure RS485 for drivers that directly control the transmit enable: {{{#!c #include #include #include #include #include #include #include #include #include #include /** main function */ int main(int argc, char** argv) { struct termios orig_ttystate, ttystate; int fd, sz, rz, bytes; speed_t speed; const char *baud, *mode, *dev, *txen = NULL; int timeout = 2; // time in seconds to wait for response char *msg; char buf[8192]; time_t start; if (argc < 5) { fprintf(stderr, "usage: %s []\n", argv[0]); exit(1); } dev = argv[1]; baud = argv[2]; mode = argv[3]; msg = argv[4]; if (argc > 5) txen = argv[5]; // open device fd = open(dev, O_RDWR | O_NONBLOCK | O_NOCTTY); if (fd <= 0) { perror("open"); exit(-1); } // get original ttystate tcgetattr(fd, &orig_ttystate); // create a sane TTY state (raw mode, no HW/SF flow control) memset(&ttystate, 0, sizeof(ttystate)); // enable receiver and ignore modem status lines ttystate.c_cflag |= CREAD; ttystate.c_cflag |= CLOCAL; // data-size ttystate.c_cflag &= ~CSIZE; switch(mode[0]) { case '5': ttystate.c_cflag |= CS5; break; case '6': ttystate.c_cflag |= CS6; break; case '7': ttystate.c_cflag |= CS7; break; case '8': ttystate.c_cflag |= CS8; break; default: fprintf(stderr, "invaid character size in %s\n", mode); break; } // parity ttystate.c_cflag &= ~PARODD; ttystate.c_cflag &= ~PARENB; switch(toupper(mode[1])) { case 'N': break; // no parity case 'O': ttystate.c_cflag |= (PARENB | PARODD); break; // odd case 'E': ttystate.c_cflag |= PARENB; break; // even default: fprintf(stderr, "invaid parity in %s\n", mode); break; } // stop bits switch(toupper(mode[2])) { case '1': ttystate.c_cflag &= ~CSTOPB; break; case '2': ttystate.c_cflag |= CSTOPB; break; default: fprintf(stderr, "invaid stop bit mode in %s\n", mode); break; } // baudrate switch(atoi(baud)) { case 1200: speed = B1200; break; case 2400: speed = B2400; break; case 9600: speed = B9600; break; case 19200: speed = B19200; break; case 38400: speed = B38400; break; case 57600: speed = B57600; break; case 115200: speed = B115200; break; case 230400: speed = B230400; break; case 460800: speed = B460800; break; default: fprintf(stderr, "invalid baud rate %s\n", baud); break; } if (cfsetispeed(&ttystate, speed)) perror("cfsetispeed"); if (cfsetospeed(&ttystate, speed)) perror("cfsetospeed"); // set tty state printf("setting ttystate\n"); if (tcsetattr(fd, TCSANOW, &ttystate)) perror("tcsetattr"); // configure rs485 if (txen) { struct serial_rs485 rs485; printf("enabling rs485 for %s txen\n", txen); memset(&rs485, 0, sizeof(rs485)); rs485.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; if (ioctl(fd, TIOCSRS485, &rs485)) perror("TIOCSRS485"); } // flush in/out data tcflush(fd, TCIOFLUSH); sz = atoi(msg); if (!sz) { sprintf(buf, "%s", msg); sz = strlen(msg) + 1; } printf("transmitting %d bytes...\n", sz); if (write(fd, buf, sz) != sz) perror("tx"); // receive data printf("reading...\n"); bytes = 0; memset(buf, 0, sizeof(buf)); start = time(NULL); while (1) { rz = read(fd, buf + bytes, sz - bytes); if (rz < 0) { perror("read failed"); break; } bytes += rz; if (bytes >= sz) break; if ((int)(time(NULL) - start) >= timeout) { printf("timeout\n"); break; } usleep(100000); } printf("received %d bytes in %ds\n", bytes, (int)(time(NULL) - start)); if (!atoi(msg)) printf("%s\n", buf); // restore terminal state tcsetattr(fd, TCSANOW, &orig_ttystate); close(fd); return 0; } }}} Ventana boards with on-board RS485 use ARM gpio193 as the TXEN and our Ventana BSP's support the TIOCSRS485 ioctl such that you do not need to manage the transmitter enable other than enable it and set its polarity when you configure the serial port: {{{#!c struct serial_rs485 rs485; memset(&rs485, 0, sizeof(rs485)); rs485.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; if (ioctl(fd, TIOCSRS485, &rs485)) perror("TIOCSRS485"); }}} If a board connects RTS, DTR, or a gpio to TX-Enable but does not support the TIOCSRS485 you can alter your code to enable/disable the TX-Enable as needed. For example the following function: {{{#!c /** write_file - write to a file * @param str to write * @param fname to write to * * This is used to set/configure GPIO's via the sysfs interface to gpio class */ int write_file(const char* str, const char* fname) { FILE *file; int ret = -EIO; file = fopen(fname, "w"); if (file) { ret = fprintf(file, "%s\n", str); if (ret <= 0) ret = -EIO; fclose(file); return 0; } return ret; } /** assert_tx - enable/disable TX on a device * @param dev - serial device * @param enable - enable or disable * @returns 0 on success otherwise error */ int assert_tx(int fd, const char *txen, unsigned char enable) { char str[64]; int t; if (!txen) return 0; printf("%sasserting %s\n", (enable)?"":"de-", txen); if (strcasecmp(txen, "DTR") == 0) { // assert DTR on enable, de-assert on disable t = TIOCM_DTR; return ioctl(fd, (enable)?TIOCMBIC:TIOCMBIS, &t); } else if (strcasecmp(txen, "RTS") == 0) { // assert RTS on enable, de-assert on disable t = TIOCM_RTS; return ioctl(fd, (enable)?TIOCMBIC:TIOCMBIS, &t); } else if (strncasecmp(txen, "gpio", 4) == 0) { t = atoi(txen + 4); sprintf(str, "/sys/class/gpio/gpio%d/value", t); write_file((enable)?"1":"0", str); } return 0; } int main(int argc, char **argv) { ... // txen is a string: DTR, RTS, or gpio if (txen && (0 == strncasecmp(txen, "gpio", 4))) { char str[64]; int gpio = atoi(txen + 4); printf("exporting gpio%d\n", gpio); sprintf(str, "%d", gpio); write_file(str, "/sys/class/gpio/export"); sprintf(str, "/sys/class/gpio/gpio%d/direction", gpio); write_file("out", str); sprintf(str, "/sys/class/gpio/gpio%d/value", gpio); write_file("0", str); // assuming TXEN active-high } // transmit data assert_tx(fd, txen, 1); // assert TXEN write(fd, buf, sz); // transmit data tcdrain(fd); //wait for all characters to be transmitted assert_tx(fd, txen, 0); // de-assert TXEN // receive data ... }}}