USB 带宽管理中的32个时隙(TimeSlot)
2026-05-14
本文链接为:http://www.usbzh.com/article/detail-1664.html ,欢迎转载,转载请附上本文链接。
一、时隙的概念
时隙(Time Slot) 是 USB 总线带宽管理中的最小时间单位,每个时隙对应 1 毫秒(ms) 的时间间隔。
以下为32个时隙(覆盖32ms)
| 0ms | 1ms | 2ms | 3ms | … | 28ms | 29ms | 30ms | 31ms |
|---|---|---|---|---|---|---|---|---|
| 时隙0 | 时隙1 | 时隙2 | 时隙3 | … | 时隙28 | 时隙29 | 时隙30 | 时隙31 |
二、为什么是 32 个?
设计原因
| 因素 | 说明 |
|---|---|
| USB 规范要求 | 中断端点的最大轮询间隔为 255ms,但常用范围是 1-32ms |
| 轮询间隔对齐 | USB 中断端点的轮询间隔必须是 2 的幂:1, 2, 4, 8, 16, 32ms |
| 周期性覆盖 | 32ms是所有常用轮询间隔的最小公倍数 |
| 数组大小 | 32 是2的幂,便于位运算和数组索引计算 |
代码实现
UCHAR tmp;
UCHAR hsInterval;
if (endpoint->Parameters.DeviceSpeed == HighSpeed) {
// normalize the high speed period to microframes
// for USB 20 the period specifies a power of 2
// ie period = 2^(hsInterval-1)
hsInterval = PipeHandle->EndpointDescriptor.bInterval;
if (hsInterval) {
hsInterval--;
}
// hsInterval must be 0..5
if (hsInterval > 5) {
hsInterval = 5;
}
tmp = 1<<hsInterval;
}
else
{
tmp = PipeHandle->EndpointDescriptor.bInterval;
}
// this code finds the first interval
// <= USBPORT_MAX_INTEP_POLLING_INTERVAL
// valid intervals are:
// 1, 2, 4, 8, 16, 32(USBPORT_MAX_INTEP_POLLING_INTERVAL)
所以高速原始的的hsInterval的范围为[1,6],超过6的当6处理
由于时间期定固定为[1,2,4,8,16,32],所以对于tmp的值需要落到该值中的一个
//都先为32,这样超过32的都是32
endpoint->Parameters.Period = USBPORT_MAX_INTEP_POLLING_INTERVAL;//32
if ((tmp != 0) && (tmp < USBPORT_MAX_INTEP_POLLING_INTERVAL))
{
// bInterval is in range. Adjust Period down if necessary.
if ((endpoint->Parameters.DeviceSpeed == LowSpeed) &&(tmp < 8))
{
// bInterval is not valid for LowSpeed, cap Period at 8
//低速不能有<8的情况,因为低速必须大于1ms
endpoint->Parameters.Period = 8;//1ms
} else {
// Adjust Period down to greatest power of 2 less than or equal to bInterval.
//通过位运算找到与 tmp 有重叠位的最大 2 的幂,找到最大的n,使得 2^n ≤ tmp
while ((endpoint->Parameters.Period & tmp) == 0) {
endpoint->Parameters.Period >>= 1;
}
}
}
对于低全速,超过32就没有意义了,当32处理了,低于8当8处理
后面是向下取2的N次方最接近的那一个如7取8,19取16,因为只有[1,2,4,8,16,32]这几个。
轮询间隔与时隙的关系
// 中断端点的轮询间隔必须是 2 的幂
#define USBPORT_MAX_INTEP_POLLING_INTERVAL 32
// 常用轮询间隔
ULONG intervals[] = {1, 2, 4, 8, 16, 32};
三、时隙如何用于带宽管理
3.1 时隙分配原理
对于一个周期为 period 的中断端点,它会在每 period 毫秒内占用一次带宽:
示例:周期 = 8ms 的中断端点
┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│ 时隙0│ 时隙1│ 时隙2│ 时隙3│ 时隙4│ 时隙5│ 时隙6│ 时隙7│
├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 占用 │ │ │ │ │ │ │ │
└──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│ 时隙8│ 时隙9│ 时隙10│时隙11│时隙12│时隙13│时隙14│时隙15│
├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 占用 │ │ │ │ │ │ │ │
└──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
以此类推,每隔 8ms 占用一个时隙
由于高速和低全速对bInterval的解释不一样,所以需要统一计算:
// 高速设备的周期计算
if (IsHighSpeed) {
period = (ULONG)1 << (bInterval - 1); // 2^(bInterval-1)
} else {
period = bInterval; // 低速/全速直接使用
}
3.2 数组索引计算
假设高速端点描述符中bInterval=3,那么每4ms查询一次
那么slot的值应为,其8个
slot = 0, 4, 8, 12, 16, 20, 24, 28(覆盖32ms窗口)
3.3 带宽表更新
// 分配带宽时,从对应时隙中减去带宽
BandwidthTable[slot] -= bandwidth;
// 释放带宽时,恢复对应时隙的带宽
BandwidthTable[slot] += bandwidth;
四、时隙与不同轮询间隔的关系
示例:不同轮询间隔的时隙占用
| 轮询间隔 | 32ms 窗口内占用的时隙 | 计算公式 |
|---|---|---|
| 1ms | 0, 1, 2, …, 31 | slot = i (i=0..31) |
| 2ms | 0, 2, 4, …, 30 | slot = 2*i |
| 4ms | 0, 4, 8, …, 28 | slot = 4*i |
| 8ms | 0, 8, 16, 24 | slot = 8*i |
| 16ms | 0, 16 | slot = 16*i |
| 32ms | 0 | slot = 0 |
可视化示例
32ms 时间窗口内的时隙占用情况:
轮询间隔=1ms: ██████████████████████████████
轮询间隔=2ms: █░█░█░█░█░█░█░█░█░█░█░█░█░█░█░
轮询间隔=4ms: █░░░█░░░█░░░█░░░█░░░█░░░█░░░█░
轮询间隔=8ms: █░░░░░░░█░░░░░░░█░░░░░░░█░░░░░
轮询间隔=16ms: █░░░░░░░░░░░░░░█░░░░░░░░░░░░░░
轮询间隔=32ms: █░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
█ = 占用时隙
░ = 空闲时隙
scheduleOffset
scheduleOffset 用于错开不同端点的查询时间,避免多个端点同时占用总线
当scheduleOffset=0时
for (i = 0; i < n; i++) {
slot = scheduleOffset + i * period;
// scheduleOffset=0: slot = 0,4,8,12,16,20,24,28 正确
}
当scheduleOffset=1时
for (i = 0; i < n; i++) {
slot = scheduleOffset + i * period;
// scheduleOffset=0: slot = 1,5,9,13,17,21,25,29 正确
}
scheduleOffset选择剩余带宽最大的位置 ,以平衡总线上的负载分布
┌─────────────────────────────────────────────────────────────────┐
│ 假设:period=4, bandwidth=1000 bps │
│ │
│ BandwidthTable[0..31] = [5000, 3000, 4000, 6000, ...] │
│ │
│ scheduleOffset=0: │
│ 检查 slot: 0, 4, 8, 12, 16, 20, 24, 28 │
│ 最小可用带宽 = min(5000, ...) = 4000 bps │
│ │
│ scheduleOffset=1: │
│ 检查 slot: 1, 5, 9, 13, 17, 21, 25, 29 │
│ 最小可用带宽 = min(3000, ...) = 2000 bps │
│ │
│ scheduleOffset=2: │
│ 检查 slot: 2, 6, 10, 14, 18, 22, 26, 30 │
│ 最小可用带宽 = min(4000, ...) = 3500 bps │
│ │
│ scheduleOffset=3: │
│ 检查 slot: 3, 7, 11, 15, 19, 23, 27, 31 │
│ 最小可用带宽 = min(6000, ...) = 5500 bps ← 最佳选择! │
│ │
│ 最终选择 scheduleOffset=3,因为它的最小可用带宽最大 │
└─────────────────────────────────────────────────────────────────┘
五、设计优势
为什么使用 32 时隙方案?
| 优势 | 说明 |
|---|---|
| 精确调度 | 每个时隙独立管理,支持细粒度的带宽分配 |
| 周期对齐 | 32 是所有常用轮询间隔的最小公倍数,保证周期端点能完整覆盖 |
| 高效计算 | 32 是 2 的幂,数组索引计算可以用位运算优化 |
| 资源预留 | 保留 10% 带宽给控制/批量传输 |
| 公平性保证 | 通过最佳拟合算法(best-fit)平衡各时隙的负载 |
六、总结
| 问题 | 答案 |
|---|---|
| 32个时隙是什么 | USB 总线带宽管理中的最小时间单位,每个时隙对应 1ms,共覆盖 32ms 时间窗口 |
| 为什么是32 | 32是常用轮询间隔(1/2/4/8/16/32ms)的最小公倍数,能完整覆盖所有中断端点的周期 |
| 如何使用 | 通过 BandwidthTable[32] 数组跟踪每个时隙的可用带宽,分配时从对应时隙减去带宽 |
| 设计目的 | 实现精确的带宽调度,保证实时传输的QoS,同时为异步传输预留资源 |
这种设计使得 USB 驱动能够高效地管理总线带宽,确保不同类型的传输(中断、等时、控制、批量)都能获得合理的资源分配。
本文链接为:http://www.usbzh.com/article/detail-1664.html ,欢迎转载,转载请附上本文链接。
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936 USB技术交流3:1031974172
WinXP ECHCI驱动分析





