Linux-Powered Amateur Rocket Goes USB
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.
First, copy the OpenOCD template script from lpc-kit:
$ cd ~/svn/lpcusb/trunk/target/examples/ $ cp ~/git/lpc-kit/Dev/2148/lpc-template/src/ ↪oocd_flash_lpc2148.script .
Also, copy the OpenOCD config file into the LPCUSB examples directory:
$ cp ~/git/lpc-kit/Config/2148/openocd_lpc2148_v1257.cfg .
Now, modify the script to tell OpenOCD to send the isoc_io_dma_sample.hex file to the LPC2148. Change this line:
flash write_image template.hex 0x0 ihex
flash write_image isoc_io_dma_sample.hex 0x0 ihex
Next, start the OpenOCD dæmon:
$ sudo ~/git/lpc-kit/LPC/2148/OCD/bin/openocd \ -f openocd_lpc2148_v1257.cfg
From another terminal, Telnet into the OpenOCD port, and then tell OpenOCD to run the modified script:
$ cd ~/svn/lpcusb/trunk/target/examples/ $ telnet localhost 4444 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Open On-Chip Debugger > script oocd_flash_lpc2148.script
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:
$ sudo tail -f /var/log/kern.log ... usb 2-2: New USB device found, idVendor=ffff, idProduct=0005 ... usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 ... usb 2-2: Product: USBSerial ... usb 2-2: Manufacturer: LPCUSB ... usb 2-2: SerialNumber: DEADC0DE
Type sudo lsusb to see which USB devices are connected to your system. You should see a device with an ID of ffff:0005. For me, it showed up as device 15:
$ sudo lsusb Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 015: ID ffff:0005 Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
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:
Bytes/second 1226 Input Length 4 number sent from device 0x3116D4 ret 0 status 0 flag 2 error_count 0 number_of_packets 1 actual_length 0 start_frame 614 usercontext -1077961592 iso_frame_desc.actual_length 0 iso_frame_desc.length 128 iso_frame_desc.status 0 Bytes/second 1228 Input Length 4 number sent from device 0x3116D5 ret 0 status 0 flag 2 error_count 0 number_of_packets 1 actual_length 0 start_frame 615 usercontext -1077961592 iso_frame_desc.actual_length 0 iso_frame_desc.length 128 iso_frame_desc.status 0
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.
|Designing Electronics with Linux||May 22, 2013|
|Dynamic DNS—an Object Lesson in Problem Solving||May 21, 2013|
|Using Salt Stack and Vagrant for Drupal Development||May 20, 2013|
|Making Linux and Android Get Along (It's Not as Hard as It Sounds)||May 16, 2013|
|Drupal Is a Framework: Why Everyone Needs to Understand This||May 15, 2013|
|Home, My Backup Data Center||May 13, 2013|
- Designing Electronics with Linux
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Dynamic DNS—an Object Lesson in Problem Solving
- Using Salt Stack and Vagrant for Drupal Development
- Build a Skype Server for Your Home Phone System
- New Products
- Validate an E-Mail Address with PHP, the Right Way
- Why Python?
- A Topic for Discussion - Open Source Feature-Richness?
- Tech Tip: Really Simple HTTP Server with Python
32 min 52 sec ago
- Reply to comment | Linux Journal
40 min 53 sec ago
- Understanding the Linux Kernel
2 hours 55 min ago
5 hours 25 min ago
- Kernel Problem
15 hours 28 min ago
- BASH script to log IPs on public web server
19 hours 55 min ago
23 hours 30 min ago
- Reply to comment | Linux Journal
1 day 3 min ago
- All the articles you talked
1 day 2 hours ago
- All the articles you talked
1 day 2 hours ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi
It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?