0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

你真正了解SWD如何下载调试的么?

要长高 来源:CSDN博主 作者:背包旅行码农 2023-12-06 11:20 次阅读

作为ARM嵌入式工程师下载调试器都应该知道,但你真正了解SWD如何下载调试的么?ARM 芯片通过什么物理接口和什么方式连接完全取决于芯片Debug子系统的架构如何?

你可以从芯片手册的Debug章节获得DAP(Debug Access Port)的信息。我调试的是NXP公司最新车载芯片S32K3系列的芯片,从S32K3xx Reference Manual中Debug 子系统章节中得知该芯片的debug和Trace接口基于Arm CoreSight SoC-400的标准。 从Arm CoreSight SoC-400 Technical Reference Manual章节Debug Access Port中你可以获取到详细的信息。这里只做关键内容介绍,只介绍涉及的部分。

参考文档:Arm CoreSight SoC-400 Technical Reference Manual , CoreSight Components Technical Reference Manual , Arm CoreSight Architecture Specification。

从Arm CoreSight SoC-400 Technical Reference Manual中Figure 4-1 Structure of the CoreSight SoC-400 DAP components看出SWD只是接入芯片调试子系统的一种方式而已。

1663903486186432.png

那么外部调试工具是怎么通过SWD的方式接入到ARM核内部的呢?下面我们详细介绍一下CoreSight SoC-400 DAP组件架构。

DAP是片外调试工具接入SOC组件的集合。访问方式是按照ARM®调试接口架构规范ADIv5.0~ADIv5.2实现。

DAP由以下组件组成:

•DP用于管理与外部调试器的连接。

•AP访问片上系统资源。 每种类型的AP可以有多个。

•DAPBUS互连,用于将DP连接到一个或多个AP。

AP提供了非侵入式访问权限:

•CoreSight组件下载或者烧录模型。 通常是通过系统级CoreSight APB总线和APB-AP来完成的。

•内存映射的系统组件,通常使用AXI-AP或AHB-AP。

•使用JTAG-AP的旧版JTAG配置的调试组件。

而且,某些支持CoreSight的处理器直接连接到DAPBUS互连,并实现自己的ADIv5兼容AP。

CoreSight SoC具有单个多功能DP,如下所示:

SWJ-DP 这是一个组合调试端口,可以通过ADIv5.1定义的JTAG或串行线协议进行通信。它包含两个调试端口SW-DP和JTAG-DP,您可以通过接口时序命令选择它们,以在调试端口接口之间切换。

JTAG-DP 兼容DP架构版本0。SW-DP兼容DP架构版本2和Serial Wire协议版本2,使SW-DP可以与其他SW-DP或其他实现组件共享连接。

CoreSight SoC中包含的AP端口是:

AXI-AP AXI-AP实现了ADIv5存储器访问端口(MEM-AP)架构,以直接连接到AXI存储器系统。 您可以使用适当的桥接组件将其连接到其他内存系统。

AHB-AP AHB-AP提供了一个AHB-Lite主站,用于访问系统AHB总线。 这兼容ADIv5.1中的MEM-AP并且可以执行8到32位访问。

APB-AP APB-AP在AMBA v3.0中提供了一个APB主设备,用于访问调试APB总线。 这兼容具有32位固定传输大小的MEM-AP体系结构。

JTAG-AP JTAG-AP提供对片上组件的JTAG访问,用作JTAG主端口以驱动ASIC中的JTAG链。 这是ADIv5.1中JTAG-AP的实现。

DAPBUS 互连将DP连接到AP。 系统可能不包含某些类型的AP,或者可能包含多个相同类型的AP。

单纯看CoreSight SoC-400 DAP组件架构,感觉会比较空洞,我们结合一下S32K3XX DAP架构图来看一下。

1663903499758403.png

从芯片的DAP architecture,不难看出S32K3采用的是Arm®CoreSight™架构。

你基本可以找到 CoreSight SoC-400和S32K3XX的DAP architecture对应关系:

S32K3XX CoreSight SoC-400

SWJ-DAP <--> Serial Wire JTAG Debug Port (SWJ-DP)

