Linux-Powered Amateur Rocket Goes USB

The next Portland State Aerospace Society rocket, scheduled for first launch this summer, will have new hardware, including a switch from CAN to USB.

LPC2148 USB Device

The more interesting project is to get the LPC2148 to communicate
over USB. The LPC2148
supports four different USB transfer types: control, bulk, interrupt and isochronous. A USB device can have
several data pipes, or “endpoints”, that implement one of the transfer
types. Each endpoint can either send data to the host (an IN endpoint)
or send data from the host (an OUT endpoint). Control endpoints are
bidirectional.

All USB devices must have one control endpoint over which to send their device
descriptors. PSAS needed one other IN endpoint to send over periodically
sampled sensor data, so we wanted either an interrupt or an
isochronous IN endpoint. We always want to receive the latest data, so we
chose the isochronous IN endpoint, because the host controller software
will never attempt to retry a dropped isochronous transfer. Isochronous
endpoints also could be used to turn the LPC2148 into a USB camera.

Dave and Kay recently added isochronous transfer and DMA support to the
LPCUSB library. To try it out, you need to check out the latest code from
the LPCUSB SVN repository:

$ svn co https://lpcusb.svn.sourceforge.net/svnroot/lpcusb lpcusb

I checked out version 177 into my $HOME/svn/ directory. Throughout these
examples, I assume you use the same directories.

There should be an isochronous example in lpcusb/trunk/target/examples/
called isoc_io_dma_sample.c. This is a simple program for the LPC2148
that creates two isochronous endpoints. The IN isochronous endpoint
sends a counter value into the host and then increments the counter. The
OUT endpoint allows the host to control whether LED1 on the board is on
or off.

To build the isoc example, change directories to lpcusb/trunk/target and
type make. You now should have a file called isoc_io_dma_sample.hex
in the examples directory.

Now you need to flash the .hex file to the LPC2148 board. You need to
use the OpenOCD config file from the lpc-kit, and modify the OpenOCD
script to download the correct .hex file.

If you've followed the instructions, LED2 on the Olimex board will start
to blink incessantly, and you should see an OpenOCD message similar to the
following:

wrote 9454 byte from file isoc_io_dma_sample.hex
in 0.994377s (9.284629 kb/s)

Close the connection by pressing Ctrl-] and then Ctrl-D. Kill the OpenOCD
dæmon in the other terminal by typing Ctrl-C. Remove the JTAG connector,
press the LPC2148 reset button, and connect a USB cable from the Olimex
board to your computer's USB port. Make sure to plug in to a root port,
not through a USB hub. Some hubs have issues with isochronous transfers,
so a direct connection is best. You can power the LPC2148 solely off
USB bus power, but I left the 9V wall wart plugged in.

If you have CONFIG_USB_DEBUG turned on in your Linux kernel config,
you will be able to watch the USB subsystem connect to the USB device
as you plug it in:

You can use the -v flag to examine the full device descriptors. This
outputs all descriptors for all devices, so it's best to limit the output
to the LPC2148 device with the -d <ID> option:

$ sudo lsusb -v -d ffff:0005

You should see two endpoint descriptors, one for an isochronous OUT
endpoint and one for an isochronous IN endpoint.

Congratulations! The Linux kernel can initialize the LPC2148
USB device successfully. Unfortunately, there is no standard Linux USB kernel driver
for this device. Instead, you need to compile and run a user-space program
that uses the Linux kernel USB interface (usbfs) to talk to
the device directly.

First, you need to have the libusb-dev package installed to get the
usb.h header file for usbfs:

$ sudo aptitude install libusb-dev

Now, change directories into the lpcusb host-side code examples:

$ cd ~/svn/lpcusb/trunk/host/linux_isoc_sample/

Type make. This creates src/linux_usbfs_isoc_io_test, a binary that
needs to run as root. Type sudo
src/linux_usbfs_isoc_io_test to talk
to the USB device. You will see lots of messages scroll by, similar to the
following:

The start_frame is the USB bus “frame number” in which the
transfer started. A frame represents a one millisecond time period. As long as you see
steadily incrementing start_frame numbers, you know the system isn't
dropping isochronous packets. The hexidecimal “number sent from
device”
is the counter on the LPC2148 that is incremented when the interrupt
handler is run and there's an isochronous IN transfer to send to the host.

The isochronous IN endpoint is working correctly if the start_frame and
device counter are incremented at the same rate. They may be out of sync
for the last couple transfers when you kill the program by pressing
Ctrl-C. You also can tell whether the isochronous OUT endpoint is working if
the LED1 on the board turns on and off every second.