みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

Raspberry Pi Pico J-LlinkでOpenOCD

はじめに

J-Link EDUが手元にあるので、OpenOCDでPicoのデバッグができないか試してみた。

接続

下記のように接続する。

Pico ARM-JTAG-SWD
SWDIO SWDIO(7)
SWDCLK SWDCLK(9)
GND GND(4,6,8,10,12,14,16,18,20)
VSYS VCC(1)

PlatformIOのJ-LINK

設定ファイル

${PICO_SDK_PATH}/../openocd/tcl/pico-jlink.cfgを下記の内容で作成する。

source [find interface/jlink.cfg]
transport select swd

source [find target/rp2040.cfg]
adapter speed 4000

アダプタをSWDモードに設定し、アダプタのスピードを設定する。

スピードを設定する際にadapter_khzを使うとadapter speedを使えと怒られる。

OpenOCDの実行(失敗)

下記のコマンドでOpenOCDを実行する。

$ cd ${PICO_SDK_PATH}/../openocd
$ src/openocd -f pico-jlink.cfg -s tcl

下記のようなエラーになる。

Open On-Chip Debugger 0.10.0+dev-geb22ace-dirty (2021-02-24-18:16)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
Info : Hardware thread awareness created
Info : Hardware thread awareness created
Info : RP2040 Flash Bank Command
DEPRECATED! use 'adapter speed' not 'adapter_khz'
adapter speed: 4000 kHz

Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : J-Link V10 compiled Oct 22 2019 16:28:15
Info : Hardware version: 10.10
Info : VTarget = 4.808 V
Info : clock speed 4000 kHz
Error: Sequence 4 not supported.
Info : DAP init failed


Error: Sequence 3 not supported.
Error: Sequence 4 not supported.

エラーの箇所

src/jtag/drivers/jlink.cの下記の関数でエラーになっている。

static int jlink_swd_switch_seq(enum swd_special_seq seq)
{
    const uint8_t *s;
    unsigned int s_len;

    switch (seq) {
        case LINE_RESET:
            LOG_DEBUG("SWD line reset");
            s = swd_seq_line_reset;
            s_len = swd_seq_line_reset_len;
            break;
        case JTAG_TO_SWD:
            LOG_DEBUG("JTAG-to-SWD");
            s = swd_seq_jtag_to_swd;
            s_len = swd_seq_jtag_to_swd_len;
            break;
        case SWD_TO_JTAG:
            LOG_DEBUG("SWD-to-JTAG");
            s = swd_seq_swd_to_jtag;
            s_len = swd_seq_swd_to_jtag_len;
            break;
        default:
            LOG_ERROR("Sequence %d not supported.", seq);
            return ERROR_FAIL;
    }

    jlink_queue_data_out(s, s_len);

    return ERROR_OK;
}

このseqが3、4の場合にエラーになっている。

enum swd_special_seq {
    LINE_RESET,
    JTAG_TO_SWD,
    SWD_TO_JTAG,
    SWD_TO_DORMANT,
    DORMANT_TO_SWD,
}

SWD_TO_DORMANTDORMANT_TO_SWDに未対応ということらしい。

