刚开始接触全志D1s开发板时,很多开发者都会遇到一个尴尬的问题:板子上明明有强大的平头哥C906 RISC-V内核,却只能用串口打印这种原始方式调试。这就像给你一辆跑车却只能推着走一样憋屈。我自己在开发一个实时图像处理项目时就深有体会,串口调试根本没法追踪程序崩溃时的调用栈,每次出错都要靠猜。
其实D1s芯片在设计时就考虑到了这个问题。它的PF引脚组(PF0、PF1、PF3、PF5)具有双重身份:既可以作为SD卡接口的SDIO功能引脚,也可以通过寄存器配置切换成JTAG调试接口。这就好比家里的多功能插座,既能插电视也能接电脑。东山派开发板就直接把这些引脚引出来做成了标准JTAG接口,但如果你手头只有核心板或者自制底板,就需要自己动手改造了。
硬件上最直接的解决方案就是制作一个SD卡座转JTAG的转接板。这个方案有三大优势:首先是成本极低,打板加元器件不到20元;其次是不用动开发板原有电路,就像给手机加个转接头那么简单;最重要的是完全保留SD卡功能,需要时拔掉转接板就能恢复SD卡使用。
参考东山派的原理图,转接板的核心功能其实很简单:把SD卡座的物理接口转换为标准的10针JTAG接口。但实际操作中有几个坑要特别注意:
第一是板厚必须选择0.8mm。这是因为标准SD卡座的卡槽高度就是按这个规格设计的,我用1.0mm板厚试过根本插不进去。建议直接在嘉立创下单助手选择"SD卡专用板厚"选项,避免翻车。
第二是引脚定义要再三确认。SD卡座的引脚排列比较反直觉,我第一版就画反了。正确的接法应该是:
code复制SD卡座引脚 | 对应功能
--------|---------
DAT1 | JTAG_TMS
DAT0 | JTAG_TDI
CLK | JTAG_TCK
CMD | JTAG_TDO
第三是建议在转接板上添加LED和排阻。虽然理论上直连也能用,但加上100欧姆的串联电阻可以保护IO口,LED则能直观显示供电状态。我在第二版改进时加了这些元件,调试稳定性明显提升。
焊接这种微小元器件时,我的经验是"先固定再连接":先用烙铁给一个焊盘上锡,然后用镊子把元件对齐后加热固定,最后再焊接其他引脚。特别提醒几个易错点:
硬件准备好后,需要通过修改uboot的引脚复用配置。D1s的PF引脚复用由PF_SEL寄存器控制,具体配置如下:
c复制// 在uboot的board/sunxi/sunxi.c中添加
#define PF_SEL_REG 0x030000B0
writel(0x11111111, PF_SEL_REG); // 将PF0-5设置为JTAG功能
这个配置必须在Linux内核启动前完成,否则内核会重新初始化为SDIO功能。我在实际项目中遇到过配置被覆盖的情况,后来发现是uboot环境变量中有冲突的配置项。
连接CKLINK调试器后,需要在PC端做好以下准备:
cklink.cfg:ini复制[interface]
type = jtag
speed = 1000
[target]
chip = C906
ir_len = 5
cklink -d查看设备识别情况。如果显示"TAP: C906",说明链路已通。常见问题排查:
虽然CKLINK自带调试软件,但我更推荐用OpenOCD+GDB的组合,功能更强大。编译时加入以下配置:
bash复制./configure --enable-ftdi --enable-cmsis-dap
make && make install
然后创建配置文件d1s.cfg:
tcl复制interface cmsis-dap
transport select jtag
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d
启动后会看到类似这样的输出,说明调试链路已建立:
code复制Info : JTAG tap: riscv.cpu tap/device found: 0x1000563d (mfg: 0x487 (T-Head)
默认配置下JTAG速度可能只有100kHz,调试大型程序时会非常卡顿。通过以下方法可以提升性能:
tcl复制adapter speed 1000
riscv set_prefer_sba on
c复制#define PF_DRV_REG 0x030000B8
writel(0xFFFFFFFF, PF_DRV_REG); // 设置最大驱动能力
经过这些优化,我的调试速度从原来的10KB/s提升到了300KB/s,下载1MB的固件只需要3秒左右。
在社区里看到很多开发者遇到类似问题,这里总结几个典型case:
Case 1:能识别TAP但无法读写内存
mww 0x03001060 0x1f打开所有调试权限Case 2:调试时随机断连
Case 3:下载程序后无法运行
riscv reset_assert_timeout_sec 2这个方案我已经在三个不同版本的核心板上验证过,包括哪吒D1、LicheeRV和自制的D1s模块。虽然每次都会遇到新的坑,但最终都能成功建立调试链路。建议大家在焊接时多备几个SD卡座,这种精密接插件很容易在调试过程中损坏。