Tag Archives: ttyACM

udev file for Texas Instruments LaunchPads

To be able to use the various devices on Linux as an unprivileged (non-root) user, it is required to configure udev in such a way that appropriate authorizations are assigned to it upon plugging in the device.

For both the MSP430 and the Stellaris LaunchPad I’ve developed a simple but safe udev rules file, based on its configured serial number. This means that even when more than one LaunchPad is attached to the system, it will get a unique identifier that survives reboots. Every LaunchPad supplied by TI has a unique serial number configured upon delivery.

Retrieving the serial number

To be able to create a unique device name that survives a reboot, it is essential to retrieve the serial number of the device. This can easily be done by following these instructions:

  1. Detach the LaunchPad from the system;
  2. On the command line type (this requires the expect-dev package being installed): unbuffer udevadm monitor --environment | grep 'ID_SERIAL='
  3. Plug in the LaunchPad. Notice that MSP430 takes about 10 seconds to fully register with the system.
  4. Output similar like this is displayed for MSP430:ID_SERIAL=Texas_Instruments_Texas_Instruments_MSP-FET430UIF_36FF49ABB1D22050
  5. Output similar like this is displayed for Stellaris:ID_SERIAL=Texas_Instruments_In-Circuit_Debug_Interface_0E10A714

Creating the udev rules file

With this knowledge we can build the the udev rules file:

ACTION!="add", GOTO="persistent_serial_end"
SUBSYSTEM!="tty", GOTO="persistent_serial_end"
KERNEL!="ttyACM[0−9]*", GOTO="persistent_serial_end"

ENV{ID_SERIAL}=="Texas_Instruments_In−Circuit_Debug_Interface_0E10A714" , SYMLINK="stellaris−001" , OWNER="jhendrix" , MODE:="0600"
ENV{ID_SERIAL}=="Texas_Instruments_Texas_Instruments_MSP−FET430UIF_36FF49ABB1D22050" , SYMLINK="msp430−001" , OWNER="jhendrix" , MODE:="0600"

  1. Edit lines 6 and/or 7 to contain the serial number found in the previous paragraph. Notice that only the part between double quotes needs to be edited. Of course you need as many lines as you own LaunchPads. I currently own two, so I have two lines.
  2. Where it says “jhendrix“, change that to your own username under which you will be working with the device.
  3. Save the file as /etc/udev/rules.d/60-ttyACM.rules

Using the the rules file

  1. Reload udev:
    sudo udevadm control --reload
  2. Unplug the LaunchPad;
  3. Plug the LaunchPad and wait a couple of seconds;
  4. Check the device file:ls -l /dev | grep ttyACM
    lrwxrwxrwx 1 root root 7 Feb 2 21:57 msp430-001 -> ttyACM1
    lrwxrwxrwx 1 root root 7 Feb 2 21:23 stellaris-001 -> ttyACM0
    crw------- 1 jhendrix dialout 166, 0 Feb 2 21:23 ttyACM0
    crw------- 1 jhendrix plugdev 166, 1 Feb 2 21:57 ttyACM1
  5. From this moment onward you can use the Launchpad under any of the devices listed:
    1. msp430-001 and stellaris-001 will survive a reboot;
    2. ttyACM0 and ttyACM1 are dynamic, they change according of attaching the devices.
  6. If the demo program is loaded that Stellaris comes with, you can access it from now on by typing:screen /dev/stellaris-001 115200

TI MSP430 LaunchPad Temperature Demo Application


When you receive a new Texas Instruments MSP430 LaunchPad, it comes with a small demo application installed so you can easily check its functionality. The interesting thing is that it also interfaces with the PC through a virtual serial interface, but reading the data from a Linux PC appears to be non-trivial. This is partially caused by the fact that the user’s guide states that the demo application can be read with any serial console application, which in practice just doesn’t always work.

Attaching the LaunchPad

When an MSP430 LaunchPad is attached to the system, dmesg logs a few lines similar like these:

[19:52:40] usb 2-2.3: new full-speed USB device number 85 using ehci_hcd
[19:52:40] usb 2-2.3: New USB device found, idVendor=0451, idProduct=f432
[19:52:40] usb 2-2.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[19:52:40] usb 2-2.3: Product: Texas Instruments MSP-FET430UIF
[19:52:40] usb 2-2.3: Manufacturer: Texas Instruments
[19:52:40] usb 2-2.3: SerialNumber: 36FF49ABB1D22050
[19:52:40] cdc_acm 2-2.3:1.0: This device cannot do calls on its own. It is not a modem.
[19:52:40] cdc_acm 2-2.3:1.0: No union descriptor, testing for castrated device
[19:52:40] cdc_acm 2-2.3:1.0: ttyACM0: USB ACM device
[19:52:50] hid-generic 0003:0451:F432.003E: usb_submit_urb(ctrl) failed: -1
[19:52:50] hid-generic 0003:0451:F432.003E: timeout initializing reports
[19:52:50] hid-generic 0003:0451:F432.003E: hiddev0,hidraw3: USB HID v1.01 Device [Texas Instruments Texas Instruments MSP-FET430UIF] on usb-0000:00:1d.7-2.3/input1

According to line 9 of this logging, in this case the LaunchPad is attached to the system as ‘/dev/ttyACM0′.

Reading the data from MSP430 LaunchPad

For me only minicom (2400 8N1) was showing some data, but in contrast to what I understood from the user’s guide the received data is binary, not in ASCII.  I wrote a quick and dirty Perl script that easily allows for reading the data.

After attaching the LaunchPad and pressing button P1.3 on it, it starts to send data several times per second. Running the script below from the command line, outputs the current temperature.

Receiving serial data ...
22.2C 22.2C 22.8C 22.8C 22.8C 22.2C 22.8C 22.8C
22.2C 22.8C 22.8C 22.8C 22.2C 22.8C 22.8C 22.8C
22.8C 22.8C 22.8C 22.8C 22.8C 22.2C 22.2C 22.8C

The script is no rocket science, its main goal is to prove the LaunchPad is working properly and to act as a starting point for others.


use warnings;
use strict;

use Device::SerialPort;
use Time::HiRes qw( usleep );

my $PortName = '/dev/ttyACM0';
my $PortObj;
$| = 1;

print STDERR "Waiting for serial port ...\n";
while ( not( $PortObj = new Device::SerialPort ($PortName, 'false' ) ) ) {
print STDERR "Waiting: Cannot open serial port: $!\n";
sleep( 1 );

$PortObj->databits( 8 );
$PortObj->baudrate( 2400 );
$PortObj->parity( "none" );
$PortObj->stopbits( 1 );
$PortObj->handshake( "none" );

print STDERR "Receiving serial data ...\n";
my $newline = 8;
while ( 1 ) {
if ( not $newline ) {
# print 8 values per line
print "\n";
$newline = 8;
# try to read a byte of data
my ( $count, $data ) = $PortObj->read( 1 );
if ( ( defined( $count ) ) and ( $count != 0 ) ) {
# if data available, then convert from Fahrenheit to Celcius
printf( "%3.1fC " , ( ( ord( $data ) - 32 ) * 5 / 9 ) );
usleep( 100000 ); # wait 100ms