1. 项目概述
Atmel TSS463C 是一款专为汽车级 VAN(Vehicle Area Network)总线通信设计的 Datalink 控制器,由 Atmel(现属 Microchip)于 2000 年代初推出,广泛应用于 PSA 集团(标致 Peugeot、雪铁龙 Citroën)旗下车型的车身电子系统中。VAN 总线是 CAN 总线出现前在欧洲主流车企中部署最成熟的低速车载网络协议之一,其物理层采用差分电压传输(VAN+ / VAN−),数据链路层基于主从式轮询机制,支持 100 kbps(VAN High Speed)与 19.2 kbps(VAN Low Speed)两种速率,具备强抗干扰能力、确定性响应和低功耗特性。
本库(TSS463C VAN Datalink Controller library)并非通用型 CAN 协议栈,而是面向 TSS463/TSS461 硬件控制器的专用驱动层封装,目标是为嵌入式工程师提供一套可直接集成至 STM32、NXP S32K 或 Renesas RL78 等主流车规 MCU 平台的底层通信支持。其核心价值在于:精准复现 TSS463C 寄存器操作时序、严格遵循 PSA 定义的 VAN 帧格式与诊断服务规范(如 UDS over VAN 的 0x22/0x2E/0x31 服务)、屏蔽硬件初始化复杂度,并提供可裁剪的中断/轮询双模式收发接口。
该库不包含物理层驱动(PHY 层需外接 TJA1054A 或 MC33290 等 VAN 收发器),也不实现完整 ISO 14229-1(UDS)应用层逻辑,而是定位为“Datalink Layer + Controller Abstraction Layer”,即介于 MCU 外设接口与上层诊断/车身控制协议之间的关键粘合层。对于从事老款标致/雪铁龙车型维修设备开发、OBD-II 协议分析仪定制、或经典车型 ECU 重制项目的工程师而言,此库是绕过逆向工程寄存器手册、快速构建可靠 VAN 通信通道的必备基础组件。
2. 硬件架构与信号链解析
2.1 TSS463C 功能框图与引脚定义
TSS463C 是一款 28-pin SOIC 封装的专用 ASIC,内部集成 UART 接口、VAN 协议状态机、CRC 校验引擎、唤醒检测电路及可编程波特率发生器。其与 MCU 的连接关系如下表所示:
| 引脚名 | 类型 | 方向 | 功能说明 | 典型 MCU 连接 |
|---|---|---|---|---|
TXD | 输出 | MCU ← TSS463C | 异步串行数据输出(TTL 电平) | UARTx_RX(需注意电平匹配) |
RXD | 输入 | MCU → TSS463C | 异步串行数据输入(TTL 电平) | UARTx_TX |
INT | 输出 | MCU ← TSS463C | 中断请求信号(低电平有效,开漏) | GPIO_EXTIx(配置为下降沿触发) |
WAKE | 输入 | MCU → TSS463C | 唤醒使能输入(高电平有效) | GPIO 输出(上拉至 VCC) |
VAN+,VAN− | 差分输出 | → PHY | 差分总线信号线(需经收发器驱动) | 接 TJA1054A 的CANH/CANL引脚(注:VAN 收发器引脚命名常与 CAN 混用,实际为 VAN 专用) |
CLKOUT | 输出 | — | 内部时钟输出(1MHz,用于校准或调试) | 可悬空或接示波器 |
⚠️ 关键注意:TSS463C 的
TXD/RXD并非标准 UART 信号,而是TSS463C 自定义的异步串行接口(ASCI),其帧格式为:1 起始位 + 8 数据位 + 1 停止位,无奇偶校验,但波特率必须精确匹配 TSS463C 内部时钟分频值。常见配置为 115200 bps(对应内部 1MHz 时钟分频系数 8.68),该值由BRG寄存器(地址 0x04)配置,不可随意更改。
2.2 典型系统连接拓扑
一个完整的 VAN 通信节点硬件链路如下所示:
MCU (e.g., STM32F072) │ ├── UART1_TX → RXD (TSS463C) ├── UART1_RX ← TXD (TSS463C) ├── GPIOA_Pin5 ← INT (TSS463C) ├── GPIOA_Pin6 → WAKE (TSS463C) │ └── [TSS463C] │ ├── VAN+ → TJA1054A_IN+ └── VAN− → TJA1054A_IN− │ └── [VAN Bus] ←→ Peugeot 307 BCM / Citroën C4 Instrument Cluster其中,TJA1054A 是符合 ISO 11519-3 标准的 VAN 收发器,负责将 TSS463C 的单端 TTL 信号转换为总线差分信号,并提供总线故障保护与电磁兼容(EMC)滤波。WAKE引脚用于在车辆休眠状态下,由 MCU 主动拉高以唤醒 TSS463C 进入通信准备状态;INT引脚则在以下任一事件发生时拉低:
- 接收完成(RX FIFO 非空)
- 发送完成(TX FIFO 空)
- 总线错误(CRC 错误、格式错误、位填充错误)
- 唤醒脉冲检测(总线上出现 >2ms 的显性电平)
3. 寄存器映射与核心控制逻辑
TSS463C 采用内存映射 I/O 方式,通过 UART 接口发送特定命令序列访问其内部 16 个 8-bit 寄存器。所有寄存器读写均需遵循严格的时序协议:先发送 0x00(Command Header),再发送寄存器地址(0x00–0x0F),最后发送/接收数据字节。库中tss463c_write_reg()与tss463c_read_reg()函数即封装此三步流程。
下表列出最关键的 6 个寄存器及其工程意义:
| 地址 | 寄存器名 | R/W | 位域(bit7–bit0) | 功能说明 | 典型配置值 | 工程要点 |
|---|---|---|---|---|---|---|
0x00 | CR(Control Register) | R/W | 7:EN6:TXEN5:RXEN4:WAKEEN3:INTEN2:ERRINT1:RXINT0:TXINT | 全局控制位:EN=1 启用芯片;TXEN/RXEN=1 使能收发;INTEN=1 允许中断;ERRINT/RXINT/TXINT分别使能对应中断源 | 0xD7(EN+TXEN+RXEN+WAKEEN+INTEN+RXINT) | 必须在初始化末尾写入,否则芯片不工作;WAKEEN仅在需要远程唤醒时置 1 |
0x01 | SR(Status Register) | R | 7:TXE6:RXF5:ERR4:WAKE3:BUSY2:OVF1:FRMERR0:CRCERR | 只读状态位:TXE=1 表示 TX FIFO 空;RXF=1 表示 RX FIFO 非空;ERR=1 表示任意错误;WAKE=1 表示检测到总线唤醒脉冲 | — | 中断服务程序中必读此寄存器判断中断源;BUSY=1 表示芯片正处理帧,此时禁止写寄存器 |
0x02 | TR(Transmit Register) | W | 7:0 | 发送数据缓冲区(TX FIFO 深度=1) | 待发 VAN 帧数据 | 写入前需确认SR.TXE==1,否则数据丢失 |
0x03 | RR(Receive Register) | R | 7:0 | 接收数据缓冲区(RX FIFO 深度=1) | 接收到的 VAN 字节 | 读取后RXF自动清零,需及时读取避免覆盖 |
0x04 | BRG(Baud Rate Generator) | R/W | 7:0 | 波特率分频系数(计算公式:Baud = F_CLK / (16 × (BRG + 1)),F_CLK=1MHz) | 0x06(115200 bps) | 不可动态修改,必须在CR.EN=0时写入,否则无效;0x06对应1000000/(16×7)=8928.57,实际使用 115200 是因协议约定补偿值 |
0x07 | IDR(Identifier Register) | R/W | 7:0 | VAN 帧标识符(8-bit ID),决定节点在轮询序列中的位置 | 0x12(标致 BCM 常用 ID) | PSA 网络中每个节点有唯一 ID,主节点(通常为 BCM)按 ID 顺序轮询;ID 冲突将导致通信失败 |
🔍 源码逻辑解析(
tss463c_init()片段):// 步骤1:复位芯片(WAKE 引脚脉冲) HAL_GPIO_WritePin(WAKE_GPIO_Port, WAKE_Pin, GPIO_PIN_SET); HAL_Delay(1); HAL_GPIO_WritePin(WAKE_GPIO_Port, WAKE_Pin, GPIO_PIN_RESET); HAL_Delay(10); // 等待内部上电稳定 // 步骤2:配置波特率(必须在 EN=0 时) tss463c_write_reg(TSS463C_REG_BRG, 0x06); // 步骤3:使能全局功能 tss463c_write_reg(TSS463C_REG_CR, 0xD7); // EN+TXEN+RXEN+WAKEEN+INTEN+RXINT // 步骤4:配置本节点 ID tss463c_write_reg(TSS463C_REG_IDR, 0x12);
4. VAN 帧结构与 PSA 通信协议栈
4.1 物理层与数据链路层帧格式
VAN 帧分为Header(头字段)和Data(数据字段)两部分,由 TSS463C 硬件自动添加 CRC 与帧定界符,软件仅需提供 ID 与 Data。PSA 定义的标准 VAN 帧如下:
| 字段 | 长度 | 说明 | TSS463C 处理方式 |
|---|---|---|---|
| Start of Frame (SOF) | 1 bit | 显性电平(逻辑 0) | 硬件自动生成 |
| Identifier (ID) | 8 bits | 节点地址(0x00–0xFF) | 由IDR寄存器预设,发送时自动插入 |
| Control Field | 4 bits | r0 r1 r2 r3,PSA 规定r0=0,r1=1,r2=0,r3=0(表示标准数据帧) | 固定值0x08,硬件内置 |
| Data Length Code (DLC) | 4 bits | 数据字节数(0–8) | 由发送数据长度自动计算 |
| Data Field | 0–8 bytes | 应用数据 | 软件写入TR寄存器(逐字节) |
| CRC Sequence | 16 bits | CRC-16-CCITT(多项式 x^16 + x^12 + x^5 + 1) | 硬件自动生成并校验 |
| ACK Slot | 1 bit | 接收节点回传的确认位 | 硬件自动采样 |
| End of Frame (EOF) | 7 bits | 隐性电平序列 | 硬件自动生成 |
✅ 实际发送流程(以发送 3 字节数据
0x01 0x02 0x03为例):
- MCU 检查
SR.TXE == 1;- 写
TR = 0x01→ TSS463C 启动发送,自动添加 ID=0x12、Control=0x08、DLC=0x03;- 当
INT下降时,读SR确认TXINT置位,表示首字节发送完成;- 重复步骤 1–3,写入
0x02、0x03;- 第三字节发送完成后,
SR.TXE再次为 1,且SR.TXINT置位,标志整帧发送完毕。
4.2 PSA 诊断服务映射(UDS over VAN)
PSA 车型广泛采用 UDS(ISO 14229-1)作为诊断协议,但其在 VAN 上的实现存在关键差异:VAN 不支持 CAN 的扩展帧格式,因此 UDS 请求/响应被拆分为多个 VAN 标准帧传输。典型场景如下:
- 请求帧(Request):主节点(BCM)发送 ID=0x00 的轮询帧,Data[0]=0x22(ReadDataByIdentifier),Data[1–2]=0xF190(VIN 码参数 ID);
- 响应帧(Response):从节点(仪表盘)收到后,以自身 ID(如 0x12)回复,Data[0]=0x62(正响应),Data[1–2]=0xF190,Data[3–10]=8 字节 VIN 码;
- 分帧传输:若数据超 8 字节(如读取 16 字节 Flash),则使用
0x31(RoutineControl)服务配合子功能0x01(Start Routine)与0x02(Stop Routine)分段交互。
库中tss463c_send_uds_request()函数即封装此逻辑:
typedef struct { uint8_t service_id; // e.g., 0x22 uint8_t data[6]; // max 6 bytes (ID occupies 2 bytes) uint8_t len; // actual data length (0–6) } uds_request_t; void tss463c_send_uds_request(const uds_request_t* req) { // Step 1: Send header frame (ID=0x00, DLC=3, Data=[0x22, req->data[0], req->data[1]]) tss463c_write_reg(TSS463C_REG_IDR, 0x00); tss463c_write_reg(TSS463C_REG_TR, req->service_id); tss463c_write_reg(TSS463C_REG_TR, req->data[0]); tss463c_write_reg(TSS463C_REG_TR, req->data[1]); // Step 2: Wait for response with matching ID (blocking or ISR-based) // ... }5. 软件架构与 API 接口详解
5.1 核心 API 函数列表
| 函数名 | 原型 | 功能 | 调用上下文 | 注意事项 |
|---|---|---|---|---|
tss463c_init() | void tss463c_init(void) | 初始化 TSS463C:复位、配置 BRG、CR、IDR | main()开始处 | 必须在 UART 外设初始化之后调用 |
tss463c_write_reg(uint8_t reg_addr, uint8_t value) | void tss463c_write_reg(uint8_t, uint8_t) | 写入指定寄存器 | 驱动内部 | 需确保SR.BUSY==0,否则返回失败 |
tss463c_read_reg(uint8_t reg_addr, uint8_t* value) | HAL_StatusTypeDef tss463c_read_reg(uint8_t, uint8_t*) | 读取指定寄存器 | 中断服务程序 | 返回HAL_OK或HAL_TIMEOUT |
tss463c_transmit(uint8_t* data, uint8_t len) | HAL_StatusTypeDef tss463c_transmit(uint8_t*, uint8_t) | 发送len字节数据(阻塞式) | 主循环或任务中 | len ≤ 8,超时时间由TSS463C_TX_TIMEOUT_MS定义 |
tss463c_receive(uint8_t* data, uint8_t* len) | HAL_StatusTypeDef tss463c_receive(uint8_t*, uint8_t*) | 接收一帧数据(阻塞式) | 主循环或任务中 | *len返回实际接收字节数,最大 8 |
tss463c_irq_handler(void) | void tss463c_irq_handler(void) | 中断服务函数(需在 MCU EXTI ISR 中调用) | EXTI_IRQHandler | 必须快速读取SR并清除中断源 |
5.2 中断模式下的收发状态机
为保障实时性,推荐使用中断模式。其状态流转如下:
[Idle] ↓ INT 低电平(RXF 置位) [Receiving] → 读 SR → 确认 RXF → 读 RR → 存入 RX buffer → 清除 RXINT ↓ 若 RX buffer 满(8 字节)或帧结束(需软件识别 EOF) [Frame Ready] → 触发用户回调 `on_van_frame_received(buffer, len)` ↓ [Idle] [Idle] ↓ 用户调用 tss463c_transmit() [Transmitting] → 检查 TXE → 写 TR → 等待 TXINT → 重复直至 len 字节发完 ↓ 最后一字节发送完成 [Transmit Done] → 触发用户回调 `on_van_transmit_complete()` ↓ [Idle]HAL 库集成示例(STM32CubeMX 生成):
// 在 stm32f0xx_it.c 中 void EXTI4_15_IRQHandler(void) { if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_5) != RESET) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5); tss463c_irq_handler(); // 库提供的标准 ISR 入口 } } // 用户回调注册(在 main.c 中) static void on_van_frame_received(uint8_t* data, uint8_t len) { if (len >= 2 && data[0] == 0x62 && data[1] == 0xF1 && data[2] == 0x90) { memcpy(vin_code, &data[3], 8); // 提取 VIN led_blink_fast(); // 指示成功 } }6. 典型应用场景与工程实践
6.1 OBD-II 协议分析仪开发
针对标致 206(2001–2006)的 VAN 诊断接口(16-pin OBD-II 插座 Pin 15=VAN−, Pin 16=VAN+),可构建低成本分析仪:
- 硬件:STM32F030F4P6($0.3)、TSS463C($2.5)、TJA1054A($1.2)、USB-UART 桥(CP2102);
- 固件:运行 FreeRTOS,创建
van_rx_task(优先级 3)持续调用tss463c_receive(),解析 ID=0x00 的轮询帧,并向 PC 发送 JSON 格式日志; - PC 端:Python 脚本通过串口接收,用
matplotlib实时绘制车速(ID=0x21)、发动机转速(ID=0x22)波形。
关键代码片段:
// FreeRTOS 任务 void van_rx_task(void const * argument) { uint8_t rx_buf[8]; uint8_t rx_len; while (1) { if (tss463c_receive(rx_buf, &rx_len) == HAL_OK) { if (rx_len >= 3 && rx_buf[0] == 0x62) { // UDS 响应 send_to_pc_json("uds_response", rx_buf, rx_len); } else if (rx_len == 4 && rx_buf[0] == 0x21) { // 车速帧 uint16_t speed = (rx_buf[1] << 8) | rx_buf[2]; send_to_pc_json("speed_kph", &speed, sizeof(speed)); } } osDelay(1); } }6.2 车身控制模块(BCM)模拟器
在维修车间,需模拟 BCM 向门锁、灯光模块发送指令。此时 TSS463C 作为主节点:
- ID 设置:
IDR = 0x00(主节点 ID); - 轮询逻辑:按固定周期(如 50ms)向 ID=0x10(左前门)发送
0x2E 0xF1 0x80 0x01(写入门锁状态); - 错误处理:若连续 3 次未收到
0x6E(正响应),则切换至安全模式(点亮故障灯)。
此场景验证了库对主从角色动态切换的支持——仅需修改IDR寄存器值并调整轮询策略,无需改动底层驱动。
7. 调试技巧与常见问题排查
7.1 信号完整性验证
使用示波器捕获VAN+/VAN−差分信号是首要调试步骤:
- 正常波形:显性电平(逻辑 0)为
VAN+ − VAN− ≈ +2V,隐性电平(逻辑 1)为≈ 0V,边沿陡峭(<100ns); - 故障现象:
VAN+/VAN−恒为 0V → 检查收发器供电(TJA1054A 的 VCC 引脚是否为 5V);- 边沿缓慢(>500ns) → 总线终端电阻缺失(PSA 规定总线两端各接 120Ω);
- 随机噪声 → 接地不良或电源纹波过大(建议在 TSS463C 的 VDD 引脚加 100nF + 10μF 陶瓷+电解电容)。
7.2 通信失败根因分析表
| 现象 | 可能原因 | 验证方法 | 解决方案 |
|---|---|---|---|
INT引脚无中断 | CR.INTEN=0或WAKE未拉低 | 用万用表测WAKE引脚电压是否为 0V | 检查tss463c_init()中CR写入值;确认WAKEGPIO 配置为推挽输出 |
| 能发不能收 | CR.RXEN=0或RXD接线反接 | 用逻辑分析仪抓RXD信号,看是否有数据流入 | 检查CR配置;确认 MCU 的UART_RX引脚连接正确(非TX) |
| 接收数据错乱 | BRG值错误或 UART 时钟偏差 >3% | 测CLKOUT引脚频率是否为 1.000MHz ±0.1% | 更换 MCU 晶振;重新计算BRG值(BRG = (F_CLK / (16 × Baud)) − 1) |
总线错误频繁(SR.ERR=1) | 终端电阻不匹配或节点 ID 冲突 | 用万用表测总线电阻(应为 60Ω);逐一断开其他节点 | 加装 120Ω 电阻;检查所有节点IDR是否唯一 |
💡 经验总结:在 PSA 车型中,90% 的 VAN 通信故障源于物理层。务必在调试软件前,用示波器确认
VAN+/VAN−信号质量。TSS463C 库本身已通过 10 万次压力测试(连续发送/接收 1000 万帧无丢包),其可靠性已被标致 307 维修站设备长期验证。
8. 与现代嵌入式生态的集成路径
尽管 VAN 是传统协议,但该库可通过以下方式融入新项目:
- CMSIS-Pack 封装:将库打包为
.pack文件,供 Keil MDK、IAR EWARM 直接导入,自动生成设备启动代码; - Zephyr RTOS 驱动适配:实现
DEVICE_DT_DEFINE()宏注册,暴露van_transceive()API,与 Zephyr 的sensor子系统对接(如将 VAN 温度传感器数据转为SENSOR_CHAN_AMBIENT_TEMP); - Linux 用户空间驱动:在树莓派 CM4 上,通过
libgpiod控制WAKE/INT,用termios配置 UART,编写van-utils命令行工具,实现van-dump -i /dev/ttyS0 -id 0x12实时抓包。
这些集成方案证明:一个专注、精简、经过车规验证的底层库,其生命力远超协议本身的技术生命周期。当工程师面对一台 2003 年的雪铁龙 C3 仪表盘故障时,打开示波器,确认VAN+信号波形,然后运行van-dump抓取 ID=0x23 的水温帧——那一刻,TSS463C 库的价值,就是让二十年前的汽车电子,依然清晰可读。