Developing USB Peripheral Devices DRFT

Installing pyUSB in mac. Download the folder and run

python install

To list USB devices

system_profiler SPUSBDataType

Face time Hd camera

Product ID: 0x8510   and Vendor ID: 0x05ac



Product ID: 0x05e1

Vendor ID: 0x16c0

using python


import usb.core

import usb.util

import sys

dev = usb.core.find(idVendor=0x16c0, idProduct=0x05e1)




Intro to USB – USB in nutshell (teach thing give demo in pyUSB)

Hub connected to USB function. one host many function (diagramn). host communicate by sending packets to host. Each USB transaction consists of serveral packets mainly token packet, data packet and status packet.

There are four types of packets – Token packet (sub divided into in our setup), data pacekt (sub divided into data0 and data1) , handhshake packet  (sub divided into ACK, NAK, STALL, start of frame packet

Each packet has certain fields
Sync PIDvalue (4bit decide what kind of packet/subpacket) – 7bit address of device (127 devices) –  4-bit Endpoint (16end point possible) – Cycle redudency check – End of teoken

he Universal Serial Bus specification defines four transfer/endpoint types,

Because ther is so many ways, you define something called USB class

Device descroptor (e device descriptor includes information such as what USB revision the device complies to, the Product and Vendor IDs used to load the appropriate drivers and the number of possible configurations the device can have.)
– Configuration descriptor (power options)
— interface descriptor
— Endpoint descriptor

Demo descriptor
lsusb -vv

connect atmel avrisp2 connector and go through device descroptor

For example you could have a multi-function fax/scanner/printer device. Interface descriptor one could describe the endpoints of the fax function, Interface descriptor two the scanner function and Interface descriptor three the printer function. Unlike the configuration descriptor, there is no limitation as to having only one interface enabled at a time.

Go detail each function has address and endpoints. Every device has E0 in and E0out, rest depends upon your device. Host come to know about it with device descriptor.

– Start with pyUSB, tell how all devices are connected, getting there ID etc.
Hardware consideration – 3.3V schottky diode, pull-up resisotr
Zener diodes come with a broad range of characteristics, especially at low currents, results may not be reproducible.

Software :Firmware-only Implimentation

Demo – Easylogger/keyboard
Download from here
Go to examples, change makefile use what you are using, fuses etc. Burn the code. This will do

Dedicated USB-Controller

atmega32u4 has in built usb-driver (search datasheet) show datasheet connection, inbuilt 3.3V regulator. Now every vendor has there own library files. Fortunately, for avr there is free library called lufa
LUFA tutorial
– Download LUFA .zip file extract t. you need doxygen for documentation in ubutu type
sudo apt-get install doxygen
once installed navigate to root directory of LUFA and type
make doxygen
 navigate to root/LUFA/Documentation
note – there are many documentaiton in the website look for your version. For latest below is the link
-call with “make all” to rebuild everything, “make clean” to clean everything,
Mouse done
keyboard – done
Virtual port – done
serial port as ttyACM0
– AnalogOut (show in device system setting – sound)

– virtual serial port
—  before using any demo you would need its documentation file. go to perticular demo folder and run “make doxygen” this will create a folder called “Documentaiton” and inside it html, and run index.html

Board file, Drivers/Board has various .h files which provide corresponding .h file for various boards. For example if Drivers/Board/joystic.h is included in project and board is say USBKEY then this “Dirvers/Board/Joystic.h” will provide path for “AVR8/USBKEY/Joystic.h” . if the file is not there then it will look for “Board/Joystic.h” so if adding some hardware to say micro inorder for it to be include create folder “Board” inside “Driver/Board” folder and keep all header file.

– LUFA keyboard mouse sparkfun tutorial
– lists all usb devices in linux

First off you need to install the tools required to compile things for AVR chips, and the programmer used to flash the devices:

$ sudo apt-get install gcc-avr binutils-avr avr-libc avrdude


Blinky example

#define F_CPU 1000000UL  // 1 MHz
int main() {
        DDRB |= 1; // LED on PB0
        while(1) {
                PORTB |= 1; // Turn LED on
                PORTB &= ~1; // Turn LED off

        return 1;



Developing USB devices is a two part job, one side you have to develop USB perhipheral device (called “USB function” according to usb standards) and a USB host. Here, we will use libusb/pyusb for host side programing and STM32F4Discovery board for USB function. We will first start with USB host programing and then gradually move to developing usb peripheral devices

USB Host Programming

USB is host centric. USB host initiate all transaction and controls all data communication. Host sends data in from of packets.
| USB Host | –> packet –> packet –> packet –> | USB Peripheral device |
Each packet has bits for
Sync | Packet ID | Address of Device | End Point | Cycle Redundancy | End of Packet |
Sync – To sync with clock. It consist of 8 bits for FS and 32 bits for HS usb. The last two bits tell when packet ID starts.
Packet ID – Determines group of packete and also specify which packet in that group
These packets can be classified into four types of “packet -group”
1 – Token Packet – It send at the beginning of every communication and indicate type of transaction to follow.
2- Data Packet – It carries the data to be transfered i.e. payload
3 – Handshake Packet – Acknowledge data or report error
4 – Special Packet –
Open terminal and type following command:
lsusb -vv
This will output list of all the usb function connected to your computer.  Lets write driver for one of these device.

Install pyUSB

sudo apt-get update
sudo apt-get install libusb-dev
sudo apt-get install python
sudo apt-get install python-usb
sudo apt-get install python-pip
sudo pip install –upgrade pyusb 
To test success full installation
import usb.core
dev = usb.core.find()

The loading of the appropriate driver is done using a PID/VID (Product ID/Vendor ID) combination. The VID is supplied by the USB Implementor’s forum at a cost
Isochronous allows a device to reserve a defined amount of bandwidth with guaranteed latency
USB supports Control, Interrupt, Bulk and Isochronous transfers.

Start with this

While developing always thinks in term of host. For example IN packate for device is host asking for input data or read data.

Editing the VCP for Discovery board code

– In code when you send a data, the code will sent it to Tx, Rx will recieve it and intrupt code will be executed, now Rx recieving code should be thre in the intruppt code else the uC will not come out of intruppt.

Developing Driver

the output should be something like
To test VendorID and ProductID of your devices, simply create “” with following code
import sys
import usb.core
# find USB devices
dev = usb.core.find(find_all=True)
# loop through devices, printing vendor and product ids in decimal and hex
for cfg in dev:
sys.stdout.write(‘Decimal VendorID=’ + str(cfg.idVendor) + ‘ & ProductID=’ + str(cfg.idProduct) + ‘\n’)
sys.stdout.write(‘Hexadecimal VendorID=’ + hex(cfg.idVendor) + ‘ & ProductID=’ + hex(cfg.idProduct) + ‘\n\n’)
save it and run it
You will get a list of connected devices. Connect a STM32Disc board (after uploading VCP code) device and run the code again. A new entry will appear in the list. This is your products VendorID and productID. Most likely it will be
VendorID = 0x483 and ProductID = 0x5740
Now, open VCP project and in usbd_desc.c change the entry
#define USBD_VID     0x0482
save and recompile and burn it to board.  run the again and you should see the vendorID updated.
VCP implimentation is FS. During running code DIEPCTL1 and DOEPCTL1 changes value when data sent from terminal.
Device descriptor can have many configuration( although most of them just have one configuration), this can be check my value bNumConfiguration. Each configuration can have multiple interfaces.
STM32 VCP code is detected as ttyACM0 (ls /dev)
Once you connect the board, Ubuntu will read the device descriptor and based on entry in “bDevcieClass” for CDC its 02h and hence in VCP code in usbd_cdc_core.c its its set as 0x02. To make sure OS doesn’t load default COM port driver, change this value to 0xFF (which means class code is vendor specified, see here) . SB defines class code information that is used to identify a device’s functionality and to nominally load a device driver based on that functionality. SB defines class code information that is used to identify a device’s functionality and to nominally load a device driver based on that functionality. There are two places on a device where class code information can be placed.One place is in the Device Descriptor, and the other is in Interface Descriptors

– a serial port may have set two Interrupt endpoints for transferring data in and out and then a control endpoint for setting the baud rate. For stm32f4 vcp, The CDC core uses two endpoint/transfer types:
● Bulk endpoints for data transfers (1 OUT endpoint and 1 IN endpoint). EP1 out (bulk) and EP1 IN (bulk)
● Interrupt endpoints for communication control (CDC requests; 2 IN endpoint). EP2 IN (interrupt type).

#define CDC_IN_EP                       0x81  /* EP1 for data IN */
#define CDC_OUT_EP                      0x01  /* EP1 for data OUT */
#define CDC_CMD_EP                      0x82  /* EP2 for CDC commands */

configuration descriptor and all other descriptor is defined in library usbd_cdc_core.c. You can varify the output of lsusb -vv with the data in this file.

ediging usbd_cdc_core.c
– removed HS core code.

ST Library
usbd_cdc_core.c manages all CDC communication and uses lower level drive to access hardware.  usbd_cdc_core.c talks to usbd_cdc_vcp.c using following structure –

typedef struct _CDC_IF_PROP
uint16_t (*pIf_Init) (void);
uint16_t (*pIf_DeInit) (void);
uint16_t (*pIf_Ctrl) (uint32_t Cmd, uint8_t* Buf, uint32_t Len);
uint16_t (*pIf_DataTx) (uint8_t* Buf, uint32_t Len);
uint16_t (*pIf_DataRx) (uint8_t* Buf, uint32_t Len);

above structure is defined in usbd_cdc_core.h , is defined as

extern CDC_IF_Prop_TypeDef  APP_FOPS;

in usbd_cdc_core.c and in usbd_conf.h defines APP_FOPS as VCP_FOPS. In short usbd_cdc_core.c is accessing functions defined in usb_cdc_vpc.c files.

in STM32F4 USB_Rx_Buffer(unsignedchar[64]) stores all the data. So if you send dev.write(1,’test’,1) then this buffer if wateched in watch window will show you ‘test’. App_Rs_Buffer (unsignedchar[2048]) stores data that is to be sent to host.

Functions defined in  usb_dcd.c
DCD_EP_Tx – Transmit data over USB

– 03/19/14
USB1 has only bulk interrupts, pyusb can send data.
– While defining descriptor make sure wTotalLength is properly set. I was removing other times form descriptor keeping wTotalLength same which created read problem. Modified the code so that it can return exactly what I typed. Modified cdc_vcp.c functions.

An unsigned char is a (unsigned) byte value (0 to 255). In code USB_Rx_Buffer is [64] and each of the bite value can be seen in debug mode if you expand it.

Adding USB capability to your project
-Files needed
— usbd_conf.h
To change USB IN data size change
#define APP_RX_DATA_SIZE               20 /* Total size of IN buffer: in 2048  */
#define APP_FOPS                        VCP_fops

–usbd_desc.c – Defines usb descriptor and string format.
#define USBD_VID                        0x0483
#define USBD_PID                        0x5740

#define USB_OTG_FS_MAX_PACKET_SIZE           64
#define USB_OTG_MAX_EP0_SIZE                 64



usbd_usr.c/h   For user application interface.

Note – usbd_cdc_core.c talks to usbd)cdc_vcp.c using CDC_IF_Prop_TypeDef pointer which is defined in usbd_cdc_core.h

The Setup Packet

Every USB device must respond to setup packets on the default pipe. The setup packets are used for detection and configuration of the device, setting device address, requesting device descriptor or checking the status of  a endpoint.
 In STM32 this is taken care by structure usb_setup_req and is defined in usb_core.h.
typedef  struct  usb_setup_req {

uint8_t   bmRequest;
uint8_t   bRequest;
uint16_t  wValue;
uint16_t  wIndex;
uint16_t  wLength;

 Request type can be standard (further divided into standard, interface and endpoint) or Class specific.
This structure is used in setup stage function USBD_SetupStage() decide if its standard device request, interface request or endpoint request and accordingly calls the functions.
This structure is used in usbd_cdc_core.c to take care of cdc class specific requests. This class specific request are then handle by usb_cdc_vcp.c
To change packet size of IN/OUT EP change following value in usbd_conf.h

#define CDC_DATA_MAX_PACKET_SIZE       64

#define APP_RX_DATA_SIZE               2048

Starting a Keil Project From Scratch

Create a Folder “Project Name” and inside it create folder “MDK-ARM” . We want to keep all the files seperate from uVision folder so that the project can be easily ported to new IDE.
1. Select Project > New uVision Project
2. Select Device for Target ‘Target 1’ – STMicroelectronics > STM32F407VG
In Manage run time environment – do nothing
Go to project- manage-component, environments groups and rename Target1  and group. Create main.c and save it one folder outside location of “MDK-ARM”
Note – When writing tutorial, first mention directory structure as it can be confusing.
copy “Utilities” folder in “Project Name” folder. Now add “stm32f4_discovery.c” to the “User” group, this file is inside Utilities” folder
Crate a new group”MDK-ARM” in “Project Target”, copy startup_stm32f4xx.s inside “MDK-ARM” folder and add this file to newly created “MDK-ARM” group.
While adding usb to other project make sure to add usb interrupt functions interrupt file in  in stm32f4xx_it (both in .c and .h)
* @brief  This function handles EXTI15_10_IRQ Handler.
* @param  None
* @retval None
void OTG_FS_WKUP_IRQHandler(void)
*(uint32_t *)(0xE000ED10) &= 0xFFFFFFF9 ;

* @brief  This function handles OTG_FS Handler.
* @param  None
* @retval None

void OTG_FS_IRQHandler(void)
USBD_OTG_ISR_Handler (&USB_OTG_dev);


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s