这几日看到坛里有几个关于SWD协议相关的文章,自己也尝试了下,有点体会,也有些疑惑,写出来与大家分享和交流下。
    以下我的模拟SWD接口的板子简称为Host,目标MCU(即我要连接的板子)简称为Target。
SWD协议
         故名思议,串行总线调试接口。我们需要3根线与目标MCU相连,SWDIO,SWDCLK和GND。
        -SWDIO 为双向Data口,主机到目标的数据传送。
        -SWDCLK 为时钟口,主机驱动。
        -GND  GND脚。
        首先参考《ARM Debug Interface V5》(注:该文档已有更新版本,并且对V5版本做了勘误),对一些相关的协议相关说明有了较浅的认识。那接下来便找了个带SWD接口的板子,我这首先选了STM32F030,因为以后可以为生产线做离线编程器,当然随后也出现了一些问题,下文会说明。
        连上相关物理连线,开始折腾。
        看手册中有几个相对较重要的时序说明。
Trn-Trn:即Line turn-round,当总线上的数据传输方向发送改变时(比如由Host->Target变为Target->Host),需要插入Trn,Trn为一个CLK时序,关于对于Trn的理解自己也有些疑问。
Idle  cycles:在一个总线完成后,可以立即进入下一个总线操作或者是勒令总线进入Idle 状态,此时可以插入Idle cycle。在这我用连续送出8个’0b0’来使得总线进入Idle状态。
Parity :校验位,这个比较简单。分两个内容对命令头进行校验和对数据进行校验。命令头下文会说明。数据校验是对Data的0b0-0b31进行校验,如果‘1’的个数为奇数那校验位就为‘0b1’,如果‘0b1’的个数为偶数校验位就为‘0b0’。
        理解了这几个,我们接下来看读写命令。
        每个读写命令之前都会有个Host->Target的数据头。每个数据头为1Byte.
-Start     起始位,始终为1,这也是Target判断总线从空闲状态退出的条件。
-APnDP  选择要访问的是DP寄存器还是AP寄存器。
- Rnw    选择是读还是写。
-A[2:3]   DP或者AP寄存器的地址,注意它是低位在前。比如寄存器DP寄存器 Select 它的地址为0x08,那这儿的A为C(0b1000),显然A[2:3]就为01。
-Praity   校验位,它是APnDP、RnW和A[2:3]共4个bit的校验位。
-Stop    停止位。始终为0。
-Park     该位确切来说应该始终为1,ADI V5中描述此位由总线上拉,但由于总线的上拉能力不足,会导致Target识别不了这个1。该勘误在ADI V5.2中有说明。

读命令为数据头+Trn+ACK+RDATA+Parity构成,但实际操作发现Trn这位是忽略掉的(所以不知道对此Trn的理解是否有误),及发送完数据头后立即读入ACK,判断Target是否正确响应。

写命令为数据头+Trn+ACK+Trn+WDATA+Parity,在这不同的是,在写命令时必须要考虑2个Trn的位置。

看协议中首先在连接Target时需要进行LineReset,这个是最基础也是最最简单的命令。

具体实现为首先保证Host连续送出至少50个“1”,使得Target进行Line Reset,至少插入2个Idle,然后可以读取目标板的IDR,判断Target的类型。
理解了整个,然后就进行操作验证,发现偶尔可以有数据ACK,继续查看手册,发现需要进行JTAG和SWD的切换操作。查看手册发现切换操作的时序如下。

可以简化为先进行一次LineReset,随后发送0X79,0XE7(高字节首先传送),接着再一次LineReset,随后便可以读IDR。但是发现了问题,用此方式可以读取到STM32F103的IDR,但STM32F030不行,在ARM网站查阅相关资料,发现了这个。

上图主要说在一个更早的协议中需要发送如下命令才能进行JTAG和SWD的切换。就是要发送0X6D,0XB7,尝试了下,这下能顺利读取到IDR了。疑惑的是STM32F0系列比F1出来要晚,居然用的老版本的协议?
既然能够获取到IDR了,那接下来可以尝试着进行连接到AHB-AP了。用DP寄存器的SELECT来进行选择。这儿为了能够使得结果明显和确切,我选择了读取AP 0XFC 的IDR寄存器,来获取AP的特性,因为这个数据是只读的和确切的。
首先要用写入DP寄存器SELECT。

