skip navigational linksPJRC
Shopping Cart Download Website
Home Products Teensy Blog Forum
You are here: Teensy Code Library USB Raw HID

PJRC Store
Teensy 4.1, $31.50
Teensy 4.0, $23.80
Teensy
Main Page
Hardware
Getting Started
Tutorial
How-To Tips
Code Library
Projects
Teensyduino
Reference

USB: Raw HID

If you want to create a custom application, Raw HID is simple way to send 64 byte packets between your code on the Teensy and your application on the PC or Mac.

HID works automatically with built-in drivers in Linux, Mac OS X and Windows, so users will not need to load any drivers. Your application can detect your Teensy running your customized Raw HID, so to the user everything "just works" automatically.

You can send up to 1000 packets per second in each direction. The USB host controller will reserve USB bandwidth. You are not required send all packets, but if you do, you are guaranteed to be able to transmit the number of packets per second your code specifies, even when other USB devices are active.

Download Files

Example Application

As a simple example, the Teensy-side code sends a packet every 2 seconds containing all A/D inputs. When it receives a packet, the first 4 bits are output to pins D0 through D3. Four LEDs can be connected to D0-D3 and trim pots connected to the analog inputs to use the example.

The PC-side example code is a command line program which prints all packets it receives, and when you press any key that byte is sent in a packet (padded with 63 zeros).

Raw HID allows you to build your own application for nearly any purpose. This example is intended to demonstrate how to use the functions and give you something simple that works to get started.

Host (PC or Mac) Side Functions

int rawhid_open(int max, int vid, int pid, int usage_page, int usage);

Open up to "max" devices that match vid, pid, usage_page and usage. Return is the number of devices actually opened.

int rawhid_recv(int num, void *buf, int len, int timeout);

Receive a packet from device "num" (zero based). Buffer "buf" receives the data, and "len" must be the packet size (default is 64 bytes). Wait up to "timeout" milliseconds. Return is the number of bytes received, or zero if no packet received within timeout, or -1 if an error (typically indicating the device was unplugged).

int rawhid_send(int num, void *buf, int len, int timeout);

Send a packet to device "num" (zero based). Buffer "buf" contains the data to transmit, and "len" must be the packet size (default is 64 bytes). Wait up to "timeout" milliseconds. Return is the number of bytes sent, or zero if unable to send before timeout, or -1 if an error (typically indicating the device was unplugged).

void rawhid_close(int num);

Close device "num" (zero based).

Device (Teensy) Side Functions

void usb_init(void);

Initialize the USB port.

uint8_t usb_configured(void);

Check if the host has configured the USB and is online.

int8_t usb_rawhid_recv(uint8_t *buffer, uint8_t timeout);

Receive a packet. "buffer" must be the size of a full packet. Wait up to "timeout" milliseconds. Return is the number of bytes received, which will always be a full packet, or 0 if timeout, or -1 if the USB is not configured or online. To check if a packet is buffered but avoid waiting, a timeout of 0 may be specified.

int8_t usb_rawhid_send(const uint8_t *buffer, uint8_t timeout);

Transmit a packet. "buffer" must contain the full packet to send. Wait up to "timeout" milliseconds. Return is the number of bytes send, which will always be a full packet, or 0 if timeout, or -1 i f the USB is not configured or online. To transmit only if a buffer is immediately available, a timeout of 0 may be used.

Device Configuration Options

Four unique numbers identify your device. Usually you can just pick a usage page and usage number. These 4 numbers must be the same as the 4 numbers you give to rawhid_open() to access your device.
#define VENDOR_ID               0x16C0
#define PRODUCT_ID              0x0480
#define RAWHID_USAGE_PAGE       0xFFAB  // recommended: 0xFF00 to 0xFFFF
#define RAWHID_USAGE            0x0200  // recommended: 0x0100 to 0xFFFF

The USB host controller will reserve bandwidth for your device. You can configure how much bandwidth by adjusting the packet size and the number of milliseconds between packets.

#define RAWHID_TX_SIZE          64      // transmit packet size
#define RAWHID_TX_INTERVAL      2       // max # of ms between transmit packets
#define RAWHID_RX_SIZE          64      // receive packet size
#define RAWHID_RX_INTERVAL      8       // max # of ms between receive packets
While it's tempting to set these as high as possible, reserved bandwidth will not be available to other devices that need to reserve bandwidth, and if other devices have reserved too much bandwidth before your device is connected, the operating system might refuse to configure your device.

Buffering Considerations

Typically 2 or more packets may be buffered between your code running on the Teensy and your application on the PC or Mac.

When transmitting on either end, you will get a return code indicating successful transmission, when in fact your packet was merely placed into a buffer. If your code does not receive these packets on the other side, you will get timeouts when attempting to transmit more packets after the buffers are completely full.

When receiving, the first packets you read may be old data remaining in the buffers. The example code places a 16 bit count in the last 2 bytes of every packet, so you can see this effect.

If your application depends upon information that spans multiple packets, it is highly recommended to design a count, timestamp or some other way to identify stale and missed packets. Of course, the return value should be checked when transmitting, to verify if the packet was properly buffered.

Linux UDEV Rule

On Linux, unknown devices are not accessible to non-root users. This udev rule can be used to grant access.

SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="0480", MODE:="0666"

Other Languages

If you have a favorite language and any ideas how it could implement the 4 host-side functions, please contact paul@pjrc.com.

A Python implementation was contributed by Craig Heffner.

Someday I would love to see examples for many languages, Perl, Python, PHP, Ruby, Pd, C#, maybe even Visual Basic!