您尚未登录。

楼主 #1 2021-03-07 13:19:31

metro
会员
注册时间: 2019-03-09
已发帖子: 390
积分: 329

【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

知识共享许可协议本作品采用知识共享署名 4.0 国际许可协议进行许可。

项目简介

如标题所述,TinyDAP是一个在兼容8051的单片机上实现的CMSIS-DAP调试器,不仅可以用于调试和烧录ARM Cortex-M系列单片机,配合第三方工具还能支持RISC-V等其它单片机和SoC。可以说,CMSIS-DAP是最适合实现的开源调试器协议(个人认为没有之一),而TinyDAP的目标就是做CMSIS-DAP的最小实现方案(同样没有之一!)

TinyDAP在软件和硬件两个层面都将做到极致:

  • 在软件上,通过汇编级别的优化,将CMSIS-DAP协议的几乎所有功能一一实现在小于16KB的Flash中,可以兼容JTAG和SWD的调试线协议,还能通过支持CMSIS-DAP v2达到不输于闭源调试器(如ST-Link/V2)的速度

  • 在硬件上,可以运行在CH551/552等超低价格(1.x RMB)的单片机上,芯片占用的面积可以低至4.9x3.0 mm²(CH552E),预计成品体积不大于STLINK-V3MINI,还能直接在开发板上板载。

当然,截止至今日,TinyDAP还在初步开发阶段,不过前期的验证工作已经结束(参见帖子:晒一下CH558跑的CMSIS-DAP v2调试器,下载速度可以达到70KB/s(Flash)和300KB/s(SRAM)),可以证明这个目标是能够实现的(无非就是多掉几根头发而已)

除此之外,TinyDAP还将依赖于以下工作:

  • 利用SPI等外设加快调试速度。由于SWD和JTAG都是属于类SPI协议(串行输入/输出,并且有独立时钟引脚),因此可以通过SPI等外设加快数据传输,从而加快总体的调试速度。

  • 对CMSIS-DAP的算法进行深度优化。通过阅读代码发现,当前的CMSIS-DAP代码控制调试线时的算法在有些情况下不够高效,可能会导致性能降低。在CMSIS-DAP的代码之外,作者还会参考ARM的其它文档(见下文),重新整理CMSIS-DAP的算法,进一步提升调试的性能。

  • 参考DAPLink的代码,实现更多定制的功能。DAPLink也是基于CMSIS-DAP协议的实现,在完全开源的基础上做出了虚拟串口、拖拽烧录等实用功能。在存储空间和外设允许的前提下,作者也会在项目后期尝试将这些功能加入到TinyDAP中。

由于作者已经工作(四舍五入996的那种),所以这个项目必然不会很快完成(否则也不会从去年鸽到现在),还请大家耐心等待。当然,由于TinyDAP是一个比较随性的项目,所以也不会给自己设定各种时间上的目标,但会借此机会尝试用文字等方式将自己的想法表述出来供大家参考,因此本帖会尽可能地持续更新(可以想起来的时候常来看看hhh)

文档结构

本文的目标是记录开发的过程,分享一些开发过程中遇到的问题和解决方法,也欢迎和大家一同探讨各种相关话题。

本文将会按照以下顺序编写文档:

  1. ARM调试接口

  2. CMSIS-DAP协议

  3. USB设备的协议栈(包括HID和WinUSB等)

  4. WCH CH54x/CH55x

  5. TinyDAP的实现细节

参考代码和文档

参考代码以ARM官方维护的代码为主,包括:

  • CMSIS-DAP:ARM基于CMSIS-DAP协议的一个简单实现,集成在CMSIS Version 5中。这一版本的CMSIS-DAP使用RTX v5 RTOS和Keil提供的USB设备协议栈与驱动,其中后者似乎并不开源。

  • DAPLink:ARM基于CMSIS-DAP协议的另一个实现,加入了虚拟串口、拖拽烧录等实用功能,由ARM Mbed维护。这一版本的CMSIS-DAP使用RTX v4 RTOS和开源的USB设备协议栈与驱动,代码完全开源并且可以方便地添加新设备的支持。DAPLink的主要缺点是编译后二进制文件太大(完整配置超出STM32F103C8T6的Flash空间,只能上CBT6)。

  • DesignStart:ARM的一个项目,提供了Cortex-M0和M3的RTL代码(经过混淆处理),在实现调试接口时作为参考。

参考文档则是覆盖了上面所说的所有内容,包括:

  • CMSIS-DAP:ARM官方的CMSIS-DAP文档。CMSIS-DAP包括协议和实现两部分,这个文档主要覆盖了协议部分,重要性无需多言。

  • ARM Debug Interface Architecture Specification:ARM调试接口的文档,版本是ADIv5.2。需要注意的是,该文档的最新版本是ADIv6.0,但当前主流的ARM单片机似乎并不使用v6.0,所以v5.2已经够用(v5.x加入了很多实用功能)。

  • USB相关的各个标准,包括(除了最后一项外都可以在USB官网找到):

    • USB Specification 2.0:USB 2.0的主标准。

    • 与BOS(Binary Device Object Store)描述符相关的补充标准:于Wireless USB Specification 1.0引入,在USB 3.0时被写入主标准中,主要用于实现WinUSB、WebUSB等功能。

    • USB Device Class Definition for Human Interface Devices (HID):HID类的标准,主要用于实现CMSIS-DAP v1的免驱动安装。

    • Microsoft OS 2.0 Descriptors Specification:MS OS描述符标准,主要用于实现CMSIS-DAP v2的免驱动安装(通过WinUSB),这里我们使用的是2.0的标准,可以兼容Windows 8.1和10。

  • 8051的指令集和单片机的数据手册及相关文档。