DAPMUX <--> DAPBUS interconnect

AHB_AP <--> AHB Access Port (AHB-AP)

APB-AP <--> APB Access Port (APB-AP)

MDM_AP <--> DAPBUS exported interface

SDA_AP <--> DAPBUS exported interface

SWJ-DP由JTAG-DP和SW-DP的组成。 它选择JTAG或SWD作为连接机制,并启用JTAG-DP或SW-DP作为DAP的接口。

JTAG和SWD接口

JTAG接口具有四个强制引脚tck,tms,tdi和tdo,以及一个可选的复位引脚ntrst。 JTAG-DP和SW-DP还需要独立的上电复位npotrst。

SWD接口需要两个引脚:

•双向swdio信号

时钟swclk,可以从设备输入或输出。

为了使JTAG或SWD共享连接器,必须在SWJ-DP模块外部进行连接。 特别是,tms必须是双向引脚,以支持SWD模式下的双向swdio引脚。

20-Pin ARM Standard JTAG Connector

1663903522710894.png

(From https://www2.keil.com/coresight/coresight-connectors)

它支持用于访问基于ARM7和ARM9的设备的JTAG接口。 对于Cortex-Mx设备,它支持串行线和JTAG接口,以访问Cortex-Mx设备上可用的所有SWD,SWV和JTAG信号。

那么是调试工具是通过什么方式访问Cortex-Mx内部的呢?

参考文档:ARM® Debug Interface Architecture Specification ADIv5.0 to ADIv5.2

DAP访问方式是按照ARM®调试接口架构规范ADIv5.0~ADIv5.2实现。

DAP****结构框图如下:

来自ARM® Debug Interface Architecture Specification ADIv5.0 to ADIv5.2的Figure A1-2 Structure of the DAP, showing DPv0 JTAG-DP accesses to a generic AP

1663903524417397.png

ADI包括:

Debug Access Port (DAP),DAP外部物理连接 和 DAP与内部调试资源组件的连接。

DAP包含两个逻辑模块,Debug Port(DP) 和 Access Port(AP)。DP来连接外部的host,AP来访问内部的调试组件寄存器:

• Access to the Debug Port (DP) registers. This is provided by Debug Port accesses (DPACC).

• Access to the Access Port (AP) registers. This is provided by Access Port accesses (APACC)

ADIv5标准外部接口支持一下几种DP:

• The JTAG Debug Port (JTAG-DP)

• The Serial Wire Debug Port (SW-DP)

• The Serial Wire/JTAG Debug Port (SWJ-DP)

内部资源接口包含:

AP (MEM-AP or JTAG-AP)

由于我选择使用的是SW-DP的方式访问,我这里只对SWD协议处理流程介绍。

我们下面剖析一下SW-DP报文格式(担心翻译有误,就用英文原文):

Start A single start bit, with value 0b1.

APnDP A single bit, indicating whether the Debug Port or the Access Port Access register is to be accessed. This bit is 0b0 for a DPACC access, or 0b1 for an APACC access.

RnW A single bit, indicating whether the access is a read or a write. This bit is 0b0 for a write access, or 0b1 for a read access.

A[2:3] Two bits, giving the A[3:2] address field for the DP or AP register Address:

• For a DPACC access, the register being addressed depends on the A[3:2] value and, if A[3:2]==0b01, the value that is held in SELECT. DPBANKSEL. For details, see:

— DP architecture version 1 (DPv1) address map on page B2-50

1663903536691891.png

— DP architecture version 2 (DPv2) address map on page B2-51.

1663903545571092.png

• For an APACC access, the register being addressed depends on the A[3:2] value and the value

that is held in SELECT.{APSEL,APBANKSEL}. For details about addressing, see:

— MEM-AP Programmers’ Model on page C2-169 for accesses to a MEM-AP register

1663903552519817.png

— JTAG-AP register summary on page C3-206 for accesses to a JTAG-AP register.

1663903560152462.png

Note

The A[3:2] value is transmitted Least Significant Bit (LSB) first on the wire, which is why it appears as A[2:3] on the diagrams.

Parity A single parity bit for the preceding packet. See Parity on page B4-108.

Stop A single stop bit. In the synchronous SWD protocol, this bit is always 0b0.

Park A single bit. The host must drive the Park bit HIGH to park the line before tristating it for the turnaround period, to ensure that the line is read as HIGH by the target, which is required because the pull-up on the SWD interface is weak. The target reads this bit as 0b1.

Trn Turnaround. See Line turnaround on page B4-107.

Note

All the examples that are given in this chapter show the default turnaround period of one cycle.

ACK[0:2] A three-bit target-to-host response.

1663903569279765.png

WDATA[0:31]

32 bits of write data, from host to target.

RDATA[0:31]

32 bits of read data, from target to host

我们已经了解了报文格式,那我们结合SWD的报文读写时序图来理解。

Successful write operation (OK response)

1663903577467676.png

Successful read operation (OK response)

1663903599297173.png

下面我结合Successful write operation (OK response)和Structure of the Debug Access Port举个例子演示一下SWD如何控制DAP。

Every AP or DP access transaction from the debugger includes two address bits, A[3:2]:

• For a DP register access, the address bits A[3:2] and SELECT.DPBANKSEL determine which register is accessed. SELECT is a DP register.

• For an AP register access, SELECT.APSEL selects an AP to access, and the address bits A[3:2] are combined with SELECT.APBANKSEL to determine which AP register is accessed, as summarized in Structure of the Debug Access Port. That is, the two address bits A[3:2] are decoded to select one of the four 32-bit words from the register bank indicated by SELECT.APBANKSEL in the AP indicated by SELECT.APSEL. Bits [1:0] of all AP and DP register addresses are 0b00.

假如我要向AP0寄存器0x14里写入0xF0000001,调试工具操作流程如下:

1663903615337573.png

使用DP寄存器向DP的SELECT寄存器写入:

— SELECT.APSEL to 0x00. APSEL, bits[31:24]

— SELECT.APBANKSEL to 0x1. APBANKSEL, bits[7:4]

APnDP 写0 表示DP操作,A[3:2]写0x02表示操作0x08 SELECT 寄存器。写入0x00000001.

使用AP寄存器向AP0的0x14寄存器写入:

APnDP 写1 表示AP操作,由于已经向DP的SELECT选择了APBANKSEL为0x01,A[3:2]写0x01表示操作0x14 寄存器。写入0xF0000001. 在这个情况下能访问0x10~0x1C等4个寄存器。

其他AP操作其实流程一样。

下面我稍微了解一下MEM-AP.

来自 ARM® Debug Interface Architecture Specification ADIv5.0 to ADIv5.2的Figure C2-1 MEM-AP connecting the DP to debug components

1663903652399406.png

说白了MEM-AP为DAP提供了一种直接访问系统地址空间的访问。操作其实和通用AP的访问一样。MEM-AP访问系统地址空间,其实有多了一层间接访问。我们直接从OpenOCD源码中看整个过程。

https://sourceforge.net/p/openocd/code/ci/v0.11.0/tree/src/target/cortex_m.c#l2521

struct target_type cortexm_target = {

.name = "cortex_m",

.deprecated_name = "cortex_m3",

.poll = cortex_m_poll,

.arch_state = armv7m_arch_state,

.target_request_data = cortex_m_target_request_data,

.halt = cortex_m_halt,

.resume = cortex_m_resume,

.step = cortex_m_step,

.assert_reset = cortex_m_assert_reset,

.deassert_reset = cortex_m_deassert_reset,

.soft_reset_halt = cortex_m_soft_reset_halt,

.get_gdb_arch = arm_get_gdb_arch,

.get_gdb_reg_list = armv7m_get_gdb_reg_list,

.read_memory = cortex_m_read_memory,

.write_memory = cortex_m_write_memory,

.checksum_memory = armv7m_checksum_memory,

.blank_check_memory = armv7m_blank_check_memory,

.run_algorithm = armv7m_run_algorithm,

.start_algorithm = armv7m_start_algorithm,

.wait_algorithm = armv7m_wait_algorithm,

.add_breakpoint = cortex_m_add_breakpoint,

.remove_breakpoint = cortex_m_remove_breakpoint,

.add_watchpoint = cortex_m_add_watchpoint,

.remove_watchpoint = cortex_m_remove_watchpoint,

.commands = cortex_m_command_handlers,

.target_create = cortex_m_target_create,

.target_jim_configure = adiv5_jim_configure,

.init_target = cortex_m_init_target,

.examine = cortex_m_examine,

.deinit_target = cortex_m_deinit_target,

.profiling = cortex_m_profiling,

};

OpenOCD通过DAP MEM AP的访问实现Cortex M系统地址空间的访问。

cortex_m_read_memory和cortex_m_write_memory实现了读写操作。看一下这两个函数是怎么实现的。

cortex_m_read_memory实现

static int cortex_m_read_memory(struct target *target, target_addr_t address,

uint32_t size, uint32_t count, uint8_t *buffer)

{

struct armv7m_common *armv7m = target_to_armv7m(target);

if (armv7m->arm.is_armv6m) {

/* armv6m does not handle unaligned memory access */

if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))

return ERROR_TARGET_UNALIGNED_ACCESS;

}

