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 全寄存器可写性扫描结果(reg[5]-reg[31] 全部可写)
自回环测试中,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 (推挽)。