SELECT的具体描述可以参见ADI V5手册,在这有个说明,当时走了弯路。SELECT寄存器中有个APSEL选择位,这个是选择当前连接的AP,手册中没有详细说明它的定义。后来在另外的文档中发现该值为0x00,AHB-AP。APBANKSEL为选择需要访问的BANK地址,比如IDR寄存器的地址为0XFC,那它的BANKSEL为F,如果为TAR寄存器,那它的BANKSEL为0。
连接到AHB-AP后就能进行你想要的操作了。比如我可以读取MCU的独立ID,就可以通过MEM-AP来操作。也可以对MCU进行擦除或者编程。
在做编程之前,首先将MCU进入Halt状态,然后访问MCU相关FLASH控制寄存器进行读写即可。
在STM32F030编程时需要注意的是STM32F030的FLASH的传输方式,我未采用Packet的传输方式。

LineReset代码

  1. static void SwdLineReset(void)
  2. {
  3. u8 i;
  4. SWD_OUT;
  5. SWD_DIO_H;
  6. for(i=0;i<56;i++)
  7. {
  8. SWD_Delay();
  9. SWD_CLK_H;
  10. SWD_Delay();
  11. SWD_CLK_L;
  12. }
  13. }

复制代码

写命令头函数

  1. static void SwdSendByte(u8 dat)
  2. {
  3. u8 i;
  4. SWD_OUT;
  5. for(i=0;i<8;i++)
  6. {
  7. if((dat&0x80)==0x80)
  8. {
  9. SWD_DIO_H;
  10. }
  11. else
  12. {
  13. SWD_DIO_L;
  14. }
  15. dat<<=1;
  16. SWD_CLK_H;
  17. SWD_Delay();
  18. SWD_CLK_L;
  19. SWD_Delay();
  20. }
  21. }

复制代码

读取一个data函数

  1. static u32 SeqRead(u8 cmd)
  2. {
  3. u32 dat=0;
  4. u8 i=0;
  5. SwdSendByte(cmd);
  6. SWD_IN;
  7. for(i=0;i<3;i++)//ack 此处需要处理判断
  8. {
  9. SWD_CLK_H;
  10. SWD_Delay();
  11. SWD_CLK_L;
  12. SWD_Delay();
  13. }
  14. dat=0;
  15. for(i=0;i<32;i++)
  16. {
  17. dat=dat>>1;
  18. SWD_CLK_H;
  19. SWD_Delay();
  20. SWD_CLK_L;
  21. if(SWD_DII)
  22. {
  23. dat|=0x80000000;
  24. }
  25. SWD_Delay();
  26. }
  27. //parity
  28. SWD_IN; //trn
  29. for(i=0;i<2;i++)
  30. {
  31. SWD_CLK_H;
  32. SWD_Delay();
  33. SWD_CLK_L;
  34. SWD_Delay();
  35. }
  36. SWD_DIO_L;
  37. SWD_OUT;
  38. for(i=0;i<5;i++)
  39. {
  40. SWD_CLK_H;
  41. SWD_Delay();
  42. SWD_CLK_L;
  43. SWD_Delay();
  44. SWD_CLK_H;
  45. SWD_Delay();
  46. SWD_CLK_L;
  47. SWD_Delay();
  48. }
  49. SWD_IN; //trn
  50. return dat;
  51. }

复制代码

以上函数未加入ACK判断处理,实际使用时需要考虑并判断! 
下面是用逻辑分析仪抓取的相关时序。
JTAG到SWD的切换

读取IDR寄存器

数据传输

识别STM32F103

飞思卡尔KL16识别

STM32F030 编程测试

先写到这,有空再继续分享。上传几份相关ARM的说明,欢迎拍砖。

