TinyUsb的类设备驱动
2026-06-14
本文链接为:http://www.usbzh.com/article/detail-1715.html ,欢迎转载,转载请附上本文链接。
USB复杂在于极其宠大的类设备,如HID,BOT,UAC,UVC等。tinyusb通过对不同的USB类实现相同的类回调函数实现其功能。这些抽像的回调函数由结构体usbd_class_driver_t中的函数指针实现。
typedef struct {
char const* name;
void (* init ) (void);
bool (* deinit ) (void);
void (* reset ) (uint8_t rhport);
uint16_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len);
bool (* control_xfer_cb ) (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
bool (* xfer_cb ) (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
bool (* xfer_isr ) (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); // optional, return false to defer to xfer_cb()
void (* sof ) (uint8_t rhport, uint32_t frame_count); // optional
} usbd_class_driver_t;
这是 TinyUSB 协议栈中 usbd_class_driver_t 结构体的定义,用于描述一个 USB 设备类驱动。各函数指针的功能如下:
| 函数指针 | 功能说明 |
|---|---|
| name | 驱动名称(字符串常量),用于调试和日志输出,标识该类驱动的类型(如 “CDC”, “HID”, “MSC”)。 |
| init | 初始化该类驱动。在 USB 设备栈启动时调用,用于分配资源、初始化内部状态变量、注册回调等。 |
| deinit | 反初始化该类驱动。用于释放 init 中分配的资源,清理状态。返回 true 表示成功,false 表示失败。 |
| reset | 复位指定端口(rhport)上的该类驱动。当 USB 总线复位时调用,用于重置端点状态、清除挂起的传输等。 |
| open | 打开(注册)一个接口。当主机发送 SET_INTERFACE 或枚举时匹配到该类驱动的接口描述符时调用。参数包括端口号、接口描述符指针、剩余数据长度。返回实际解析/消耗的字节数。 |
| control_xfer_cb | 控制传输回调。当接收到针对该类驱动的端点0控制请求(Setup 包)时调用。stage 表示当前阶段(Setup/Data/Ack),request 是解析后的请求结构体。返回 true 表示已处理。 |
| xfer_cb | 普通(非控制)端点传输完成回调。当数据通过 IN/OUT 端点传输完成后调用(中断或批量传输)。参数包括端口、端点地址、传输结果、实际传输字节数。 |
| xfer_isr | 传输完成的中级回调(可选)。在中断上下文中立即执行,比 xfer_cb 更早触发。若返回 false,则后续会再调用 xfer_cb;若返回 true,则不再调用 xfer_cb(用于需要极低延迟处理的场景)。 |
| sof | Start Of Frame 回调(可选)。每收到一个 SOF 帧(约每 1ms 全速 / 125μs 高速)时调用。可用于需要精确时间同步或周期性任务处理的驱动(如音频类、MIDI 类)。 |
对于不同的类设备,usbd_class_driver_t可以支持不同的回调。例如usbd.c中对当前 tinyusb支持的类:
// Built-in class drivers
static const usbd_class_driver_t _usbd_driver[] = {
#if CFG_TUD_CDC
{
.name = DRIVER_NAME("CDC"),
.init = cdcd_init,
.deinit = cdcd_deinit,
.reset = cdcd_reset,
.open = cdcd_open,
.control_xfer_cb = cdcd_control_xfer_cb,
.xfer_cb = cdcd_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_MSC
{
.name = DRIVER_NAME("MSC"),
.init = mscd_init,
.deinit = NULL,
.reset = mscd_reset,
.open = mscd_open,
.control_xfer_cb = mscd_control_xfer_cb,
.xfer_cb = mscd_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_HID
{
.name = DRIVER_NAME("HID"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
.xfer_cb = hidd_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_AUDIO
{
.name = DRIVER_NAME("AUDIO"),
.init = audiod_init,
.deinit = audiod_deinit,
.reset = audiod_reset,
.open = audiod_open,
.control_xfer_cb = audiod_control_xfer_cb,
.xfer_cb = audiod_xfer_cb,
.xfer_isr = audiod_xfer_isr,
.sof = audiod_sof_isr
},
#endif
#if CFG_TUD_VIDEO
{
.name = DRIVER_NAME("VIDEO"),
.init = videod_init,
.deinit = videod_deinit,
.reset = videod_reset,
.open = videod_open,
.control_xfer_cb = videod_control_xfer_cb,
.xfer_cb = videod_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_MIDI
{
.name = DRIVER_NAME("MIDI"),
.init = midid_init,
.deinit = midid_deinit,
.open = midid_open,
.reset = midid_reset,
.control_xfer_cb = midid_control_xfer_cb,
.xfer_cb = midid_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_MIDI2
{
.name = DRIVER_NAME("MIDI2"),
.init = midi2d_init,
.deinit = midi2d_deinit,
.open = midi2d_open,
.reset = midi2d_reset,
.control_xfer_cb = midi2d_control_xfer_cb,
.xfer_cb = midi2d_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_VENDOR
{
.name = DRIVER_NAME("VENDOR"),
.init = vendord_init,
.deinit = vendord_deinit,
.reset = vendord_reset,
.open = vendord_open,
.control_xfer_cb = tud_vendor_control_xfer_cb,
.xfer_cb = vendord_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_USBTMC
{
.name = DRIVER_NAME("TMC"),
.init = usbtmcd_init_cb,
.deinit = usbtmcd_deinit,
.reset = usbtmcd_reset_cb,
.open = usbtmcd_open_cb,
.control_xfer_cb = usbtmcd_control_xfer_cb,
.xfer_cb = usbtmcd_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_DFU_RUNTIME
{
.name = DRIVER_NAME("DFU-RUNTIME"),
.init = dfu_rtd_init,
.deinit = dfu_rtd_deinit,
.reset = dfu_rtd_reset,
.open = dfu_rtd_open,
.control_xfer_cb = dfu_rtd_control_xfer_cb,
.xfer_cb = NULL,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_DFU
{
.name = DRIVER_NAME("DFU"),
.init = dfu_moded_init,
.deinit = dfu_moded_deinit,
.reset = dfu_moded_reset,
.open = dfu_moded_open,
.control_xfer_cb = dfu_moded_control_xfer_cb,
.xfer_cb = NULL,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM
{
.name = DRIVER_NAME("NET"),
.init = netd_init,
.deinit = netd_deinit,
.reset = netd_reset,
.open = netd_open,
.control_xfer_cb = netd_control_xfer_cb,
.xfer_cb = netd_xfer_cb,
.xfer_isr = NULL,
.sof = NULL,
},
#endif
#if CFG_TUD_BTH
{
.name = DRIVER_NAME("BTH"),
.init = btd_init,
.deinit = btd_deinit,
.reset = btd_reset,
.open = btd_open,
.control_xfer_cb = btd_control_xfer_cb,
.xfer_cb = btd_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_MTP
{
.name = DRIVER_NAME("MTP"),
.init = mtpd_init,
.deinit = mtpd_deinit,
.reset = mtpd_reset,
.open = mtpd_open,
.control_xfer_cb = mtpd_control_xfer_cb,
.xfer_cb = mtpd_xfer_cb,
.xfer_isr = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_PRINTER
{
.name = DRIVER_NAME("PRINTER"),
.init = printerd_init,
.deinit = printerd_deinit,
.reset = printerd_reset,
.open = printerd_open,
.control_xfer_cb = printerd_control_xfer_cb,
.xfer_cb = printerd_xfer_cb,
.sof = NULL
},
#endif
};
enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) };
TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8_t drvid) {
usbd_class_driver_t const *driver = NULL;
if (drvid < _app_driver_count) {
// Application drivers
driver = &_app_driver[drvid];
} else{
drvid -= _app_driver_count;
if (drvid < BUILTIN_DRIVER_COUNT) {
driver = &_usbd_driver[drvid];
}
}
return driver;
}
调试宏
#define CFG_TUSB_DEBUG 3 // 启用枚举过程调试,(0-3,3为最详细)
串品打印日志
#define CFG_TUSB_DEBUG_PRINTF my_debug_printf // 自定义打印函数
本文链接为:http://www.usbzh.com/article/detail-1715.html ,欢迎转载,转载请附上本文链接。
TinyUSB





