安装 ESP-IDF USB Host
这里会初始化:
- ESP32-P4 USB 2.0 High-Speed控制器
- USB PHY
- USB Host协议栈
- Root Hub:usb支持很多hub枚举,这里是根hub。板子高速USB口接了USB HUB
- USB设备枚举能力
#include "usb/usb_host.h" //主要头文件
const usb_host_config_t config = {
.skip_phy_setup = false,
.intr_flags = ESP_INTR_FLAG_LEVEL1, //USB控制器产生的中断使用Level 1中断优先级。
.peripheral_map = BIT1 //BIT0 → USB 2.0 High-Speed DWC控制器; BIT1 → Full-Speed USB控制器 默认的BIT0
};
esp_err_t err = usb_host_install(&config);
if (err != ESP_OK) {
return err;
}
static usb_host_client_handle_t s_probe_client;
static void usb_probe_event(const usb_host_client_event_msg_t *event, void *arg)
{
(void)arg;
switch (event->event) {
case USB_HOST_CLIENT_EVENT_NEW_DEV:
inspect_usb_device(event->new_dev.address);
break;
case USB_HOST_CLIENT_EVENT_DEV_REMOVED:
ESP_LOGI(TAG, "USB device address=%u removed", event->dev_removed.address);
break;
default:
break;
}
}
const usb_host_client_config_t probe_config = {
.is_synchronous = false, //采用异步事件模式
.max_num_event_msg = 4,
.flags = {
.notify_dev_removed = 1,
},
.async.client_event_callback = usb_probe_event, //消息回调 上面的函数
.async.callback_arg = NULL,
};
usb_host_client_register(&probe_config, &s_probe_client);
xTaskCreate(usb_library_task, "usb_lib", 4096, NULL, 15, NULL); //见下usb_library_task
usb_host_install安装的是整个USB Host系统
但是具体业务模块还需要作为Client注册进去。
USB Host事件处理任务
启动一个任务用来处理
这个任务负责处理:
- USB设备插入
- USB设备拔出
- USB传输完成
- Hub端口变化
- 设备地址分配
- 设备资源释放
xTaskCreate(usb_library_task, "usb_lib", 4096, NULL, 15, NULL)
static void usb_library_task(void *arg)
{
(void)arg;
for (;;) {
uint32_t flags = 0;
esp_err_t err = usb_host_lib_handle_events(portMAX_DELAY, &flags); //维护整个USB总线正常运行
if (err != ESP_OK) {
vTaskDelay(pdMS_TO_TICKS(100));
} else if (flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
(void)usb_host_device_free_all(); //Host栈准备退出时,释放仍由Host库管理的全部USB设备。
}
}
}
usb_host_lib_handle_events
它会处理:
- USB控制器事件
- USB传输完成
- Root Hub端口变化
- 外部Hub端口变化
- 设备插入和拔出
- 设备复位
- 分配USB地址
- 枚举状态机
- 断开设备后的资源回收
如果不持续调用usb_host_lib_handle_events(),可能出现:
- 设备不能完成枚举
- 插拔事件不处理
- 传输完成事件积压
- 拔出后资源无法释放
- Hub下游设备无法继续工作
static void usb_probe_task(void *arg)
{
while (true) {
esp_err_t err = usb_host_client_handle_events(
s_probe_client,
portMAX_DELAY
);
if (err != ESP_OK) {
break;
}
}
vTaskDelete(NULL);
}
Client的事件需要有人持续处理。