調べてみると、既にPR(Rp2040 jlink #19)は出されている。

patchは2つあり、下記の修正はドンピシャの内容となっている。

From ef234fa045dfae30e4557db0867d4720f46bbbd3 Mon Sep 17 00:00:00 2001
From: Liam Fraser <liam@raspberrypi.com>
Date: Sun, 24 Jan 2021 08:59:02 +0000
Subject: [PATCH] Add DORMANT_TO_SWD and SWD_TO_DORMANT sequences to jlink
 driver

---
 src/jtag/drivers/jlink.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c
index ae8ce49c6..5b2c1ea89 100644
--- a/src/jtag/drivers/jlink.c
+++ b/src/jtag/drivers/jlink.c
@@ -2149,6 +2149,16 @@ static int jlink_swd_switch_seq(enum swd_special_seq seq)
            s = swd_seq_swd_to_jtag;
            s_len = swd_seq_swd_to_jtag_len;
            break;
+       case DORMANT_TO_SWD:
+           LOG_DEBUG("DORMANT-to-SWD");
+           s = swd_seq_dormant_to_swd;
+           s_len = swd_seq_dormant_to_swd_len;
+           break;
+       case SWD_TO_DORMANT:
+           LOG_DEBUG("SWD-to-DORMANT");
+           s = swd_seq_swd_to_dormant;
+           s_len = swd_seq_swd_to_dormant_len;
+           break;
        default:
            LOG_ERROR("Sequence %d not supported.", seq);
            return ERROR_FAIL;

もう一つの方はack待ちが不要なコマンドに対応するものらしい。

From 7e5ea1861a118120a78dac1fd812f1bdcaedc0cc Mon Sep 17 00:00:00 2001
From: graham sanderson <graham.sanderson@gmail.com>
Date: Mon, 25 Jan 2021 12:09:03 -0600
Subject: [PATCH] Add handling of no-ack commands to jlink driver

Change-Id: I4f7b0dad37bc68cde168962d86e53d7f5ea1cad7
---
 src/jtag/drivers/jlink.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c
index 5b2c1ea89..e2537b78f 100644
--- a/src/jtag/drivers/jlink.c
+++ b/src/jtag/drivers/jlink.c
@@ -2002,6 +2002,8 @@ struct pending_scan_result {
    void *buffer;
    /** Offset in the destination buffer */
    unsigned buffer_offset;
+   /** true if the command has nmo acknowledgement */
+   bool no_ack;
 };
 
 #define MAX_PENDING_SCAN_RESULTS 256
@@ -2195,7 +2197,9 @@ static int jlink_swd_run_queue(void)
    }
 
    for (i = 0; i < pending_scan_results_length; i++) {
-      int ack = buf_get_u32(tdo_buffer, pending_scan_results_buffer[i].first, 3);
+       int ack = pending_scan_results_buffer[i].no_ack ?
+               SWD_ACK_OK :
+               buf_get_u32(tdo_buffer, pending_scan_results_buffer[i].first, 3);
 
        if (ack != SWD_ACK_OK) {
            LOG_DEBUG("SWD ack not OK: %d %s", ack,
@@ -2259,6 +2263,9 @@ static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint3
 
        jlink_queue_data_out(data_parity_trn, 32 + 1);
    }
+   pending_scan_results_buffer[pending_scan_results_length].no_ack =
+           (0 == ((cmd ^ swd_cmd(false, false, DP_TARGETSEL)) &
+                         (SWD_CMD_APnDP|SWD_CMD_RnW|SWD_CMD_A32)));
 
    pending_scan_results_length++;

Checkに引っかかっておりマージされないらしい。

パッチの適用

ローカルのソースコードにこれらの変更を適用してみる。手元ではとりあえず手で修正した。

$ make -j $(nproc)

ビルドが通った。

OpenOCDの実行(成功)

再度実行してみる

$ cd ${PICO_SDK_PATH}/../openocd
$ src/openocd -f pico-jlink.cfg -s tcl
Open On-Chip Debugger 0.10.0+dev-geb22ace-dirty (2021-02-24-18:16)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
Info : Hardware thread awareness created
Info : Hardware thread awareness created
Info : RP2040 Flash Bank Command
DEPRECATED! use 'adapter speed' not 'adapter_khz'
adapter speed: 4000 kHz

Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : J-Link V10 compiled Oct 22 2019 16:28:15
Info : Hardware version: 10.10
Info : VTarget = 4.825 V
Info : clock speed 4000 kHz
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x00000001
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x10000001
Info : rp2040.core0: hardware has 4 breakpoints, 2 watchpoints
Info : rp2040.core1: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for rp2040.core0 on 3333
Info : Listening on port 3333 for gdb connections

問題なく起動した。

blinkを実行

pico-examplesのblinkを実行してみる。

OpenOCDとは別のターミナルで下記を実行する。

$ cd ${PICO_EXAMPLES_PATH}/build/blink
$ gdb-multiarch blink.elf
(gdb) target remote :3333
(gdb) mon reset init
(gdb) load
(gdb) c

LEDがチカチカした。

f:id:mickey_happygolucky:20210224193102g:plain
Lチカ

まとめ

J-Link対応のためのPRは既に出されているが 2021/2/24時点ではマージされていない。

修正内容自体は正しそうなので、自分でこれらの修正を取り込むか、PR用のブランチを使用すればJ-Link自体は使用できそう。

CIがしくじっているだけのような気もするので、もうすぐ取り込まれるかも。