return mem_ap_read_buf(armv7m->debug_ap, buffer, size, count, address);

}

int mem_ap_read_buf(struct adiv5_ap *ap,

uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address)

{

return mem_ap_read(ap, buffer, size, count, address, true);

}

/**

* Synchronous read of a block of memory, using a specific access size.

*

* @param ap The MEM-AP to access.

* @param buffer The data buffer to receive the data. No particular alignment is assumed.

* @param size Which access size to use, in bytes. 1, 2 or 4.

* @param count The number of reads to do (in size units, not bytes).

* @param adr Address to be read; it must be readable by the currently selected MEM-AP.

* @param addrinc Whether the target address should be increased after each read or not. This

* should normally be true, except when reading from e.g. a FIFO.

* @return ERROR_OK on success, otherwise an error code.

*/

static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint32_t count,

uint32_t adr, bool addrinc)

{

struct adiv5_dap *dap = ap->dap;

size_t nbytes = size * count;

const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF;

uint32_t csw_size;

uint32_t address = adr;

int retval = ERROR_OK;

/* TI BE-32 Quirks mode:

* Reads on big-endian TMS570 behave strangely differently than writes.

* They read from the physical address requested, but with DRW byte-reversed.

* For example, a byte read from address 0 will place the result in the high bytes of DRW.

* Also, packed 8-bit and 16-bit transfers seem to sometimes return garbage in some bytes,

* so avoid them. */

if (size == 4)

csw_size = CSW_32BIT;

else if (size == 2)

csw_size = CSW_16BIT;

else if (size == 1)

csw_size = CSW_8BIT;

else

return ERROR_TARGET_UNALIGNED_ACCESS;

if (ap->unaligned_access_bad && (adr % size != 0))

return ERROR_TARGET_UNALIGNED_ACCESS;

/* Allocate buffer to hold the sequence of DRW reads that will be made. This is a significant

* over-allocation if packed transfers are going to be used, but determining the real need at

* this point would be messy. */

uint32_t *read_buf = calloc(count, sizeof(uint32_t));

/* Multiplication count * sizeof(uint32_t) may overflow, calloc() is safe */

uint32_t *read_ptr = read_buf;

if (read_buf == NULL) {

LOG_ERROR("Failed to allocate read buffer");

return ERROR_FAIL;

}

/* Queue up all reads. Each read will store the entire DRW word in the read buffer. How many

* useful bytes it contains, and their location in the word, depends on the type of transfer

* and alignment. */

while (nbytes > 0) {

uint32_t this_size = size;

/* Select packed transfer if possible */

if (addrinc && ap->packed_transfers && nbytes >= 4

&& max_tar_block_size(ap->tar_autoincr_block, address) >= 4) {

this_size = 4;

retval = mem_ap_setup_csw(ap, csw_size | CSW_ADDRINC_PACKED);

} else {

retval = mem_ap_setup_csw(ap, csw_size | csw_addrincr);

}

if (retval != ERROR_OK)

break;

retval = mem_ap_setup_tar(ap, address);

if (retval != ERROR_OK)

break;

retval = dap_queue_ap_read(ap, MEM_AP_REG_DRW, read_ptr++);

if (retval != ERROR_OK)

break;

nbytes -= this_size;

if (addrinc)

address += this_size;

mem_ap_update_tar_cache(ap);

}

if (retval == ERROR_OK)

retval = dap_run(dap);

/* Restore state */

address = adr;

nbytes = size * count;

read_ptr = read_buf;

/* If something failed, read TAR to find out how much data was successfully read, so we can

* at least give the caller what we have. */

if (retval != ERROR_OK) {

uint32_t tar;

if (mem_ap_read_tar(ap, &tar) == ERROR_OK) {

/* TAR is incremented after failed transfer on some devices (eg Cortex-M4) */

LOG_ERROR("Failed to read memory at 0x%08"PRIx32, tar);

if (nbytes > tar - address)

nbytes = tar - address;

} else {

LOG_ERROR("Failed to read memory and, additionally, failed to find out where");

nbytes = 0;

}

}

/* Replay loop to populate caller's buffer from the correct word and byte lane */

while (nbytes > 0) {

uint32_t this_size = size;

if (addrinc && ap->packed_transfers && nbytes >= 4

&& max_tar_block_size(ap->tar_autoincr_block, address) >= 4) {

this_size = 4;

}

if (dap->ti_be_32_quirks) {

switch (this_size) {

case 4:

*buffer++ = *read_ptr >> 8 * (3 - (address++ & 3));

*buffer++ = *read_ptr >> 8 * (3 - (address++ & 3));

/* fallthrough */

case 2:

*buffer++ = *read_ptr >> 8 * (3 - (address++ & 3));

/* fallthrough */

case 1:

*buffer++ = *read_ptr >> 8 * (3 - (address++ & 3));

}

} else {

switch (this_size) {

case 4:

*buffer++ = *read_ptr >> 8 * (address++ & 3);

*buffer++ = *read_ptr >> 8 * (address++ & 3);

/* fallthrough */

case 2:

*buffer++ = *read_ptr >> 8 * (address++ & 3);

/* fallthrough */

case 1:

*buffer++ = *read_ptr >> 8 * (address++ & 3);

}

}

read_ptr++;

nbytes -= this_size;

}

free(read_buf);

return retval;

}

