- Written by Akiba
Okay, just got my Sourceforge account approved so you can pick up the files from SourceForge now. The address is:
You can also access the Subversion repository at:
- Written by Akiba
Well, now that I published a USB device stack, I guess I should say a couple words about it. Most people are probably thinking that I got tired of Zigbee and went to something easier. Uhhh...yeah...actually, that's pretty true. Actually, I didn't get tired of Zigbee, but I thought it would be a nice change of pace to work on something different, since it's been over seven months of straight Zigbee.
A USB device stack is actually much easier than Zigbee, and after wrestling with the FreakZ stack for so long, I've pretty much gotten a good feel for the flow of protocol stack architecture. All protocol stacks share a couple of common features:
- They need an event handling system
- They need a buffer management system
- They all decode chunks of data into smaller chunks of data
With that framework in mind, it wasn't too bad to crank out the USB stack. The event handling system is just some flags contained in the protocol control block. Since USB is basically a transport protocol with no routing involved, you just need to handle basic Tx and Rx events and the occasional management event (control transfer). That's why you can just use a couple of flags and check them in a polling loop.
There's not a lot of sophisticated timeout mechanisms or waiting for simultaneous events on the device side so there was no real need for an OS or an OS-type of setup. In fact, the USB protocol was implemented so that the device side can be made small and cost-efficient, while the host has to shoulder the majority of the work. That's because the host is usually a PC and the USB-IF decided that the PC had much more horsepower than the USB devices should have.
For buffer management, I used an array of buffers configured as circular FIFOs. Circular FIFOs are more efficient than a straight buffer because you can keep on writing to them as long as they have space. They make sense in cases where there is a well-defined number of data sources or sinks. One good example would be an ethernet router with a fixed number of ports. You would normally have some type of buffer or FIFO mechanism to handle data transport for each port.
That type of setup wouldn't work well for a protocol stack like Zigbee because there isn't a well defined number of data sources. Since Zigbee is a routing protocol, and wireless at that, you can have a (theoretically) infinite number of devices sending data to you and some would be meant for you while others are meant to be forwarded. In that case, a FIFO mechanism wouldn't be very ideal because you wouldn't know how many FIFOs you needed. There is no defined number of ports, and even though Zigbee has a defined number of endpoints for a profile, you still have to take into account that some incoming frames will never go to those endpoints because they need to be forwarded.
Anyways, I don't want to get into too many details about protocol stacks, but I do feel like I'm starting to get the hang of writing them. At least I can make the tough architectural decisions faster than I used to.
Regarding the USB stack, the memory footprint is about 4kB of flash and 100 bytes of RAM. Actually, I made a performance tradeoff to reduce the amount of RAM I used. For full-speed (12 Mbps) USB, the max packet size for a bulk transfer is 64 bytes. However since I implemented a serial port emulator (Virtual COM Port), there wasn't really a need to transfer 64 bytes at a time. In fact, the vast majority of transfers will probably be one byte. So I tweaked the endpoint settings in the descriptors so that the max packet size would only be 16 bytes. That way, I could use smaller buffers and was able to get the RAM usage down to about 100 bytes. There is a slight delay in responding to the control transfers, but most hosts allow a couple of seconds delay before timing them out. Basically, there shouldn't be any performance impact for standard serial emulator applications (ie: printf) but there is a large reduction in RAM. Hmph...an easy choice.
It is also possible to reduce the code size, but I think that any major reduction in code size would come at the expense of readability and portability. One of the main reasons why I decided to design the USB stack was because there is an apparent lack of open source, portable USB stacks available. The only ones I found were vendor-made or tied so closely to the hardware that porting them to a different platform would have probably taken longer than writing one from scratch. With that in mind, I tried to write the stack in more of a modular way so that I can port it over to other platforms in the future. The main targets I have in mind are the TI MSP430 and ARM-based MCUs which usually have a built-in USB device.
And that brings me to the reasons why I wrote the stack. Actually, it's nothing really noble. I was just working on a demo for the disti that I contract with, but I ran into a situation where USB was required instead of a serial port. I had originally planned to use the Atmel USB stack since I was using an AVR, but the stack would intermittently crash on me. So I made the decision to write my own.
Even if I had found an open source stack, I probably would have written my own, since I needed something that I could support myself, and that I could port easily. Basically, after I started really thinking seriously about it, I figured that it would be a good to tool to have in my kit. I mean, there are only a couple of communication stacks that are essential today. I would say that for wired protocols, USB and TCP/IP over ethernet can pretty much cover 90% of most design needs. TCP/IP handles internet connectivity and USB handles interfacing to a PC. TCP/IP is already taken care of with Contiki and the uIP stack and that just left USB.
Hmmm....I can feel myself rambling now...
Anyways, the first release of the USB stack is now available from this site and I'll be updating the site to have a Projects section for the FreakZ stack and the USB stack. By the way, I chose the name FreakUSB not because it was boring, but because I liked the initials...F.U. heh, heh...
For F.U., only a Virtual COM device is implemented for now. In the future, I hope to add things like a mass storage class driver and other ones that are useful. However the Virtual COM device is probably one of the best devices for engineers since it allows you to use to send print statements over the USB to your terminal program (and believe me, most software programmers are on laptops with no serial ports), and it also provides a source of power for your board. A double whammy!
I've already written a putchar function in the demo and hooked it into the printf library implemented by avr-libc so you can do printf's over the USB. One interesting thing about sending serial data over USB is that you're not really tied down to the baud rate. The line settings for virtual serial ports are just for decoration or so that you can configure the UART on the other side of the USB serial bridge for those settings. However if you're not bridging to a UART, but communicating with a PC directly over the USB, there are no baudrate limitations. You should be able to go all the way up until you top out the USB bitrate. I'll need to do more testing, but it may be possible to use Virtual COM as an easy way to interface designs to a PC at a high speed, rather than writing a custom USB PC driver. I'll need to do more research on that, but it does have some possibilities. I can just hear those streaming MP3s over 802.15.4 now...uhhh...of course only on radios that have a non-compliant high speed mode (Freescale/Atmel)....
Well, I guess that's about it. I originally thought I would just write a few words, but it's turned into miscellaneous ramblings. I guess the wine is starting to kick in.