What is TinyUSB and Why Do I Need It?

There are two different methods of transmitting USB data between your microcontroller board and your PC. They are called "USB Stacks". They are layers of code that handle all of the protocols for transmitting data whether you are using it to upload your program to the board, receiving data via the serial monitor or serial plotter, or talking back to your computer emulating a mouse, keyboard or other device.

Traditional Arduino 8-bit boards all use the original Arduino stack. Newer boards such as M0 and M4 based on the SAMD21 and SAMD51 have the option of using either the Arduino stack or a different version called the TinyUSB Stack. Still other boards such as the nRF52840 based boards use only TinyUSB and it is likely that upcoming boards such as the ESP32-S2 will continue to use only TinyUSB. This is primarily because TinyUSB is the underlying architecture for implementing CircuitPython on these boards.

If you are using an M0 or M4 board you select which stack you want to use in the Tools menu of the Arduino IDE as shown below.

The image shows the tools menu of the Arduino IDE and we have selected an Adafruit Feather M0 Express board. Here you have a choice between using the Arduino stack or the TinyUSB stack.

However in the image below, we have configured for an Adafruit Feather nRF52840 Express. As you can see there is no "USB Stack" option. What you cannot see is that this particular board only uses TinyUSB. If you try to #include it will not find the proper library because is not supported under TinyUSB.

For the M0 and M4 boards you can simply choose to select the Arduino stack and there's no problem. However the TinyUSB stack also has many other features that might be useful to you. Among them are the ability to use WebUSB and to use the onboard flash chip of your board as a mass storage device. This essentially turns your Feather board into a flash drive where you can drag-and-drop files. We will not be covering those capabilities in this tutorial. Of course if you're using the nRF52840 based systems don't have a choice. You have to use TinyUSB.

Using the TinyUSB Mouse and Keyboard Library

As mentioned previously, the traditional way to control mouse or keyboard is the following include files.

Download: file
#include <HID.h>
#include <Mouse.h>
#include <Keyboard.h>

You should erase those lines and replace them with

Download: file
#include <TinyUSB_Mouse_and_Keyboard.h>

This will automatically detect whether you are using the Arduino Stack or the TinyUSB Stack. If you are using the original Arduino Stack it will simply do the necessary include files for you. And if you're using TinyUSB Stack it will instead use its own code that works exactly like the originals. Note that there is no way to separate Mouse and Keyboard inclusion in our system. It was much easier to implement both at once rather than implementing them separately because of the way TinyUSB implements its HID functions. Theoretically when you compile your code if you did not make any reference to Keyboard and only to Mouse the linking loader will eliminate the Keyboard code. And vice versa if you use only Keyboard and not Mouse. Combining these into a single library saved us a lot of headaches.

If you have existing code that uses Mouse.h or Keyboard.h or both you should make the changes noted above and give it a try.

WARNING: If you did not do a Mouse.begin() or Keyboard.begin() in your code, you MUST add that in your setup section. The original mouse and keyboard did not require it but we do.

If you are using an M0 or M4 based board, you will have to set the Tools->USB Stack to "TinyUSB". In fact try switching back and forth between the two stacks and recompiling. You should see the same results using either stack. If you are using the nRF52840 processor, you do not need to select the TinyUSB option.

When to begin the Keyboard or Mouse

While developing and testing this library, we discovered that occasionally it makes a difference when you call the Mouse.begin() or Keyboard.begin() methods relative to the Serial.begin(…) method. Sometimes your computer would get confused as to how your USB was operating. Was it a mouse? Was it a keyboard? Was it a serial device? We had inconsistent results. Our best results came if you did your Mouse.begin() and/or Keyboard.begin() before doing Serial.begin(…). No such restriction is necessary when using the BLE52 version of the library. It only affects the TinyUSB version.

In the next section, we will describe the BLE52 library followed by a series of three demonstration examples.

This guide was first published on May 13, 2020. It was last updated on May 13, 2020.
This page (TinyUSB Mouse and Keyboard Usage) was last updated on Oct 20, 2020.