To incorporate tinyusb to your project
- Copy or
git submodulethis repo into your project in a subfolder. Let's say it isyour_project/tinyusb - Add all the
.cin thetinyusb/srcfolder to your project - Add
your_project/tinyusb/srcto your include path. Also make sure your current include path also contains the configuration filetusb_config.h. - Make sure all required macros are all defined properly in
tusb_config.h(configure file in demo application is sufficient, but you need to add a few more such asCFG_TUSB_MCU,CFG_TUSB_OSsince they are passed by make/cmake to maintain a unique configure for all boards). - If you use the device stack, make sure you have created/modified usb descriptors for your own need. Ultimately you need to implement all tud descriptor callbacks for the stack to work.
- Add
tusb_init(rhport, role)call to your reset initialization code. - Call
tusb_int_handler(rhport, in_isr)in your USB IRQ Handler - Implement all enabled classes's callbacks.
- If you don't use any RTOSes at all, you need to continuously and/or periodically call
tud_task()/tuh_task()function. All of the callbacks and functionality are handled and invoked within the call of that task runner.
int main(void) {
tusb_rhport_init_t dev_init = {
.role = TUSB_ROLE_DEVICE,
.speed = TUSB_SPEED_AUTO
};
tusb_init(0, &dev_init); // initialize device stack on roothub port 0
tusb_rhport_init_t host_init = {
.role = TUSB_ROLE_HOST,
.speed = TUSB_SPEED_AUTO
};
tusb_init(1, &host_init); // initialize host stack on roothub port 1
while(1) { // the mainloop
your_application_code();
tud_task(); // device task
tuh_task(); // host task
}
}
void USB0_IRQHandler(void) {
tusb_int_handler(0, true);
}
void USB1_IRQHandler(void) {
tusb_int_handler(1, true);
}For your convenience, TinyUSB contains a handful of examples for both host and device with/without RTOS to quickly test the functionality as well as demonstrate how API should be used. Most examples will work on most of :doc:`the supported boards <boards>`. Firstly we need to git clone if not already
$ git clone https://github.com/hathach/tinyusb tinyusb
$ cd tinyusbSome ports will also require a port-specific SDK (e.g. RP2040) or binary (e.g. Sony Spresense) to build examples. They are out of scope for tinyusb, you should download/install it first according to its manufacturer guide.
The hardware code is located in hw/bsp folder, and is organized by family/boards. e.g raspberry_pi_pico is located in hw/bsp/rp2040/boards/raspberry_pi_pico where FAMILY=rp2040 and BOARD=raspberry_pi_pico. Before building, we firstly need to download dependencies such as: MCU low-level peripheral driver and external libraries e.g FreeRTOS (required by some examples). We can do that by either ways:
- Run
tools/get_deps.py {FAMILY}script to download all dependencies for a family as follow. Note: For TinyUSB developer to download all dependencies, use FAMILY=all.
$ python tools/get_deps.py rp2040- Or run the
get-depstarget in one of the example folder as follow.
$ cd examples/device/cdc_msc
$ make BOARD=feather_nrf52840_express get-depsYou only need to do this once per family. Check out :doc:`complete list of dependencies and their designated path here <dependencies>`
Examples support make and cmake build system for most MCUs, however some MCU families such as espressif or rp2040 only support cmake. First change directory to an example folder.
$ cd examples/device/cdc_mscThen compile with make or cmake
$ # make
$ make BOARD=feather_nrf52840_express all
$ # cmake
$ mkdir build && cd build
$ cmake -DBOARD=raspberry_pi_pico ..
$ makeTo list all available targets with cmake
$ cmake --build . --target helpNote: some examples especially those that uses Vendor class (e.g webUSB) may requires udev permission on Linux (and/or macOS) to access usb device. It depends on your OS distro, typically copy 99-tinyusb.rules and reload your udev is good to go
$ cp examples/device/99-tinyusb.rules /etc/udev/rules.d/
$ sudo udevadm control --reload-rules && sudo udevadm triggerIf a board has several ports, one port is chosen by default in the individual board.mk file. Use option RHPORT_DEVICE=x or RHPORT_HOST=x To choose another port. For example to select the HS port of a STM32F746Disco board, use:
$ make BOARD=stm32f746disco RHPORT_DEVICE=1 all
$ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE=1 ..A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option RHPORT_DEVICE_SPEED=OPT_MODE_FULL/HIGH_SPEED/ or RHPORT_HOST_SPEED=OPT_MODE_FULL/HIGH_SPEED/ e.g To force F723 operate at full instead of default high speed
$ make BOARD=stm32f746disco RHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED all
$ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED ..First install linkermap tool then linkermap target can be used to analyze code size. You may want to compile with NO_LTO=1 since -flto merges code across .o files and make it difficult to analyze.
$ make BOARD=feather_nrf52840_express NO_LTO=1 all linkermapTo compile for debugging add DEBUG=1, for example
$ make BOARD=feather_nrf52840_express DEBUG=1 all
$ cmake -DBOARD=feather_nrf52840_express -DCMAKE_BUILD_TYPE=Debug ..Should you have an issue running example and/or submitting an bug report. You could enable TinyUSB built-in debug logging with optional LOG=. LOG=1 will only print out error message, LOG=2 print more information with on-going events. LOG=3 or higher is not used yet.
$ make BOARD=feather_nrf52840_express LOG=2 all
$ cmake -DBOARD=feather_nrf52840_express -DLOG=2 ..By default log message is printed via on-board UART which is slow and take lots of CPU time comparing to USB speed. If your board support on-board/external debugger, it would be more efficient to use it for logging. There are 2 protocols:
- LOGGER=rtt: use Segger RTT protocol
- Cons: requires jlink as the debugger.
- Pros: work with most if not all MCUs
- Software viewer is JLink RTT Viewer/Client/Logger which is bundled with JLink driver package.
LOGGER=swo: Use dedicated SWO pin of ARM Cortex SWD debug header.- Cons: only work with ARM Cortex MCUs minus M0
- Pros: should be compatible with more debugger that support SWO.
- Software viewer should be provided along with your debugger driver.
$ make BOARD=feather_nrf52840_express LOG=2 LOGGER=rtt all
$ make BOARD=feather_nrf52840_express LOG=2 LOGGER=swo all
$ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=rtt ..
$ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=swo ..flash target will use the default on-board debugger (jlink/cmsisdap/stlink/dfu) to flash the binary, please install those support software in advance. Some board use bootloader/DFU via serial which is required to pass to make command
$ make BOARD=feather_nrf52840_express flash
$ make SERIAL=/dev/ttyACM0 BOARD=feather_nrf52840_express flashSince jlink/openocd can be used with most of the boards, there is also flash-jlink/openocd (make) and EXAMPLE-jlink/openocd target for your convenience. Note for stm32 board with stlink, you can use flash-stlink target as well.
$ make BOARD=feather_nrf52840_express flash-jlink
$ make BOARD=feather_nrf52840_express flash-openocd
$ cmake --build . --target cdc_msc-jlink
$ cmake --build . --target cdc_msc-openocdSome board use uf2 bootloader for drag & drop in to mass storage device, uf2 can be generated with uf2 target
$ make BOARD=feather_nrf52840_express all uf2
$ cmake --build . --target cdc_msc-uf2IAR Project Connection files are provided to import TinyUSB stack into your project.
- A buildable project of your MCU need to be created in advance.
- Take example of STM32F0:
- You need
stm32l0xx.h,startup_stm32f0xx.s,system_stm32f0xx.c. STM32L0xx_HAL_Driveris only needed to run examples, TinyUSB stack itself doesn't rely on MCU's SDKs.
- You need
- Take example of STM32F0:
- Open
Tools -> Configure Custom Argument Variables(Switch toGlobaltab if you want to do it for all your projects) - Click
New Group ..., name it toTUSB, ClickAdd Variable ..., name it toTUSB_DIR, change it's value to the path of your TinyUSB stack, for exampleC:\\tinyusb
- Open
Import stack only
Open Project -> Add project Connection ..., click OK, choose tinyusb\\tools\\iar_template.ipcf.
Run examples
Run
iar_gen.pyto generate .ipcf files of examples:> cd C:\tinyusb\tools > python iar_gen.py
Open
Project -> Add project Connection ..., clickOK, choosetinyusb\\examples\\(.ipcf of example). For exampleC:\\tinyusb\\examples\\device\\cdc_msc\\iar_cdc_msc.ipcf
With 9.50.1 release, IAR added experimental native CMake support (strangely not mentioned in public release note). Now it's possible to import CMakeLists.txt then build and debug as a normal project.
Following these steps:
- Add IAR compiler binary path to system
PATHenvironment variable, such asC:\Program Files\IAR Systems\Embedded Workbench 9.2\arm\bin. - Create new project in IAR, in Tool chain dropdown menu, choose CMake for Arm then Import
CMakeLists.txtfrom chosen example directory. - Set up board option in
Option - CMake/CMSIS-TOOLBOX - CMake, for example-DBOARD=stm32f439nucleo -DTOOLCHAIN=iar, Uncheck 'Override tools in env'. - (For debug only) Choose correct CPU model in
Option - General Options - Target, to profit register and memory view.