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.
USB không có một loại transfer duy nhất. 4 loại transfer phục vụ 4 mục đích khác nhau và có đặc tính timing, reliability, bandwidth rất khác nhau.
Chọn sai loại transfer là lý do phổ biến khiến device hoạt động trên bench nhưng không ổn định trong thực tế — đặc biệt khi bus bận hoặc kết nối qua hub.
1. So sánh 4 loại
| Loại | Lịch bus | Retry khi lỗi? |
|---|---|---|
| Control | Không guaranteed | Có |
| Interrupt | Có lịch polling định kỳ | Có |
| Bulk | Không guaranteed | Có |
| Isochronous | Có lịch cố định | Không |
Bảng này chỉ là bản đồ tổng quan. Khi viết firmware thật, điểm quan trọng hơn là hiểu host sẽ cấp lịch bus cho từng loại transfer như thế nào.
Control Transfer là loại duy nhất bắt buộc phải có trên mọi USB device. Enumeration hoàn toàn chạy trên Control Transfer qua Endpoint 0.
Interrupt Transfer không phải interrupt theo nghĩa phần cứng. Host poll device theo lịch của host controller. Nếu lúc đó device có report mới, device trả data. HID dùng Interrupt Transfer vì host dành lịch polling định kỳ cho endpoint, nhờ đó device có cơ hội gửi report với độ trễ dễ dự đoán hơn Bulk Transfer.
Bulk Transfer dùng bandwidth còn lại sau khi Control và Interrupt đã được phân bổ. Throughput cao nhất trong 3 loại không-isochronous, nhưng không có timing guarantee — khi bus bận, bulk transfer bị delay.
Isochronous Transfer dành riêng bandwidth và không retry khi lỗi. Phù hợp với audio vì mất một vài sample còn chấp nhận được, nhưng delay thì không.
2. Endpoint và transfer type
Mỗi endpoint chỉ hỗ trợ một loại transfer, được khai báo trong Endpoint Descriptor:
bEndpointAddress : 0x81 (IN, address 1)
bmAttributes : 0x03 (Interrupt Transfer)
wMaxPacketSize : 8
bInterval : 1 (poll mỗi 1 ms trên Full-speed)
bmAttributes byte thấp quyết định transfer type:
0x00 = Control
0x01 = Isochronous
0x02 = Bulk
0x03 = Interrupt
Endpoint 0 luôn là Control. Các endpoint khác mới có thể là Interrupt, Bulk hoặc Isochronous.
3. bInterval và cách Windows lên lịch
bInterval trong Interrupt Endpoint Descriptor là polling interval — không phải “firmware gửi mỗi N ms”.
Device HID không tự đẩy data lên host bất kỳ lúc nào. Host poll endpoint theo lịch của host controller. Nếu lúc đó device có report mới, device trả data. Nếu không có data, device trả NAK hoặc không có payload tùy stack/peripheral behavior.
Với Full-speed interrupt endpoint, bInterval được ghi trong descriptor theo đơn vị frame 1 ms. Tuy nhiên trên Windows, polling period thực tế không phải lúc nào cũng đúng y hệt giá trị bạn set. Windows có thể map bInterval vào các mốc polling dạng bucket:
Full-speed interrupt endpoint trên Windows:
bInterval = 1 → poll period ~1 ms
bInterval = 2–3 → poll period ~2 ms
bInterval = 4–7 → poll period ~4 ms
bInterval = 8–15 → poll period ~8 ms
bInterval = 16–31 → poll period ~16 ms
bInterval = 32–255 → poll period ~32 ms
Vì vậy nếu trong descriptor set bInterval = 10, đừng ngạc nhiên khi analyzer lại thấy host poll khoảng 8 ms. Đây không phải firmware gửi sai report, mà là cách host controller/OS lên lịch interrupt transfer.
4. Bulk vs Interrupt cho CDC
Một chỗ rất dễ nhầm là CDC. Nó cũng là USB device, cũng cần độ tin cậy, nhưng lại không dùng Interrupt endpoint cho data chính.
CDC (Virtual COM Port) dùng Bulk Transfer cho data channel. Bulk phù hợp vì throughput quan trọng hơn latency với serial data, retry khi lỗi đảm bảo không mất byte, và Bulk cho phép packet lớn hơn trong khi Interrupt thường giới hạn ở 8–64 byte.
CDC data channel:
IN endpoint (Bulk) - device gửi data lên host
OUT endpoint (Bulk) - host gửi data xuống device
CDC notification:
IN endpoint (Interrupt) - báo line state change
5. Dễ nhầm
Interrupt Transfer không phải hardware interrupt. Device không tự gửi data. Host poll đúng lịch của host controller, device trả lời có data hay không.
bInterval không phải lúc nào cũng bằng polling period đo được. Trên Windows với Full-speed interrupt endpoint, host có thể map bInterval vào các mốc 1, 2, 4, 8, 16 hoặc 32 ms. Ví dụ bInterval = 10 có thể được schedule thành khoảng 8 ms.
Isochronous không retry. Nếu dùng Isochronous cho keyboard và một packet bị drop, keystroke đó mất hoàn toàn. HID không dùng Isochronous vì lý do này.
Bulk không guaranteed timing. CDC data có thể bị delay khi bus bận. Không dùng Bulk khi cần real-time response.
Đây là lý do cùng một đoạn firmware có thể chạy đúng trên bench nhưng fail khi đổi host, đổi hub hoặc đổi OS.
Bài liên quan
- USB Enumeration Process là gì?
- USB Descriptor Overview là gì?
- USB Transfer Types từ góc firmware (blog)
Nguồn tham khảo public
- USB 2.0 Specification, Chapter 5: USB Data Flow Model
- USB in a NutShell — beyondlogic.org, Chapter 4: Endpoint Types
- Microsoft USB_ENDPOINT_DESCRIPTOR structure
Ghi chú từ project thực tế
- bInterval Full Speed: là số ms trực tiếp (1–255) theo spec, nhưng nhiều host
controller Windows làm tròn về lũy thừa của 2.
bInterval=10thực đo là 8ms trên STM32G0 với USBPcap. - Bulk không có ZLP bắt buộc nếu host đã biết trước kích thước từ response
của lệnh điều khiển (như
START_RAM_DUMPtrong series này). - Interrupt endpoint không phải device interrupt host - host poll theo lịch riêng, device chỉ ACK hoặc NAK.
Xem chi tiết: bài 2 USB Transfer Types
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.
Bốn loại Transfer dưới góc nhìn firmware
Khi nào dùng Interrupt, Bulk, Control hay Isochronous? Vai trò và ảnh hưởng của bInterval, SOF timing đến việc thiết kế USB Device.
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.
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.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.