主机边界:默认使用标准库模型、C 源文件和协议序列;没有目标板也能完成帧编码、错误分类、事务重放和超时测试。
目标机边界:真实电平、引脚复用、上拉、时钟容差、采样裕量、片选、对端状态、收发器和 EMI 必须回到当前芯片、器件、板卡、仪器和工具链的官方资料。
01 · SERIAL BUS MODEL
串行通信模型:帧、时序与边界
UART、I²C 和 SPI 都把数据变成线上的时序,但它们对时钟、帧边界、方向、确认和错误的回答完全不同。本单元先建立串行通信的共同模型:对象是谁、线有几根、谁提供时钟、一个符号何时有效、帧怎样开始结束、失败如何被观察。
7.1.1 从符号到帧:协议的最小单位
物理电平是线上的高低,位是协议对某段时间的解释,字节是若干位的组合,帧则加入起始、停止、地址、校验或控制字段;事务通常还包含请求、响应和结束条件。把一串十六进制打印值称作‘协议’会跳过这些层,导致软件正确而线路不成立。
7.1.2 谁提供时钟,谁承担采样责任
UART 依赖双方各自的时钟和约定采样,I²C 与 SPI 则由一方提供时钟线;但同步也不意味着没有时钟偏斜、拉伸、边沿或模式要求。记录协议时,应同时写 baud/频率、采样边沿、有效电平、时钟容差和线上的参考点。
C · FRAME TIMELINEtypedef struct { uint32_t baud; uint8_t data_bits; uint8_t parity; uint8_t stop_bits; } serial_cfg_t; uint32_t frame_bits(const serial_cfg_t *c) { return 1u + c->data_bits + (c->parity != 0u) + c->stop_bits; }
这是帧时间模型;实际采样、引脚电平和外设分频仍需按目标 UART/总线核对。
PYTHON · BUS EVENTSevents = ["idle", "start", "data", "ack", "stop"] assert events[0] == "idle" print(" -> ".join(events))
主机序列帮助读者标记边界,不能代替逻辑分析仪的原始采样。
7.1.3 空闲、起始、结束与方向
空闲电平、起始边沿、停止条件、片选变化或 ACK 都可能标志一个边界。边界必须能在原始波形上找到,不能只依赖驱动 API 的调用时间。半双工方向切换、I²C repeated start 和 SPI CS 间隙都应作为事务的一部分记录。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 物理 | 电平/拓扑/引脚 | 软件字节就代表线路成立 |
| 时序 | 位/采样/边界 | API 调用时间就是线上时间 |
| 消息 | 帧/事务/校验 | 解码器文本就是原始证据 |
7.1.4 引脚复用、电平和电气拓扑
引脚复用决定外设信号能否到达焊盘,电平标准决定对端是否把它解释成高/低,开漏和推挽决定谁能主动拉高,外部上拉决定上升时间。电平转换器、线长和探头电容也会改变波形。未经电气核对,不应把乱码归因于软件。
7.1.5 发送完成不等于对端收到
应用写入 TX FIFO 只证明软件交给了外设;移位寄存器空才接近线上发送完,协议 ACK 又是对端的一次确认。不同层的完成标志不能互换。驱动接口应明确返回的是入队、发送完成、帧确认还是仅仅没有本地错误。
从左到右是思考顺序,不是把电平、协议、日志和结论压缩成一个“通过”。
7.1.6 帧、事务与上层消息的边界
总线帧通常只承载一段字节,应用消息还需要长度、类型、版本、校验和超时。变长帧应有明确的同步字节或长度可信度,并能在丢一个字节后重新找到边界。把‘每次读固定 N 字节’当成通用协议,会让错误扩散到下一帧。
7.1.7 协议分析仪能证明什么
逻辑分析仪的解码器可以帮忙定位位和字节,但参数错了时也会生成看似合理的错误解释。保留原始采样、通道映射、采样率、阈值、解码配置和软件日志,别人才能重新解码。解码文本是派生证据,不能替代原始证据。
7.1.8 本节交付:串行总线观察卡
串行总线观察卡应包含 endpoint_identity、pin_mux、voltage、topology、clock_or_baud、idle、frame_boundary、transaction_end、completion_level、error_flags、raw_capture 和 unverified_scope。它把协议阅读从‘能发字节’提升为可复查的行为合同。
请围绕“串行通信模型:帧、时序与边界”写出对象、引脚/电平和输入条件、帧或事务机制、输出/响应、一个时序或安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、外设、器件、供电、线缆、工具链、仪器和观察条件。不要用一段十六进制日志、一个 API 返回值或一张解码截图覆盖没有做过的验证。
02 · UART
UART:异步帧、波特率与错误
UART 用双方约定的波特率、数据位、奇偶校验和停止位,把空闲线上的起始边沿当作一次采样基准。它简单,却会暴露时钟误差、采样点、FIFO、溢出、奇偶校验、帧错误、半双工方向和电平转换的全部边界。本单元从一帧位图走到驱动可观测性。
7.2.1 UART 一帧的位图
典型 8N1 帧包含一个起始位、八个数据位、没有奇偶位和一个停止位;线通常空闲为高,起始位拉低后按约定的位时间采样。LSB-first、反相电平或特殊同步模式会改变这张图。写配置时应把每个字段列出,不能只写一个 baud 数字。
7.2.2 波特率、位时间和时钟容差
理想位时间是 baud 的倒数,但真实分频常需要整数或小数取整,双方时钟误差会在帧内累积。采样器通常在起始边沿后按内部 oversampling 找中心点;帧越长、误差越大,采样窗口越危险。应把源时钟、分频寄存器、实际 baud 和容差一起记录。
C · UART FRAME BITSuint16_t uart_frame(uint8_t value, bool even) { uint16_t frame = 0u; frame |= 0u << 0; /* start */ frame |= (uint16_t)value << 1; frame |= (uint16_t)parity_bit(value, even) << 9; frame |= 1u << 10; /* stop */ return frame; }
示例展示位图思路;反相、LSB 顺序、硬件奇偶和具体寄存器需按 MCU 核对。
C · UART ERROR SNAPSHOTuint32_t flags = UART_STATUS; if (flags & (UART_OVERRUN | UART_FRAMING | UART_PARITY)) { record_uart_error(flags, rx_index); clear_uart_error_in_documented_order(); }
错误清除顺序和读取副作用是具体 UART 的合同,不能跨系列照搬。
7.2.3 数据位、LSB 顺序与奇偶校验
数据位的逻辑顺序、字节在缓冲中的顺序和线上电平的顺序不是一回事。奇偶校验通常对数据位计算一个 parity bit,但偶/奇、标记/空格和硬件反相都可能不同。拿一个已知字节配合原始波形验证,比凭字符串猜格式可靠。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 格式 | baud/位/校验/停止 | baud 数字精确且双方必同 |
| 缓冲 | FIFO/错误/方向 | TX FIFO 空就是对端确认 |
| 诊断 | 波形/状态/计数 | 乱码只有一个原因 |
7.2.4 停止位、break 与帧边界
停止位提供接收器回到空闲并准备下一帧的时间,break 是持续超过正常帧的低电平,常用于唤醒或协议同步。接收器把异常长低电平如何报告由具体外设定义。驱动应保留 break/framing 状态,不要把它直接丢进普通数据流。
7.2.5 FIFO、overrun 与读取顺序
FIFO 水位和 overrun 标志的清除顺序会影响还能读出哪些字节。若先清状态再读数据,可能丢掉定位线索;若 ISR 读取太慢,硬件可能覆盖最早字节。用接收计数、FIFO 水位、错误计数和输入波形对账,才能证明没有静默丢样。
从左到右是思考顺序,不是把电平、协议、日志和结论压缩成一个“通过”。
7.2.6 半双工与 RS-485 方向控制
RS-485 半双工需要在最后一个停止位真正移出后再释放驱动使能,否则最后几位可能被截断;过晚释放又会阻塞对端响应。DE/RE 的 GPIO、收发器传播延迟和总线偏置都属于协议时序。一个 TX FIFO 空标志通常还不够作为换向条件。
7.2.7 把乱码分类而不是猜原因
乱码先按层分类:若波形位时间不对,查时钟/baud;若边沿电平不对,查电平/引脚;若位图正确但校验错,查格式/噪声;若驱动缺字节,查 FIFO/ISR/方向;若帧正确但应用错,查编码和消息边界。每层都需要相应原始证据。
7.2.8 本节交付:UART 帧与错误卡
UART 卡至少包含 source_clock_hz、divider、actual_baud、format、sampling、line_level、fifo_depth、error_flags、direction_gpio、completion_definition、timeout、raw_channels 和 peer_contract。这样调试串口和产品协议可以共享证据字段。
7.2.9 读者实验:只改变一个帧字段
主机练习可以编码 UART 帧并计算奇偶、停止位和帧时间,但不能证明目标机采样中心或 RS-485 的电气波形。只改变一个格式字段并保存预测与差异,读者会看到‘同一字节’如何在不同帧合同下变成不同的线路证据。
请围绕“UART:异步帧、波特率与错误”写出对象、引脚/电平和输入条件、帧或事务机制、输出/响应、一个时序或安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、外设、器件、供电、线缆、工具链、仪器和观察条件。不要用一段十六进制日志、一个 API 返回值或一张解码截图覆盖没有做过的验证。
03 · I²C
I²C:开漏总线、地址与仲裁
I²C 用 SDA 与 SCL 的开漏/开集电极拓扑、上拉电阻、起始/停止条件、地址、ACK/NACK、重复起始和时钟拉伸组织多设备事务。它的难点不在‘发出一个地址’,而在总线电气、仲裁、方向切换、时序裕量、总线卡死和设备状态共同构成一个可恢复合同。
7.3.1 开漏与上拉:高电平是谁提供的
开漏输出只能主动拉低,释放后由上拉电阻把线拉高,因此任意设备都可以把总线保持低电平而不会与另一个主动高电平直接对冲。上升时间由电阻、总线电容、引脚和探头共同决定;上拉太弱会慢,太强会增加低电平电流。电气参数先于软件速率。
7.3.2 START、STOP 与 repeated START
START 通常由 SDA 在 SCL 高电平时下降表示,STOP 则是 SDA 在 SCL 高电平时上升;repeated START 允许主机不释放总线就改变方向或目标。具体高速模式对边沿和保持时间有更多要求。每一笔事务都应在波形上标出边界和总线占用。
C · I2C TRANSACTIONi2c_start(); i2c_write((address << 1) | WRITE); expect_ack("address"); i2c_write(register_index); expect_ack("register"); i2c_repeated_start(); i2c_write((address << 1) | READ); read_bytes(buffer, count, NACK_LAST); i2c_stop();
START、ACK、拉伸、超时和恢复要按控制器与从设备资料实现。
C · BUS CLEARrelease_sda(); for (unsigned pulse = 0; pulse < 9 && sda_is_low(); ++pulse) { drive_scl_low(); release_scl_and_wait(); } issue_stop_if_bus_is_released();
清线是有条件、有上限的恢复动作;先确认电平、供电和设备安全,不能无限脉冲。
7.3.3 地址、R/W 位与 ACK 位
7 位地址在总线上常与 R/W 位组成一个地址字节,随后每个字节都有第九个时钟让接收方 ACK 或 NACK。地址左移/右移是常见软件误解。不要只看 API 的‘地址参数’,要在原始波形上确认八个位和 ACK 位置。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 电气 | 开漏/上拉/RC | 两根线可以主动拉高 |
| 事务 | 地址/ACK/拉伸 | NACK 都应无限重试 |
| 恢复 | 卡线/清线/STOP | 九个脉冲必然修好 |
7.3.4 时钟拉伸与主机超时
从设备拉低 SCL 等待内部准备称为 clock stretching,但不是所有控制器、模式或从设备都支持。主机必须有上限,超过上限要记录 SCL/SDA、事务阶段和设备状态并停止。无限等待会把一个异常器件变成整机死锁。
7.3.5 多主仲裁与丢失处理
多主仲裁时主机在发送高电平期间监测 SDA;若自己释放而线被另一方拉低,就失去仲裁。软件不应继续驱动或把丢失当作普通 NACK。需要保存仲裁丢失位置、重新获得总线的条件和重试退避,避免多个主机同步重试。
从左到右是思考顺序,不是把电平、协议、日志和结论压缩成一个“通过”。
7.3.6 NACK 的多种含义
NACK 可能表示地址不存在、器件忙、数据字节不接受、读事务最后一个字节由主机 NACK,或者器件希望结束。日志应包含方向、字节索引、地址阶段/数据阶段和是否预期 NACK。把所有 NACK 都重试可能掩盖一个正常读结束或写保护。
7.3.7 总线卡死与 bus clear
SDA 低可能是从设备仍在等待时钟,SCL 低可能是拉伸、主机复位中断或短路。bus clear 常由主机释放 SDA 并手动产生有限个 SCL 脉冲,再发 STOP 并重新采样总线。恢复前后要记录电平、脉冲数、供电和设备复位,否则无法判断恢复是否安全。
7.3.8 器件寄存器指针和重复读
很多传感器和 EEPROM 先写寄存器地址,再 repeated START 读数据;STOP、内部写周期和地址指针是否保留由器件协议决定。总线层成功只证明字节得到 ACK,不证明寄存器内容、校验或测量结果正确。应用合同需要设备资料和数据有效位。
7.3.9 本节交付:I²C 事务与电气卡
I²C 卡包括 topology、pullup_ohm、bus_capacitance、speed_mode、address_bits、rw_bit、ack_index、stretch_timeout、arbitration_policy、nack_reason、bus_clear、register_protocol 和 raw_capture。它把电气、事务和恢复放在一个可交付对象里。
请围绕“I²C:开漏总线、地址与仲裁”写出对象、引脚/电平和输入条件、帧或事务机制、输出/响应、一个时序或安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、外设、器件、供电、线缆、工具链、仪器和观察条件。不要用一段十六进制日志、一个 API 返回值或一张解码截图覆盖没有做过的验证。
04 · SPI
SPI:片选、模式与吞吐
SPI 通常由主机提供 SCK、片选和 MOSI/MISO 两条数据线,没有统一的地址或 ACK,设备选择、CPOL/CPHA、位序、字宽、片选间隙和最大频率由具体器件约定。它能很快,却容易把‘时钟跑起来’误认为‘设备读对了’。
7.4.1 SPI 没有统一帧:片选就是边界
SPI 没有一个跨设备统一的地址、确认或帧格式,CS 通常由主机选择设备并定义事务边界。某些设备要求 CS 在命令、地址、dummy 和数据期间保持低,另一些设备允许分段。驱动 API 的一次 transfer 是否保持 CS,要查当前控制器和器件资料。
7.4.2 CPOL/CPHA 与采样边沿
CPOL 定义空闲 SCK 电平,CPHA 定义数据在第一个还是第二个边沿附近采样/改变;模式 0–3 只是组合名称。波形判断应同时看空闲电平、第一个有效边沿、MOSI 稳定时间和 MISO 采样点。一个模式数字不能代替这些可观察事实。
C · SPI SEGMENTSspi_select(); spi_write(command, 1u); spi_write(address, 3u); spi_write(dummy, dummy_count); spi_read(data, data_count); spi_deselect();
CS 保持、dummy 数量、模式和 ready 轮询必须按具体设备协议确认。
C · SPI CONFIGspi_cfg_t cfg = { .mode = 0u, .sck_hz = 8000000u, .bit_order = MSB_FIRST, .word_bits = 8u }; spi_configure(&cfg);
模式数字不能替代 CPOL/CPHA 波形;最高频率还需电气和器件时序证据。
7.4.3 位序、字宽与 dummy byte
设备命令经常按 MSB-first 或 LSB-first 发送,字宽可能是 8、16 或非整字节,读命令还要发送 dummy byte 才产生时钟让设备返回数据。把接收缓冲的第一个字节当作第一个有效字段会把 dummy、状态和数据错位。应保存完整收发序列。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 选择 | CS/三态/设备 | transfer 自动定义片选 |
| 采样 | CPOL/CPHA/SCK | 模式数字无需波形 |
| 设备 | 命令/dummy/ready | DMA 完成就是设备完成 |
7.4.4 多设备共享总线与 MISO 三态
多个设备可以共享 SCK/MOSI/MISO,但未选中的设备必须释放 MISO;片选极性、上电默认态和 GPIO 复用错误都会让两个输出相冲。连接逻辑分析仪前先确认电平和电流安全。发现 MISO 被强拉或总线异常时停止,不能继续提高频率。
7.4.5 最大 SCK、边沿质量与线长
最大 SCK 由设备时序、电路上升/下降时间、线长、负载、串联电阻和探头影响共同决定。降速后数据正确只能说明在更宽裕条件下可工作,不能推出原频率安全。应记录频率、波形边沿、误码/CRC、供电和温度,比较单变量变化。
从左到右是思考顺序,不是把电平、协议、日志和结论压缩成一个“通过”。
7.4.6 全双工、半双工与三线变体
全双工控制器在每个 SCK 同时移出和移入一个位,读操作往往需要发送占位字节;半双工或三线变体会在命令后切换数据方向。驱动必须描述每一段的方向、字数、何时切换引脚和谁负责三态,否则‘读 N 字节’没有足够信息。
7.4.7 FIFO、DMA 与片选保持
DMA 可以高效搬运连续字节,但控制器是否自动控制 CS、是否允许在一个设备命令中插入分段、FIFO 阈值和缓存一致性都要核对。DMA 完成只说明内存搬运结束,不说明设备内部擦除/转换/ready 已完成;通常还要读状态并设置超时。
7.4.8 本节交付:SPI 设备事务卡
SPI 设备事务卡至少包含 device_id、cs_gpio、mode、sck_hz、bit_order、word_size、segments、dummy_bytes、cs_hold、ready_poll、max_timeout、miso_idle、crc_or_status 和 raw_capture。它把高速总线的时序和器件语义放在同一条交付链上。
请围绕“SPI:片选、模式与吞吐”写出对象、引脚/电平和输入条件、帧或事务机制、输出/响应、一个时序或安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、外设、器件、供电、线缆、工具链、仪器和观察条件。不要用一段十六进制日志、一个 API 返回值或一张解码截图覆盖没有做过的验证。
05 · DRIVER CONTRACT
驱动合同:超时、重试与可观测性
可用的总线驱动不只是初始化外设和提供 read/write 函数。它要定义完成层级、超时来源、取消动作、重试条件、错误分类、缓冲所有权、并发调用、恢复流程和日志字段。本单元把 UART、I²C、SPI 的差异收束成读者可以复查和迁移的驱动合同。
7.5.1 完成语义:入队、线上完成还是设备确认
一个 send API 可以表示‘数据已复制到软件缓冲’、‘已进入外设 FIFO’、‘最后一位已移出’或‘对端返回确认’;这些完成层级的时间和可靠性完全不同。函数名不够,合同必须写返回时刻、缓冲何时可重用、失败时哪些字节可能已在线上。
7.5.2 deadline 与超时计时源
超时需要单调、可回绕且与总线状态相匹配的计时源。UART 等待最后停止位、I²C 等待 SCL 释放、SPI 等待设备 ready 的 deadline 不应混成一个固定 delay。超时记录 now、deadline、阶段、引脚电平和计数器,才能判断是设备慢还是总线卡住。
C · DRIVER DEADLINEuint32_t deadline = monotonic_now() + timeout_ticks; while (!device_ready()) { if (deadline_reached(monotonic_now(), deadline)) { record_timeout(PHASE_READY); recover_bus(); return ERR_TIMEOUT; } }
超时计时源、回绕窗口和恢复顺序必须写入驱动合同。
C · ERROR CLASSswitch (error.phase) { case ADDRESS: return error.nack ? ERR_NO_DEVICE : ERR_BUS; case DATA: return error.crc ? ERR_BAD_FRAME : ERR_DEVICE_REJECT; case RECOVERY: return ERR_BUS_STUCK; default: return ERR_UNKNOWN; }
错误分类只是模型;具体 HAL/RTOS 错误码和副作用需保留原始状态。
7.5.3 错误码要保留阶段和方向
错误码应包含协议阶段和方向,例如地址 NACK、数据 NACK、仲裁丢失、RX overrun、帧错误、CRC 错误、CS 异常、设备 busy 和 timeout。一个通用 EIO 会让上层无法决定重试、降级或报警。日志还应索引原始波形或寄存器快照。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 完成 | 入队/移位/确认 | 函数返回层级不需要说明 |
| 失败 | 阶段/超时/重试 | 负数错误码足够定位 |
| 恢复 | 取消/复位/证据 | 重试次数越多越可靠 |
7.5.4 重试、退避与幂等性
重试前先问操作是否幂等。重复读取通常风险较小,重复 EEPROM 写、清除状态寄存器或发送控制命令可能产生双重副作用。重试次数、退避、随机抖动和最终降级都要写进合同;重试不能成为掩盖物理故障的无限循环。
7.5.5 取消、复位与总线恢复
超时恢复可能需要停止 DMA、禁用 IRQ、等待移位器空、释放 CS、发送 I²C STOP/清线、复位 UART 状态或重新初始化外设。顺序错误会截断最后一位、让对端保持忙或丢失现场。恢复动作应有独立计数和明确的最大持续时间。
从左到右是思考顺序,不是把电平、协议、日志和结论压缩成一个“通过”。
7.5.6 并发、互斥与优先级
总线通常是共享资源,锁保护的是事务边界而不只是一个寄存器。锁内等待慢设备会阻塞高优先级调用,锁外分段又可能让另一个设备插入命令。把总线锁、片选、DMA、回调和线程优先级画成时间线,才能发现隐含的系统级 deadline。
7.5.7 日志、计数器和故障快照
故障日志至少包括 endpoint、bus、speed/baud、transaction_id、phase、byte_index、expected/actual、flags、deadline、retry_count、line_levels、recovery_action 和 raw_capture_ref。计数器要在重启或复位后可解释,避免只保留最后一条‘通信失败’。
7.5.8 本节交付:可迁移驱动合同
可迁移驱动合同把硬件差异留在适配层,把完成定义、错误阶段、超时、重试、所有权和证据字段暴露给上层。这样从 STM32 HAL 换到 Zephyr 或 Linux 时,API 名称会变,验收问题不变。
请围绕“驱动合同:超时、重试与可观测性”写出对象、引脚/电平和输入条件、帧或事务机制、输出/响应、一个时序或安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、外设、器件、供电、线缆、工具链、仪器和观察条件。不要用一段十六进制日志、一个 API 返回值或一张解码截图覆盖没有做过的验证。
06 · BUS DELIVERY
总线交付:从逻辑分析到可复查协议
本章最后把共同模型、UART、I²C、SPI 和驱动合同收束为一份总线交付包:对象与引脚、协议版本、帧/事务、时钟和电气、输入序列、原始波形、解码参数、软件日志、错误与恢复、主机实验和目标机未验证项。交付的目标不是‘线上有字节’,而是边界完整、证据可重放。
7.6.1 交付文件的最小集合
可重放的交付包至少包含准确的芯片/板卡/器件、引脚和电平、总线配置、协议版本、输入序列、原始采样文件、解码参数、软件日志、测试命令和固件哈希。截图或一段十六进制输出只能作为目录,不能替代原始数据和生成步骤。
7.6.2 协议与设备资料版本
数据手册和驱动文档会随器件修订、SDK、HAL/RTOS 版本和板卡连接变化。保存访问日期、页码或 URL、配置生成文件和工具版本;换一个看似兼容的传感器地址、上拉或收发器都可能改变 ACK、时序和电气边界。
PYTHON · FRAME CHECKdef frame_bits(data_bits=8, parity=False, stop_bits=1): if data_bits not in (7, 8, 9) or stop_bits < 1: raise ValueError("invalid serial format") return 1 + data_bits + int(parity) + stop_bits def bus_result(expected, actual): return {"ok": expected == actual, "expected": expected, "actual": actual}
主机函数检查帧长度和字节结果,不能证明电平、采样点或对端状态。
SHELL · BUS EVIDENCEsha256sum build/firmware.elf evidence/raw_bus_capture.bin evidence/driver.log python tools/replay_protocol.py --config evidence/bus.json --capture evidence/raw_bus_capture.bin
目标工具链或重放工具未安装时,仍应保存命令、版本、原始采样和未验证字段。
7.6.3 UART/I²C/SPI 原始波形对齐
UART 的位边界、I²C 的 ACK/START/STOP、SPI 的 CS/采样边沿和软件日志要用共同触发或标记对齐。解码器可能丢失毛刺或使用错误阈值,日志也可能在 DMA/缓存之后才出现。三类证据不一致时保留原始材料,不要挑一条顺眼的。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 身份 | 端点/引脚/版本 | 同一协议名就是同一行为 |
| 事实 | 原始波形/日志/状态 | 一张解码截图覆盖全部 |
| 边界 | 主机/目标/停止 | 未验证项可以省略 |
7.6.4 电气、时序和负载边界
通信正确还需要电气和时序余量:UART 电平与波特率容差、I²C 上拉 RC/电容/拉伸、SPI 边沿/SCK/CS 间隙和收发器负载都要记录。出现总线冲突、过压、异常电流、不可解释的毛刺或温升时停止,先断开负载保存现场。
7.6.5 主机路径:协议模型和故障注入
没有目标板时可以运行帧编码、奇偶、地址/ACK、SPI 模式、队列、超时、重试和故障注入模型;不能声称真实引脚电平、采样裕量、上拉、对端状态或收发器方向已经验证。未执行字段必须写清楚,让读者知道下一步需要什么设备。
从左到右是思考顺序,不是把电平、协议、日志和结论压缩成一个“通过”。
7.6.6 目标机路径:安全连接与恢复
目标机实验先用限流供电、已知无危险负载和可恢复固件,验证引脚复用与电平,再接目标器件。保存错误波形和寄存器状态;卡线、持续 NACK、MISO 冲突、乱码、设备过热或无法重新下载时停止,不要用无限重试扩大风险。
7.6.7 单变量通信回归
单变量回归可以只改 baud/格式、I²C 上拉或速率、SPI mode/SCK/CS 间隙、超时或重试,但不能同时换器件、线缆、探头和驱动。先预测帧、波形、错误、吞吐和恢复,再比较原始证据并记录意外变化。
7.6.8 资料卡:厂商 HAL、Zephyr 与 Linux
STM32 HAL 的 UART/I²C/SPI 文档、Zephyr 的 UART/I²C/SPI API 和 Linux 的 serial/I²C/SPI 子系统可以帮助定位软件入口;它们不能代替当前板卡的电气连接、器件时序、引脚复用、工具设置和线路测量。抽象层越高,边界越要显式。
7.6.9 本章结业:交给 ADC、驱动与联网的接口
交给后续 ADC、驱动、网络和综合交付章节的接口包括 endpoint_identity、pin_mux、voltage、bus_config、frame_or_transaction、completion_level、timeout、retry、error_phase、recovery、raw_capture_ref 和 unverified_scope。下一章应从这些可追溯字段继续。
请围绕“总线交付:从逻辑分析到可复查协议”写出对象、引脚/电平和输入条件、帧或事务机制、输出/响应、一个时序或安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、外设、器件、供电、线缆、工具链、仪器和观察条件。不要用一段十六进制日志、一个 API 返回值或一张解码截图覆盖没有做过的验证。
资料卡(访问日期:2026-09-04):STM32 HAL、Zephyr 和 Linux 的 UART/I²C/SPI 文档展示不同生态的驱动入口;它们帮助定位软件接口,但不能替代当前芯片、器件、板卡电气和线路测量。