ITPub博客

首页 > 应用开发 > IT综合 > USB协议层数据格式:深入解析通信帧结构

USB协议层数据格式:深入解析通信帧结构

投稿 IT综合 作者:bhluo 时间:2026-01-21 14:15:56 0 删除 编辑

# USB协议层数据格式:深入解析通信帧结构


## USB协议框架概述


USB(通用串行总线)协议采用分层架构,从物理连接层到应用层共分为四个主要层次。协议层作为USB通信的核心,定义了数据传输的格式和规则,确保主机与设备间的可靠通信。


### USB通信模型基本结构


USB采用主从架构,主机控制所有通信过程。通信的基本单位是"事务",多个事务组成"传输"。USB支持四种传输类型:控制传输、中断传输、批量传输和同步传输,每种类型针对不同的数据传输需求。


## 数据包基本格式


USB通信以数据包为基本单元,所有数据包都遵循特定的格式结构。


### 同步字段与包标识符


```c

// USB数据包基本结构

typedef struct {

    uint8_t sync_pattern[8];    // 同步字段:KJKJKJKK(NRZI编码)

    uint8_t pid;                // 包标识符

    uint8_t payload[];          // 数据载荷(可变长度)

    uint16_t crc;               // 循环冗余校验

} usb_packet_t;


// PID类型定义

typedef enum {

    // 令牌包PID

    PID_OUT     = 0xE1,  // 主机到设备传输

    PID_IN      = 0x69,  // 设备到主机传输

    PID_SOF     = 0xA5,  // 帧起始

    PID_SETUP   = 0x2D,  // 控制传输建立阶段

    

    // 数据包PID  

    PID_DATA0   = 0xC3,  // 数据包交替位0

    PID_DATA1   = 0x4B,  // 数据包交替位1

    PID_DATA2   = 0x87,  // 高速同步传输

    PID_MDATA   = 0x0F,  // 高速分割与高带宽事务

    

    // 握手包PID

    PID_ACK     = 0xD2,  // 确认接收

    PID_NAK     = 0x5A,  // 暂时无法响应

    PID_STALL   = 0x1E,  // 端点挂起

    PID_NYET    = 0x96,  // 未准备好(仅高速)

    

    // 特殊PID

    PID_PRE     = 0x3C,  // 前导包(低速设备)

    PID_ERR     = 0x3C,  // 错误条件

    PID_SPLIT   = 0x78,  // 分割事务

    PID_PING    = 0xB4,  // 流控制探测

} pid_type_t;

```


## 令牌包详细解析


令牌包由主机发出,用于启动一个USB事务,定义事务的类型和方向。


### 标准令牌包格式


```c

// 令牌包结构体定义

typedef struct __attribute__((packed)) {

    uint8_t sync;           // 同步字段

    uint8_t pid;            // 包标识符

    uint16_t device_info;   // 设备地址和端点号

    uint8_t crc5;           // 5位CRC校验

} token_packet_t;


// 设备信息字段解析宏

#define USB_DEVICE_ADDR(device_info)    ((device_info >> 7) & 0x7F)

#define USB_ENDPOINT_NUM(device_info)   ((device_info >> 0) & 0x0F)

#define USB_CRC5_MASK                    0x001F


// 特殊令牌包:SOF包

typedef struct __attribute__((packed)) {

    uint8_t sync;

    uint8_t pid;            // PID_SOF

    uint16_t frame_number;  // 11位帧编号

    uint8_t crc5;

} sof_packet_t;

```


## 数据包格式详解


数据包携带实际传输的数据内容,支持不同的数据PID类型以实现流控制和错误检测。


### 数据包结构


