<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
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

    文章

    8708

    瀏覽量

    362609
  • 調試器
    +關注

    關注

    1

    文章

    292

    瀏覽量

    23441
  • 車載芯片
    +關注

    關注

    0

    文章

    68

    瀏覽量

    14559
  • SWD
    SWD
    +關注

    關注

    1

    文章

    54

    瀏覽量

    11708
  • 調試接口
    +關注

    關注

    0

    文章

    10

    瀏覽量

    5068
收藏 人收藏

    評論

    相關推薦

    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

    SWD和傳統的調試方式區別在哪

    SWD 和傳統的調試方式區別 1. SWD 模式比 JTAG 在高速模式下面更加可靠。 在大數據量的情況下面 JTAG 下載程序會失敗, 但是 SW
    發表于 01-26 06:10

    如何解決STM32禁用SWD調試接口后不能下載程序的問題?

    如何解決STM32禁用SWD調試接口后不能下載程序的問題?
    發表于 01-27 07:53

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

    本文為大家介紹JTAG接口轉SWD接口方法,利用此轉換方式,可以簡化板載調試接口(相應單片機應支持SWD調試)。
    發表于 01-11 10:23 ?3.1w次閱讀
    JTAG接口如何轉<b class='flag-5'>SWD</b>接口_JTAG接口轉<b class='flag-5'>SWD</b>接口方法

    調試接口SWD和JTAG的區別

    作者 | strongerHuang 微信公眾號 | strongerHuang 作為嵌入式工程師,下載調試器都應該知道,但你真正了解SWD
    的頭像 發表于 10-27 09:29 ?1.6w次閱讀
    <b class='flag-5'>調試</b>接口<b class='flag-5'>SWD</b>和JTAG的區別

    下載調試接口SWD和JTAG的區別

    作為嵌入式工程師,下載調試器都應該知道,但你真正了解SWD 和 JTAG 接口的含義和區別嗎? 1、什么是
    的頭像 發表于 11-28 11:44 ?4057次閱讀

    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默認把這兩個接口當作了下載接口,所以如果程序中有用到這兩個接口的任意一個(比如用來作為普通
    發表于 12-02 18:51 ?29次下載
    解決STM32禁用<b class='flag-5'>SWD</b><b class='flag-5'>調試</b>接口后不能<b class='flag-5'>下載</b>程序的問題

    SWD 仿真模式

    轉自https://zhidao.baidu.com/question/15403504727290183871)SWD 仿真模式概念簡述先所說 SWD 和傳統的調試方式有什么不一樣:首先給大家介紹
    發表于 12-29 19:52 ?5次下載
    <b class='flag-5'>SWD</b> 仿真模式

    華大芯片入坑系列-SWD調試

    華大芯片入坑系列-SWD調試這兩天調自制的板子,發現可以使用離線編程器的SWD模式燒錄,但是Jlink的SWD模式怎么也調不通,那就無法仿真,很糟心。后來詢問廠家后,說這塊芯片可能不支
    發表于 01-12 18:47 ?10次下載
    華大芯片入坑系列-<b class='flag-5'>SWD</b><b class='flag-5'>調試</b>

    簡述SWD下載器通信協議底層原理

    基于Cortex-M內核的單片機,目前主流的下載接口就是JTAG和SWD。 SWD 和 JTAG引腳區別: **JTAG:** * **TDI:**
    發表于 02-20 16:05 ?2501次閱讀
    簡述<b class='flag-5'>SWD</b><b class='flag-5'>下載</b>器通信協議底層原理
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>