CAN 驱动调试
硬件架构
1 硬件链路
CAN 信号从 P2020 处理器到外部接口经过以下环节:
- P2020 e500mc 处理器 (eLBC Local Bus 控制器)
- → 主板 CPLD (FSP2020-MC203, 地址译码)
- → M890 载板 CPLD (EPM1270T144I4 MAXII)
- → SN74LVC4245APW (3.3V ↔ 5V 电平转换)
- → SJA1000T (U11, 独立 CAN 控制器, 16MHz 晶振 Y2)
- → TJA1040T (U9, CAN 收发器)
- → J3 接口 (1=GND, 3=CAN+, 5=CAN-, 7=GND)
2 关键芯片
|----------------|-------------|----------|------------------|
| 芯片型号 | 功能 | 位置 | 关键参数 |
| P2020 | PowerPC 处理器 | 主板 | e500mc, eLBC 控制器 |
| EPM1270T144I4 | 载板 CPLD | M890 载板 | MAXII, 协议转换 |
| SJA1000T | CAN 控制器 | M890 U11 | PeliCAN, 16MHz |
| TJA1040T | CAN 收发器 | M890 U9 | 5V, 1Mbps |
| SN74LVC4245APW | 电平转换 | M890 U8 | 3.3V↔5V |
3 内存映射
|----------|------------|--------------|--------|---------------|
| 区域 | 物理地址 | 虚拟地址(VA) | 大小 | 用途 |
| eLBC CS2 | 0xC0000000 | 0xC5000000 | 1MB | SJA1000 寄存器窗口 |
| CPLD 控制 | 0xFFA00000 | 0xC6000000 | 1MB | 载板 CPLD 控制寄存器 |
SJA1000 寄存器访问方式:8-bit 字节访问,基址偏移 0x020,stride=2。即 sja_rd(reg) = *(volatile uint8_t *)(0xC5000000 + 0x020 + reg*2)。
2 . SJA1000 驱动设计原理
1 PeliCAN 寄存器映射
|--------|--------------|--------|---------|-------------------------------------|
| 偏移 | 寄存器名 | 读写 | 复位值 | 说明 |
| 0x00 | MOD | R/W | 0x01 | 模式寄存器 (RM/STM/LOM/AFM/SM) |
| 0x01 | CMR | W | --- | 命令寄存器 (TR/AT/RRB/CDO/SRR) |
| 0x02 | SR | R | --- | 状态寄存器 (RBS/DOS/TBS/TCS/RS/TS/ES/BS) |
| 0x03 | IR | R | 0x00 | 中断寄存器 |
| 0x04 | IER | R/W | 0x00 | 中断使能 |
| 0x06 | BTR0 | R/W* | 0x00 | 总线定时 0 (BRP/SJW) |
| 0x07 | BTR1 | R/W* | 0x00 | 总线定时 1 (TSEG1/TSEG2/SAM) |
| 0x08 | OCR | R/W* | 0x12 | 输出控制 |
| 0x0E | RXERR | R | 0x00 | RX 错误计数器 |
| 0x0F | TXERR | R/W* | 0x00 | TX 错误计数器 |
| 0x10+ | TX/RX Buffer | R/W | --- | 发送/接收缓冲 |
| 0x1F | CDR | R/W* | 0x20 | 时钟分频 (bit7=PeliCAN) |
注:标 * 的寄存器仅在复位模式 (RM=1) 下可配置。
2 初始化流程
步骤 1: 进入复位模式:写 MOD = 0x01 (RM=1)
步骤 2: 切换 PeliCAN:写 CDR = 0x80 (bit7=1)
步骤 3: 配置波特率:写 BTR0/BTR1 (500kbps@16MHz)
步骤 4: 配置输出:写 OCR = 0x1A (推挽输出)
步骤 5: 配置验收滤波器:ACR=0x00, AMR=0xFF (全部接收)
步骤 6: 设置自测模式:写 MOD = 0x05 (RM=1 | STM=1)
步骤 7: 退出复位:写 MOD = 0x04 (RM=0, STM=1)
步骤 8: 等待稳定:延时后读 MOD/SR 确认状态
3 自回环测试原理
SJA1000 自测模式 (STM=1) 下,芯片发送的帧会被自身接收,无需外部 CAN 节点即可完成自收自发。测试流程:
- 等待 TBS=1 (发送缓冲空闲)
- 写入 TX Buffer:ID=0x123, DLC=8, data=11 22 33 44 55 66 77 88
- 写 CMR = TR|SRR (请求发送+自接收)
- 等待 TCS=1 (发送完成)
- 等待 RBS=1 (收到帧)
- 读 RX Buffer,与发送数据比对
3 . 调试过程与实测截图
1 寄存器全读 0xFF
最初 SJA1000 寄存器全部读 0xFF,芯片似乎完全不响应。尝试了 8/16/32 位访问、各种 base 偏移和 stride 值,均无效果。
图 1 早期状态:所有寄存器读 0xFF
最终确认:8-bit 访问,基址偏移 0x020,stride=2 可正确读写 MOD/CDR/BTR/OCR。
图 2 调整访问方式后寄存器读值仍为 FF(RM 未退出时正常)
2 复位模式 (RM) 无法退出
核心卡点:写 MOD 清 RM=0 后读回仍为 1。尝试了 PeliCAN/BasicCAN 切换、不同 OCR/BTR 参数、先设 STM 再清 RM、多次重试等,均无法让 RM 清除。
图 3 反复修改驱动代码过程中的编译错误
3 CPLD 窗口映射
通过阅读原厂 Linux 示例代码,发现载板 CPLD 控制寄存器在物理地址 0xFFA00000。添加 TLB 映射后,首次成功退出复位(MOD=0x04, RM=0)。但同时发现访问 CPLD 窗口后 SJA1000 其他寄存器全部读 0xFF,最终回退了 CPLD 窗口映射。
图 4 CPLD 窗口映射相关的内存配置
4 初始化成功
回退 CPLD 窗口后,SJA1000 成功退出复位:MOD=0x04, SR=0x0F。芯片进入正常工作模式,TBS/TCS/RS/TS/ES/BS 全部置位。
图 5 SJA1000 成功退出复位:MD=0x04, RM=0
5全寄存器扫描与 TX/RX Buffer 异常
通过全寄存器可写性扫描(写 0xAA 读回验证),发现复位模式下寄存器 5-31全部"可写可读",包括保留寄存器。这表明读路径可能存在总线浮空问题------读回值只是上次写入总线的数据。
图 6 全寄存器可写性扫描结果(reg5-reg31 全部可写)
自回环测试中,TX Buffer 写入后读回全 0xFF,RX 数据也全 0xFF。TBS/TCS 均正常置位(芯片认为发送完成),但 RBS 未置位(没有收到帧)。
图 7 发送后状态:TBS=1 TCS=1,但 RX Buffer 为 FF
图 8 TX/RX Buffer 读取异常:全部返回 0xFF
6 完整测试套件输出
编写了全量测试套件(T1-T4),一次性测试所有可能配置:T1 基本寄存器读写、T2 复位退出、T3 可写寄存器扫描、T4 五种波特率/OCR 组合回环。所有配置均自回环失败,RX 数据全 0xFF。
图 9 完整测试套件 T1-T4 输出(5 种配置全部 FAIL)
7 当前版本启动日
图 10 最新版最小化初始化启动日志
图 11 自回环测试结果:data mismatch
5. 问题 发现
**■ 总线浮空现象:**SJA1000 写操作正常(可写入寄存器),但读操作返回 0xFF 或上次写入值。往保留寄存器写 0xAA 后读回仍为 0xAA,说明读数据通路可能存在连接问题。
**■ 批量读寄存器风险:**连续读取多个寄存器(特别是保留寄存器)会导致总线浮空,后续所有读取均返回 0xFF。必须逐个寄存器读写,写后立即读。
**■ CPLD 窗口副作用:**添加 0xFFA00000 的 TLB 映射后,SJA1000 寄存器从正确值变为 0xFF。推测 TLB 表项影响了 eLBC 总线配置。
**■ RM 退出条件:**必须先在复位模式下设置 STM=1,再清 RM=0。直接写 MOD=0x00 会导致芯片立即重新进入复位。
**■ 波特率参数:**500kbps@16MHz:BTR0=0x41, BTR1=0x56, OCR=0x1A (推挽)。