4、DSI数据包格式:长包与短包结构、Packet Header/Footer、ECC与Checksum计算
MIPI DSI协议在高速模式下通过差分信号线(Data Lane)传输串行化数据包。理解数据包格式是驱动开发中解析初始化序列、配置寄存器以及调试链路稳定性的基础。DSI数据包分为短包和长包两种类型,它们在结构、用途和错误检测机制上存在显著差异。
4.1 短包结构(Short Packet)
短包用于传输控制信息或少量数据,其总长度为4字节(32位),不包含数据负载。短包由Packet Header(数据包头)组成,没有Packet Footer(数据包尾)。
| 字节偏移 | 字段名称 | 位宽(bit) | 描述 |
|---|---|---|---|
| 0 | Data ID (DI) | 8 | 包含虚拟通道标识(VC, 高2位)和数据类型(DT, 低6位) |
| 1 | Data Byte 0 | 8 | 短包数据低字节(或命令参数) |
| 2 | Data Byte 1 | 8 | 短包数据高字节(或命令参数) |
| 3 | ECC | 8 | 错误校正码,覆盖前3个字节 |
短包典型应用场景包括:
- 命令模式(Command Mode):发送DCS短包写命令(如0x05、0x15)配置显示寄存器。
- 同步信号:V-Sync、H-Sync等事件触发包。
- 读取响应:从外设读取状态或数据。
4.2 长包结构(Long Packet)
长包用于传输大量数据负载,例如图像帧数据、初始化参数块或Gamma校正表。长包由三部分组成:Packet Header(4字节)、Data Payload(可变长度,0~65535字节)和Packet Footer(2字节Checksum)。
| 部分 | 字段 | 位宽 | 说明 |
|---|---|---|---|
| Header | Data ID (DI) | 8 bit | VC + DT,标识包类型和虚拟通道 |
| Word Count (WC) | 16 bit | Payload字节数(低字节在前) | |
| ECC | 8 bit | 覆盖Header的3个字节(DI + WC) | |
| Header总长4字节 | |||
| Payload | Data Bytes | WC × 8 bit | 实际传输的数据内容 |
| Footer | Checksum | 16 bit | 对Payload进行16位CRC校验 |
长包的关键特性:
- Word Count (WC):指示Payload的字节数,最大值为65535。WC为0时表示空负载长包,此时Footer仍存在。
- Payload对齐:协议要求Payload字节数必须为偶数,若WC为奇数,接收端需做填充处理(通常忽略最后一个字节)。
- Footer:仅保护Payload数据,不保护Header。
4.3 Packet Header与ECC计算
Packet Header是DSI数据包的“身份证”,包含路由信息(VC)、类型标识(DT)以及长度/参数。ECC(Error Correction Code)采用汉明码(Hamming Code),能够检测并纠正1位错误,检测2位错误。
ECC计算覆盖Header的前3个字节(24位),生成8位校验码。其生成多项式基于(12,8)汉明码扩展。驱动开发中通常不需要手动计算ECC,但理解其原理有助于调试链路错误。
ECC校验码的生成规则(简化):
// 伪代码:ECC生成(基于24位输入)
// 输入:byte[0] (DI), byte[1] (WC_Low), byte[2] (WC_High)
// 输出:ecc_byte (8位)
uint8_t calculate_ecc(uint8_t b0, uint8_t b1, uint8_t b2) {
uint32_t data = (b2 << 16) | (b1 << 8) | b0;
uint8_t ecc = 0;
// 位交织奇偶计算(具体位映射参考MIPI DSI规范v1.3.2第8.2节)
// 实际驱动中可使用查表法或硬件CRC单元加速
// ...
return ecc;
}
4.4 Packet Footer与Checksum计算
长包的Footer包含一个16位的Checksum,用于验证Payload数据的完整性。Checksum算法采用CRC-16-CCITT,生成多项式为:
G(x) = x¹⁶ + x¹² + x⁵ + 1 (0x1021)
计算步骤:
- 初始化CRC寄存器为0xFFFF。
- 对Payload的每个字节(从第一个到最后一个)进行CRC计算。
- 计算完成后,对结果取反(One's Complement),得到最终的Checksum值。
- Checksum以低字节在前(Little-Endian)的顺序放入Footer。
// C语言示例:DSI CRC-16计算
#include <stdint.h>
uint16_t dsi_crc16(const uint8_t *data, uint16_t len) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < len; i++) {
crc ^= (uint16_t)data[i] << 8;
for (int j = 0; j < 8; j++) {
if (crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
}
}
return ~crc; // 取反
}
4.5 长包与短包对比总结
| 特性 | 短包 | 长包 |
|---|---|---|
| 总长度 | 4字节(固定) | 6 + WC 字节(可变) |
| 数据负载 | 最多2字节(Data Byte 0/1) | 0 ~ 65535字节 |
| 错误检测 | ECC(1位纠错,2位检错) | Header: ECC;Payload: CRC-16 |
| 典型用途 | 命令、同步、读取 | 图像数据、大块参数 |
| 传输效率 | 高(无负载开销) | 低(有Footer开销) |
4.6 DSI数据包结构总览图
下图展示了DSI短包与长包在数据通道上的完整结构,以及ECC和Checksum的保护范围。
4.7 驱动开发中的实际应用
在初始化序列配置中,驱动工程师需要将显示控制器的寄存器配置命令封装为DSI数据包。以下是一个典型的初始化序列片段,展示了短包和长包的使用:
// 伪代码:DSI初始化序列发送
void dsi_send_init_sequence(DSI_Handle *dsi) {
// 1. 短包:发送 Software Reset (0x01)
dsi_send_short_packet(dsi, VC_0, DT_DCS_SHORT_WRITE, 0x01, 0x00);
// 2. 短包:发送 Sleep Out (0x11)
dsi_send_short_packet(dsi, VC_0, DT_DCS_SHORT_WRITE, 0x11, 0x00);
// 3. 长包:发送 Pixel Format (0x3A) 带参数 0x77
uint8_t payload[] = {0x3A, 0x77};
dsi_send_long_packet(dsi, VC_0, DT_DCS_LONG_WRITE, payload, 2);
// 4. 长包:发送 Gamma 校正表 (128字节)
uint8_t gamma_table[128];
// ... 填充 gamma 表数据
dsi_send_long_packet(dsi, VC_0, DT_GAMMA_LONG_WRITE, gamma_table, 128);
// 5. 短包:发送 Display On (0x29)
dsi_send_short_packet(dsi, VC_0, DT_DCS_SHORT_WRITE, 0x29, 0x00);
}
理解DSI数据包格式是驱动开发的基础。短包用于高效的控制命令,长包用于大块数据传输。ECC和Checksum提供了链路层的错误检测能力,驱动工程师需要确保这些校验字段的正确性,以保证初始化序列的可靠执行。