```c

// 数据包结构体

typedef struct __attribute__((packed)) {

    uint8_t sync;

    uint8_t pid;            // DATA0, DATA1, DATA2, MDATA

    uint8_t data[];         // 数据载荷(最多1024字节)

    uint16_t crc16;         // 16位CRC校验

} data_packet_t;


// CRC16计算函数

uint16_t usb_crc16(const uint8_t *data, uint32_t length) {

    uint16_t crc = 0xFFFF;

    

    for (uint32_t i = 0; i < length; i++) {

        crc ^= (uint16_t)data[i];

        for (uint8_t j = 0; j < 8; j++) {

            if (crc & 0x0001) {

                crc = (crc >> 1) ^ 0xA001;

            } else {

                crc >>= 1;

            }

        }

    }

    

    return crc;

}


// 数据交替机制实现

typedef struct {

    uint8_t expected_data_pid;  // 期望接收的数据PID

} endpoint_state_t;


int process_data_packet(data_packet_t *packet, endpoint_state_t *state) {

    // 检查数据交替位

    if ((packet->pid == PID_DATA0 || packet->pid == PID_DATA1) &&

        packet->pid != state->expected_data_pid) {

        // 数据交替位错误

        return -1;

    }

    

    // 更新期望的PID

    if (packet->pid == PID_DATA0) {

        state->expected_data_pid = PID_DATA1;

    } else if (packet->pid == PID_DATA1) {

        state->expected_data_pid = PID_DATA0;

    }

    

    return 0;

}

```


## 握手包与特殊包


### 握手包处理


```c

// 握手包类型

typedef enum {

    HANDSHAKE_ACK,      // 正确接收数据

    HANDSHAKE_NAK,      // 暂时无法响应

    HANDSHAKE_STALL,    // 端点挂起

    HANDSHAKE_NYET      // 高速设备未准备好

} handshake_type_t;


// 握手包响应决策

handshake_type_t determine_handshake_response(

    data_packet_t *data_packet,

    endpoint_status_t *endpoint

) {

    // 检查CRC

    uint16_t calculated_crc = usb_crc16(

        data_packet->data, 

        get_packet_length(data_packet)

    );

    

    if (calculated_crc != data_packet->crc16) {

        // CRC错误,丢弃数据但不发送握手包

        return -1;

    }

    

    // 检查端点状态

    if (endpoint->stalled) {

        return HANDSHAKE_STALL;

    }

    

    if (!endpoint->ready_to_receive) {

        return HANDSHAKE_NAK;

    }

    

    if (endpoint->buffer_full) {

        // 高速设备特有响应

        if (endpoint->high_speed) {

            return HANDSHAKE_NYET;

        } else {

            return HANDSHAKE_NAK;

        }

    }

    

    return HANDSHAKE_ACK;

}

```


## 事务与传输结构


### 控制传输事务


```c

// 控制传输建立阶段

typedef struct __attribute__((packed)) {

    uint8_t bmRequestType;  // 请求特征

    uint8_t bRequest;       // 请求代码

    uint16_t wValue;        // 请求参数

    uint16_t wIndex;        // 请求参数

    uint16_t wLength;       // 数据阶段长度

} setup_stage_t;


// 完整的控制传输

typedef struct {

    token_packet_t setup_token;    // SETUP令牌

    data_packet_t setup_data;      // 建立数据

    handshake_packet_t setup_handshake;

    

    // 可选的数据阶段

    token_packet_t data_token;

    data_packet_t data_packet;

    handshake_packet_t data_handshake;

    

    // 状态阶段

    token_packet_t status_token;

    handshake_packet_t status_handshake;

} control_transfer_t;

```


## 描述符数据结构


USB设备通过描述符向主机报告其能力和配置信息。


### 标准描述符格式


