正版Jlink速度很牛么?中国开源轻松拿捏

文摘   2024-11-11 09:40   英国  

曾几何时。。。

我们还沉浸在使用盗版J-Link的安逸中,没意识到封锁会突然来临。 

只到有一天SEGGER加大了对盗版J-Link的打击力度,淘宝纷纷下架了JLINK。

随着盗版JLINK的下架,我第一次打开了SEGGER的网站,

看到正版Jlink的价格,我悟了——在关键技术上被“卡脖子”的感觉,原来是这么“烧钱”又扎心。

正版的价格早已高得让我们凡人望而却步。你封你的,我们改我们的!换个名字叫“ARM仿真器”,继续开卖!

但是,其实拆开市面上常见的“ARM仿真器”,质量真的是一言难尽,这样的东西在我手里至少坏的也有七八个了!

并且,SEGGER 通过技术封锁,在 J-Link 固件和软件更新中引入了检测机制,防止盗版设备使用新功能。目前盗版JLINK仿真器固件最高支持4.40的版本,如果安装了超过4.40版本的驱动,并且一旦升级就会造成Jlink无法使用。这些JLINK的报错,广大网友一定也被盗版JLINK深受其害过!

  1. 盗版检测:the connected probe appears to be a j-link clone
当使用非正常版本的JLink连接高版本的MDK时,再加上JLink驱动程序版本过高,就会被检测出这个问题。
  1. 连接故障:The connected J-Link is defective

问题出现的原因是keil5的J_Link驱动是最新版本的,而我们手里的J_Link固件不是最新版本的。

作为一名辛苦的嵌入式码农,天天修bug已经心力交瘁,还得应付那些动不动就“罢工”的工具,真是一天都不能忍!

要是自己做一个专属的烧录器,ARMmbed开源多年的DAPLink绝对是不二之选。毕竟,俗话说得好,站在巨人的肩膀上,才能看得更远,走得更稳!

CMSIS-DAP介绍 
在早期的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作为ARM开源的调试和编程工具,提供了广泛的支持和易用性,然而由于CMSIS-DAP协议传输效率不高,USB HID协议的低效传输、较小的数据块大小、较低的SWD/JTAG时钟频率,以及硬件和固件没有进行专门的速度优化。尽管DAPLink具有较好的通用性和兼容性,但在性能上与专业的JLINK调试工具相比有所不足。

既然要做,那就要做到最好!为了弥补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测试结果

测试结果对比:
调试器总耗时(擦除,编程,校验)
MicroLink24.205秒
J-LINK V1233.439秒
经过对比可以发现,下载速度已经超过了最新的JLINKV12。

优化虚拟串口

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

SWD(Serial Wire Debug)接口是ARM为Cortex-M系列处理器设计的一种两线制调试协议,旨在为嵌入式系统提供低引脚占用、高效率的调试功能。它是JTAG(Joint Test Action Group)接口的替代方案,以简化硬件设计、减少管脚使用,同时保留高效调试功能。

要想实现离线下载,连接上芯片以后,还要提供目标芯片的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 446 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 000170010a0 00   A  0   0  4
  [ 4] .debug_abbrev     PROGBITS        00000000 001210005a4 00      0   0  1
  [ 5] .debug_frame      PROGBITS        00000000 0017c0 000104 00      0   0  1
  [ 6] .debug_info       PROGBITS        00000000 0018c4 0006400      0   0  1
  [ 7] .debug_line       PROGBITS        00000000 001f10 000218 00      0   0  1
  [ 8] .debug_loc        PROGBITS        00000000 002128 0001b00      0   0  1
  [ 9] .debug_macinfo    PROGBITS        00000000 0022e0 000614 00      0   0  1
  [10] .debug_pubnames   PROGBITS        00000000 0028f000096 00      0   0  1
  [11] .symtab           SYMTAB          00000000 00298000110 10     12   9  4
  [12] .strtab           STRTAB          00000000 002a9c 000100 00      0   0  1
  [13] .note             NOTE            00000000 002b9c 0000100      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
     000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     100000000     0 NOTYPE  LOCAL  DEFAULT    1 $t
     200000122     0 NOTYPE  LOCAL  DEFAULT    1 $d
     300000144     0 NOTYPE  LOCAL  DEFAULT    2 $d.realdata
     400000148     0 NOTYPE  LOCAL  DEFAULT    3 $d.realdata
     500000000     0 FILE    LOCAL  DEFAULT  ABS FlashPrg.c
     600000000     0 SECTION LOCAL  DEFAULT    1 .text
     700000000     0 FILE    LOCAL  DEFAULT  ABS FlashDev.c
     800000148  4256 SECTION LOCAL  DEFAULT    3 .constdata
     900000000     0 NOTYPE  GLOBAL HIDDEN   ABS BuildAttributes$$THM_ISAv
    1000000001    28 FUNC    GLOBAL HIDDEN     1 GetSecNum
    110000001d    46 FUNC    GLOBAL HIDDEN     1 Init
    120000004b    14 FUNC    GLOBAL HIDDEN     1 UnInit
    1300000059    44 FUNC    GLOBAL HIDDEN     1 EraseChip
    1400000085    76 FUNC    GLOBAL HIDDEN     1 EraseSector
    15000000d1    82 FUNC    GLOBAL HIDDEN     1 ProgramPage
    1600000148  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 0003000202802d3 400900170471028  .... (..@...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协议发送文件,仅有下载器还是不够的,还需要目标设备支持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 被老板当众灵魂拷问:“为啥烧进去就起不来了?”

下篇文章将为你提供一站式解决方案!敬请关注






精选文章




变参函数和可变参数宏
支持任意数据类型的环形队列
C语言模拟QT的信号与槽功能


如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈。您的支持和鼓励是我最大的动力。长按加我微信,备注“加群”,拉入微信技术交流群。


长按二维码

拉入技术交流群



裸机思维
傻孩子图书工作室。探讨嵌入式系统开发的相关思维、方法、技巧。
 最新文章