How do you write a USB stack? - Page 1
Forum section: electronics / general

author: technix
author_rank: Super Contributor
timestamp: September 25, 2016, 04:28:31 pm
content: So far I have a few chips that have USB hardware built in: PIC18F4550, ATmega32U4, its smaller sibling ATmega16U2, STM32F103ZE and its smaller sibling STM32F103CB. However I have absolutely no idea how to write a USB stack.I tried to read the USB protocol manuals but those documents are more like a barrier for newcomers. I don't really want to use those open-source USB stacks as those are usually not portable (since I have three system architectures to tackle) and have restrictive licensing terms (GPL that somehow propagates to the hardware itself)

author: ataradov
author_rank: Super Contributor
timestamp: September 25, 2016, 06:51:46 pm
content: Working with USB without libraries is really tough, it is a very poorly designed interface with a bunch of legacy stuff.I struggled with this quite a bit, but eventually came up with a simple stack architecture that is reasonably portable. You can find the code for Atmel SAM D21 herehttps://github.com/ataradov/dgw/tree/master/embedded.In theory code in usb.c, usb.h, usb_descriptors.c and usb_descriptors.h is universal and portable. And udc.c and udc.h contain all platform code with very limited APIs that should be easy to implement.The downside of this approach is that you mask out all potential hardware features that can improve the performance of your stack. In this case simplicity was the goal, so all advanced USB controller features are not used.In general creating USB stack is a pain, and you will find out just how buggy USB host implementations are in Windows and Linux. I would recommend using a separate machine for testing your stack at the beginning - you will have to reboot that machine many times.

author: rstofer
author_rank: Super Contributor
timestamp: September 25, 2016, 07:16:04 pm
content: Almost every uC manufacturer will have USB code for their processors. I would certainly start with that code.I might read the book:http://s.eeweb.com/members/mark_harrington/answers/1333179451-USB_Complete_3rdEdition.pdf

author: ataradov
author_rank: Super Contributor
timestamp: September 25, 2016, 07:17:48 pm
content: Quote from: rstofer on September 25, 2016, 07:16:04 pmOnly if you actually want to use that code in the end. In my experience USB stacks are so bloated and have so may dependencies, that minimizing them is more work than writing a new one from scratch.

author: aandrew
author_rank: Frequent Contributor
timestamp: September 25, 2016, 09:30:40 pm
content: That's not been my experience, at least with STM32 and Cypress.The libraries *are* convoluted, but the code is relatively lean and get the job done. gcc does a pretty fine job at optimization on ARM (I usually use -Os) and while I really dislike going into the USB libraries themselves, they are functional and reasonable in size.

author: Fungus
author_rank: Super Contributor
timestamp: September 25, 2016, 10:28:46 pm
content: Start with the Arduino mouse/keyboard libraries. They're quite small.

author: KE5FX
author_rank: Super Contributor
timestamp: September 25, 2016, 10:32:17 pm
content: If you can possibly treat the USB connection as a virtual COM port, you should do that. The key to retaining your sanity in a USB project is to (re)invent as little as possible.

author: bobaruni
author_rank: Regular Contributor
timestamp: September 26, 2016, 01:06:45 am
content: If you are considering bit banging USB protocol then you will need a fairly fast MCU with very predictable instruction execution times.USB 1.1 should be doable on most modern MCUs with 12MIPS or more performace.Take a look at V-USB, this is a mature and well written bit banged USB 1.1 stack for AVR/ATTiny.https://www.obdev.at/products/vusb/index.htmlAlso have a look at Atmel's app note AVR309, there is a some info there to get you started if you want to roll your own.http://www.tuxgraphics.org/common/src2/article08101/avr309.pdf

author: technix
author_rank: Super Contributor
timestamp: September 26, 2016, 01:16:01 am
content: Quote from: blueskull on September 25, 2016, 10:35:54 pmA few USB libraries like V-USB have clauses that end up propagating its GPL-like license to the hardware itself. Not all of my hardware design are open source (some are not even suitable to be so,) and for the ones that are I may prefer a permissive license like BSD over GPL.

