USB Enumeration Process là gì?
Chuỗi hỏi–đáp qua Endpoint 0 từ lúc device cắm vào đến khi host giao address và chọn configuration. 7 bước, điểm nào dễ fail và cách debug từ dưới lên.
Enumeration là quá trình host nhận diện device ngay sau khi cắm vào. Nếu enumeration fail sớm, device có thể không xuất hiện đúng trong Device Manager, hoặc chỉ hiện dưới dạng Unknown USB Device với dấu ! màu vàng. Khi đó, dù phần application như gửi HID report hay xử lý data endpoint đã viết đúng, host vẫn chưa đi tới bước sử dụng chúng.
Hiểu rõ 7 bước enumeration giúp biết chính xác đang debug ở tầng nào khi device không được nhận diện.
1. Tổng quan 7 bước
Device cắm vào
Host phát hiện qua D+ hoặc D− pull-up. Full-speed device kéo D+ lên 3.3 V.
Bus reset
Host gửi SE0 (Single Ended Zero) trong 10–50 ms để reset device về trạng thái Default.
GET_DESCRIPTOR (Device, 8 byte)
Host xin 8 byte đầu của Device Descriptor để biết bMaxPacketSize0.
Bus reset lần 2
Host reset lại trước khi giao address. Không phải lúc nào cũng có nhưng phổ biến trên Windows.
SET_ADDRESS
Host giao address khác 0 cho device. Từ đây mọi communication dùng address mới.
GET_DESCRIPTOR (toàn bộ)
Host xin Device Descriptor đầy đủ, rồi Configuration Descriptor, String Descriptors.
SET_CONFIGURATION
Host chọn configuration. Device bắt đầu hoạt động ở configuration đó.
Nhìn flow này có thể thấy enumeration không phải một bước duy nhất — nó là một chuỗi hỏi–đáp trên Endpoint 0. Vì vậy khi USB fail, câu hỏi đầu tiên không nên là “code gửi report sai ở đâu?”, mà là “host đã đi tới bước nào rồi?”.
Sau SET_CONFIGURATION, device mới được đặt vào configuration mà host chọn. Với HID device, host thường sẽ đọc thêm HID descriptor, report descriptor và có thể gửi class request như SET_IDLE. Thứ tự chi tiết có thể khác nhau tùy host, nhưng nếu descriptor hoặc request handling sai, HID driver sẽ không hoạt động đúng.
2. Device thấy gì trong quá trình này?
Từ góc firmware, enumeration là một chuỗi Control Transfer qua Endpoint 0. Mỗi transfer bắt đầu bằng một Setup Packet 8 byte mà host gửi xuống, device phải trả lời đúng trong thời gian quy định.
Host → Device : Setup Packet (8 byte)
Host ← Device : Data Stage (nếu có)
Host → Device : Status Stage (ACK)
Nếu device không trả lời trong timeout hoặc trả lời sai, host coi đó là error và có thể retry hoặc fail enumeration.
Với ST Middleware (STM32_USB_Device_Library), firmware không tự xử lý từng bước — middleware handle toàn bộ Control Transfer và gọi callback USBD_ClassName_Setup() khi có class-specific request. Firmware chỉ cần cung cấp đúng descriptor và implement đúng callback.
3. Pull-up resistor và tốc độ
USB Full-speed device cần kéo D+ lên 3.3 V để host biết có device Full-speed vừa cắm vào. Trên nhiều STM32 có USB device peripheral, pull-up thường được điều khiển bởi USB peripheral/PCD layer khi USB device stack được start.
Trong project dùng STM32Cube, flow thường là:
MX_USB_DEVICE_Init();Bên dưới, middleware đi qua USBD_Init(), USBD_RegisterClass(), USBD_Start() và cuối cùng gọi low-level start thông qua layer USBD_LL_Start(). Pull-up không nên được bật trước khi USB peripheral và clock 48 MHz đã sẵn sàng.
4. Default address là 0
Ngay sau reset, mọi device đều dùng address 0. Host giao tiếp với device mới qua address 0 cho đến khi SET_ADDRESS hoàn tất. Sau đó device phải chuyển sang address mới trong vòng 2 ms.
Vì mọi device sau reset đều bắt đầu ở address 0, host phải kiểm soát quá trình reset và enumerate từng device. Trong thực tế, host/hub sẽ quản lý việc này theo từng port để tránh nhiều device cùng trả lời address 0 trong cùng một thời điểm.
5. Tại sao GET_DESCRIPTOR được gọi hai lần?
Host xin 8 byte đầu trước vì chỉ cần biết bMaxPacketSize0 — kích thước tối đa của Endpoint 0 — để biết có thể nhận bao nhiêu byte trong mỗi packet. Sau khi có thông tin đó, host mới xin full descriptor.
GET_DESCRIPTOR (8 byte) → biết bMaxPacketSize0
GET_DESCRIPTOR (full) → biết bcdUSB, idVendor, idProduct, bNumConfigurations...
Nếu firmware trả descriptor sai ở bước 8 byte, host có thể timeout hoặc fail ở bước tiếp theo.
6. Khi nào enumeration fail?
| Bước | Lỗi thường gặp | Dấu hiệu |
|---|---|---|
| Attach | Pull-up không active hoặc clock chưa ổn | Device không xuất hiện, hoặc xuất hiện rồi biến mất |
| Bus reset | Firmware không xử lý được reset đúng | Device attach xong nhưng không đi tiếp |
| GET_DESCRIPTOR lần 1 | Descriptor sai bMaxPacketSize0 | Unknown USB Device, dấu ! vàng, lỗi code 43 |
| GET_DESCRIPTOR lần 2 | Descriptor sai cấu trúc hoặc bLength | Device chạy được nhưng class không load |
| SET_ADDRESS | Firmware không chuyển address kịp 2 ms | Host retry, đôi khi timeout |
| SET_CONFIGURATION | Configuration Descriptor thiếu endpoint | Device enumerate xong nhưng không giao tiếp được |
| Class request | GET_REPORT_DESCRIPTOR fail (HID) | HID device không load driver, không nhận input |
7. Debug checklist
Khi debug USB, nên đi từ dưới lên: dây và clock trước, descriptor sau, rồi mới tới class request.
Khi device không được nhận diện hoặc fail enumeration
Bài liên quan
- USB Transfer Types là gì?
- USB Descriptor Overview là gì?
- STM32 HAL USB Device Architecture là gì?
- Series: USB Device trên STM32
- USB Descriptor từng field + HID Report Descriptor
Nguồn tham khảo public
- USB 2.0 Specification, Chapter 9: Device Framework
- USB in a NutShell — beyondlogic.org, Chapter 3: USB Protocols
- STM32CubeG0 USB Device examples
Bài viết này hữu ích với bạn?
Chia sẻ, góp ý, hoặc ủng hộ nếu bạn thấy nội dung này có giá trị.
Nội dung liên quan
Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.
USB Transfer Types là gì?
So sánh Control, Interrupt, Bulk và Isochronous transfer: dùng ở đâu, đảm bảo gì, và dễ debug sai ở điểm nào — đặc biệt là cách bInterval thực sự hoạt động trên Windows.
STM32G0 USB Lab: Composite Device
USB composite device trên STM32G0B1RE: HID Keyboard + CDC log + EP0 Vendor Request + Vendor Bulk IN. Một codebase phát triển từ HID đơn đến debug tool hoàn chỉnh qua commit/tag.
Mở đầu series về USB Device trên STM32
Hành trình tổng hợp lại kiến thức USB từ lý thuyết cho đến thực hành với project thực tế trên STM32G0.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.