GPIO 访问 SWD 接口的心得体会

2019-12-10 18:20发布

本帖最后由 helislayer 于 2016-6-23 22:30 编辑

最近写了些用 GPIO 访问 swd 的程序来玩。记录一下体会:

1)ARM Debug Interface Architecture Specification 这个是 ARM
给的规范,初学不要去读。用这个上手极其困难。这个规范讲了
太多细节,很多常识性的东西没有讲。例如我一直疑惑 turn around
的时候是谁驱动 swclk,应该是 host 但是没有说。这个规范比较
适合已经把底层跑通了,看细节某个寄存器如何用的。适合做 ARM
的厂家不适合作为程序员来写个 swd 访问的程序。

2)上手收建议这个:EFM32: Programming Internal Flash
Over the Serial Wire Debug Interface。
这个手册是从如何写 SWD 接口程序的,虽然不是 STM32 的,
但是比较清楚,例如我前面的疑惑就讲很明白。这个手册也不长。
我上传上来了。

3)那个 SWD 接口其实就是和 SPI 非常像,基本上可以理解为
MOSI 和 MISO 合并成一根线SWD-IO。中间有软件协议上下文来
协商谁来驱动这根线。这个转换需要一个 clock, 就是 turn around。

4) 那个 SWD 的 CLK 就是 SPI CLK, 永远由 host 来驱动。

5)target 永远再上升沿采集和放新的数据。这个意味着 host 从
target 读数的时候是在下降沿读比较方便。

6)思路和攻略大概是这样,要先写个底层的接口可以 reset。
就是发一堆 1 (50 以上) 和 中间发一个 0xE79E 再发 50 多个 1.
0xE79E 就是说老子要用 SWD 而不是 JTAG。

7)接下来就要写 读写 AP 和 DP 的寄存器。每种一共 4 个地址很简单。
这个 DP 就是调试接口的硬件。这个 AP 就是一个访问周边外设和内存
的硬件接口。因为 ARM 的外设都是影射到内存地址的,所以可以访问
任意内存地址就可以刷程序和调试了。

8)访问内存需要通过 AP。就是先写访问内存的地址到一个地址寄存器,
然后通过另外一个数据寄存器读写内存。

大概就是这样,我先在也就只是做到这一步。



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
98条回答
boboo
1楼-- · 2019-12-15 16:39
我觉得速度是关键,没有速度swd实用性降低很多。时钟频率至少是2m才有意义。
wangweigang0
2楼-- · 2019-12-15 16:46
 精彩回答 2  元偷偷看……
helislayer
3楼-- · 2019-12-15 17:37
刚刚从一个大坑爬出来,庆祝一下。

我在试图用 flash loader 的程序来刷 flash。
就是前面说的第二种策略。

但是每次一跑就 lockup condition。程序感觉
就是跑飞了那样。各种验证百思不得其解。
把程序从 ram 读出来没有问题。

一怒之下写了个单步调试的功能,跟踪我那个
flash loader 的代码。这下就把问题暴露了,跑
的程序是乱码。根本不是我的flash loader 程序。
难怪一跑就崩掉。

然后各种调试看什么地方把我的 flash loader 程序
给覆盖掉了。最后发现这个特别坑的东西。

就是 AHB-AP 里面这个 TAR 地址的自动增加只会
在 4K 页面里面增加。超出了 4K 页面就会绕回来。
于是绕回来就把我的 flash loader 给刷掉了。
太坑了。

后来我找到了 ARM 的官方依据:

Auto address increment and pack mode on Read or Write data access. Only increments if the current transaction completes with no error.
Auto address incrementing and packed transfers are not performed on access to Banked Data registers 0x10 - 0x1C. The status of these bits is ignored in these cases.
Increments and wraps within a 4-KB address boundary, for example from 0x1000 to 0x1FFC. If the start is at 0x14A0, then the counter increments to 0x1FFC, wraps to 0x1000, then continues incrementing to 0x149C.

浪费了我不少时间。不过写了半个调试器也挺有用的。
helislayer
4楼-- · 2019-12-15 18:29
楼主有什么新的进展吗?很期待啊
蓝蓝的恋
5楼-- · 2019-12-15 19:59
蓝蓝的恋 发表于 2016-8-2 15:52
楼主有什么新的进展吗?很期待啊

这个我已经可以刷 F0,F1,F3 了,F4 还没有试。F2 我没有。
然后我发现其实 F0 到 F3 都可以用同样的 flash loader 的程序
来刷,就是只用 Thumb 的代码就可以了。因为刷 flash 本来
时间就是花在等待那个 busy。 所以用Thumb-2 的指令完全
不必要。

我发现基本上用 flash loader 比外部直接操作flash 寄存器快
差不多 1 倍左右。

然后我也实现了类似 RTT 那样通过 SWD 来打印的功能。
原来的实现是覆盖的,然后发现这个覆盖很糟糕,基本上
stm32打多了不能知道什么时候发生了覆盖,读出来的
每个位置都有可能是覆盖过的。所以又实现了不覆盖的
版本。这个就好很多了。stm32 可以先reset 跑一阵子
再去读输出也不会漏掉开始的那些信息。
打印速度基本上可以接近 SWD 速度的极限,差不多 2M
左右,比 uart 快多了。而且是写内存的,不需要配置
任何东西。连接调用就好了。

自己写了个 sprintf,因为 gcc 那个 sprintf 一用就把我 f030
的 16K flash 爆掉了。

F3 的 swd reset 有些小问题,erase 以后需要外部 reset
一下就可以刷了。似乎 swd reset 以后寄存器的值没有归零。
外部reset 就归零了。
还没有仔细调。估计和 swd 关系不大,是如何用 F3 的调
试寄存器问题。反正 F0 和 F1 没有这个问题。

我已经好久都没有用过官方的 stlink 来刷程序了。
我自己的刷程序比 stutil 的那个快很多。

自己的 swd 打印输出控制比较方便,用程序自动采集
处理调试打印输出都容易。
helislayer
6楼-- · 2019-12-16 01:48
期待高手 的大作。

一周热门 更多>