author: nctnico
author_rank: Super Contributor
timestamp: September 26, 2016, 01:19:20 am
content: I've wrote it before and I'll write it again: look into LUFA. It is a very versatile stack which should be easy to port if the hardware isn't already supported.

author: helius
author_rank: Super Contributor
timestamp: September 26, 2016, 02:48:56 am
content: Q: How do you write a USB stack?A: Very carefully...

author: amyk
author_rank: Super Contributor
timestamp: September 26, 2016, 03:29:22 am
content: Here's a good beginner's guide to USB, it starts at the bit level and goes up from there:http://www.beyondlogic.org/usbnutshell/usb1.shtmlBut I don't find the USB standard docs all that difficult to read --- you just have to read slowly, they're not the sort of document you can just glance through and immediately understand. It'll also give you the background to understanding the terms (configuration, descriptor, endpoint, pipe, IN, OUT, transaction, frame, microframe, etc.) that will appear in your MCU's hardware documentation.

author: rfbroadband
author_rank: Unknown
timestamp: November 10, 2016, 05:10:01 pm
content: first identify the type of USB device class you really need. You can do many things with the Human Interface Device class (HID). So if you just want to do bit banging at low speeds, HID is perfectly fine, especially since every PC and OS has good host drivers installed per default.If the HID is sufficient for you there is a very nice option, a software called "HID-Maker" that writes the PIC firmware for you as well as the PC host software (choose between Delphi, C, Basic and others...)http://www.tracesystemsinc.com/hidmaker-fs/hidmaker-fs.htmlIt may save you weeks and weeks of development time and gets you up and running very! fast.

author: MosherIV
author_rank: Super Contributor
timestamp: November 10, 2016, 05:39:47 pm
content: HiNot easy for beginners!First understand the USB protocol and the USB layers (eg the USB device class is 1 layer above the USB transport layer)Then understand how the Processor hardware works.Then you figure out how to write a driver for the Processor to deal with USB packets.Then you build a layer on top of that to deal with the USB device type, ie where to route the USB packets to.I have used the ST libraries for USB and they are a good starting point to see how it can be done.

author: rfbroadband
author_rank: Unknown
timestamp: November 10, 2016, 06:03:58 pm
content: what is your goal? Do you want to become a USB expert or do you need to get something done using USB? I would strongly!!! recommend to not start writing USB lower level stacks if your goal is to get a few bits from the host to a uC.The Windows host is not! very friendly when it comes to USB, if you do something wrong on the device side it will not work, but don't expect the host to tell you what you did wrong. You need to deal with enumerating your device first, "explaining to the host" what kind of device your are, what you want to do ...if the host doesn't like what you tell him he simply won't enumerate but he will not tell what you did wrong. USB is complicated!What USB device class do you think you need? and why?

author: technix
author_rank: Super Contributor
timestamp: November 10, 2016, 06:09:13 pm
content: Quote from: rfbroadband on November 10, 2016, 06:03:58 pmI want to use USB to control one PWM output. And I don't want GPL to spread onto my code so V-USB is not an option.

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: November 10, 2016, 06:14:36 pm
content: If you want to write your own USB stack from scratch (and I applaud anyone who does), then read some of Jan Axelson's books. They're much more approachable than the standard document.http://janaxelson.com/usb.htm

author: rfbroadband
author_rank: Unknown
timestamp: November 10, 2016, 07:11:49 pm
content: ok so if you want to control a PWM output using a uC using a PWM hardware module inside the uC, you only need to communicate to the PWM module once in a while that you need x% output signal and the uC will take of the rest. If that is the case then USB HID class is perfectly sufficient. You can send data every 1ms which sounds like more than sufficient for what you need. No worries about the host drivers, they will be installed on all types of OS per default.The other advantage of staying with HID is that your hardware will work immediately with any OS without! the need to install any host drivers at all. You just copy your host software to any PC and you are done.So buy the HID Maker software and you will have USB host to a uC interface up and running in a day.