更新记录
  • 2021/3/7:开坑,更新简介部分.

离线

#2 2021-03-08 12:37:07

chaplin1999
会员
注册时间: 2019-11-08
已发帖子: 15
积分: 14.5

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

关注:)

离线

#3 2021-03-08 16:22:18

hox
会员
注册时间: 2020-02-17
已发帖子: 38
积分: 26.5

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

关注一下,看看最终还有几根头发 big_smile

离线

#4 2021-03-09 13:44:15

wm20031015
会员
注册时间: 2017-10-18
已发帖子: 48
积分: 152

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

顶楼主,关注中!

离线

#5 2021-03-13 04:41:31

iamseer
会员
注册时间: 2020-06-06
已发帖子: 35
积分: 30.5

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

 关注

离线

楼主 #6 2021-04-05 00:08:08

metro
会员
注册时间: 2019-03-09
已发帖子: 390
积分: 329

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

第一部分:ARM调试接口
ARM的调试架构

ARM调试接口(即ADI,ARM Debug Interface),定义了基于ARM的SoC中所有调试组件的功能;而我们常说的DAP(即Debug Access Port),可以认为是基于ADI标准的一个实现。
对于DAP,我们又可以进一步分为两个部分:

  • Debug Port:面向调试器的接口,主要用于接收来自调试器的请求,并将Access Port的数据和响应传回到调试器。

  • Access Port:面向SoC内各个组件的接口,主要用于将Debug Port传来的请求转换成对SoC内对应组件的传输操作,并且将结果返回到Debug Port。

DAP的基本架构如下图所示。
block-diagram-of-an-adiv5-implementation.svg
可以发现,对于一个部署了ADI的系统来说,通常会存在一个DP和若干个AP,并且DP通过选择AP的方式一次只和一个AP进行交互。一方面,DP与(外置的)调试器相连,并根据调试器的协议进行数据交换;另一方面,AP和系统中的某个组件(一般是总线之类的组件)相连,可以将DP传来的请求进一步翻译成系统可以处理的操作(一般是寄存器或内存的读写操作)。
下图展示了一种包含了DPv0 JTAG-DP和通用AP的示意图,可以一窥DAP的架构。
structure-of-the-dap.svg
常见的DP包括:

  • JTAG-DP:使用了JTAG接口,一种四线(另有可选的TRST,加上之后有五线)的全双工同步协议。

  • SW-DP:使用了SWD接口,一种两线的半双工同步协议。

  • SWJ-DP:同时兼容JTAG-DP和SW-DP接口,并且包含了JTAG/SWD双协议切换的一种特殊协议。

常见的AP包括:

  • MEM-AP:包括一大类调试组件的AP,特点是通过内存映射(Memory-mapped)的方式进行访问,覆盖了SoC的各种功能。

  • JTAG-AP:一个面向传统JTAG接口的AP,可以外接系统中已经存在的包含JTAG接口的非ARM组件。

MEM-AP的一个实现如下图所示。可以看到,MEM-AP可以通过ROM Table获取其它调试组件的定义情况,并且通过访问特定的调试组件以实现特定的调试功能。
mem-ap-connecting-the-dp-to-debug-components.svg
对调试架构感兴趣的同学,可以阅读ADIv5标准的Chapter A1部分;对各个AP和CoreSight各个调试组件感兴趣的同学,可以阅读ADIv5标准的Part C以及CoreSight的相关文档。在下文中,我们主要介绍DP,因为这与我们的调试器设计密切相关。

最近编辑记录 metro (2021-04-05 00:48:19)

离线

#7 2021-04-15 22:49:53

hdtq99
会员
注册时间: 2021-04-15
已发帖子: 0
积分: 0

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:与技术无关

#8 2021-04-20 16:32:37

woyanihao
会员
注册时间: 2021-01-07
已发帖子: 17
积分: 17

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:与技术无关

#9 2021-04-20 20:00:55

echo
会员
注册时间: 2020-04-16
已发帖子: 231
积分: 243.5

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

关注一下。要是以后gd32没有芯片用了,就做一版ch552版本的gdlink。这事情伤害不大,侮辱性比较强。

离线

#10 2021-04-21 09:33:10

演技担当黄晓明
会员
注册时间: 2017-10-17
已发帖子: 156
积分: 103.5

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

用wch的 USB3.0 能做一个么?那个速度会不会起飞

离线

楼主 #11 2021-04-21 18:03:32

metro
会员
注册时间: 2019-03-09
已发帖子: 390
积分: 329

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

演技担当黄晓明 说:

用wch的 USB3.0 能做一个么?那个速度会不会起飞

大概不会,因为JTAG/SWD都是串行协议,速度能到几十Mbps就不错了。USB 3.0应该更适合trace的用途。

离线