static int cortex_m_write_memory(struct target *target, target_addr_t address,

uint32_t size, uint32_t count, const uint8_t *buffer)

{

struct armv7m_common *armv7m = target_to_armv7m(target);

if (armv7m->arm.is_armv6m) {

/* armv6m does not handle unaligned memory access */

if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))

return ERROR_TARGET_UNALIGNED_ACCESS;

}

return mem_ap_write_buf(armv7m->debug_ap, buffer, size, count, address);

}

int mem_ap_write_buf(struct adiv5_ap *ap,

const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address)

{

return mem_ap_write(ap, buffer, size, count, address, true);

}

/**

* Synchronous write of a block of memory, using a specific access size.

*

* @param ap The MEM-AP to access.

* @param buffer The data buffer to write. No particular alignment is assumed.

* @param size Which access size to use, in bytes. 1, 2 or 4.

* @param count The number of writes to do (in size units, not bytes).

* @param address Address to be written; it must be writable by the currently selected MEM-AP.

* @param addrinc Whether the target address should be increased for each write or not. This

* should normally be true, except when writing to e.g. a FIFO.

* @return ERROR_OK on success, otherwise an error code.

*/

static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t size, uint32_t count,

uint32_t address, bool addrinc)

{

struct adiv5_dap *dap = ap->dap;

size_t nbytes = size * count;

const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF;

uint32_t csw_size;

uint32_t addr_xor;

int retval = ERROR_OK;

/* TI BE-32 Quirks mode:

* Writes on big-endian TMS570 behave very strangely. Observed behavior:

* size write address bytes written in order

* 4 TAR ^ 0 (val >> 24), (val >> 16), (val >> 8), (val)

* 2 TAR ^ 2 (val >> 8), (val)

* 1 TAR ^ 3 (val)

* For example, if you attempt to write a single byte to address 0, the processor

* will actually write a byte to address 3.

*

* To make writes of size < 4 work as expected, we xor a value with the address before

* setting the TAP, and we set the TAP after every transfer rather then relying on

* address increment. */

if (size == 4) {

csw_size = CSW_32BIT;

addr_xor = 0;

} else if (size == 2) {

csw_size = CSW_16BIT;

addr_xor = dap->ti_be_32_quirks ? 2 : 0;

} else if (size == 1) {

csw_size = CSW_8BIT;

addr_xor = dap->ti_be_32_quirks ? 3 : 0;

} else {

return ERROR_TARGET_UNALIGNED_ACCESS;

}

if (ap->unaligned_access_bad && (address % size != 0))

return ERROR_TARGET_UNALIGNED_ACCESS;

while (nbytes > 0) {

uint32_t this_size = size;

/* Select packed transfer if possible */

if (addrinc && ap->packed_transfers && nbytes >= 4

&& max_tar_block_size(ap->tar_autoincr_block, address) >= 4) {

this_size = 4;

retval = mem_ap_setup_csw(ap, csw_size | CSW_ADDRINC_PACKED);

} else {

retval = mem_ap_setup_csw(ap, csw_size | csw_addrincr);

}

if (retval != ERROR_OK)

break;

retval = mem_ap_setup_tar(ap, address ^ addr_xor);

if (retval != ERROR_OK)

return retval;

/* How many source bytes each transfer will consume, and their location in the DRW,

* depends on the type of transfer and alignment. See ARM document IHI0031C. */

uint32_t outvalue = 0;

uint32_t drw_byte_idx = address;

if (dap->ti_be_32_quirks) {

switch (this_size) {

case 4:

outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor);

outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor);

outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor);

outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx & 3) ^ addr_xor);

break;

case 2:

outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx++ & 3) ^ addr_xor);

outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx & 3) ^ addr_xor);

break;

case 1:

outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ (drw_byte_idx & 3) ^ addr_xor);

break;

}

} else {

switch (this_size) {

case 4:

outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3);

outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3);

/* fallthrough */

case 2:

outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3);

/* fallthrough */

case 1:

outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx & 3);

}

}

nbytes -= this_size;

retval = dap_queue_ap_write(ap, MEM_AP_REG_DRW, outvalue);

if (retval != ERROR_OK)

break;

mem_ap_update_tar_cache(ap);

if (addrinc)

address += this_size;

}

/* REVISIT: Might want to have a queued version of this function that does not run. */

if (retval == ERROR_OK)

retval = dap_run(dap);

if (retval != ERROR_OK) {

uint32_t tar;

if (mem_ap_read_tar(ap, &tar) == ERROR_OK)

LOG_ERROR("Failed to write memory at 0x%08"PRIx32, tar);

else

LOG_ERROR("Failed to write memory and, additionally, failed to find out where");

}

return retval;

}

MEM-AP这里我就不画图介绍了,对于我来说只要知道MEM-AP是如何帮助DAP访问到系统地址空间的原理就可以了,大家直接看源码实现去理解。大家想要知道更多细节可以参考ADIv5.0~ADIv5.2章节 7. The Memory Access Port (MEM-AP)

