Skip to main content

Serial Port I/O

Until about 20 years ago, most desktop and portable computers had serial and parallel ports built in.  Those ports were great for controlling and testing home brew gadgets.  Modern machines are blessed/cursed with USB ports, which are just getting more and more complex.

The result is that if you want to do anything at all in your Underground Lab or Rooftop Radio Shack, you need an Arduino,  a Raspberry or a Beaglebone embedded computer.

However, every respectable engineer has two or three FTDI USB to RS232 serial adaptors lying in a drawer (to control his Raspberry or Beaglebone).  These adaptors are great, since they effectively insulate your target system from your expensive computer, therefore whatever goes wrong on the far end, is unlikely to fry your machine and they are delightfully hackable.

I prefer the dongles made by SerialComm.  They are cheap and both RS232 and RS422/485 are available.

You can also get ones from Sparkfun that are even more hackable, or you can crack the case and remove the line driver chip from a regular off the shelf one if you are desperate for TTL I/O lines.

The secret Open Sauce is the libftdi project, which is available for Linux and Mac systems. Documentation and examples are here.  The online files are the latest and greatest.  Therefore it may be best to work with the header file on your machine which is /usr/include/ftdi.h since your installed version of the library may be older and some functions may be deprecated or missing.

Simple Bitbanging with libftdi

Here is a tiny little C program for an older version of libftdi, that will toggle the Tx, DTR and CTS lines on a USB RS232 adaptor.  Note that you have to run it as root (or join some or other USB group), otherwise the USB device will not open.

/* File flasher.c */
/* libftdi API Example LED Flasher */

#include <stdio.h>
#include <ftdi.h>

/* RS232 DE9 pins */
#define DCD 0x40 /* 1 in */
#define RX  0x02 /* 2 in */
#define TX  0x01 /* 3 out */
#define DTR 0x10 /* 4 out */
#define DSR 0x20 /* 6 in */
#define RTS 0x04 /* 7 out */
#define CTS 0x08 /* 8 in */
#define RI  0x80 /* 9 in */
/* 5 GND */


int main()
{
    unsigned char data = 0;
    unsigned char pins = TX | DTR | RTS;
    struct ftdi_context context;

    /* Initialize libftdi */
    ftdi_init(&context);

    /* Open FTDI dongle using FT232RL vendor & product IDs */
    if(ftdi_usb_open(&context, 0x0403, 0x6001) < 0) 

    {
        puts("ERROR: ftdi_usb_open()");
        return 1;
    }

    /* Set bitbang mode on the RS232 output pins */
    ftdi_enable_bitbang(&context, pins);

    /* Forever */
    for(;;) 

    {
        data ^= pins;
        ftdi_write_data(&context, &data, 1);
        sleep(1);
    }
}


Improved Bitbanging with libftdi

Here is a more advanced program with proper error checking.  Note that you have to run it as root (or join some or other USB group), otherwise the USB device will not open.

/* File flasher.c */
/* libftdi.so API Example LED Flasher */
/* Copyright reserved Herman Oosthuysen, 2015 */
/* License: GPL version 2 or later */
/* Use at your own peril */

#include <stdio.h>
#include <stdlib.h>
#include <ftdi.h>

/* RS232 DE9 pins */
#define DCD 0x40 /* 1 in */
#define RX  0x02 /* 2 in */
#define TX  0x01 /* 3 out */
#define DTR 0x10 /* 4 out */
#define DSR 0x20 /* 6 in */
#define RTS 0x04 /* 7 out */
#define CTS 0x08 /* 8 in */
#define RI  0x80 /* 9 in */
/* 5 GND */


int main()
{
    int i;
    int ret;
    unsigned char data = 0;
    unsigned char outputs = TX | DTR | RTS;
    struct ftdi_context *ftdi;

    /* Initialize libftdi */
    printf("FTDI Initialize\n");
    ftdi = ftdi_new();
    if (ftdi == NULL)
    {
        fprintf(stderr, "ERROR: ftdi_new()\n");
        return EXIT_FAILURE;
    }

    ret = ftdi_init(ftdi);
    if (ret < 0)
    {
        fprintf(stderr, "ERROR: ftdi_init() = %d\n", ret);
        ftdi_free(ftdi);
        return EXIT_FAILURE;
    }

    /* Open FTDI dongle using FT232RL vendor & product IDs */
    /* Plug the device in and run 'dmesg' to see these codes */
    printf("FTDI USB Open\n");
    ret = ftdi_usb_open(ftdi, 0x0403, 0x6001);
    if (ret < 0)
    {
        fprintf(stderr, "ERROR: ftdi_usb_open() = %d\n", ret);
        ftdi_free(ftdi);
        return EXIT_FAILURE;
    }

    /* Set bitbang mode on the RS232 output pins */
    /* pins: Output = 1, Input = 0 */
    printf("FTDI set Bitbang Mode\n");
    ret = ftdi_set_bitmode(ftdi, outputs, BITMODE_BITBANG);
    if (ret < 0)
    {
        fprintf(stderr, "ERROR: ftdi_set_bitmode() = %d\n", ret);
        ftdi_free(ftdi);
        return EXIT_FAILURE;
    }

    /* Flash for a little while */

    /* Note: Use ftdi_read_pins() to read data directly */
    printf("FTDI Flashing...\n");
    for(i = 0; i < 10; i++)
    {
        printf("%d\r", i);
        data ^= outputs;
        ret = ftdi_write_data(ftdi, &data, sizeof(data));
        if (ret < 0)
        {
            ftdi_free(ftdi);
            fprintf(stderr, "ERROR: ftdi_write_data() = %d\n", ret);
            return EXIT_FAILURE;
        }
        usleep(500000);
    }

    /* Done */
    printf("\nDone\n");
    ret = ftdi_usb_close(ftdi);
    if (ret)
    {
        ftdi_free(ftdi);
        fprintf(stderr, "ERROR: ftdi_usb_close() = %d\n", ret);
        return EXIT_FAILURE;
    }

    ftdi_free(ftdi);
    return EXIT_SUCCESS;
}


