曾几何时。。。
我们还沉浸在使用盗版J-Link的安逸中,没意识到封锁会突然来临。
只到有一天SEGGER加大了对盗版J-Link的打击力度,淘宝纷纷下架了JLINK。
随着盗版JLINK的下架,我第一次打开了SEGGER的网站,
看到正版Jlink的价格,我悟了——在关键技术上被“卡脖子”的感觉,原来是这么“烧钱”又扎心。
正版的价格早已高得让我们凡人望而却步。你封你的,我们改我们的!换个名字叫“ARM仿真器”,继续开卖!
但是,其实拆开市面上常见的“ARM仿真器”,质量真的是一言难尽,这样的东西在我手里至少坏的也有七八个了!
并且,SEGGER 通过技术封锁,在 J-Link 固件和软件更新中引入了检测机制,防止盗版设备使用新功能。目前盗版JLINK仿真器固件最高支持4.40的版本,如果安装了超过4.40版本的驱动,并且一旦升级就会造成Jlink无法使用。这些JLINK的报错,广大网友一定也被盗版JLINK深受其害过!
盗版检测:the connected probe appears to be a j-link clone
连接故障:The connected J-Link is defective
作为一名辛苦的嵌入式码农,天天修bug已经心力交瘁,还得应付那些动不动就“罢工”的工具,真是一天都不能忍!
要是自己做一个专属的烧录器,ARMmbed开源多年的DAPLink绝对是不二之选。毕竟,俗话说得好,站在巨人的肩膀上,才能看得更远,走得更稳!
在早期的STM32调试中,我们一般采用的是ST官方的STLink进行程序的烧写和调试,后来ARM开发了一个新兴的项目CMSIS-DAP,CMSIS-DAP是一个ARM开源的一个调试器项目,其支持所有Cortex-A/R/M的元器件,采用了HID连接,可实现无驱动连接电脑并进行调试。CMSIS-DAP的理解可以分为两部分,CMSIS和DAP。CMSIS全称为ARMCortex-M SoftWare Interface Standard,是一种ARM的软件接口标准;而DAP全程为Debug Access Port,即软件调试访问口,CMSIS-DAP可以理解为ARM开发的一种软件调试接口,可以使用JATG或SWD的连接方式连接到ARM下的Cortex-A/R/M系列元器件。
移植DAPLINK可以分为两步,第一步移植在线下载调试部分CMSIS-DAP,ARM最新的代码位置就在MDK的安装路径...\AppData\Local\Arm\Packs\ARM\CMSIS\5.9.0\CMSIS\DAP\Firmware\Source
,当前最新的版本为V2.1.1,移植DAP的过程,其实也就是将CMSIS-DAP协议对接到USB协议栈的过程,文件如下:
提升下载速度
既然要做,那就要做到最好!为了弥补DAPLINK性能上的不足,硬件方面,采用了先辑半导体的高性能HPM5301芯片,该芯片主频高达480MHz,内置PHY的高速USB接口;软件方面,将USB协议替换为传输速度更快的CherryUSB协议栈,并且对DAPLink固件中的数据处理和通信代码进行了深度优化,减少了内部延迟和等待时间,将SWD时钟速度提升至10MHz。
这里要特别感谢 CherryUSB 协议栈的作者 sakumisu,和先辑半导体的大神RCSN在技术上的大力支持。CherryDAP的开源地址:https://github.com/cherry-embedded/CherryDAP
优化后的时钟速率如下:
与目前市面上最新的J-LINK-V12速度对比,目标芯片使用STM32H743,开发环境MDK V5.39,分别使用MicroLink和Jlink V12将2558KB的HEX文件下载到内部FLASH中。使用逻辑分析仪测试时钟引脚,计算出擦除,编程,校验全过程的时间,自己做的下载器使用时间为24.205秒,Jlink V12使用时间为33.439秒,测试数据如下图:
Jlink V12测试结果:
MicroLink测试结果:
调试器 | 总耗时(擦除,编程,校验) |
---|---|
MicroLink | 24.205秒 |
J-LINK V12 | 33.439秒 |
优化虚拟串口
DAPLINK还支持一路虚拟串口,但是虚拟串口的功能其实与DAPLINK关系不大,虚拟串口是利用USB协议栈的CDC类设备,CDC是USB定义的设备类之一,允许通信设备通过USB接口进行数据传输。
下载速度提升上来了,USB转串口的速度自然也不能落下,一般的USB转串口波特率速度支持到2M就已经很猛了,但是谁让我上了国产最强MCU先辑的主控,直接把串口性能拉满,使串口最大支持10M波特率,无丢包。
使用逻辑分析仪抓取波形如图所示,可以看到每个bit传输的时间为1/10M=100ns。
增强拖拽下载
以上就是移植DAPLINK最基本的在线下载调试功能,第二步是移植DAPLINK的离线下载功能,离线烧写器的实现主要通过CMSIS-DAP里的DAP连接协议来进行实现,这一部分ARM官方已经帮我们写好了,DAP离线下载主要分为几个过程:初始化DAP–>DAP连接芯片–>确认连接方式–>清除目标板读保护(可忽略)–>清除目标板Flash–>烧写程序–>复位运行。连接方式分为SWD接口,和JTAG接口,我们需要移植的是官方代码的DAPLink/source/daplink/interface /swd_host.c
要想实现离线下载,连接上芯片以后,还要提供目标芯片的FLASH烧写算法,才能对目标芯片进行下载,理论上我们要为每颗想要支持的芯片提供相应的烧写算法,可喜的是MDK的安装路径上为我们提供了这样的算法文件,比如STM32F1系列的下载算法目录就在...\Arm\Packs\Keil\STM32F1xx_DFP\2.0.0\Flash
,STM32F10x文件夹是下载算法的源码,FLM文件就是下载算法。
FLM文件本质是一个ELF格式的文件,Keil规定了FLM文件的构成,它是一成不变的,包含强制性flash编程函数Init、UnInit、EraseSector和ProgramPage。根据设备特性,可以实现函数EraseChip、BlankCheck和Verify 。
我们解析一下现有的FLM文件,以STM32F4xx_1024.FLM为例。
打开命令行工具,输入arm-none-eabi-readelf -a STM32F4xx_1024.FLM:
$ arm-none-eabi-readelf -a STM32F4xx_1024.FLM
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 12172 (bytes into file)
Start of section headers: 12236 (bytes into file)
Flags: 0x5000000, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 2
Size of section headers: 40 (bytes)
Number of section headers: 16
Section header string table index: 15
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] PrgCode PROGBITS 00000000 000034 000144 00 AX 0 0 4
[ 2] PrgData PROGBITS 00000144 000178 000004 00 WA 0 0 4
[ 3] DevDscr PROGBITS 00000148 00017c 0010a0 00 A 0 0 4
[ 4] .debug_abbrev PROGBITS 00000000 00121c 0005a4 00 0 0 1
[ 5] .debug_frame PROGBITS 00000000 0017c0 000104 00 0 0 1
[ 6] .debug_info PROGBITS 00000000 0018c4 00064c 00 0 0 1
[ 7] .debug_line PROGBITS 00000000 001f10 000218 00 0 0 1
[ 8] .debug_loc PROGBITS 00000000 002128 0001b8 00 0 0 1
[ 9] .debug_macinfo PROGBITS 00000000 0022e0 000614 00 0 0 1
[10] .debug_pubnames PROGBITS 00000000 0028f4 000096 00 0 0 1
[11] .symtab SYMTAB 00000000 00298c 000110 10 12 9 4
[12] .strtab STRTAB 00000000 002a9c 000100 00 0 0 1
[13] .note NOTE 00000000 002b9c 00001c 00 0 0 4
[14] .comment PROGBITS 00000000 002bb8 000334 00 0 0 1
[15] .shstrtab STRTAB 00000000 002eec 0000a0 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000034 0x00000000 0x00000000 0x00148 0x00148 RWE 0x4
LOAD 0x00017c 0x00000148 0x00000148 0x010a0 0x010a0 R 0x4
Section to Segment mapping:
Segment Sections...
00 PrgCode PrgData
01 DevDscr
There is no dynamic section in this file.
There are no relocations in this file.
There are no unwind sections in this file.
Symbol table '.symtab' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 NOTYPE LOCAL DEFAULT 1 $t
2: 00000122 0 NOTYPE LOCAL DEFAULT 1 $d
3: 00000144 0 NOTYPE LOCAL DEFAULT 2 $d.realdata
4: 00000148 0 NOTYPE LOCAL DEFAULT 3 $d.realdata
5: 00000000 0 FILE LOCAL DEFAULT ABS FlashPrg.c
6: 00000000 0 SECTION LOCAL DEFAULT 1 .text
7: 00000000 0 FILE LOCAL DEFAULT ABS FlashDev.c
8: 00000148 4256 SECTION LOCAL DEFAULT 3 .constdata
9: 00000000 0 NOTYPE GLOBAL HIDDEN ABS BuildAttributes$$THM_ISAv
10: 00000001 28 FUNC GLOBAL HIDDEN 1 GetSecNum
11: 0000001d 46 FUNC GLOBAL HIDDEN 1 Init
12: 0000004b 14 FUNC GLOBAL HIDDEN 1 UnInit
13: 00000059 44 FUNC GLOBAL HIDDEN 1 EraseChip
14: 00000085 76 FUNC GLOBAL HIDDEN 1 EraseSector
15: 000000d1 82 FUNC GLOBAL HIDDEN 1 ProgramPage
16: 00000148 4256 OBJECT GLOBAL HIDDEN 3 FlashDevice
No version information found in this file.
Displaying notes found at file offset 0x00002b9c with length 0x0000001c:
Owner Data size Description
ARM 0x0000000c Unknown note type: (0x40000000)
通过Symbol table信息我们可以找到Init、UnInit、EraseSector和ProgramPage函数所在的位置。
我们还需要根据Section Headers所描述的位置提取出Prgcode(代码),PrgData(数据),DevDscr(设备描述)的信息。
在命令行中输入arm-none-eabi-objdump -s -d STM32F4xx_1024.FLM:-s参数可以将所有段的内容一十六进制方式打印出来,-d参数可以将所有包含指令的段反汇编。
$ arm-none-eabi-objdump -s -d STM32F4xx_1024.FLM
STM32F4xx_1024.FLM: file format elf32-littlearm
Contents of section PrgCode:
0000 0003000e 202802d3 4009001d 70471028 .... (..@...pG.(
0010 02d30009 c01c7047 80087047 42484149 ......pG..pGBHAI
0020 41604249 41600021 0160c168 f0221143 A`BIA`.!.`.h.".C
0030 c1604069 800606d4 3e483d49 01600621 .`@i....>H=I.`.!
0040 41603d49 81600020 70473748 01694205 A`=I.`. pG7H.iB.
0050 11430161 00207047 10b53348 01690424 .C.a. pG..3H.i.$
0060 21430161 0169a203 11430161 3349314a !C.a.i...C.a3I1J
0070 00e01160 c368db03 fbd40169 a1430161 ...`.h.....i.C.a
0080 002010bd 30b5fff7 bbff2749 ca68f023 . ..0.....'I.h.#
0090 1a43ca60 02240c61 0a690007 400e0243 .C.`.$.a.i..@..C
00a0 0a610869 e2031043 08612448 214a00e0 .a.i...C.a$H!J..
00b0 1060cd68 ed03fbd4 0869a043 0861c868 .`.h.....i.C.a.h
00c0 0006000f 03d0c868 1843c860 012030bd .......h.C.`. 0.
00d0 70b5154d c91c8908 eb688900 f0263343 p..M.....h...&3C
00e0 eb600023 2b61164b 17e02c69 1c432c61 .`.#+a.K..,i.C,a
00f0 14680460 ec68e403 fcd42c69 64086400 .h.`.h....,id.d.
0100 2c61ec68 2406240f 04d0e868 3043e860 ,a.h$.$....h0C.`
0110 012070bd 001d121d 091f0029 e5d10020 . p........)...
0120 70bd0000 23016745 003c0240 ab89efcd p...#.gE.<.@....
0130 55550000 00300040 ff0f0000 aaaa0000 UU...0.@........
0140 01020000 ....
Contents of section PrgData:
0144 00000000 ....
Contents of section DevDscr:
0148 01015354 4d333246 34787820 466c6173 ..STM32F4xx Flas
0158 68000000 00000000 00000000 00000000 h...............
0168 00000000 00000000 00000000 00000000 ................
0178 00000000 00000000 00000000 00000000 ................
0188 00000000 00000000 00000000 00000000 ................
0198 00000000 00000000 00000000 00000000 ................
01a8 00000000 00000000 00000000 00000000 ................
01b8 00000000 00000000 00000000 00000000 ................
01c8 00000100 00000008 00001000 00040000 ................
01d8 00000000 ff000000 64000000 70170000 ........d...p...
01e8 00400000 00000000 00000100 00000100 .@..............
01f8 00000200 00000200 ffffffff ffffffff ................
我们所需要的正是以上信息,接下来的任务只需要将以上文件的几个函数提取出来即可。
将要烧写的文件放到外部flash中,通过文件系统读取文件(脱机下载) 通过模拟U盘,将烧写文件拖拽到U盘中,直接一包包转发出去(拖拽下载)
两种获取文件的方式,分别实现的两种离线下载的方式,DAPLINK的源码提供的正是拖拽下载的方式,然而美中不足的是ARM官方DAPLINK的拖拽烧录只能针对某一个型号单片机,要想支持其他单片机必须手动更新调试器的固件,对使用者门槛较高,导致这么方便的功能食之无味弃之可惜。
作为一个下载器,如果只能对一款芯片进行离线下载,那就太不合格了,所以我对Cortex-M系列的大量芯片做了适配工作,其中意法半导体STM32,国产芯片兆易创新GD32基本都以适配完成,还在持续增加其他型号。
U盘拖拽下载支持HEX文件和BIN文件,HEX文件自带地址信息,自动根据HEX中的地址选择烧录的位置,BIN文件默认下载的地址为0x08000000,以下演示视频是将HEX文件复制到U盘中,完成固件下载:
看到此处,自制的这款下载器已经可以满足我的日常需求了,但是,你以为就此结束了吗?
内置ymodem协议
作为一个搬了小十年砖的码农,深知并不是每一个设备装机后都会预留SWD接口或者JTAG接口的,并且出厂的产品中“肯定”还存留着一些漏网之鱼的BUG等着去修复。
所以能不能提供一个稳定可靠的BootLoader程序嵌入到产品中,一旦需要升级,仅仅通过预留的串口、485或者其他通信接口,客户就可以傻瓜式的将升级文件拖拽到虚拟U盘中自动完成升级固件呢,就像这样:视频是将bin文件复制到U盘中,完成升级文件的传输
要想实现这样的功能,我在这个下载器中内置了ymodem文件传输协议。Ymodem协议在多次重传时仍能保持数据的完整性,非常适用于嵌入式系统的固件更新。
YModem协议是一种串行通信文件传输协议,基于早期的XModem协议进行改进,增加了对批量传输多个文件的支持,并在传输时提供了文件名、大小、修改日期等元数据信息。它使用CRC(循环冗余校验)进行错误检测,相比XModem具有更高的传输效率,并支持1KB的数据块大小(YModem-1K),因此能加快大文件的传输速度。
要想使用内置的ymodem协议发送文件,仅有下载器还是不够的,还需要目标设备支持ymodem协议接收文件,好人要做就要做到底,我做了一个非常稳定可靠的BootLoader开源代码框架:
MicorLink 简介:
https://microboot.readthedocs.io/zh-cn/latest/tools/microlink/microlink/
MicorBoot 简介:
https://microboot.readthedocs.io/zh-cn/latest/
MicorBoot 开源代码:
https://github.com/Aladdin-Wang/MicroBoot
至此,本下载器功能已基本完成, 但是还远远没有结束。。。
功能特点
[√] 支持SWD/JTAG接口,下载调试速度超越JLINK V12(时钟10Mhz)
[√] 支持使用OpenOCD的IDE下载调试ARM/RISC-V等芯片
[√] 支持USB转串口,最大10M波特率无丢包
[√] 支持大量Cortex-M系列芯片U盘拖拽下载,内置大量下载算法,自动识别目标芯片
[√] 内置ymodem协议栈,U盘拖拽文件自动触发ymodem通过串口传输文件到目标设备(需配合带ymodem协议的bootloader)
[√] 支持系统固件升级,为后续添加更多功能
[√] 采用winusb对window10免驱,即插即用
[√] 支持3V3/5V大电流输出电源
[√] 内置防倒灌和过流保护,外部电流无法反向流入USB口,防止损坏USB
[ ] 支持通过U盘读取目标芯片固件
[ ] 支持通过U盘读取目标芯片任意文件
[ ] 支持Cortex-M系列芯片脱机下载,自动识别目标芯片,自动触发下载
[ ] 支持RISC-V系列芯片U盘拖拽下载,内置大量下载算法,自动识别目标芯片
[ ] 支持RISC-V系列芯片脱机下载,自动识别目标芯片,自动触发下载
结合以上特点,为开发者提供了下载调试,批量生产,售后维护,固件升级等一站式解决方案。
产品购买链接:https://item.taobao.com/item.htm?ft=t&id=826800975011
技术支持微信群:
彩蛋
你有没有为写 BootLoader 无从下手发愁过?
你有没有为出厂的产品还需要开盖刷程序苦恼过?
你有没有为程序升级失败,产品变成“砖头”而抓耳挠腮过?
你有没有为升级完成后设备神秘失联而怀疑人生过?
你有没有因为固件升级 Bug 被老板当众灵魂拷问:“为啥烧进去就起不来了?”
下篇文章将为你提供一站式解决方案!敬请关注
如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈。您的支持和鼓励是我最大的动力。长按加我微信,备注“加群”,拉入微信技术交流群。
长按二维码
拉入技术交流群