关于嵌入式:如何使用OpenOCD ping芯片(检测是否连接了芯片)

How to ping a chip (detect if a chip is connected) with OpenOCD

1.问题解释

我正在尝试使用OpenOCD进行一些罕见的操作。除了连接芯片,我只想检测芯片。
我想到的过程将如下所示:

  • Start OpenOCD with the probe config file (eg. stlink.cfg ) given as -f parameter. So OpenOCD knows what probe to use, but doesn't know what chip it will find.

  • OpenOCD detects a chip and reports this somehow (eg. write something to stdout). If possible, this action should not be intrusive to the chip (like resetting it).

  • OpenOCD shuts down.

  • 有关此过程的更多说明:

    注1:如果OpenOCD未能达到我需要设置Telnet或GDB客户端与之交互的服务器状态,那就太好了。我很乐意以更方便的方式获得芯片检测报告,例如在stdout通道上获取芯片信息。

    注2:检测不应对芯片造成干扰。但是,如果OpenOCD找不到任何东西,我希望有一种备份方法,其中OpenOCD尝试更积极地查找芯片(例如按住nRST引脚)。如果需要,我可以自己调用其他方法(因此,OpenOCD无需自动执行此操作)。

    注3:首先,我将只在具有STLinkV2或STLinkV3探头的STM32芯片上应用此"芯片检测"功能,然后再将其应用于其他探头和芯片。

    注4:某些板仅具有SWD连接(无JTAG)。

    注5:我正在Windows 10计算机上工作,并从https://www.playembedded.org/blog/下载了最新的OpenOCD版本(版本0.10.0_dev00921,于2019年7月6日构建)。下载/

    2.到目前为止我尝试过的

    先生汤米·墨菲(Tommy Murphy)使我参考了OpenOCD参考手册中的10.7节(请参见http://openocd.org/doc/pdf/openocd.pdf)。我已经阅读了本节,并观察了以下示例:

    1
    2
    3
    4
    5
    # openocd.cfg file
    # -----------------
        source [find interface/olimex-arm-usb-tiny-h.cfg]
        reset_config trst_and_srst
        jtag_rclk 8

    由于我的芯片通过STLink探针连接并使用SWD传输协议(而不是JTAG),因此对示例进行了一些修改:

    1
    2
    3
    4
    5
    6
    # openocd.cfg file
    # -----------------
        source [find interface/stlink.cfg]
        transport select hla_swd
        reset_config srst_only
        adapter_khz 480

    我将NUCLEO_F303K8板连接到PC进行此测试。然后在控制台中发出以下命令:

    > openocd -s"C:\\...\\scripts" -f"C:\\...\\openocd.cfg"

    OpenOCD输出以下内容,然后终止:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Open On-Chip Debugger 0.10.0+dev-00921-gef8c69ff9 (2019-07-06-01:00)
    Licensed under GNU GPL v2
    For bug reports, read
            http://openocd.org/doc/doxygen/bugs.html
    adapter speed: 480 kHz

    Info : Listening on port 6666 for tcl connections
    Info : Listening on port 4444 for telnet connections
    Info : clock speed 480 kHz
    Error: BUG: current_target out of bounds

    因此,我最后遇到了一些有关自动探测的问题。

    3.我的问题

    问题1:
    我真正需要的是"自动探测"(如第10.7节中所述)吗?如果答案为"否",请忽略下一个问题。

    问题2:
    我试图模仿第10.7节中给出的示例,并进行了一些小的修改以使该示例适合我的Nucleo开发板。不幸的是,自动探测失败。这是因为OpenOCD不支持使用SWD协议进行自动探测吗?还是我只是在我的.cfg文件中犯了一个错误?

    问题3:
    我注意到第10.7节中的"自动探测"示例配置了OpenOCD的重置行为。从自动复位芯片的意义上来说,这是否意味着自动探测将始终是"侵入式"的?

    问题4:
    无论如何,第10.7节中的自动探测示例似乎使OpenOCD进入服务器状态。有可能避免这种情况吗?我想使"芯片检测"这一事情保持简单,而无需Telnet或GDB客户端。

    编辑

    感谢您@nattgris的出色回答。不过,我还有其他一些实际问题。

    1.使用ST-Link

    假设我们正在使用ST-Link,尽管它与OpenOCD的合作欠佳。您说:

    .. if all you need is to know is whether a chip is there at all, in some configurations the ST-Link can probably be persuaded to give you that info.

    我实际上如何说服ST-Link做到这一点?换句话说,我应该在我的openocd.cfg文件中放入什么来实现此目的?

    2.使用SWD探针(但不使用ST-Link)

    假设我们使用的是真正的SWD探针。您说:

    Autoprobing, as described in Section 10.7, is only relevant for JTAG [...]. Simply connecting via SWD prints the corresponding information (the DPIDR register instead of the TAP IDCODE). So either way, you can get similar info about the chip over both protocols. [...] For all Cortex-chips, you will basically get"ARM" instead of the actual manufacturer of the chip (e.g."ST"). Though ST (and perhaps other manufacturers) chips have a separate boundary scan TAP (i.e. JTAG only) that provides an actual ST IDCODE that can be used for chip identification.

    据此,我得出以下结论:

  • 第10.7节中所述的自动探测仅适用于JTAG,不适用于SWD。

  • 由于自动探测不适用于SWD,因此另一种方法是简单地连接到芯片,然后OpenOCD自动打印DPIDR寄存器。可以说,该DPIDR寄存器与JTAG TAP IDCODE的SWD等效,并且可以在某种程度上识别芯片。
    但是,如果首先不知道将哪个芯片连接到PC,那么如何简单地连接到芯片呢?如果我没记错的话,OpenOCD总是需要特定的配置文件(例如stm32f7x.cfgstm32f4x.cfgstm32l0.cfg,...)连接到芯片。

  • 显然,JTAG IDCODE和与SWD等效的DPIDR寄存器提供了芯片设计器,对于ARM-Cortex芯片,该设计器始终为" ARM "。这还不足以进行完整的芯片识别。但是,您说ARM芯片具有单独的边界扫描TAP,这些TAP提供了更多的IDCODE寄存器以进行更完整的标识。不幸的是,这些仅是JTAG。这意味着SWD在芯片识别方面处于死胡同?

  • 使用JTAG自动探测(并因此读取IDCODE reg)可能是完全非侵入式的。因此,可能会使系统复位信号不可用:reset_config none您说通过SWD读取DPIDR(我认为这与JTAG自动探测的SWD等效)也是非侵入性的。我还可以通过使重置信号不可用来强制执行该"非侵入性"吗?

  • 3.使用JTAG探针(但不使用ST-Link)

    JTAG协议似乎为芯片识别(使用自动探测)提供了最佳支持。我的结论:

  • 第10.7节中描述的自动探测将从芯片上打印TAP IDCODE。对于仅打印" ARM "而不是实际制造商(例如" ST ")和芯片名称(例如" STM32F767ZI ")的ARM芯片。

  • 我实际上如何确保该程序还打印这些进一步的信息,尤其是实际的芯片名称?换句话说,我应该在我的openocd.cfg文件(可能还有openocd启动命令)中放入什么来实现这一目标?

  • 非常感谢您:-)


    问题1:

    这是您需要的吗?要看。如10.7节所述,自动探测仅与JTAG相关。因此,它本身无法满足您的需求。但是只要通过SWD连接就可以打印相应的信息(DPIDR寄存器而不是TAP IDCODE),因此无论哪种方式,您都可以通过两种协议获得有关芯片的类似信息。

    但是,我不确定这是否足以满足您的需求。如果您只想检测一个芯片(任何芯片)有响应,这可能就足够了。如果您还需要详细标识芯片,则通常需要进一步检查,因为通过两种方法获得的ID码都可以标识芯片的设计者。因此,对于所有Cortex芯片,您基本上都会得到" ARM",而不是芯片的实际制造商(例如" ST")。尽管ST(可能还有其他制造商)芯片具有单独的边界扫描TAP(即仅JTAG),该TAP提供了可用于芯片识别的实际ST IDCODE。

    但是,由于SWD仅与ARM Cortex类型(或ADI v5)目标相关,因此,如果可以使用SWD,则还可以读取调试组件的ROM表,该表可以提供芯片制造商的其他信息。 :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # Your JTAG adapter config
    script interface.cfg

    transport select swd
    adapter_khz 100

    swd newdap chip cpu -enable
    dap create chip.dap -chain-position chip.cpu
    target create chip.cpu cortex_m -dap chip.dap

    init
    dap info
    shutdown

    STM32F103的输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    Info : SWD DPIDR 0x1ba01477
    Info : chip.cpu: hardware has 6 breakpoints, 4 watchpoints
    Info : gdb port disabled
    AP ID register 0x14770011
        Type is MEM-AP AHB
    MEM-AP BASE 0xe00ff003
        Valid ROM table present
            Component base address 0xe00ff000
            Peripheral ID 0x00000a0410
            Designer is 0x0a0, STMicroelectronics
            Part is 0x410, Unrecognized
            Component class is 0x1, ROM table
            MEMTYPE system memory present on bus
        ROMTABLE[0x0] = 0xfff0f003
            Component base address 0xe000e000
            Peripheral ID 0x04001bb000
            Designer is 0x4bb, ARM Ltd.
            Part is 0x0, Cortex-M3 SCS (System Control Space)
            Component class is 0xe, Generic IP component
        ROMTABLE[0x4] = 0xfff02003
            Component base address 0xe0001000
            Peripheral ID 0x04001bb002
            Designer is 0x4bb, ARM Ltd.
            Part is 0x2, Cortex-M3 DWT (Data Watchpoint and Trace)
            Component class is 0xe, Generic IP component
        ROMTABLE[0x8] = 0xfff03003
            Component base address 0xe0002000
            Peripheral ID 0x04000bb003
            Designer is 0x4bb, ARM Ltd.
            Part is 0x3, Cortex-M3 FPB (Flash Patch and Breakpoint)
            Component class is 0xe, Generic IP component
        ROMTABLE[0xc] = 0xfff01003
            Component base address 0xe0000000
            Peripheral ID 0x04001bb001
            Designer is 0x4bb, ARM Ltd.
            Part is 0x1, Cortex-M3 ITM (Instrumentation Trace Module)
            Component class is 0xe, Generic IP component
        ROMTABLE[0x10] = 0xfff41003
            Component base address 0xe0040000
            Peripheral ID 0x04001bb923
            Designer is 0x4bb, ARM Ltd.
            Part is 0x923, Cortex-M3 TPIU (Trace Port Interface Unit)
            Component class is 0x9, CoreSight component
            Type is 0x11, Trace Sink, Port
        ROMTABLE[0x14] = 0xfff42002
            Component not present
        ROMTABLE[0x18] = 0x0
            End of ROM table

    对于非Cortex芯片,仅通过自动探测就可以使用JTAG TAP IDCODE获得良好的识别,例如在此示例中使用旧的STR750:

    1
    2
    3
    4
    5
    6
    7
    8
    # Your JTAG adapter config
    script interface.cfg

    transport select jtag
    adapter_khz 100

    init
    shutdown
    1
    Info : JTAG tap: auto0.tap tap/device found: 0x4f1f0041 (mfg: 0x020 (STMicroelectronics), part: 0xf1f0, ver: 0x4)

    问题2:

    如上所述,"自动探测"仅与JTAG相关,但是您也可以通过SWD获得相同的功能(读取ID代码)。不幸的是,这对您无济于事,因为您无权访问这两种协议!

    问题是您使用ST-Link。尽管人们倾向于思考,但这并不是真正的JTAG / SWD适配器。是的,它同时具有JTAG和SWD的功能,但是它完全将协议隐藏在适配器固件中。它仅向主机(OpenOCD)提供高级命令集,类型为"重置目标","步进目标","读取此内存"等。因此,ST-Link的OpenOCD支持是一个丑陋的hack,它位于目标层而不是适配器层。因此,OpenOCD的大多数适配器,传输级别或DAP级别的功能根本不存在,并且从OpenOCD的意义上讲,自动探测与您的设置完全无关。

    要进行简单的刷新和非常基本的GDB调试,可以使用ST-Link。但是,对于任何更底层的内容,请远离ST-Link。对于OpenOCD来说,这根本不是一个很好的选择。

    也就是说,如果您只需要知道是否有芯片,在某些配置中,可以说服ST-Link为您提供该信息,例如,使用以下配置文件:

    1
    2
    3
    4
    5
    6
    7
    8
    script interface/stlink.cfg

    transport select hla_swd
    adapter_khz 100

    hla newtap chip cpu -enable
    dap create chip.dap -chain-position chip.cpu
    target create chip.cpu cortex_m -dap chip.dap

    您将得到其中一个

    1
    Warn : UNEXPECTED idcode: 0x2ba01477

    1
    Error: init mode failed (unable to connect to the target)

    其余问题与ST-Link无关,因此我假定您已切换到真正的JTAG / SWD适配器。

    问题3:

    JTAG自动探测以及通过SWD读取DPIDR完全是非侵入性的。通常,对于Cortex-M目标,大多数对目标的调试访问都是非侵入式的,因此您可以在目标几乎不运行的情况下读/写内存等,而不会影响目标。

    JTAG完全没有定义或要求提供系统复位信号。没有它,自动探测可以正常工作,您应该可以使用

    1
    reset_config none

    问题4:

    您是否要完全避免启动gdb服务器/ telnet服务器?然后,您可以使用以下配置禁用它们:

    1
    2
    3
    gdb_port disabled
    telnet_port disabled
    tcl_port disabled

    但是,如果您只是启动OpenOCD以检测芯片然后将其关闭,则暂时启动这些服务可能不是问题。

    此外,至少只有在创建目标后才启动GDB服务器,这对于执行JTAG自动探针不是必需的。

    摘要

    是的,您应该可以做您想做的事,但也许不能使用ST-Link。使用真正的适配器,您可以执行JTAG自动探测,以在扫描链上打印检测到的TAP。对于SWD,OpenOCD始终打印检测到的DPIDR寄存器(如果找不到目标,则通常会中断;输出至少会有所不同)。

    如果目标本身支持连接/检测,则连接/检测可以是完全非侵入性的,就像大多数Cortex-M一样。如果目标固件已禁用调试引脚或关闭了调试逻辑,则可能需要保持或脉冲复位,具体取决于目标。


    使用主线OpenOCD代码,您可以轻松访问目标的内存。您可以从目标读取一些标识数据并将其解码并检测芯片。

    顺便说一句,这可能不适用于高级适配器(例如STLink)。请使用通用适配器(J-Link,基于FTDI的适配器,CMSIS-DAP等)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    source [find interface/jlink.cfg]
    transport select swd
    adapter_khz 1000

    set _CHIPNAME generic_dap_access

    # 1. DECLARE A DAP
    # -----------------
    # Declare a single DAP (a DAP is the SWD counterpart for a JTAG TAP)
    # for the chip's cpu. The command `swd newdap` has the same parameters
    # as `jtag newtap`.
    # param one:      Name of the module in the JTAG scan chain (usually a chip).
    # param two:      Tapname, reflects the role of the TAP (bs, cpu, flash, ...).
    # -irlen 4:       Instruction register length is 4 bits
    # -ircapture 0x1: The bit pattern loaded by the TAP into the JTAG shift register on entry
    #                 to the ircapture state. Default is 0x01.
    # -irmask 0xf:    A mask used with-ircaptureto verify that instruction scans work correctly.
    swd newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf

    # 2. CREATE (?) A DAP AND LINK TO JTAG TAP
    # -----------------------------------------
    # Since OpenOCD version 0.11.0, the Debug Access Port (DAP) is no longer implicitely
    # created together with the target. It must be explicitely declared.
    # Declare a DAP instance named $_CHIPNAME.dap linked to the JTAG tap $_CHIPNAME.cpu.
    dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
    # Note: Observe important note in manual
    #       for ARMv6-M, ARMv7 and ARMv8 targets.


    # 3. DECLARE SOME PROCEDURES
    # ---------------------------
    # 3.1 Writes 'val' to address 'addr' via AP 'ap'
    proc mww_ll { ap addr val } {
        global _CHIPNAME
        # I'm a bit confused how the following commands achieve just that.
        $_CHIPNAME.dap apreg $ap 0x04 $addr
        $_CHIPNAME.dap apreg $ap 0x0C $val
    }

    # 3.2 Reads and displays data from address 'addr' via AP 'ap'
    proc mdw_ll { ap addr } {
        global _CHIPNAME
        $_CHIPNAME.dap apreg $ap 0x04 $addr
        $_CHIPNAME.dap apreg $ap 0x0C
    }

    # 3.3 Reads data from address 'addr' via AP 'ap' and returns it
    # Can be used to read data and pass it to other commands
    proc mrw_ll { ap addr } {
        global _CHIPNAME
        $_CHIPNAME.dap apreg $ap 0x04 $addr
        set ap [ocd_$_CHIPNAME.dap apreg $ap 0x0C]
        regsub -all {(\\s*\
    )+} $ap"" ap
        return $ap
    }

    # 4. INITIALIZE
    # --------------
    init     # <- What does this actually do? I'm used to see `reset-init`
             #    everywhere in OpenOCD, but I don't know what simple `init` does.

    # 5. READ VALUE AT 0x10000000
    # ----------------------------
    # Reads and displays value at 0x10000000 <- Why? What's special about
    mdw_ll 0 0x10000000 #                            this memory location?

    # 6. MODIFY RAM DATA
    # -------------------
    # Modify some data in RAM <- Why?
    mdw_ll 0 0x08000000
    mww_ll 0 0x08000000 0xdeadbeef
    mdw_ll 0 0x08000000
    exit

    OpenOCD输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Open On-Chip Debugger 0.10.0+dev-01116-gfc2e5110d-dirty (2019-07-11-16:04)
    Licensed under GNU GPL v2
    For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
    adapter speed: 1000 kHz
    Info : J-Link Ultra V4 compiled May 27 2019 15:49:24
    Info : Hardware version: 4.00
    Info : VTarget = 4.850 V
    Info : clock speed 1000 kHz
    Info : SWD DPIDR 0x6ba02477
    Warn : gdb services need one or more targets defined
    0x976562e5
    0x20004602
    0xdeadbeef