arduino 现在已是大行其道,但玩玩还行,真正使用中有很多不便之处。其中,最影响我的一点就是调试很麻烦。以前我一直用avr模拟器simavr来调试,但缺点很明显,首先模拟器本身bug很多,而且无法方便的连接外设,聊胜于无。
子曰,工欲善其事,必先利其器,我们需要在 arduino 上使用 gdb 这种功能强大的东西。经过我的不懈努力,终于在 datasheet 上找到了线索(Atmel-42735B-ATmega328/P_Datasheet_Complete-11/2016 p327.),atmega328p 是支持 debugWIRE 的,有希望了!
下面记录一下我的一点用 gdb 调 arduino 的经验
准备
硬件
* arduino uno 兼容板
* 支持 debugWIRE 协议的仿真器
arduino uno 兼容板淘宝上买三十多块就可以用了。但别用二十几块的“改进版”,所谓“改进版”就是将 usb 转 ttl 芯片由 atmega16u2 替换为便宜的 ch340。寨板可能就不会引出 RESET EN 焊点,影响进一步操作。不过这种“改进”还是值得鼓励的,atmega16u2放这也是大材小用,ch340才更接地气,我国劳动人民又一次用勤劳和智慧造福了自己(一个正品能买十个山寨,太强大)。
支持 debugWIRE 协议的调试器有很多,我感觉用的比较多的是 avr dragon 和 jtagice mkii。我用的 mkii,原厂的太贵了所以从一家叫做“野芯科技”的店买了个高仿。。。据说可以上 avr studio,只能说技术太牛逼。
软件
* arduino IDE
* avrdude
* avarice
* avr-gdb
硬件操作
debugWIRE 接线
官网上说 debugWIRE 是 Atmel 公司为引脚少的单片机设计的,它只需要接上 RESET 一个脚就可以用了,半双工双向异步通信。
虽然一根线就能用,但我们还是将六针 SPI 接到 arduino 的引出的 ICSP 排针上,方便用 mkii 作为 isp 下载。这样,无论使用 mkii 进行下载还是调试,都不需要改变电路。
arduino schematic 割脉
连接好 debugWIRE 后,其实还是不能愉快使用的,笔者在这里卡了很久,屡战屡败。其实原因就在 arduino 的电路里, reset pin 接到两个东西上,一个是通过一个电容接到 16u2 的 PD7 上,另一个通过电阻 RN1D 接到 +5V 上。
通过这种设置,当 PD7 拉低时,由于电容的作用 RESET 也会瞬间拉低,之后电容缓慢充电,RESET 电压缓慢提升至 5V。网上有人说这样做的目的是为了消除抖动,我想这也是通过精确设置简化代码的办法(PD7只需要关心拉低就可以)。
所以,我们需要将 RESET EN 的连线割断,以防电容干扰 debugWIRE 的通信。
割脉成功的标识就是 arduino 不能自动复位了,用串口是无法烧程序的。
至此,硬件上的准备已全部完成。
软件操作
programmer
不用原本的串口烧程序,我们只能用编程器了,但如果是用较老的 arduino IDE,则并不支持 JTAGICE MKII。没关系,打开 arduino/hardware/arduino/programmers.txt 加上下面几行就搞定了。
1 | # mkii |
接下来从 Tools -> Programmer -> JTAGICE MKII 就可以选择 MKII 作为编程器了。
弄个 demo,点一下 upload,so easy。
进入 gdb
首先,设置 熔丝位,使能 DWEN。
1 | avrdude -c jtag2isp -p m328p -P usb -U hfuse:w:0x9E:m |
然后,启动 avarice 作为 gdb 和 仿真器的接口
1 | avarice -j usb -w -P atmega328p :4242 |
最后,启动 gdb,可以在log中找到 elf 文件的位置
1 | gdb -ex "target remote :4242" -ex "set architecture avr" -ex "file /tmp/buildxxxx.elf" |
这编起程来就很舒服了
重新烧程序的时候不要忘记清除 DWEN
1 | avrdude -c jtag2isp -p m328p -P usb -U hfuse:w:0xDE:m |
未解之谜
同时产生的问题列在这里,高手可以帮我解答一下
1. mac os x 下的bug
1
2
3
4
5
6
AVaRICE version 2.13svn20160229, Jun 16 2018 16:28:10
JTAG config starting.
Assertion failed: (ctx->pollfds_cnt >= internal_nfds), function handle_events, file io.c, line 2116.
[1] 43313 abort avarice -j usb -w -P atmega328p :4242
2. gdb看不到bootloader,讲道理,应该在 flash 0x7e00 的地方
3. gdb 给地址增加一个 0x800000 的 offset。虽然我知道这是 SRAM 的位置,但有时候我就是想看flash啊
4. gdb dump 命令失效
待解之谜
16u2这下用不到了,看看能不能干点别的
尝试一下mega2560原生jtag接口
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章