审核编辑:黄飞

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • ARM
    ARM
    +关注

    关注

    134

    文章

    9084

    浏览量

    367373
  • 调试器
    +关注

    关注

    1

    文章

    303

    浏览量

    23716
  • 车载芯片
    +关注

    关注

    0

    文章

    73

    浏览量

    14681
  • SWD
    SWD
    +关注

    关注

    1

    文章

    57

    浏览量

    11827
  • 调试接口
    +关注

    关注

    0

    文章

    10

    浏览量

    5099
收藏 人收藏

    评论

    相关推荐

    程序下载接口的区别----JTAG vs SWD

    简单来说,下载调试器是将PC(例如通过USB协议)发送的命令转换为MCU(负责MCU内部外围设备)理解的语言(例如SWD或JTAG协议)的设备,加载代码并精确控制执行。
    的头像 发表于 09-28 14:44 4101次阅读
    程序<b class='flag-5'>下载</b>接口的区别----JTAG vs <b class='flag-5'>SWD</b>

    stm32w的下载调试方式包含了jtage,swd是否支持串口isp下载

    大侠 请支支招吧stm32w的下载调试方式包含了jtage,swd是否支持串口isp下载
    发表于 03-28 10:17

    调试器能用SWD下载,为什么有些调试器还要带一个虚拟串口?

    新手请教一下,淘宝买了个stlink能 运行SWD和JTAG,SWD下载。为什么有些其它的调试器在支持SWD的情况下还要带一个虚拟串口来
    发表于 08-07 11:46

    为什么STM32会禁止JTAG调试功能却保留SWD下载调试功能呢

    为什么STM32会禁止JTAG调试功能却保留SWD下载调试功能呢?
    发表于 11-25 08:56

    SWD和JTAG接口的含义和区别

    作为嵌入式软件工程师,下载调试器都应该知道,但真正了解SWD 和 JTAG接口的含义和区别吗
    发表于 12-10 07:24

    STLINK和JLINK使用SWD四线调试下载STM32的方法

    STLINK和JLINK使用SWD四线调试下载STM32的方法
    发表于 01-19 06:48

    如何解决STM32禁用SWD调试接口后不能下载程序的问题?

    如何解决STM32禁用SWD调试接口后不能下载程序的问题?
    发表于 01-27 07:53

    JTAG接口如何转SWD接口_JTAG接口转SWD接口方法

    本文为大家介绍JTAG接口转SWD接口方法,利用此转换方式,可以简化板载调试接口(相应单片机应支持SWD调试)。
    发表于 01-11 10:23 3.3w次阅读
    JTAG接口如何转<b class='flag-5'>SWD</b>接口_JTAG接口转<b class='flag-5'>SWD</b>接口方法

    了解这些常用器件封装和其名字来历

    了解这些常用器件封装及其名字来历
    的头像 发表于 01-16 11:06 4628次阅读

    调试接口SWD和JTAG的区别

    作者 | strongerHuang 微信公众号 | strongerHuang 作为嵌入式工程师,下载调试器都应该知道,但真正了解
    的头像 发表于 10-27 09:29 1.7w次阅读
    <b class='flag-5'>调试</b>接口<b class='flag-5'>SWD</b>和JTAG的区别

    下载调试接口SWD和JTAG的区别

    作为嵌入式工程师,下载调试器都应该知道,但真正了解SWD 和 JTAG 接口的含义和区别吗
    的头像 发表于 11-28 11:44 4587次阅读

    stm32 SWD调试接口的使用

    SWD 和传统的调试方式区别    1. SWD 模式比 JTAG 在高速模式下面更加可靠。 在大数据量的情况下面 JTAG 下载程序会失败, 但是
    发表于 12-02 17:06 27次下载
    stm32 <b class='flag-5'>SWD</b><b class='flag-5'>调试</b>接口的使用

    解决STM32禁用SWD调试接口后不能下载程序的问题

    STM32的PA13(SWDIO)、PA14(SWCLK)这两个引脚为SWD调试接口,因为STM32默认把这两个接口当作了下载接口,所以如果程序中有用到这两个接口的任意一个(比如用来作为普通I/O口
    发表于 12-02 18:51 29次下载
    解决STM32禁用<b class='flag-5'>SWD</b><b class='flag-5'>调试</b>接口后不能<b class='flag-5'>下载</b>程序的问题

    华大芯片入坑系列-SWD调试

    华大芯片入坑系列-SWD调试这两天调自制的板子,发现可以使用离线编程器的SWD模式烧录,但是Jlink的SWD模式怎么也调不通,那就无法仿真,很糟心。后来询问厂家后,说这块芯片可能不支
    发表于 01-12 18:47 10次下载
    华大芯片入坑系列-<b class='flag-5'>SWD</b><b class='flag-5'>调试</b>

    这种修复转炉耳轴轴承位磨损的方法,了解

    这种修复转炉耳轴轴承位磨损的方法,了解
    发表于 06-01 15:50 0次下载