author: janoc
author_rank: Super Contributor
timestamp: November 10, 2016, 09:16:20 pm
content: How does this:Quote from: rfbroadband on November 10, 2016, 07:11:49 pmsolve this problem?Quote from: technixHID Maker supports only PIC.

author: rfbroadband
author_rank: Unknown
timestamp: November 10, 2016, 09:51:36 pm
content: oops, that was my oversight, sorry. If you need to support additional uC chips besides PICs, HID maker can't help. It was clearly stated in the first post, for some reason I missed it. HID maker supports the PIC devices.

author: westfw
author_rank: Super Contributor
timestamp: November 11, 2016, 02:27:17 am
content: Quote from: technix on September 25, 2016, 08:28:31 AMWell, yes. Backward compatibility over three versions, 4 speed ranges, several data "classes", and mixed in licensing and trademarking issues, all written by a massive committee. I have no doubt that the official documents are pretty close to incomprehensible.Someone has already suggested Jan Axelson's book. It's pretty good. There is also this free "book" from FTDI:http://www.ftdichip.com/Support/Documents/TechnicalPublications/USBDesignByExample.htmLUFA is probably a good example. Originally written for Atmel AVRs, my understanding is that NXP hired the LUFA developer to do their USB libraries, so they are also LUFA-like. LUFA has pretty favorable licensing terms; it would be a good starting point. I don't think that you should consider bit-banging USB (ala VUSB); that's a whole different set of problems.(Take the following with a grain of salt. I haven't actually written and USB code; though I have read the books and READ some USB code.)A simple USB driver shouldn't be TOO awful to write. For your simple case, it might not be any more difficult to write than it is to understand vendor libraries that were written to be able to support much more complicated scenarios. USB reminds me a lot of other networking protocols and their attempts to establish communications with "zero configuration" - so USB enumeration is a lot like TCP/IP DHCP or the old ARPANet NCP/ICP mechanism: "how do I establish a data communications path based on a bunch of internal information that is NOT a HW addressable entity?"There are essentially two phases of USB communications:1) "Enumeration" - the USB device sends a bunch of information to the USB Host telling it what kind of device(s) it is, what kind of data it is going to send, and the host uses that info to pick a driver. (Writing a USB stack for a host would be much more complicated, BTW.) For simple devices, you'll want to piggyback on one of the existing device types like HID (mouse/keyboard) or CDC/ACM (Modem. Of which "COM Port" is a subset), because otherwise you'll have to write host side drivers as well...2) Data transfer. This is relatively traditional, except that data is packetized, and packet transmission is likely to take place annoyingly asynchronously to the actual microcontroller application. Should be easy if you have small amounts of data and don't care too much about performance. But it will require an understanding of interrupts and an appreciation of concurrency issues.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: November 11, 2016, 08:17:38 am
content: You don't need to stick to some predefined USB class to avoid host driver programming anymore. There are easy to use host-side drivers/libraries: Windows-only WinUSB and more or less cross-platform libUSB. Their use simplifies both device and host sides: you don't need to implement class features like HID report structs or CDC fake baudrates/data formats/events unrelated to your real needs, saving both time and program memory of your device.For a basic device that gets recognized by OS you need to process this minimal subset of standard requests:GET DESCRIPTOR returning device or configuration descriptor (they are just carefully filled static structures, you can treat them like an array of unknown data at runtime).SET ADDRESS writing passed address value to hardware (if it needs it)SET CONFIGURATION doing nothing (just reporting success)Neither WinUSB nor libUSB drivers will never ask you to do those many other things like SET FEATURE or SET DESCRIPTOR (unless you program them to do that).With proper HW initialization and these handlers implemented in ISR you can forget about all other complexities and do some straight read(MY_OUT_EP, buf, len), write(MY_IN_EP, buf, len) whose task will be to wait for EP ready, read/write hw data buffer, signal buffer ready to hw.