转ARM CMSIS DAP源码分析(一)_穿透灵魂的鼓点的博客-CSDN博客
结合ARM文档ADIv5,分析一下ARM提供的CMSIS DAP的开源代码,写点个人心得。
1.USB的整个传输有2个全局变量二维数组用作缓冲区,如下:
static uint8_t USB_Request [DAP_PACKET_COUNT][DAP_PACKET_SIZE]; // Request Buffer
static uint8_t USB_Response[DAP_PACKET_COUNT][DAP_PACKET_SIZE]; // Response Buffer
1
2
分别是输入缓冲和输出缓冲,固件从上位机接收数据后都会存放在这两个缓冲区,之后才会对缓冲区中的数据慢慢进行处理。
2.大概分析了一下SWD通信协议下,USB请求的结构被定义成为uint8_t类型的数组:
1)Request[0]:DAP Command IDs,该变量取值为
/* DAP Command IDs */
#define ID_DAP_Info 0x00
#define ID_DAP_LED 0x01
#define ID_DAP_Connect 0x02
#define ID_DAP_Disconnect 0x03
#define ID_DAP_TransferConfigure 0x04
#define ID_DAP_Transfer 0x05
#define ID_DAP_TransferBlock 0x06
#define ID_DAP_TransferAbort 0x07
#define ID_DAP_WriteABORT 0x08
#define ID_DAP_Delay 0x09
#define ID_DAP_ResetTarget 0x0A
#define ID_DAP_SWJ_Pins 0x10
#define ID_DAP_SWJ_Clock 0x11
#define ID_DAP_SWJ_Sequence 0x12
#define ID_DAP_SWD_Configure 0x13
#define ID_DAP_JTAG_Sequence 0x14
#define ID_DAP_JTAG_Configure 0x15
#define ID_DAP_JTAG_IDCODE 0x16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2)Request[1]:DAP Index;该字段在ID_DAP_Transfer命令中会被忽略
3)Request[2]:request_count;该字段表示当前请求的数量
4)Request[3]:request_value;该字段的含义比较多
/* DAP Transfer Request */
#define DAP_TRANSFER_APnDP (1<<0)
#define DAP_TRANSFER_RnW (1<<1)
#define DAP_TRANSFER_A2 (1<<2)
#define DAP_TRANSFER_A3 (1<<3)
#define DAP_TRANSFER_MATCH_VALUE (1<<4)
#define DAP_TRANSFER_MATCH_MASK (1<<5)
1
2
3
4
5
6
7
该字段在SWD传输协议中也很重要,分别用于表示
a)访问AP/DP(1为AP操作)
b)读操作/写操作(1为读操作)
c)A2,A3表示两个bit,用于确定AP或者DP中的具体寄存器,在确定寄存器时,Bits [1:0]一直都是0b00,例如,在DP访问时,[A3:A2] = 0b10,那么代表访问的寄存器偏移就是[A3:A2]+Bits [1:0] = 0b1000 = 0x08,根据ARM手册,该地址应该是SELECT寄存器,如下图:
d)最后两个用于推动比较和推动验证操作(Pushed compare and pushed verify)
今天分析的是RDDI_DAP_GetARMRegs(DWORD *regs, DWORD *rfpu, ULONG64 mask)和RDDI_DAP_SetARMRegs(DWORD *regs, DWORD *rfpu, ULONG64 mask)这两个函数。
以RDDI_DAP_GetARMRegs(DWORD *regs, DWORD *rfpu, ULONG64 mask)为例,代码如下:
// RDDI-DAP Get ARM Registers
// regs : Pointer to ARM Registers
// rfpu : Pointer to FPU Registers
// mask : Register Mask
// return value: error status
int RDDI_DAP_GetARMRegs (DWORD *regs, DWORD *rfpu, ULONG64 mask) {
int status;
int regID [3*64];
int regData[3*64];
int i, n, m;
DWORD val;
if (rddiHandle == NULL) return (RDDI_DAP_ERROR_INTERNAL);
if (mask == 0) return (RDDI_DAP_ERROR_INTERNAL);
// Match Retry = 100
regID[0] = DAP_REG_MATCH_RETRY;
regData[0] = 100;
// Match Mask = 0x00010000
regID[1] = DAP_REG_MATCH_MASK;
regData[1] = 0x00010000;
// TAR = DBG_Addr
regID[2] = DAP_AP_REG_TAR;
regData[2] = DBG_Addr;
// SELECT = AP_Sel | 0x10
regID[3] = DAP_DP_REG_APSEL;
regData[3] = AP_Sel | 0x10;
// R/W DAP Registers
status = rddi_DAP_RegAccessBlock(rddiHandle, rddiDAP_ID, 4, regID, regData);
status = RDDI_DAP_CheckStatus(status);
if (status) return (status);
AP_Bank = 0x10;
// Prepare Register Access
for (i = 0, n = 0; n < 64; n++) {
if (mask & (1ULL << n)) {
// Get register selector
if (n < 21) {
m = n; // Core Registers
} else if (n >= 32) {
m = 64 + (n - 32); // FPU Sn
} else if (n == 31) {
m = 33; // FPU FPCSR
} else {
continue;
}
// Select register to read (write to DCRSR)
regID [i+0] = DAP_REG_AP_0x4;
regData[i+0] = m;
// Read and wait for register ready flag (read DHCSR.16)
regID [i+1] = DAP_REG_AP_0x0 | DAP_REG_RnW | DAP_REG_WaitForValue;
regData[i+1] = 0x00010000; // Value to Match
// Read register value (read DCRDR)
regID [i+2] = DAP_REG_AP_0x8 | DAP_REG_RnW;
i += 3;
}
}
// R/W DAP Registers
status = rddi_DAP_RegAccessBlock(rddiHandle, rddiDAP_ID, i, regID, regData);
status = RDDI_DAP_CheckStatus(status);
if (status) return (status);
status = RDDI_DAP_StickyError();
if (status) return (status);
// Store register values
for (i = 0, n = 0; n < 64; n++) {
if (mask & (1ULL << n)) {
val = regData[i+2];
i += 3;
if ((n < 21) && regs) {
*((DWORD *)regs + n) = val;
} else if ((n >= 32) && rfpu) {
*((DWORD *)rfpu + (n - 32)) = val;
} else if ((n == 31) && rfpu) {
//rfpu->FPSCR = val;
}
}
}
return (0);
}
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
1.根据ARM的注释,
> #define DAP_REG_MATCH_MASK 16 //!< ID to write virtual match mask (used as mask for read operation which waits for value match)
> #define DAP_REG_MATCH_RETRY 17 //!< ID to write virtual match retry (used as retry count for read operation which waits for value
> match)
1
2
3
这两个值是一个虚拟的,用于读操作的匹配掩码和对应的匹配值
,这个不是很重要。
2.
regID[2] = DAP_AP_REG_TAR;
regData[2] = DBG_Addr;
1
2
这段代码设置的是AP的TAR寄存器。因为这个函数是用来访问ARM的内核寄存器,TAR设置为调试寄存器的基址0xE000EDF0,表示之后的读或者写操作的地址为TAR中写入的地址。
3.
regID[3] = DAP_DP_REG_APSEL;
regData[3] = AP_Sel | 0x10;
1
2
这段代码设置的是DP的SELECT寄存器,0x10用于修改APBANKSEL字段,表示选择的是Bank 0x01。这种情况下对应的是AP的BD0~BD3寄存器,即读写对应地址0xE000EDF0~0xE000EDFC。
4.之后的for循环中,
regID [i+0] = DAP_REG_AP_0x4;
regData[i+0] = m;
1
2
AP中TAR地址偏移0x4的位置是DCRSR寄存器
(1)[4:0]为REGSEL字段,具体含义如下:
00000=R0
00001=R1
...
01111=R15
10000=xPSR
10001=MSP
10010=PSP
10100=特殊功能寄存器组
[31:24]:CONTROL
[23:16]:FAULTMASK
[15:8]:BASEEPRI
[7:0]:PRIMASK
1
2
3
4
5
6
7
8
9
10
11
12
(2)[16]为REGWNR字段,1表示写寄存器,0表示读寄存器
5.regID [i+2] = DAP_REG_AP_0x8 | DAP_REG_RnW;
这一段表示的是访问相对TAR偏移0x08位置的寄存器,即0xE000EDF8,DCRDR寄存器。具体是读或者写操作,由4中的比特16来决定。
以上操作循环执行即可获取到对应的内核寄存器R0~R15等
————————————————
版权声明:本文为CSDN博主「穿透灵魂的鼓点」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/pengxiao618/article/details/47663773