CBUS Discretes

In addition to the 8 lines used for RS232, there are 4 more, which are used to control the LEDs and RS485 drivers.  These lines can be controlled in a similar fashion using BITMODE_CBUS.  It is not clear whether one can interleave the two bitbashing modes in order to control all 12 lines at the same time and whether the lines will glitch if one does. See this example.

I also read that one can use the CBUS bitbashing concurrently with the normal serial mode, to provide a UART plus 4 discretes, but I have not tried it.

Compile and Test

Assuming that your Linux machine is configured properly with GCC, compile it thus:
$ gcc -o flasher flasher.c -lftdi
$ chmod 754 flasher

Now stick a LED with a 1k resistor in series onto the RS232 adaptor Tx and Gnd pins to see how it works and run it:
$ ./flasher

Install and Configuration of libftdi

If you don't have a GCC and libftdi configured system yet, then assuming that you have Fedora Linux:
$ su -
# yum update

# yum install kernel-headers

# yum groupinstall "Development Tools" "Development Libraries"
# yum install libftdi libftdi-devel

Now you can control the world!

Cmake

Also see the next post on Makefiles

Serial Port Tips

www.aeronetworks.ca/2015/01/serial-port-io.html
www.aeronetworks.ca/2014/10/serial-ports-revisited.html
www.aeronetworks.ca/2014/01/crcs-and-serial-ports.html
www.aeronetworks.ca/2013/10/serial-port-tricks.html
www.aeronetworks.ca/2013/05/usb-serial-device-with-unknown-ids.html
www.aeronetworks.ca/2015/10/reading-and-parsing-data-from-serial.html
www.aeronetworks.ca/2013/05/compile-moxa-serial-widget-device.html

La voila,

Herman

Comments

  1. This is a nice combo:
    http://www.serialcomm.com/USB_adapters/USB_converters/usb_to_5v_ttl_adapter/usb_to_5v_ttl_adapter.product_general_info.aspx

    ReplyDelete

Post a Comment

On topic comments are welcome. Junk will be deleted.

Popular posts from this blog

OpenEMS with Octave and SciLAB

I wanted to do some advanced RF antenna development work and needed an electromagnetic field solver that is a bit more up to date than NEC2 .  Commercial solvers from Matlab , Ansys and others are hideously expensive (in the order of $20,000 to $50,000) and do not fit in the wallet of a hobbyist or a small consulting company.  Recently, openEMS became available and it fills the niche with a capable free tool.  In general, openEMS is a solver - a Finite-Difference Time-Domain (FDTD) numerical engine.  You interact with it through Octave , which is almost identical to Matlab .  You can watch a good video by Thorsten Liebig here: https://www.youtube.com/watch?app=desktop&v=ThMLf0d5gaE   Getting it to work is a little painful, but it is free, so bear with it - then save a backup clone, or a zipped copy of the whole virtual machine directory and NEVER update it, to ensure that it keeps going and doesn't get broken by future updates, right when you are ...

Parasitic Quadrifilar Helical Antenna

This article was reprinted in OSCAR News, March 2018:  http://www.amsat-uk.org If you want to receive Satellite Weather Pictures , then you need a decent antenna, otherwise you will receive more noise than picture. For polar orbit satellites, one needs an antenna with a mushroom shaped radiation pattern .  It needs to have strong gain towards the horizon where the satellites are distant, less gain upwards where they are close and as little as possible downwards, which would be wasted and a source of noise.  Most satellites are spin stabilized and therefore the antenna also needs circular polarization, otherwise the received signal will flutter as the antennas rotate through nulls. The helical antenna, first proposed by Kraus in 1948, is the natural solution to circular polarized satellite communications.  It is a simple twisted wire - there seems to be nothing to it.  Various papers have been published on helix antennas, so the operation is pretty well ...

Yagi Antenna for 900 MHz ISM Band

I like tinkering with wire antenna designs, since they are simple and cheap to make.  Mr Yagi invented his antenna about 100 years ago, but there are still some things left to learn about it. 900 MHz ISM Band Yagi The 900 MHz ISM band ranges from 902 to 928 MHz.  Covering the whole band with a single Yagi antenna is difficult, since they are inherently narrow band devices.  Consequently some tweaking is required and the result below is a desensitized design that can be built and replicated quite easily, but you need a network analyzer - "To Measure, is to Know!" A Yagi generally consists of a Reflector, Radiator and one or more Director elements, arranged on a boom.  For a small Yagi, a wooden ruler works a treat, since one can easily mark the position of the wires.  The wire elements are fastened to the bottom of the ruler with hot glue.  The wire elements are  made from straightened out jumbo size paper clips.  The balun, is tw...