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.

Cập nhật 7 phút đọc
USB cover

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

01 Attach

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.

02 Reset

Bus reset

Host gửi SE0 (Single Ended Zero) trong 10–50 ms để reset device về trạng thái Default.

03 GetDesc

GET_DESCRIPTOR (Device, 8 byte)

Host xin 8 byte đầu của Device Descriptor để biết bMaxPacketSize0.

04 Reset2

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.

05 SetAddr

SET_ADDRESS

Host giao address khác 0 cho device. Từ đây mọi communication dùng address mới.

06 GetAll

GET_DESCRIPTOR (toàn bộ)

Host xin Device Descriptor đầy đủ, rồi Configuration Descriptor, String Descriptors.

07 SetConf

SET_CONFIGURATION

Host chọn configuration. Device bắt đầu hoạt động ở configuration đó.

USB enumeration: host dẫn dắt toàn bộ quá trình, device chỉ trả lời.

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?

Điểm thường fail trong enumeration
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

Nguồn tham khảo public

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ị.

Góp ý

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.

Biến note thành bài viết hoàn chỉnh

Notes là nơi ghi nhanh khái niệm.