#12 2021-05-19 14:41:47

duanhnhy
会员
注册时间: 2020-05-16
已发帖子: 33
积分: 0

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:与技术无关

#13 2021-06-02 09:46:35

mini_uc
会员
注册时间: 2020-03-05
已发帖子: 11
积分: 4.5

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

关注一下,现在CH的芯片也缺货了.

离线

楼主 #14 2021-06-02 13:11:50

metro
会员
注册时间: 2019-03-09
已发帖子: 390
积分: 329

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

mini_uc 说:

关注一下,现在CH的芯片也缺货了.

是啊,又找到了一个拖更的理由(不是

离线

#15 2021-08-31 22:15:18

ifree64
会员
注册时间: 2019-06-27
已发帖子: 71
积分: 50.5

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

强帖,最新进展有没?

离线

#16 2021-10-17 16:51:04

vigour1000
会员
注册时间: 2018-11-19
已发帖子: 40
积分: 0

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:其他

#17 2021-10-19 21:19:19

echo
会员
注册时间: 2020-04-16
已发帖子: 231
积分: 243.5

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

最近想用CH552实现一个usb-blaster,掉坑里了。

离线

#18 2022-01-06 07:53:17

desertsailor
会员
注册时间: 2022-01-06
已发帖子: 15
积分: 0

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:其他

#19 2022-02-07 18:48:14

posystorage
会员
注册时间: 2018-05-06
已发帖子: 123
积分: 118

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

欢迎探讨
开源CH551/2实现的汇编优化高速DAP-Link (CMSIS-DAP v2)
https://whycan.com/t_7786.html

离线

楼主 #20 2022-06-05 15:08:04

metro
会员
注册时间: 2019-03-09
已发帖子: 390
积分: 329

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

距离上次更新已经过了14个月了,还好最近又想起来了,闲话不多说,让我们继续之前的内容吧。

ARM调试协议简介

说到ARM的调试协议,必然绕不开ADI(ARM Debug Interface)相关的规范了。目前,ARM在新型号CPU上主要使用ADIv5和ADIv6这两个规范,两者之间互不兼容(主要是AP接口的区别),因此调试器这边需要分别支持。

根据规范,ADIv6(当然v5也是)由低到高可以分为以下层次:

  • 物理层(Physical Layer):定义各种物理信号,包括SWD和JTAG

  • 协议层(Protocal Layer):定义数据包的格式,维护SWD和JTAG的状态机

  • 数据链路层(Data Link Layer):定义如何访问DP寄存器和AP寄存器,实现基本的调试功能

  • AP层(AP Layer):定义如何访问SoC上的一个或多个子系统

从这个角度来说,市面上已有的调试器方案可以按照使用的最高层次分为以下几类:

  • 只使用物理层:FTDI家的所有方案,与操作GPIO无异,突出一个“又不是不能用”,效率通常最低,当然优势是比较灵活,只要改改上位机代码理论上就能支持所有协议。当然,除了大家熟知的bit-bang之外,也有像MPSSE这种效率比较高的方案,不过依然需要上位机赋予其“灵魂”。

  • 支持协议层:ARM自家的CMSIS-DAP,为协议层访问做了一些优化,DAP_Transfer和DAP_TransferBlock命令了解一下?不过更高级的操作(例如访问SoC上的内存地址)单靠调试器本身做不来,需要上位机下发一系列命令来完成,没有上位机的配合基本只能歇逼。

  • 支持所有层次:J-Link等商用调试器,为了功能和效率,通常在调试器上集成了各种高级操作,访问个内存地址之类的不在话下,当然调试器的实现上会比较复杂。开源的方案可以参考Black Magic Probe

接下来我们按照由低到高的顺序介绍每个层次的相关规范。

物理层

物理层关心的部分如下:

  • 信号名称及必要性

    • 部分信号是可选的,例如JTAG中的TRST

  • 信号的敏感沿

    • 当前的调试接口都是带同步时钟的,需要定义信号在何时被采样

  • 信号的传输方向

    • 主要包括调试器到DPDP到调试器双向这三种情况,其中双向传输需要在协议层约定好传输方向的切换

  • 信号的其它物理层需求

    • 举个栗子,SWD要求给SWDIO一个上拉电阻,以保持该信号在未被驱动时的状态确定

SW-DP

SW-DP共有两个必需的引脚,分别是SWCLKSWDIO,分别表示时钟和数据。
SWCLK没啥好说的,唯一需要说明的是该信号可以是门控时钟,这意味着SWCLK可以在不需要传输数据的时候停止翻转,这样可以节省功耗,并简化调试器的逻辑。
SWDIO是双向信号,这意味着信号的传输方向需要调试协议规定好,通过状态机的方式实现信号方向切换。对于调试器而言,通常需要额外输出SWDIO_TXEN信号(CMSIS-DAP中定义,表示当前调试器是否驱动SWDIO信号),以控制电平转换电路的工作方向,但这一信号并不包括在SW-DP内。
在SW-DP中,规定了DP在SWCLK信号上升沿的时候采样或切换数据(取决于当前状态是输入或输出)。对于调试器而言,这意味着需要在SWCLK信号下降沿的时候采样或切换数据(假设占空比是50%)。
另外,SW-DP要求SWDIO信号上拉100 kΩ的电阻,以保持该信号在未被驱动时的状态确定。

JTAG-DP

JTAG-DP使用的引脚和普通的JTAG区别不大,最大的区别是修改了引脚名称。可以参考IEEE Std 1149.1获取更多信息。

JTAG信号和SPI Mode 0或3类似,都是在时钟信号下降沿改变数据、上升沿采样数据。

ADIv6并未对JTAG引脚的外部连接进行更多说明,不过根据IEEE Std 1149.1,还是建议在设备端对TMS和TDI等引脚上拉,以满足稳定性的需求。

SWJ-DP

前面已经介绍了SW-DP和JTAG-DP,那么这个SWJ-DP又是何物呢?看名字就知道,这个其实就是Serial Wire + J(TAG)的组合。
实际上,SWJ-DP并不负责具体的DP功能,其主要作用就是将SW-DP和JTAG-DP使用的引脚整合在一起,并且允许使用特定的序列切换实际使用的DP,这样便可使用相同的引脚和连接器定义(例如Coresight 10),节省引脚数量。
SWJ-DP定义的引脚名称如下表所示。需要说明的是,SWJ-DP可以只拉出SW-DP相关的引脚,并可在使用SW-DP时重新定义TDI、TDO和TRSTn这几个引脚的功能,当然在这种情况下就只能使用SWD进行调试了。

table-b5-1.png

离线

楼主 #21 2022-06-05 15:23:21

metro
会员
注册时间: 2019-03-09
已发帖子: 390
积分: 329

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

协议层

协议层关心的主要是所谓“数据包”的收发,也就是调试协议每次传输的最小单位。
一般而言,协议层的数据传递需要依靠收发双方各自维护一个状态机,引脚的状态变化会使得这个状态机不断更新到下一个状态,直到停留到目的状态,收发双方获取到所需的信息为止(传输错误等也可以看作是一种信息)。
需要说明的是,协议层一般只维护基本的传输功能,并不对收发的数据进行进一步分析,这些分析操作应该交由上层(数据链路层和AP层)完成。

因此,像CMSIS-DAP这样只做到协议层的调试器而言,其实只需要上位机(通常是OpenOCD等)将高级操作(例如访问寄存器等)翻译成协议层的指令,并不需要调试器“理解”指令的含义,所以CMSIS-DAP的方案可以在小Flash的MCU上实现(例如CH552),功能上并不打折扣;相对应的,CMSIS-DAP需要上位机配合才能工作,单独使用时需要手动操作AP层的寄存器,比较麻烦。

SWD

SWD作为两线协议,传输数据的过程必然需要协商好数据传输的方向,否则可能会导致信号冲突或者握手失败。好在SWD的协议并不复杂,下面我们来一窥端倪。

传输格式

SWD的数据包可以分为以下三个主要部分:

  • Packet request:表示调试器的命令,传输方向为从调试器到DP

  • Acknowledge response:表示DP对请求的响应,传输方向为从DP到调试器

  • Data transfer phase:表示实际传输的数据,传输方向根据命令确定

另外,在切换传输方向时,需要数个周期的时间,这个阶段被称为turnaround。一次正常的传输总会包括两次turnaround,原因是packet request和acknowledge response的传输方向总是相反的。

注:turnaround的设置位于SW-DP的DLCR寄存器中,可选值为1到4个周期,line reset后默认值为1,且可以被调试器设置。

接下来我们看各个部分的格式。

对于packet request,共有8个bit,按传输顺序分别如下(均为小端序,下同):

  • Start:表示开始发送,恒为0b1

  • APnDP:表示传输的寄存器,0b0为DP,0b1为AP

  • RnW:表示数据的传输方向,0b0为调试器写(DP读),0b1为调试器读(DP写)

  • A[2:3]:表示寄存器的索引

  • Parity:表示APnDP到A[3]这4个bit的偶校验结果(其实就是将这4个bit异或后得到1个bit的结果)

  • Stop:表示结束发送,恒为0b0

  • Park:将SWDIO置为高电平,以便后续turnaround保持高电平状态(通过上拉电阻)

对于Acknowledge response,共有3个bit,其中:

  • 0b100:OK,表示读写操作正常发起

  • 0b010:WAIT,表示当前DP正忙,需要调试器重试,或是(在重试一定次数后)使用ABORT寄存器终止传输

  • 0b001:FAULT,表示之前的传输有误,需要调试器读取相应寄存器获取出错原因

  • 其它:表示可能出现其它错误,包括协议错误(protocol error)或是与DP断开连接等,由于packet request阶段结束时已经将SWDIO设为高电平,因此最有可能出现的是0b111,表示DP没有驱动SWDIO

对于Data transfer phase,共有33个bit,传输方向由Packet request中的RnW确定,其中:

  • 前32个bit表示传输的数据

  • 最后1个bit表示前32个bit的偶校验结果

从上面可以看出,一个数据包的长度为(Read) 8 + Trn + 3 + 33 + Trn = (Write) 8 + Trn + 3 + Trn + 33 = 44 + 2 * Trn,其中Trn表示turnaround的时钟周期数。

读写方式和错误处理

在明确传输格式后,接下来就可以让调试器和DP开始沟通了。不过,一次完整的传输需要考虑的事情可不少:

  • DP和AP寄存器的读写方式有所不同。由于AP寄存器的访问需要时间,因此相对于DP寄存器而言等待时间可能更长,并且可能出现的状况也更多。

  • 在acknowledge response返回不同值的时候,需要有不同的处理方法。成功的时候自然是最好,如果遇到了其它状况,也应该妥善处理,以保证调试器和DP能够正常工作。

我们先来说写寄存器的情况。在成功写寄存器时,波形图如图B4-1所示。

figure-b4-1.png

注:在ADIv6中,SWDIO的波形均被描述为上升沿时改变,这对调试器而言实际上不够好,见物理层部分的相应描述。

可以看到,在acknowledge response阶段,DP通过返回OK表明自己有能力接收新的数据。至于此次传输的数据是否被DP成功接收,则需要等待下一次传输的acknowledge response返回,其中:

  • 若写的是DP寄存器,则通常可以直接获知是否成功传输,也就是说会在下一次传输时返回OK/FAULT或其它错误

  • 若写的是AP寄存器,则由于可能需要等待上次传输完毕,可能需要等待一段时间才能获知传输是否成功,也就是说下一次传输时可能会返回WAIT,直到上次传输完毕

注:写AP寄存器在下一次传输返回OK并不代表已经成功写入到AP部分的相应寄存器,而只是表示已经写入到写缓冲(write buffering)区域。如果写操作进入到写缓冲但最终被丢弃,将会通过CTRL/STAT.WDATAERR标志位来表示。这一部分内容可以参考B4.2.7的SW-DP write buffering部分。

接下来是读寄存器的情况。在成功读寄存器时,波形图如图B4-2所示。

figure-b4-2.png

这里需要区分读DP寄存器和读AP寄存器的情况了。对于读DP寄存器,这种情况比较简单,只需要一次传输就能获取到acknowledge response和所需的状态;与之相对应的是,读AP寄存器需要考虑AP寄存器的延迟,需要两次传输才能获取到实际的数据。

读AP寄存器的流程如下:

  1. 第一次传输,需要在packet request指明传输的AP寄存器;在acknowledge response阶段,DP通过返回OK表明自己有能力处理此次请求;此时传输的数据内容无意义,应当丢弃。

  2. 第二次传输,需要在packet request指明读取DP寄存器中的RDBUFF寄存器;在acknowledge response阶段,DP通过返回OK表明自己已经从AP获取到新的数据并准备好回传给调试器;此时传输的数据即为所需的内容。如果数据没有准备好,DP会返回WAIT,需要重复第二次传输直到DP返回OK为止。

可以看到,读AP寄存器实际上需要分为先提交接收的两个步骤。当然,如果需要多次读取AP寄存器,则提交和接收可以在同一次传输中交替完成(在ADIv6中被称为流水线化),即:

  1. 首先发起第1个AP寄存器的读取,并且丢弃此时返回的数据。

  2. 接下来发起第2个AP寄存器的读取,等待acknowledge response返回OK,此时返回的数据即为第1个AP寄存器的结果。

  3. 重复2的步骤,每次发起第n个寄存器的读取时,都会返回第(n-1)个寄存器的结果。

  4. 在所有AP寄存器均发起读取后,需要再额外发起一次传输,读取DP寄存器中的RDBUFF寄存器,以获取最后一次传输的结果。

到这里为止,我们就把成功传输时的处理方式介绍完了。但是,调试器的传输过程不可能做到尽善尽美,那么在遇到意外状况时,应该怎么处理呢?这里我们按照错误类型进行介绍:

  • WAIT:一般表示上一次读写AP寄存器的操作还未结束,这种情况下常规操作是继续发起相同的传输,直到响应OK为止;当然也可以通过ABORT寄存器终止传输,这个会在后续数据链路层中介绍。

  • FAULT:技术上说,返回FAULT表示的是CTRL/STAT寄存器有sticky flag被设为0b1,而这通常表示DP发现了一些错误,包括写寄存器时data packet phase的校验位出错等,感兴趣的读者可以参考数据链路层部分。

  • Protocol error:包含了一系列不符合传输协议的错误,例如packet request中的校验位出错、Stop和Park出错、不支持的turnaround周期数等。

大家可能会有些疑惑,为啥还没有看到错误发生时的波形图呢?这是因为,WAIT和FAULT时的波形与overrun detection有关。Overrun detection是DP的一个特性,针对调试器在高可靠性、高延迟、高吞吐量的场合使用,可以有效加快处理效率。当然,我们这里主要说明的还是打开和关闭overrun detection的不同之处。

注:针对overrun detection的特性,我这边举一个可能实用的例子。

对于FTDI这种只使用物理层的调试器,输出信号通常是bit-bang或类似的方案,这需要上位机发出一系列指令来模拟SWD协议。一个可能的使用方式是这样的(假设是写寄存器):

  1. USB发送一个命令,写入8个bit,也就是packet request部分

  2. USB发送一个命令,读取5个bit,包括了两个turnaround和acknowledge response部分

  3. USB发送一个命令,写入33个bit,也就是data transfer phase部分

可以发现,在overrun detection关闭前,是否执行3依赖于2的结果,而相关的结果并不能在物理层中得到反馈,必须要回传到上位机,并由上位机来决定下一步的处理方式。这样的一大缺点是,2和3之间必然会有很大延迟(如果使用interrupt transfer,延迟通常是ms级的),这会严重制约SWD的实际读写效率。

对于这个问题,打开overrun detection就能得到有效缓解,原因是overrun detection打开后data transfer phase就是一直存在的,并不受到acknowledge response返回结果的影响,上位机完全可以在发起一系列传输后通过检查CTRL/STAT寄存器获取传输结果,也就是说上位机可以尽可能多的填充传输队列,从而提高传输效率。

当然,这么做也有一个显而易见的缺点:如果传输不稳定或成功率过低,则每次发起一系列传输后DP大概率会进入到需要从错误中恢复的状态,这也会导致效率下降。因此,overrun detection只适合在高可靠性、高延迟、高吞吐量的场合使用。

在关闭overrun detection时,如果DP返回WAIT或FAULT,则跳过接下来的data transfer phase,直接开始下次传输,如下图B4-3和B4-4所示。

figure-b4-3.png

figure-b4-4.png

但是,如果打开overrun detection,不论DP返回WAIT还是FAULT,接下来的data transfer phase都和成功传输一样进行,只是传输的数据无效,如图B4-6和B-7所示。

figure-b4-6.png

figure-b4-7.png

最后说说Protocol error。一般来说,protocol error的错误是比较严重的,通常意味着信号传输不稳定,导致调试器或DP读取到了错误的结果。这种情况下,DP的策略是比较保守的,一般是直接终止所有传输(除特定寄存器外),调试器需要尽快发起line reset以重置DP状态;因此,DP将会在检测到错误后释放对SWDIO的驱动,在调试器一端通常会读到0b111的响应,如下图B4-5所示。

figure-b4-5.png

对于protocol error,详细的处理方式可以参考ADIv6中的B4.2.5,这里不再赘述。

其它细节

从上面我们知道,SW-DP是有状态的,读写结果会和之前的传输有关,因此恢复到初始状态显得非常重要。

在ADIv6中,SWD有个名为line reset的特性,就是在必要的时候对SW-DP进行重置,以保证SW-DP能工作在确定的状态,这个特性会在以下场景使用:

  • SW-DP初始化:在首次连接到SW-DP时,需要在传输前先来一发line reset,以保证SW-DP不会受到上电时不定态或已传输数据的影响。

  • 切换DP:无论是从JTAG-DP切换到SW-DP,还是从其它SW-DP切换过来,也都需要一次line reset。

  • 错误恢复:前面提到的protocol error需要通过一次line reset才能恢复。

注意到line reset只重置SW-DP部分寄存器(DLCR和SELECT.DPBANKSEL),不影响SW-DP的其它寄存器、JTAG-DP、SWJ-DP和所有AP。

那么,line reset要怎么做到呢?其实很简单,就是传输以下序列即可:

  1. 首先,给至少50个周期的SWDIO高电平,此时SW-DP可以识别到line reset。

  2. 紧接着给至少2个周期的SWDIO低电平,让SW-DP做好准备。

  3. 最后正常传输即可。

Line reset的波形图如图B4-8所示。

figure-b4-8.png

可以看到,2的话并不影响结果,这实际上是SW-DP的一个特性:空闲周期(idle cycles)。回想起每次传输的Start信号为0b1,如果在此时传输的是0b0,则传输不会开始,SW-DP可以维持在空闲状态,等待SWDIO传输0b1后传输才正式开始。

注:CMSIS-DAP中,可以定义每次传输后附加的空闲周期数,这部分的内容并不需要修改DP和AP寄存器。合理使用空闲周期可以减少DP响应WAIT的次数,从而减少实际的传输时间。

JTAG-DP

对于JTAG,想必大家都不陌生(陌生的建议先看看IEEE Std 1149.1,逃),在其它器件上已经使用过。由于JTAG的引脚都是单向传输的(到了1149.7才有两线调试的方案,才会涉及到引脚传输方向切换),并且JTAG在协议层本质上就是一个状态机(见图B3-2),因此说明起来会比较容易。这里就尽量简明扼要地描述其中需要关注的部分。

figure-b3-2.png

传输格式

JTAG-DP和普通的JTAG状态机的用法基本一致,都是分为指令寄存器(Instruction Register,即IR)和数据寄存器(Data Register,即DR)。对于JTAG而言,一般是有一个IR和多个DR,其中:

  • IR用于选择和控制JTAG扫描链,位数是固定的

  • DR用于交换暴露在JTAG扫描链的信息,具体的信息一般由IR决定,位数是可变的

因此,一次传输需要先选择IR再向DR写数据同时读返回结果。具体的传输过程在B3.2.3中已有详细描述,这里不再赘述。

读写方式和错误处理

table-b3-3.png

从ADIv6的表B3-3中,我们可以获知,标准IR指令如下:

  • ABORT

  • DPACC

  • APACC

  • IDCODE

  • BYPASS

其中,IDCODE和BYPASS是JTAG标准要求的部分,DPACC和APACC基本对应SW-DP中的DP和AP寄存器,而ABORT则是单独列出。后面主要提到DPACC和APACC部分。

注:

  1. IEEE Std 1149.1要求IR全1时对应BYPASS指令。

  2. IEEE Std 1149.1要求Test-Logic-Reset状态下IR对应的是IDCODE或BYPASS,JTAG-DP使用的是IDCODE。

figure-b3.4.3.png

DPACC和APACC的操作如B3.4.3的图所示。可以看到,这两个DR都是35位,数据结构如下:

  • 对于TDO这一端,JTAG依次输出ACK[0:2]和ReadResult[0:31]

  • 对于TDI这一端,JTAG依次输入RnW、A[2:3]和DATAIN[0:31]

相对于SW-DP,由于JTAG-DP的Capture-DR在Update-DR之前执行,而JTAG-DP的acknowledge response和ReadResult在Capture-DR阶段确定、packet request和DATAIN在Update-DR阶段生效,因此当前传输的数据包需要在下一次传输时给出。当然,和SW-DP中读AP寄存器类似,JTAG-DP也可以通过流水线执行的方式“重叠”这些命令,执行过程如下:

  1. 首先发起第1个寄存器的传输,并且丢弃此时返回的acknowledge response和ReadResult。

  2. 接下来发起第2个寄存器的传输,并且从acknowledge response的结果获知传输是否成功,如果第1个寄存器对应的传输是读取,则还需同时读取ReadResult并作为第1个寄存器的读取结果,否则直接丢弃。

  3. 重复2的步骤,每次发起第n个寄存器的传输时,都会返回第(n-1)个寄存器的acknowledge response,并根据需要判断是否需要读取ReadResult。

  4. 在所有寄存器均发起传输后,需要再额外发起一次传输,读取DPACC中的RDBUFF寄存器,以获取最后一次传输的acknowledge response。如果第n个寄存器对应的传输是读取,则还需同时读取ReadResult并作为第1个寄存器的读取结果,否则直接丢弃。

这里有一些需要注意的细节:

  • 由于JTAG-DP对所有指令的写入和读取都是流水线化的,因此要确保此次传输被成功接受,就必须发起下一条指令来读取结果。可以通过读取DPACC寄存器的RDBUFF寄存器来获取acknowledge response,这是因为读取RDBUFF寄存器总是不会产生其它副作用。

  • 当返回的结果为WAIT,或者有sticky flag为0b1时,此次传输将被丢弃,因此可以仅通过读取TDO输出的前3位(即ACK[0:2])来判断上一次传输是否成功进行,若非成功进行则可以直接结束传输。

  • JTAG-DP返回的ReadResult仅在上一个传输访问的是DPACC、APACC和BYPASS这三个DR时才有意义,因此不能在执行DPACC和APACC的传输过程中切换到其它DR。

注:注意第二点原理和SW-DP的overrun detection不同,JTAG可以在传输会被丢弃的情况读取任意位数(前提是不会影响扫描链上的其它设备,这可以通过将其它设备的IR均设为BYPASS来做到),这可以减少传输时间(在WAIT状态时尤其有用)。

另外,JTAG-DP在协议版本不同的时候acknowledge response的定义会有所不同,见表B3-6。在v0中,OK和FAULT合并为一个,即OK/FAULT,对应的ACK[2:0]为0b010,是否传输成功需要读取CTRL/STAT寄存器才能获知;而v1中,又将OK和FAULT分离。

其它细节

在Capture-IR阶段,JTAG扫描链会写入0b0001或0b00000001(取决于IR长度为4位或8位),并且最靠近TDO的是0b1,这个可以在后续更新IR时被移出,用来检查扫描链的连接是否正常。

注:根据IEEE Std 1149.1,JTAG扫描链需要保证在Capture-IR阶段写入到扫描链中最靠近TDO的2个bit为0b01,JTAG-DP显然符合此要求。

和SW-DP类似,JTAG-DP也有自己的idle cycles,不过这一定义借用了JTAG状态机中的Run-Test/Idle状态。除了和SW-DP类似用于减少实际执行时间的作用外,如果host需要在传输结束后停止TCK,需要保证在Update-DR后至少在Run-Test/Idle状态转8个周期,以保证传输结束(当然如果继续使用JTAG或者不需要最后一次传输结果时则不受此影响)。

注:一般来说,在最后一次传输发起后(无论读写),调试器会至少再发送一次读RDBUFF寄存器请求,确认传输是否成功进行,因此这个设定对正确进行的读写操作没有影响。

JTAG-DP和SW-DP的一大不同是没有line reset,这意味着JTAG-DP不能(其实也不需要)将传输恢复到初始状态。从ADIv6中,我们知道,JTAG-DP仅能在上电复位时重置DP寄存器,但是JTAG-DP不需要像SW-DP那样设置turnaround,因此初始化对于JTAG-DP来说只需要重新设置一遍寄存器就好,不会和当前的状态冲突。

SWJ-DP

在协议层,SWJ-DP主要做的事情就是处理SW-DP和JTAG-DP之间的切换。根据SWD协议版本不同,SWJ-DP最多有两套切换方式,分别是:

  • SWD和JTAG之间的切换

  • 休眠状态和相关操作

接下来详细介绍这两种切换方式。

SWD和JTAG之间的切换

这种方式多用于SWD协议v1,v2也可以支持但被废弃(deprecated)。

先贴个状态转移图,见图B5-1。

figure-b5-1.png

从图上可以看出:

  • SWJ-DP的初始状态为JTAG-Sel TLR,也就是JTAG状态机中的Test-Logic-Reset状态

  • SWD和JTAG之间的切换需要在特定的状态完成,成功的话会切换到相应状态,失败的话则会保持在原有状态

当然,实际应用中,我们只需要使用JTAG-to-SWD和SWD-to-JTAG这两种序列就可以了。这部分是ARM规定好的,因此没啥好说的,照做就是了。

JTAG-to-SWD的引脚时序如图B5-2所示。

figure-b5-2.png

注:和正常的line reset不同,在JTAG-to-SWD序列中,最后不允许将SWDIOTMS拉低两个周期。

SWD-to-JTAG的引脚时序如图B5-3所示。

figure-b5-3.png

注:和正常的line reset不同,在SWD-to-JTAG序列中,在至少50个周期的SWDIOTMS高电平后,不存在将SWDIOTMS拉低两个周期。

休眠状态和相关操作

SWD协议v2引入了休眠状态(dormant state),所有的切换操作都需要途径dormant state状态进行,这有助于目标设备使用不同的混合协议。

原话如下:Using dormant state allows the target to be placed into a quiescent mode, allowing devices to inter-operate with other devices implementing other protocols. Those other protocols must also implement a quiescent state, with a mechanism for entering and leaving that state that is compatible, but not necessarily compliant, with the SWJ-DP and SW-DP protocols.

在引入休眠状态后,SWJ-DP的协议选择如图B5-4所示,注意到前面提到的JTAG-to-SWD和SWD-to-JTAG已被废弃。

figure-b5-4.png

对于SW-DP,相关状态转移图中JTAG相关状态被移除,且初始状态即为dormant state,如图B5-5所示。

figure-b5-5.png

JTAG-to-DS涉及到ZBS(zero-bit-DR-scan)序列,并没有统一的引脚时序,其中一个推荐的引脚时序如图B5-7。需要注意的是,这里需要事先将IR切换到IDCODE或BYPASS,否则行为无法预测。对ZBS有兴趣的同学可以参考B5.3.2。

figure-b5-7.png

SWD-to-DS则是固定序列,引脚时序如图B5-8所示。

figure-b5-8.png

从dormant state离开时,根据activation code确定下一个使用的协议,相关序列被称为Selection Alert sequence(这里不知道怎么翻译比较好),如图B5-9所示。Activation code的取值如表B5-2所示。

figure-b5-9.png

table-b5-2.png

最近编辑记录 metro (2022-06-05 15:24:22)

离线

#22 2022-06-08 10:05:43

llinjupt
会员
注册时间: 2020-12-21
已发帖子: 68
积分: 162

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

大神回归,“建议在设备端对TMS和TDI等引脚上拉”,这个忘记是在ST还是ARM的文档中看到过,官方推荐设备端不要接任何上下拉电阻,而是由调试器端控制。遇到过有些开发板使用了太小阻值的上下拉电阻,而导致调试异常问题,主要是调试器一侧没有使用推挽方式,而导致驱动力不足。

期待楼主后序。

离线

楼主 #23 2022-06-09 01:47:07

metro
会员
注册时间: 2019-03-09
已发帖子: 390
积分: 329

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

@llinjupt

大神回归,“建议在设备端对TMS和TDI等引脚上拉”,这个忘记是在ST还是ARM的文档中看到过,官方推荐设备端不要接任何上下拉电阻,而是由调试器端控制。遇到过有些开发板使用了太小阻值的上下拉电阻,而导致调试异常问题,主要是调试器一侧没有使用推挽方式,而导致驱动力不足。

期待楼主后序。

感谢回复。这部分内容是JTAG规范提到的,我理解是否接上下拉电阻应该取决于具体的硬件设计,如果硬件厂商或者IP核厂商不建议这么搞,一般是有硬件上的一些考量,这个时候应该优先遵循这些规则(毕竟JTAG规范只是建议而不是强制)。

最近编辑记录 metro (2022-06-09 01:48:14)

离线

#24 2022-06-09 08:58:43

jordonwu
会员
注册时间: 2021-07-05
已发帖子: 47
积分: 28

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

大佬们是在哪个硬件上搞的,是自己做的硬件吗?

在线

楼主 #25 2022-06-09 10:55:04

metro
会员
注册时间: 2019-03-09
已发帖子: 390
积分: 329

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

jordonwu 说:

大佬们是在哪个硬件上搞的,是自己做的硬件吗?

硬件八字还没一撇呢,目前都是理论研究😅

离线

#26 2022-07-19 14:11:45

Chin
会员
注册时间: 2020-10-19
已发帖子: 5
积分: 4

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

metro 说:
jordonwu 说:

大佬们是在哪个硬件上搞的,是自己做的硬件吗?

硬件八字还没一撇呢,目前都是理论研究😅

硬件不急,把理论说清楚呀!

离线

#27 2022-07-23 11:55:47

Vans000
会员
注册时间: 2022-01-04
已发帖子: 10
积分: 5

Re: 【重开旧坑】8051上的CMSIS-DAP调试器——TinyDAP开发过程记录

楼主 用CH549是不是好一些

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn