RK3506 JTAG调试

/ 0评 / 0

这次我打算一步一步找,包括我调试的过程,所以可能会稍微有点长.

第一步,进入U-Boot的console,从GRF_SOC_CON0选择JTAG端口,比如我要把A7走到这个接口.

mw.l 0xFF288000 0x00300000 

因为bit4-bit5是选择,但是有一个高位写使能,算是掩码写,属于RK典型,这里等于要写grf_jtag_sel=00.

第二步,读这个寄存器,确定SWD是有效.

md.l 0xFF840060 1

接下来有两条路,一条路是用force_jtag,这样可以保留Console直到主动切换,第二条路是直接切换IOMUXC,先说第一条.

这样只要RXD接地时间到uart_jtag_dly_cnt (OSC计数),就会自动切换IOMUXC.

=> mw.l 0xFF910010 0x0000FFFF
=> mw.l 0xFF910000 0x00020002

这时候RXD接地一会,再接仿真器,配置OpenOCD的配置.

adapter driver cmsis-dap
transport select swd
adapter speed 2000
reset_config none

set _CHIPNAME rk
swd newdap $_CHIPNAME cpu -irlen 4
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu

target create rk.a7 cortex_a -dap $_CHIPNAME.dap -coreid 0

init
targets rk.a7
halt

测试连接OK.

taterli@taterli-desktop:~/code$ sudo openocd -f openocd.cfg 
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : Using CMSIS-DAPv2 interface with VID:PID=0xc251:0xf00a, serial=0028003D3537511333383331
Info : CMSIS-DAP: SWD supported
Info : CMSIS-DAP: Atomic commands supported
Info : CMSIS-DAP: Test domain timer supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1
Info : CMSIS-DAP: Interface ready
Info : clock speed 2000 kHz
Info : SWD DPIDR 0x2ba01477
Info : rk.a7: hardware has 6 breakpoints, 4 watchpoints
Info : rk.a7: MPIDR level2 0, cluster f, core 0, multi core, no SMT
Info : starting gdb server for rk.a7 on 3333
Info : Listening on port 3333 for gdb connections
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections

从Telnet测试,读ID.

但是这样需要RXD接地,如果希望上电MUX就要第二个方法.我们用menuconfig开启board_early_init_f调用(CONFIG_BOARD_EARLY_INIT_F).

#include <asm/io.h>

#define GRF_BASE         0xFF288000
#define PMUGRF_BASE      0xFF910000
#define GPIO0_IOC_BASE   0xFF950000

#define GRF_SOC_CON0           0x0000
#define PMUGRF_SOC_CON0        0x0000
#define PMUGRF_SOC_CON4        0x0010
#define GPIO0C_IOMUX_SEL_1     0x0014

#define HIWORD_UPDATE(val, m)  (((m) << 16) | ((val) & (m)))

int board_early_init_f(void)
{
    // GPIO0_C6/C7 -> JTAG_TCK_M1 / JTAG_TMS_M1
    writel(0xFF002200, GPIO0_IOC_BASE + GPIO0C_IOMUX_SEL_1); // IOC: C7=2, C6=2

    // grf_jtag_sel
    writel(HIWORD_UPDATE(0x0000, 0x0030), GRF_BASE + GRF_SOC_CON0);

    // 当RXD接低一段时间,也会切换.
    writel(0x0000FFFF, PMUGRF_BASE + PMUGRF_SOC_CON4);
    writel(0x00020002, PMUGRF_BASE + PMUGRF_SOC_CON0);
    return 0;
}

默认的状态下,U-Boot其实没初始化uart0,如果有,你需要一起修改,然后下载时为了不被内核各种干扰,先全擦.

然后只烧录uboot

这时候启动除了loader,就没输出了,如果还要输出就要mux到其他位置了.

现在设置VSC的launch.json.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Cortex-Debug external (U-Boot@127.0.0.1:3333)",
      "type": "cortex-debug",
      "request": "launch",
      "servertype": "external",
      "gdbTarget": "127.0.0.1:3333",
      "gdbPath": "/usr/bin/gdb-multiarch",
      "cwd": "${workspaceFolder}",
      "executable": "${workspaceFolder}/u-boot/u-boot",

      "overrideLaunchCommands": [
        "-enable-pretty-printing"
      ],

      "preLaunchCommands": [
        "set architecture arm"
      ],

      "postLaunchCommands": [
        "add-symbol-file ${workspaceFolder}/u-boot/u-boot 0x00200000",
      ],

      "showDevDebugOutput": "raw"
    }
  ]
}

进入后强制进_start这个位置,这不是真冷复位,他其实是跳过loader的.

tbreak _start
jump _start

看图,其实这就是入口了.

执行几次si单步,可以看到正常调试.

其实到这里就可以结束了,不过我打算再说说复位,这也是卡了我很久的地方.一开始我打算走真复位,然后硬断点,不行,因为闭源区里有BKPT,会打断,最后还是到_start才能继续.你就当闭源区是BOOTROM,用这种方式跳过也没问题.

有两个触发方式,第一个触发基本等于冷复位,全重置,第二个是部分外设重置,CPU重置,但是两个SWD都掉,主要是loader会把SWD用的引脚重新初始化为UART0.

mww 0xFF9A0C08 0x0000FDB9      ;# 触发 glb_srstn_1
mww 0xFF9A0C0C 0x0000ECA8      ;# 触发 glb_srstn_2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注