```c

// 设备描述符

typedef struct __attribute__((packed)) {

    uint8_t bLength;            // 描述符长度(18字节)

    uint8_t bDescriptorType;    // 描述符类型(0x01)

    uint16_t bcdUSB;           // USB规范版本号

    uint8_t bDeviceClass;      // 设备类代码

    uint8_t bDeviceSubClass;   // 设备子类代码

    uint8_t bDeviceProtocol;   // 设备协议代码

    uint8_t bMaxPacketSize0;   // 端点0最大包大小

    uint16_t idVendor;         // 厂商ID

    uint16_t idProduct;        // 产品ID

    uint16_t bcdDevice;        // 设备版本号

    uint8_t iManufacturer;     // 厂商字符串索引

    uint8_t iProduct;          // 产品字符串索引

    uint8_t iSerialNumber;     // 序列号字符串索引

    uint8_t bNumConfigurations;// 配置描述符数量

} device_descriptor_t;


// 配置描述符

typedef struct __attribute__((packed)) {

    uint8_t bLength;            // 描述符长度(9字节)

    uint8_t bDescriptorType;    // 描述符类型(0x02)

    uint16_t wTotalLength;     // 配置信息总长度

    uint8_t bNumInterfaces;    // 接口数量

    uint8_t bConfigurationValue;// 配置值

    uint8_t iConfiguration;     // 配置字符串索引

    uint8_t bmAttributes;       // 配置特性

    uint8_t bMaxPower;         // 最大功耗(2mA单位)

} configuration_descriptor_t;

<"1q.q6k0.org.cn"><"3m.q6k0.org.cn"><"7d.q6k0.org.cn">


// 端点描述符

typedef struct __attribute__((packed)) {

    uint8_t bLength;            // 描述符长度(7字节)

    uint8_t bDescriptorType;    // 描述符类型(0x05)

    uint8_t bEndpointAddress;  // 端点地址和方向

    uint8_t bmAttributes;       // 端点特性

    uint16_t wMaxPacketSize;   // 最大包大小

    uint8_t bInterval;         // 轮询间隔

} endpoint_descriptor_t;

```


## 协议状态机实现


### 设备状态管理


```c

// USB设备状态定义

typedef enum {

    USB_STATE_DETACHED,     // 未连接

    USB_STATE_ATTACHED,     // 已连接

    USB_STATE_POWERED,      // 已供电

    USB_STATE_DEFAULT,      // 默认状态

    USB_STATE_ADDRESS,      // 已分配地址

    USB_STATE_CONFIGURED,   // 已配置

    USB_STATE_SUSPENDED     // 挂起状态

} usb_device_state_t;


// 状态机处理函数

void usb_state_machine(usb_device_t *device, usb_event_t event) {

    switch (device->state) {

        case USB_STATE_DEFAULT:

            if (event == EVENT_SET_ADDRESS) {

                device->state = USB_STATE_ADDRESS;

                configure_device_address(device->assigned_address);

            }

            break;

            

        case USB_STATE_ADDRESS:

            if (event == EVENT_SET_CONFIGURATION) {

                device->state = USB_STATE_CONFIGURED;

                enable_endpoints(device);

            }

            break;

            

        case USB_STATE_CONFIGURED:

            if (event == EVENT_SUSPEND) {

                device->state = USB_STATE_SUSPENDED;

                reduce_power_consumption();

            }

            break;

            

        // 其他状态转换...

    }

}

```


## 错误检测与恢复机制


### 协议层错误处理


```c

// 超时检测

typedef struct {

    uint32_t last_activity_time;

    uint32_t timeout_threshold;

} timeout_monitor_t;


int check_timeout(timeout_monitor_t *monitor) {

    uint32_t current_time = get_current_time();

    uint32_t elapsed = current_time - monitor->last_activity_time;

    

    if (elapsed > monitor->timeout_threshold) {

        // 触发超时恢复

        initiate_error_recovery();

        return 1;

    }

    

    monitor->last_activity_time = current_time;

    return 0;

}


// 协议错误恢复

void usb_protocol_recovery(usb_device_t *device) {

    switch (device->recovery_level) {

        case RECOVERY_LEVEL_SOFT:

            // 软复位:重置端点状态

            reset_endpoint_states(device);

            reset_data_toggle();

            break;

            

        case RECOVERY_LEVEL_HARD:

            // 硬复位:重新初始化控制器

            usb_controller_reset();

            reinitialize_descriptors();

            break;

            

        case RECOVERY_LEVEL_FULL:

            // 完全恢复:模拟重新连接

            simulate_disconnect();

            simulate_reconnect();

            perform_enumeration();

            break;

    }

}

```


## 实际数据分析示例


### USB数据包解析工具


