【说在前面的话】
家人们,扎心了啊!自从上次通过文章《【独家】我就要用MDK来开发树莓Pico,怎么地吧!》发布了使用MDK编译和开发Pico应用的模板以来,虽然Github仓库里的clone总数是蹭蹭的网上窜,但顺手Star一下的小伙伴却没几个……
这里,我一定要谢谢那几个不远万里过来给我Star的兄弟:
谢谢啦。
对于还没有star的小伙伴,我理解你们也许是忘记了,也许是不方便,总之呢,我把项目连接放这里了,你们看着办……
https://github.com/GorgonMeducer/Pico_Template
我能怎么办?
给你们跪下了,求求家人们给个Star吧……
你们的支持是不会白费的。这不,之前有小伙伴反馈说Seggar官方虽然通过J-Link对Pico的调试提供了支持,实际支持调试的J-Link hw revision 11据说贵得离谱,问我有没有更便宜的调试方式……
为了获得MDK环境下“编译、下载、调试”一条龙服务的完整体验,我这几天一直通过各种渠道在网上转悠,头都要秃了……终于,功夫不负有心人,找到了一个让远超我想象的方案。
我们都知道Pico所使用的RP2040实际上是一个双核Cortex-M0 ,一般情况下,我们都只会使用其中一个核,而另外一个核就处于啥事不干的休眠状态。所以呢,网上就有兄弟琢磨着把其中一个Cortex-M0 拿来做调试器。于是就有了Github上的这个开源项目 Pico-debug。
https://github.com/majbthrd/pico-debug
这方案有多离谱呢?我给你比划比划:
- 它不需要额外的硬件:一根USB线,加你手上已有的Pico就行;
- 它不需要额外的上位机软件,只要一个额外提供的 uf2 文件就行;
- 它直接把其中一个Cortex-M0 变成了 CMSIS-DAP 调试器,而且是无需用户额外连SWD线——直接就在内部对另外一个Cortex-M0 进行调试。
- 它不占用Flash,只占用 0x2003C000 ~ 0x2003FFFF 区间的 16K RAM。考虑到Pico总共有264KB的SRAM,这种安排实际上保留了绝大部分的SRAM(248KB)给用户使用。
对大部分人来说,双核的Pico实际上永远只是一个单核M0 而已,这种把另外一个核当做调试器的做法简直是“变废为宝”、“点石成精”啊。
话说,自带调试器的开发板很常见,但通过pico-debug项目树莓派Pico一跃成为世界上第一个自带调试器的Cortex-M0 单片机。
—— “我调试我自己” 可还行?!
【如何实现调试的“单体自助”】
要想让你手中的Pico变成自带调试器的单片机,你需要访问下面的网址:
https://github.com/majbthrd/pico-debug/releases
下载这里的 pico-debug-gimmecache.uf2 文件(不要下错了哦),留着备用。
此外,我已经对Pico-Template进行了更新,发布了v1.1.x 版本——对用户来说,MDK工程模板已经为您配置好了一切。新版本的获取方式请参考往期文章《【独家】我就要用MDK来开发树莓Pico,怎么地吧!》或者,在订阅【裸机思维】公众号后,发送关键字“pico”来获取网盘链接。(有机会的话,还是跪求一个Star,谢谢啦)。
【如何享受调试的最佳姿势】
对大部分人来说,Pico-Template所提供的 AC6-DebugInSRAM 实现了“编译、下载、调试”一条龙服务。
由于pico-debug所实现的CMSIS-DAP调试器运行在SRAM中,因此很容易注意到每次对Pico进行断电后,都需要重新进行一次如下步骤:
1、按住Pico上的白色按钮不放、将Pico的USB接口连接PC。当我们在文件管理器中发现一个新的叫做 PRI-RP2 的U盘时,说明Pico已经成功进入烧录准备状态。
2、将pico-debug-gimmecache.uf2 拖放到U盘中即可。
3、如果一切顺利,我们可以在资源管理器中发现一个新的HID-compiliant设备。
这里,还请放宽心,这个步骤每次断电后的第一次连接都只要做一次就行——不必每次启动调试都做一遍。
打开MDK,切换到 DebugInSRAM 工程配置。在Options for Target窗口中,我们可以从Debug选项卡里看到:调试器已经被选择为 CMSIS-DAP Debugger。
单击 Settings,我们应该看到 Pico 的其中一个 Cortex-M0 已经被检测到了:
注意:由于MDK工程模板中所有三个工程configuration(也就是RunInFlash、RunInSRAM和DebugInSRAM)都使用了同一个Objects文件夹来保存生成的 axf 文件,为了避免误会,在开始RunInSRAM环境下的调试之前,一定要对当前工程进行至少一次重新编译——以确保载入的template.axf是对应当前工程配置的。
对工程进行编译后,单击调试按钮,我们应该看到指针停在了Reset_Handler程序上:
【一些已知的问题】
- main()断点问题:
由于未知的原因,仅仅在 DebugInSRAM 配置下,无论我们选择何种优化等级,总之就是无法让调试过程停在main() 函数的入口处(你可以下断点,但实际全速跑以后是会遇到错误提示):
代码语言:javascript复制Warning: BKPT instruction at 0x2000A724 externally modified! May have missed required breakpoint.
这算是一个小遗憾,但有趣的是,除此以外的地方,都可以在“第一次全速运行后的暂停期间正确设置,并有效的让代码停止下来”…… 这也算是“未解之谜”了……
- 复位失效问题:
另外一个问题是:由于DebugInSRAM实现原理上的特殊之处——它实际上是利用了RP2040留下的所谓工厂模式,绕过了stage2 boot,而直接跳到用户指定的地方开始执行——因此任何形式的RESET其实都会导致芯片退出这个工厂模式,这就意味着DebugInSRAM失效了。
换句话说,如果你想RESET,有一简一繁两种方式:
【繁琐方案】:
1、先找到Debug的Command命令行窗口
2、输入 debug_in_ram()
回车后,你将看到窗口中打印出了程序的入口地址和主栈顶指针:
这表明我们已经成功的为RESET做好了准备。
3、在命令行中输入"RESET"后回车。
4、在命令行中输入"G, Reset_Handler" 后回车。
此时,我们就完成了整个复位过程。
【简单方案】:直接关闭调试,重新再开即可。
两个方案“孰优孰劣”,我想你“一试便知”。
【如何对RunInFlash和RunInSRAM进行调试】
除了前面所说的 DebugInSRAM 方案外,Pico-Template模板还提供了一般工程开发所需的 RunInFlash 和 RunInSRAM 两个配置。
它们的调试本身并不复杂,甚至没有前面提到的 DebugInSRAM 中的两个问题:“main() 断点问题”和“复位失效问题”。
但这两个配置有自己的难言之隐,即:每次重新编译工程后,都需要用户:
- 首先,通过常规方法将 uf2 文件拖放到 RPI-RP2 盘中完成“手工下载”;
- 紧接着,还要再次Boot Pico使其进入U盘模式后拖放 pico-debug-gimmecache.uf2 使Pico具有调试能力
- 最后才是通过MDK进入调试模式。
总结一下:RunInFlash和RunInSRAM的调试优点是非常方便、没有弯弯绕;缺点是下载纯手工。
【说在后面的话】
开源项目的魅力是:你永远不知道在什么地方可以遇到惊喜,比如 pico-debug 这个项目的存在——它把Pico其中一个Cortex-M0 变成 CMSIS-DAP的操作实在是“太骚气了”。
开源项目的好处是:有众多用户支持的项目,通常是用户的反馈越多,其演进的可能性也越大——你永远可以通过自己的支持和反馈来推动它不停的改进。
开源项目的烦恼是:都是免费的,要啥自行车……如果你遇到孜孜不倦维护开源项目的博主,还请珍惜吧——就算是雷锋,薅秃一个也少一个……
最后的最后,我想回答一个上期文章评论区的一种言论态度:一些小伙伴看到有人用MDK来玩Pico,仿佛就觉得我在说“cmake”不是好东西,仿佛我说了“只有用MDK开发才是对的”——如果我没说清楚,这里我就再说一次:
- cmake很香,我没说用cmake不好
- cmake再好,不代表所有人都应该会觉得它好
- 你、我觉得cmake好,不代表所有人都应该跟我们一样觉得cmake好;我们也不应该对不用cmake的人嗤之以鼻——我们配么?!
- 我提供Pico-Template让大家可以用MDK来开发Pico,只是提供了一个额外的可能性——多了一个选项。这就好比菜单上,一个鸭子多了一吃——选择权始终在用户手里,没有强迫你去用这种方法,也没有因为多了一个选项就意味着这个选项更好而其它的更差。
- 如果你在认真看完这些内容后,不同意以上观点,请取关【裸机思维】,谢谢。