SWD通讯的更多相关文章

  1. SWD接口:探索&泄密&延伸

    http://bbs.21ic.com/icview-871133-1-1.html 文买了个JLINKV9,以为神器,拿到手发现根本不是,完全没必要替换V8,想自己做个另类的调试器,当然想只是想而已 ...

  2. stm32的两种固件下载模式:JTAG和SWD

    一.JTAG模式 这种模式一般有10pin的.14pin的和20pin的,尽管引脚数和引脚的排列顺序不同,但是其中有一些引脚是一样的.值得注意的是,不同的IC公司会自己定义自家产品专属的Jtag头,来 ...

  3. 三线SWD模式Jlink

    三线SWD模式Jlink   在公司实习,部门经理让我做一个USB-CAN的适配器. 在网上找资料,找到一个开源的USB-CAN的适配器的资料. 采用的是CP2102芯片实现USB转串口.STM32作 ...

  4. HTML5笔记:跨域通讯、多线程、本地存储和多图片上传技术

    最近做项目在前端我使用了很多新技术,这些技术有bootstrap.angularjs,不过最让我兴奋的还是使用了HTML5的技术,今天我想总结一些HTML5的技术,好记性不如烂笔头,写写文章可以很好的 ...

  5. (转)利用libcurl和国内著名的两个物联网云端通讯的例程, ubuntu和openwrt下调试成功(四)

    1. libcurl 的参考文档如下 CURLOPT_HEADERFUNCTION Pass a pointer to a function that matches the following pr ...

  6. (转)linux下和云端通讯的例程, ubuntu和openwrt下实验成功(二)

    前言: 上节用纯linux的函数实现了和云端通讯, 本节开始利用传说中的神器libcurl 话说一个网络程序员对书法十分感兴趣,退休后决定在这方面有所建树. 于是花重金购买了上等的文房四宝.    一 ...

  7. (转)linux下和云端通讯的例程, ubuntu和openwrt实验成功(一)

    一.  HTTP请求的数据流总结#上传数据, yeelink的数据流如下POST /v1.0/device/4420/sensor/9089/datapoints HTTP/1.1Host: api. ...

  8. 用SignalR 2.0开发客服系统[系列1:实现群发通讯]

    前言 交流群:195866844 先说一下我为什么会写这个博客吧,(首先说一下,我是一个小菜鸟,讲的不好请指导 - -,)  前段时间公司的项目涉及到在B/S上使用即时通讯,(其实就是做一个B/S的客 ...

  9. 用SignalR 2.0开发客服系统[系列3:实现点对点通讯]

    前言 交流群:195866844 目录: 用SignalR 2.0开发客服系统[系列1:实现群发通讯] 用SignalR 2.0开发客服系统[系列2:实现聊天室] 真的很感谢大家的支持,今天发表系列3 ...

随机推荐

  1. 读取磁盘:CHS方式

    读取磁盘:CHS方式 BIOS读取磁盘 读取磁盘也是调用BIOS: 中断命令: INT 13H 读取扇区的入口参数为 AH = 02H 功能参数,读取扇区 AL = 扇区数 CH = 柱面 CL = ...

  2. springCloud配置本地配中心SpringCloudConfig

    多环境配置 在一般开发过程中如果调试都在本地进行,则可以设置一个多环境配置,在本地与线上配置间来回切换. springcloud默认会访问的配置文件名是application.properties, ...

  3. CLR via C#--------CLR的执行模式

    CLR:是一个可由多种编程语言使用的“运行时”. CLR的核心功能(比如 内存管理.程序集加载.安全性.异常处理.线程同步)可由面向CLR的所有语言使用. CLR是完全围绕类型展开的. 面向CLR的语 ...

  4. Java容器解析系列(1) 迭代的进化——从Enumeration到Iterator

    在Java中,对于所有的Collection,都有一个特性,可以通过迭代器来遍历和删除其中的元素,因为Collection接口继承自Iterable接口. public interface Colle ...

  5. DisplayLink 安装错误

    根据 在官网论坛上的反馈结果,程序自己有验证数字签名,数字签名验证不通过,即如上图所示.可能的原因:病毒:下载不完全:证书链出问题

  6. php查询快递的类

    <?php/** *  Express.class.php           快递查询类 * * @copyright            widuu * @license          ...

  7. 学习python随笔记

    1.一定要记得在英文输入法下编辑 2.tab键的缩进也很重要

  8. 改善Python程序的条条建议

    1:引论   建议1.理解Pythonic概念—-详见Python中的<Python之禅> 建议2.编写Pythonic代码 避免不规范代码,比如只用大小写区分变量.使用容易混淆的变量名. ...

  9. SpringBoot下如何配置实现跨域请求?

    一.什么是跨域请求? 跨域请求,就是说浏览器在执行脚本文件的ajax请求时,脚本文件所在的服务地址和请求的服务地址不一样.说白了就是ip.网络协议.端口都一样的时候,就是同一个域,否则就是跨域.这是由 ...

  10. python 转义字符 html 爬虫

    用python的requests包 抓取某些网页时,返回的html中,一些字段含有一些 转义字符 \\\\\\\ 这些转义字符给我们后期处理带来一些麻烦, 比方说 运行js等 python用print ...