A tinyUSB build with some extras to enable use with microzig.
This package provides 3 things:
- Build flow for building tinyUSB static library with zig
- Microzig port specific (only RP2040 currently) interface
- A module for tusb cdc logging with microzig & related default tinyusb configuration & descriptors
When used as a dependency there are a few required options: a resolved target and a port.
There are also two optional options (which defaults to false): enable_default_config, enable_debug_logging.
More details on these options is given in the below section.
const tusb_dep = b.dependency("tusb_uzig_lib", .{
.target = b.resolveTargetQuery(target.zig_target),
.port = .RP2040,
// optional settings
.enable_default_config = true,
// .enable_debug_logging = false,
});This package exposes an artifact that represents the tinyusb complied library. This artifact can be configured for a given project in a few ways. First the dependency option .target and .port will control the zig build target of the library, and port will select the port (or none if the project will implement the interface directly).
Optionally the library is effected by the .enable_default_config setting. When true a default cdc tusb_config.h and descriptors.c are added to the library. If not enabled, the tusb_config.h must be provided along with the other symbols typically provided by the descriptors file.
This can be done by adding includes and c files to the tusb library module:
const tusb_lib_mod = tusb_dep.module("tusb_lib");
tusb_lib_mod.addCSourceFile(.{ .file = b.path(...) });
tusb_lib_mod.addIncludePath(b.path(...));Finally, the .enable_debug_logging, option will enable debug logging within tinyusb file. This will a export fn _putchar(char: u8) void function to be implemented (called by the printf). Unless debugging tinyusb itself probably this in not going to be useful and should never be enabled when writing log statements out of the USB port being debugged.
Example adding the library to a microzig project:
const tusb_lib = tusb_dep.artifact("tinyusb_lib");
b.installArtifact(tusb_lib);
firmware.add_object_file(tusb_lib.getEmittedBin());In addition to the tusb_lib module, this package also exposes a tusb module. This module provides zig side helpers when using tinyusb. In the module there are three public structures: api, cdc_logging and port. Because some of these components import microzig it must be added (see example below).
Example adding these modules to the build.zig:
tusb.addMicroZig(tusb_dep, firmware.core_mod);
firmware.add_app_import("tusb", tusb_dep.module("tusb"), .{});Using in the program:
const tusb = @import("tusb");
The api provides an application interface to the tinyusb library as it has been configured. All of the expected TinyUSB API calls should be available through this interface. It's generated using the zig TranslateC build tool.
Examples:
_ = tusb.api.tud_init(0);
_ = tusb.api.tud_cdc_write_flush();
the port struct provides missing symbols required for port specific dependencies and other features to smooth the boundary between tinyusb and zig.
For example the RP2xxx port in tinyusb lacks irq HW controls so they must be implemented on the zig side.
the cdc_logging public structure exposes functions which can enable zig global logging through a tinyusb cdc device. This requires a call to logging.init(true); during runtime and also setting up the logging function:
// Tinyusb API, the default cdc control,
const tusb = @import("tusb");
const logging = tusb.cdc_logging;
pub const microzig_options = microzig.Options{
.log_level = .debug,
.logFn = logging.log,
.interrupts = .{ .USBCTRL_IRQ = .{ .c = tusb.port.irq_handler } },
};