```python

# Python实现的简单USB数据包解析器

class USBPacketParser:

    def __init__(self):

        self.pid_names = {

            0xE1: "OUT", 0x69: "IN", 0xA5: "SOF", 0x2D: "SETUP",

            0xC3: "DATA0", 0x4B: "DATA1", 0x87: "DATA2", 0x0F: "MDATA",

            0xD2: "ACK", 0x5A: "NAK", 0x1E: "STALL", 0x96: "NYET"

        }

    

    def parse_packet(self, raw_data):

        """解析原始USB数据包"""

        if len(raw_data) < 4:

            return None

        

        # 提取PID

        pid_byte = raw_data[1]

        pid_type = pid_byte & 0x0F

        pid_check = (pid_byte >> 4) & 0x0F

        

        # 验证PID(低4位应为高4位的补码)

        if (pid_type ^ pid_check) != 0x0F:

            return {"error": "Invalid PID checksum"}

        

        packet_info = {

            "sync": raw_data[0],

            "pid": self.pid_names.get(pid_type, f"UNKNOWN(0x{pid_type:02X})"),

            "raw_pid": pid_type

        }

        

        # 根据PID类型进一步解析

        if pid_type in [0xE1, 0x69, 0x2D]:  # 令牌包

            if len(raw_data) >= 4:

                device_info = raw_data[2] | (raw_data[3] << 8)

                packet_info.update({

                    "device_address": (device_info >> 7) & 0x7F,

                    "endpoint_number": device_info & 0x0F,

                    "crc5": (device_info >> 11) & 0x1F

                })

        

        elif pid_type in [0xC3, 0x4B, 0x87, 0x0F]:  # 数据包

            if len(raw_data) >= 5:

                data_length = len(raw_data) - 4

                packet_info.update({

                    "data": raw_data[2:2+data_length],

                    "crc16": raw_data[-2] | (raw_data[-1] << 8),

                    "data_length": data_length

                })

        

        elif pid_type == 0xA5:  # SOF包

            if len(raw_data) >= 4:

                frame_number = raw_data[2] | ((raw_data[3] & 0x07) << 8)

                packet_info.update({

                    "frame_number": frame_number,

                    "crc5": (raw_data[3] >> 3) & 0x1F

                })

        

        return packet_info

<"0h.q6k0.org.cn"><"4s.q6k0.org.cn"><"6f.q6k0.org.cn">

```


## 性能优化与协议调优


### 批量传输优化策略


```c

// 批量传输管道管理

typedef struct {

    uint8_t endpoint_address;

    uint16_t max_packet_size;

    uint8_t data_toggle;

    uint32_t bytes_transferred;

    uint32_t error_count;

    double average_throughput;

} bulk_pipe_t;


// 自适应包大小调整

uint16_t adjust_packet_size(bulk_pipe_t *pipe, uint32_t transfer_size) {

    if (pipe->error_count > 10) {

        // 错误率过高,减小包大小

        return max(8, pipe->max_packet_size / 2);

    }

    

    if (pipe->average_throughput < 0.5 * pipe->max_packet_size) {

        // 吞吐量低,尝试增大包大小

        uint16_t new_size = min(

            pipe->max_packet_size * 2,

            get_max_supported_packet_size()

        );

        

        if (transfer_size >= new_size) {

            return new_size;

        }

    }

    

    return pipe->max_packet_size;

}

```


## 结语


USB协议层数据格式的设计体现了在可靠性、效率和兼容性之间的精细平衡。从最基本的同步字段到复杂的描述符体系,每一层设计都服务于特定的通信需求。理解这些数据格式不仅有助于USB设备的开发调试,也为协议分析、性能优化和安全检测提供了基础。


随着USB技术的演进,从USB 1.0到最新的USB4,协议层在保持向后兼容的同时不断引入新特性。但核心的数据包格式和通信机制保持了相对稳定,这种设计哲学确保了USB作为通用接口的长期成功。深入掌握USB协议层数据格式,是开发高质量USB设备和进行底层通信分析的关键所在。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3108512/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    934027