现在绝大部分人做调试器的方向都是错的,都是想着做低成本,而不是把东西做好。
导致现在在淘宝上买的DapLink很多都不稳定,要买多个对比实测才知道好不好用。真TM的一言难进!
这点我同意,现在的DAP调试器市场主要是两种方向,一种就是像你说的,只是简单地把USB协议栈和CMSIS-DAP或者DAPLink代码拼接起来,看着还行,实际体验并不好,总有各种小问题;另一种就是使用高端芯片做更好的功能,但是价格相对来说也比较高。
我想做的可能会更“极端”一些,对于低成本的方案,还是使用廉价MCU,但是通过重写相关的代码,实现更高的性能,解决一些潜在的问题,让低价调试器不低质;高端方案我比较想尝试基于FPGA的方案,做到更好的传输质量和更低的延迟。当然,这些只是设想,不过我也不靠这个盈利,所以会花时间来慢慢打磨,满意了再发布。
好久不见,距离上次更新又过去了近两年时间。这几年时间单片机的价格大跳水,1块钱带USB的单片机已经不再是传说,是时候重启这个项目了。
在主控芯片的选择上,当初我们基本上只有CH552能选,而现在STC8H2K08U或者CH32X033都是更好的选择,两者的散片价格都在1块钱左右。考虑到开发难度和后续的升级能力,后者都是更好的选择,因此后续我们将用RISC-V核心的CH32X033来完成——虽然和标题有些冲突,但我们的目标是花最少的钱实现同价位最高的性能。
CH32X033的纸面数据还是可以的,至少从存储器来看是管够的,这意味着我们很容易就能移植现成的CMSIS-DAP甚至DAPLink并让它跑起来,但是这样的性能可能不够极致。因此,我对这个项目的要求是:
不引用其它代码库,也就是说手写包括USB协议栈和CMSIS-DAP源码内的所有代码
对于JTAG和SWD,使用SPI进行加速,SRAM的读写速度突破300KB/s
必要时编写汇编来处理关键代码,包括IO操作和ISR等
保留后续添加新功能的能力,在Flash足够的情况下可以根据需求进行扩展
丰俭由人,BOM的成本可以压到2块钱甚至更低,也可以添加电平转换芯片等外围电路构成更完整的调试器
对于一个项目,我们当然要定个目标,我觉得目标可以分成基本目标和进阶目标,基本目标是做一个可以和DAPLink的基础功能大致对齐的调试器,进阶目标则允许和其它基于DAPLink的调试器构成差异化竞争。
基本目标:
CMSIS-DAP协议支持,包括v1(基于HID)和v2(基于WinUSB),不需要切换工作模式
SWO支持,波特率可以达到3Mbaud
异步串口支持,波特率可以达到3Mbaud
进阶目标(构思中):
加入OLED显示屏和按钮,实时显示信息并允许简单操作
WCH RISC-V调试协议支持(视协议开发情况而定,目前只有单线协议开放)
基于CMSIS-DAP的Vendor Commands实现新功能(强制调试时钟频率等)
由于是从底层搭起,想必会花费不少时间把这颗单片机摸透,不过至少SWD和JTAG的前置知识已经都在前文覆盖了,关于CMSIS-DAP协议的支持应该也会在后续提到。本贴应该会在接下来的几个月中缓慢更新,敬请期待。
大家都知道,ARM Cortex-M系列CPU中,现在最猛的是Cortex-M85,而作为第一批搭载Cortex-M85的MCU,瑞萨的RA8D1已经可以通过RT-Thread新出的Vision Board玩到了。
那么,既然是CoreMark/MHz最高的Cortex-M系列CPU,跑个分自然不在话下。这个MCU的最高主频“只有”480MHz,如果能够适当超频,是否会有更好的表现呢?
以下跑分使用以下配置:
Keil V5.39
打开Ofast和LTO
CoreMark部分运行在ITCM和DTCM
打开I$和D$
超频到720MHz
基于vision_board_blink_led工程修改,使能CoreMark,循环次数72000
结果如下,4000分整(有点巧),大概是5.56CoreMark/MHz,通过调整编译选项应该可以更快,不过这个分数已经很满意了,哈哈:cool:
@metro
那个cmsislink的xvc server能不能分享一下,另大佬怎么用python直接驱动cmsislink的引脚的,pyocd我没翻到这个功能欸
之前用CMSIS-DAP测试过,速度感觉不太理想,目前在尝试其它方案,等搞定了应该会开源的。晒下目前的硬件设计,软件部分还没开始适配:
至于驱动CMSIS-DAP,俺是直接用pyUSB发送和接收数据的,用的是CMSIS-DAP的DAP_JTAG_Sequence命令,用法还是比较简单的,可以参考官方文档:CMSIS-DAP: DAP_JTAG_Sequence
尝试测了一下CoreMark,分数还不错,基本上和STM32F407在一个等级,248MHz(数据手册中最高频率)能到630,384MHz(最高可运行频率)到了976以上,不知道这个分数是否意味着AG32VF407/AGRV2K的Flash有cache或者零等待执行。
CoreMark的工程可以在这里下载:CoreMark.zip,可以通过修改coremark.ve文件中的SYSCLK来调整时钟频率。
在更新到Supra之后,看起来支持CMSIS-DAP了,这样一来可以搓一个带下崽器的最小系统,好评。
https://whycan.com/files/members/1510/AGRV32-Supra.png
验证了一下,确实是支持的,而且OpenOCD的版本很新(版本信息是Open On-Chip Debugger 0.11.0+dev-02429-g3c36bfc (2023-02-06-17:01)),可以无bug支持CMSIS-DAP V2.1。
睡前发一下老板今天(昨天?)刚给的资料,信息量还是比较大的,特别是网盘部分,需要花点时间慢慢啃。
AG1KLPQ48.rar
AG32VF407.rar
AGRV2K.rar
某天在逛淘宝时,发现AGM店里上了个有趣的芯片:AGRV2K100(CPLD) AGM FPGA CPLD替代Altera EP1270 内嵌MCU,遂买来玩玩。接下来就发生了意想不到的一些事情:
我在早上下了一单,结果晚上到家的时候就发现快递躺着家门口了,这也太效率了。后面了解到他们一天会发两次货,并且刚好有本地仓库,所以当天就收到了,而板子都还没准备好。
收到货的时候,发现并没有收到想要的AGRV2K,反而收到了AG32VF407。后来才知道,原来AGRV32和AG32VF407是同一颗芯片,估计厂家没有重新打标,直接就推了。
发现卖家“发错”之后立刻联系卖家,结果卖家在晚上直接就打电话过来了,详细解释了丝印的问题。后面我也确认过,这两个确实是同款芯片。
来点当时刚刚收到的芯片:
metro 说:趁下班时间画了一版,大家猜猜这是什么方案😏
https://whycan.com/files/members/1510/AQUA-Lite.png这是要用PIO做USB PHY?也就是只能测FS/LS咯?
是的,先从简单的做起,熟悉下上位机。
不过这个会按照自己的想法做一些功能,具体的话可以期待一下🤭
设计不错 就是内存小 要是能跟sigrok连上 功能会更好些
其实sigrok可能未必是最好的,原因上面有总结过,主要是USB分析仪需要能分层次呈现相关信息。至于其它方案,我想到的比较好的有两种:
使用已有的开源USB分析上位机,比如上面提到的ViewSB(不过这玩意实在是太半成品了一些),或者是同一个作者正在优化的Packetry。这个比较适合实时捕获,不过功能上还比较简陋,需要优化。
将数据保存为其它工具可以打开的形式,之后可以进行离线分析。这个我能想到最好的软件是Wireshark,配合相应插件可以实现USB Class级的分析,并且有强大的功能支持(例如正则表达式筛选)。按理来说这个工作量不会很大,不过似乎没有看到过成品。
既然要做一个USB分析仪,那自然要对它的原理有一个初步的了解,只知其然不知其所以然总归是不好的嘛。
在大多数应用中,USB分析仪也就是一个特殊的逻辑分析仪,通过抓取逻辑信号的方式来获取USB传输的物理层信号,之后通过层层翻译最终得到USB协议包、USB类乃至应用层的信息。当然,相对于一般意义上的逻辑分析仪,USB分析仪有以下几点不同:
USB的传输速率和当前的USB模式有关,如果是全速(12Mbps)或者低速(1.5Mbps)的话,普通的逻辑分析仪就可以实现(事实上sigrok等逻辑分析仪上位机已经支持USB全速和低速分析了);但是,高速(480Mbps)还是比较有难度的,这个速率超过了大部分逻辑分析仪可以达到的速度。
从物理层来看,高速USB其实是个比较蛋疼的存在:一方面为了兼容性需要使用3.3V CMOS电平进行握手和一些特定状态的处理,一方面为了传输效率使用了17.78mA的差分电流源,而这两种电平需要两路驱动和接收器在不同状态下进行切换。因此,如果要抓取高速USB信号,也必须要有相应的设计才行。
相对于通用的逻辑分析仪,USB传递的数据基本上是遵循一些上层协议的(如USB类),所以分析得到的数据时最好也要整理为相应形式以呈现给开发者,否则由于USB数据量大于大部分常见协议,可能会造成分析上的困难。
除了抓取物理层信号分析的方式,其实我们还有其它方式可以分析USB,比如在计算机上使用软件(例如Bus Hound等)进行抓包。实际上,软件抓包在大多数场合都要比USB分析仪好用,毕竟在计算机上更容易实现数据过滤和分析,但是,在有些场合,USB分析仪还是无法替代的:
最典型的情况是在嵌入式开发USB主机相关应用。在嵌入式中,通常难以使用软件抓包的方式来分析,即使能够通过输出log等方式获取一些简略的信息,但终究无法反映所有的信息。
对于USB无法正常使用的场合,USB分析仪能够抓取错误的波形和数据,而软件抓包只能在驱动层进行操作,对于USB控制器自动过滤或者忽略的情况则毫无办法。一个典型的例子是,Windows在获取描述符失败后无法识别设备,因此在驱动层面无法给出具体的错误信息。
USB分析仪可以抓取更精确的信息,例如时间戳等。由于驱动层给出的信息可能不准确(比如说驱动层反馈信息的时间有延迟),这个时候就需要USB分析仪补充相关信息了。
USB分析仪可以在一些特殊情况下使用,例如系统启动时、休眠时等。
考虑到USB分析仪的使用场景,我们通常可以假定其不需要分析物理层的内容,可以从协议层开始看起。那么,一个完整的USB分析仪系统,就可以分为以下这三个部分:
USB信号采集,也就是把抓取到的物理层信号翻译为USB协议包,并且附加一些信息(如时间戳等)。
USB数据转发,一般是把采集到的USB协议包传输到上位机,当然也可以保存下来之类的。
上位机分析,也就是把USB协议包翻译成方便人类阅读的方式,从而高效的定位和分析问题。
不考虑USB物理层的原因不外乎以下几点:
这部分内容以分析信号传输质量为主,通常由专业仪器测定,一般只有IC和PCB设计时会考虑,程序猿不用头疼这个事情。
高速USB的鲁棒性其实挺强的,你想想一般情况下接个几米的线都没问题,如果不是板子画得太离谱,一般不需要往这个方面去考虑问题。
退一步说,就算高速USB出问题,一般情况下都会回退到全速,这个就真的是“拉通了就能用”的程度,以USB堪比Windows的兼容性来看,只要全速USB能工作,剩下的问题应该就容易定位了。
LUNA(现在硬件部分改名为Cynthion)就是一个完整的USB分析仪实现,也是本文的主要技术参考和灵感来源。可以从官方网站Cynthion - Great Scott Gadgets获取更多信息。
USB分析仪有一点和逻辑分析仪很像:作为调试程序时使用的工具,USB分析仪的上位机是非常重要的,一个成熟可靠的上位机才是吸引大家使用的关键。对于个人来说,开发USB分析仪上位机是一件比较庞杂的工作,好在我们可以搭上开源的快车,像Great Scott Gadgets开源的ViewSB(不得不说这个名字在汉语语境中十分微妙)和Packetry都是可以参考的对象。
综上所述,如果要自制USB分析仪,我们至少需要完成以下工作:
设计一套能够抓取USB信号,并将信号传输到上位机的硬件
为这套硬件编写必要的代码,使之可以和上位机通信
在上位机中适配新的USB分析仪
接下来的帖子也将围绕这些工作展开。
最近参加了沁恒举办的[RISC-V MCU创新应用大赛](https://www.wch.cn/RISC-V-MCU-competition),虽然很可惜没能在限定的时间内完成所有工作,不过毕竟也做了一些有意义的事情。在deadline来临之际,这里我把之前整理的一些资料和已经完成的部分分享给大家,后续有时间会尽力完成这个设计,争取把BOM成本降低到可以自制的水平,做一个有实用价值的东西出来。
考虑到参加比赛的情况,这里暂时不会把参赛用的代码直接发出来,但后续会提供一个开源版本,希望能够和大家一起讨论相关技术,一起改进现有的设计。
由于楼主工作繁忙,更新进度比较随缘,还请大家见谅。
先说结论:这样做没有语法错误,但很可能达不到楼主想要的效果,除非明确自己需要做什么,否则不建议这么写。
具体代码的编译结果可以参考这个:https://godbolt.org/z/57EfcK7eM(为了避免编译器的优化,对case值进行了少许修改)。
接下来说说C语言里面switch和case的逻辑,可以参考C语言的规范,例如C99:https://www.dii.uchile.cl/~daespino/files/Iso_C_1999_definition.pdf。
可以看到,C里面的switch的功能实际上很简单,说起来就是:
首先计算switch内的表达式的值,C要求计算的结果必须为整数(即integer)。
接下来会找到值匹配的case,如果没有匹配的值则会跳转到default(如果有),如果没有则直接跳出整个switch。由于C语言限制了case值不能重复,也不能有多个default标签,所以从switch到case/default的跳转是唯一的。
跳转到相应位置后,依次执行代码,直到遇到break提前终止或者完成整个switch。
至于case,其实case可以理解成是一种带常数表达式的label(也就是goto跳转到的地方),因此case可以出现在switch内的任何位置,但这个位置是直接跳转过去的,并不会去执行前面的语句。以楼主给的代码为例,这里if(y==1)实际上就是永远不会执行到的代码,因为上一个case结束时有break,而下一个case是在if语句里面,从执行的结果上看相当于没有这一行代码。现在,对比上面给的编译结果,应该就很容易理解为啥完全没有出现r1(第二个参数)这个寄存器了。
最后贴一个C99规范里面的例子,以及相应的说明:
In the artificial program fragment
switch (expr) { int i = 4; f(i); case 0: i = 17; /* falls through into default code */ default: printf("%d\n", i); }
the object whose identifier is i exists with automatic storage duration (within the block) but is never initialized, and thus if the controlling expression has a nonzero value, the call to the printf function will access an indeterminate value. Similarly, the call to the function f cannot be reached.
顺带一提,双层沉板USB Type-A用的是这个:U224-081N-1WRZ21-S-1_(XKB Connectivity(中国星坤))U224-081N-1WRZ21-S-1中文资料_价格_PDF手册-立创电子商城,焊好后板子的厚度在1.5cm左右😎
另外,为了控制阻抗,这个板子用了4层铜,在嘉立创打样的话需要选择7628叠层。
先上链接:metro94/TinyHub: TinyHub - 4-Port USB Hub with Multi-TT
顺便贴下实拍图,可以看到真的很小,算上突出的各种接口,差不多正好是4x4 cm^2见方。
--------普通的分割线--------
那么,这次为啥画这个板子呢?简单来说就是因为便宜:虽然2块钱的Hub并不是最实惠的(SL2.1A等批量价格似乎不到1块钱?),但是带上MTT的支持的话那就不一样了。对于Single-TT和Multi-TT的区别,可以参考这篇文章:USB hub MTT STT 区别,简单来说就是对全速和低速设备的带宽有帮助。
本来对于一个Hub板子来说应该是没啥好说的,不过由于沁恒的批次有区别,这里还是详细说明下。
首先呢,在CH334的datasheet有提到,这玩意有批号的区别。对于批号倒数第五位为0的版本,由于内置的LDO最高仅支持4.5V输入,因此需要通过VBUS直接为V5供电的话,需要接一个二极管(例如1N4001)降压。在后续版本中,LDO可以支持5V直接输入,因此可以将VBUS直接接到V5上,官方建议有条件的话可以使用一个100mA的保险丝。
另外有一个坑点,这个是CH334R独有的问题。根据datasheet,CH334R应该是支持MTT的,但是我在淘宝买的散片只支持STT(批号31160HC16),这很有可能是官方初版芯片的问题。我找官方申请了一些CH334R的样片(31161HC43),发现新批次是正常的,可以识别到MTT。如果对此有疑问,可以咨询沁恒官方以获取更多消息。
总的来说,CH334系列(包括同样已经量产的CH334U)的性价比还是不错的,外围足够简单,QSOP16的封装相较于SOP16也能明显节省面积,非常适用于开发板的USB端口扩展等功能。
最后祝大家玩得愉快!
寂寞哥,上次那个CH334的hub验证成功了吗,对这个更感兴趣,可以放在全志V3s之类的板子上
暴露身份了🤣板子验证能用了,但是CH334R测试发现是STT,不是datasheet说好的MTT,怀疑可能是批次的问题,还在等官方回复,据说CH334U没这个问题。
https://www.wch.cn/bbs/thread-96354-1.html
首先感谢梦程(dreamcmi)赠送的CH340X,于是画点板子练手~
废话不多说,先上链接:metro94/TinyUSer
简单介绍下板子:超小体积,差点就可以塞进Type-C头子的那种;功能完善,CH340X新加的DTR也支持;虽然CH340已经有被CH343取代的趋势,但是偶尔用用还是不错的。至于DTR的用法,建议大家直接看datasheet,这里不再赘述。
最后晒点图,希望大家喜欢~
好消息,板子在Muse Lab上架啦~链接是https://item.taobao.com/item.htm?id=686942510375,辛苦晕哥帮忙改下标题和顶楼😘
现在推荐玩玩CH32V203G6,性能全方位优于CH552T,封装也更小(QFN28,4x4),价格的话批量也可以做到2块以内。可以参考这个帖子:CH32V203G6最小系统板正式开源,可能是最小的RISC-V全引脚开发板。
好消息,板子在Muse Lab上架啦~链接是
https://item.taobao.com/item.htm?id=686942510375
为了吸引大家点进来做一回标题党,下不为例,嘿嘿。
重要的内容放在最前面说:
CH32V203G6最小系统板开源啦,名为FlappyBoard,项目地址是https://github.com/metro94/FlappyBoard,该有的东西都有,欢迎大家围观~
说说这个板子的设计思路:
首先当然是极致体积,在保证全引脚均通过2.54mm间距排针引出的前提下,将板子体积缩小到了1.778x3.556 cm²,其中左右两排引脚的间距为600mil,正好可以适配DIP-28宽体的烧录座,也可以直插面包板。
板子当然得有各种必备的功能,包括USB-C、LED、按钮和调试接口,并且为无源晶体预留了位置。
添加了拨码开关,用于控制MCU的相关引脚是否直接接到USB-C上,解决了引脚冲突产生的问题。
丝印不仅覆盖所有引脚的名称,而且还包括阻容等器件的数值,方便手焊。
开源硬件设计,两层板布线,方便白嫖。
如果你愿意,甚至可以当钥匙扣用,哈哈哈。
这个板子可以配合MounRiver(沁恒的RISC-V单片机使用的IDE)进行开发,相关例程楼主也会持续同步到相应的GitHub中😉
话不多说,来欣赏一下渲染图和实拍图(顺便diss下嘉立创的丝印,比样板质量差多了):
原帖见Programming FTDI Devices for Vivado Hardware Manager Support,注意需要安装最新的Vivado 2022.1。
使用方法很简单,亲测可行。支持FT232H/FT2232H/FT4232H。
最后贴一下命令的使用方法:
program_ftdi
Short Description
Write/Read to FTDI EEPROM for Xilinx JTAG Tools supportSyntax:
program_ftdi {-write -ftdi=<ftdi_part> -serial=<serial_number> [-vendor=<vendor_name>][-board=<board_name>][-m=<manufacturer>][-desc=<description>] |
-write -filein=<cfg_filein> |
-read [-fileout=<cfg_fileout>]} [-help][-longhelp]Usage:
Name Description
-------------------------------------------------------------------------------------
-ftdi Specify the ftdi device to be programmed <FT232H | FT2232H | FT4232H>
-serial Serial number to be written into the EEPROM
[-vendor] Vendor information
[-board ] Name of the board being programmed
[-mfg ] Manufacturer information
[-desc ] A short description of the board
-file_in Input file with all fields to be written
[-file_out] File to which the FDI EEPROM should be read back
Description:
program_ftdi writes/reads the fdti part according to the option specified.
When called with write, either -ftdi and -serial must be used or -filein with -ftdi must be specified. The Xilinx supported configuration for the part specified using -ftdi flag is written into the EEPROM.
-vendor, --board, -m and -desc are optional arguments which can be used to specify more details to be written. All strings must be specified within inverted commas ("").
When used with read, the command reads back the content of FTDI EEPROM to standard out. if -fileout option is used, the read back information is written to the file specified.
If no arguments are passed, FTDI communication is skipped and help menu is printed.Restrictions:
Only the 1st ftdi part found will be programmed/read. If more than 1 ftdi device is detected this command will error out.Arguments:
-write - Write the FTDI EEPROM with either the options specifed with command line option of by a given input configuration file.-read - Read the contents of the FTDI device detected in chain.
-ftdi - (Required field) Specify the ftdi device to be programmed <FT232H | FT2232H | FT4232H>
This programs the ftdi part according to the supported configuration for the specified device-serial - (Required field) Serial number to be written into the EEPROM
The serial number can have digits and/or alphabets. no special characters may be used.-vendor - (Optional field) Vendor information
The vendor information should contain vendor name and other details as a string.-board - (Optional field) Name of the board being programmed
A board name can be written into FTDI using this argument.-m - (Optional field) Manufacturer information
The Manufacturer information should contain Manufacturer name and other details as a string.-desc - (Optional field) A short description of the board
-filein - (Required field) Input file with all fields to be written
If this argument is used, an input file with details about the FTDI device, serial number etc should be specified.-fileout - (Optional field) File to which the FDI EEPROM should be read back
@echo
另外,即使都是高速USB,相互之间也是有比较明显的性能差距的,这个可能和具体的实现有关,我这里不是很了解,这里有一些相关数据:https://blog.csdn.net/rui22/article/details/107814146 。DLC9和Digilent的方案的对比应该是比较多的。
(当然,最典型的反面例子就是只用CY7C68013A不用CPLD的方案,这种方案的IO速度受到CPU的限制,实际上确实不如新的USB全速方案,但是用GPIF或者Slave FIFO的方案理论上来说要好一些。)
说到底,我觉得最大的问题是高速USB对于纯下载用途而言确实应用面比较窄(原因如你所说,大容量芯片本身就是偏专业向的用途,和开源社区目前关注的方向不是很合拍),而可以发挥其优势的用途(如大容量FPGA下载,片上逻辑分析仪等)又容易受到上位机的制约(通常只支持特定型号的下载器,对开源方案不友好),估计需要多做一些工作才能达到期望的效果。
这个是之前做过的一个简单的转接板,验证过功能可用。
由于画得比较丑,就不上传到各种开源平台了,在这里随便发下,有需要的可以自取。
工程(KiCad):
DebuggerConverter-2022-06-02_213243.zip
Gerber:
DebuggerConverter-Gerber.zip
效果图(真正的转接板不需要额外的连接线.jpg):
建议参考USB-C的相关标准,里面有详细记录各种转接线和转接头的连接方式,按照这个来准没错。USB Type-C Specification Release 1.3.pdf
协议层关心的主要是所谓“数据包”的收发,也就是调试协议每次传输的最小单位。
一般而言,协议层的数据传递需要依靠收发双方各自维护一个状态机,引脚的状态变化会使得这个状态机不断更新到下一个状态,直到停留到目的状态,收发双方获取到所需的信息为止(传输错误等也可以看作是一种信息)。
需要说明的是,协议层一般只维护基本的传输功能,并不对收发的数据进行进一步分析,这些分析操作应该交由上层(数据链路层和AP层)完成。
因此,像CMSIS-DAP这样只做到协议层的调试器而言,其实只需要上位机(通常是OpenOCD等)将高级操作(例如访问寄存器等)翻译成协议层的指令,并不需要调试器“理解”指令的含义,所以CMSIS-DAP的方案可以在小Flash的MCU上实现(例如CH552),功能上并不打折扣;相对应的,CMSIS-DAP需要上位机配合才能工作,单独使用时需要手动操作AP层的寄存器,比较麻烦。
SWD
SWD作为两线协议,传输数据的过程必然需要协商好数据传输的方向,否则可能会导致信号冲突或者握手失败。好在SWD的协议并不复杂,下面我们来一窥端倪。
传输格式
SWD的数据包可以分为以下三个主要部分:
Packet request:表示调试器的命令,传输方向为从调试器到DP
Acknowledge response:表示DP对请求的响应,传输方向为从DP到调试器
Data transfer phase:表示实际传输的数据,传输方向根据命令确定
另外,在切换传输方向时,需要数个周期的时间,这个阶段被称为turnaround。一次正常的传输总会包括两次turnaround,原因是packet request和acknowledge response的传输方向总是相反的。
注:turnaround的设置位于SW-DP的DLCR寄存器中,可选值为1到4个周期,line reset后默认值为1,且可以被调试器设置。
接下来我们看各个部分的格式。
对于packet request,共有8个bit,按传输顺序分别如下(均为小端序,下同):
Start:表示开始发送,恒为0b1
APnDP:表示传输的寄存器,0b0为DP,0b1为AP
RnW:表示数据的传输方向,0b0为调试器写(DP读),0b1为调试器读(DP写)
A[2:3]:表示寄存器的索引
Parity:表示APnDP到A[3]这4个bit的偶校验结果(其实就是将这4个bit异或后得到1个bit的结果)
Stop:表示结束发送,恒为0b0
Park:将SWDIO置为高电平,以便后续turnaround保持高电平状态(通过上拉电阻)
对于Acknowledge response,共有3个bit,其中:
0b100:OK,表示读写操作正常发起
0b010:WAIT,表示当前DP正忙,需要调试器重试,或是(在重试一定次数后)使用ABORT寄存器终止传输
0b001:FAULT,表示之前的传输有误,需要调试器读取相应寄存器获取出错原因
其它:表示可能出现其它错误,包括协议错误(protocol error)或是与DP断开连接等,由于packet request阶段结束时已经将SWDIO设为高电平,因此最有可能出现的是0b111,表示DP没有驱动SWDIO
对于Data transfer phase,共有33个bit,传输方向由Packet request中的RnW确定,其中:
前32个bit表示传输的数据
最后1个bit表示前32个bit的偶校验结果
从上面可以看出,一个数据包的长度为(Read) 8 + Trn + 3 + 33 + Trn = (Write) 8 + Trn + 3 + Trn + 33 = 44 + 2 * Trn,其中Trn表示turnaround的时钟周期数。
读写方式和错误处理
在明确传输格式后,接下来就可以让调试器和DP开始沟通了。不过,一次完整的传输需要考虑的事情可不少:
DP和AP寄存器的读写方式有所不同。由于AP寄存器的访问需要时间,因此相对于DP寄存器而言等待时间可能更长,并且可能出现的状况也更多。
在acknowledge response返回不同值的时候,需要有不同的处理方法。成功的时候自然是最好,如果遇到了其它状况,也应该妥善处理,以保证调试器和DP能够正常工作。
我们先来说写寄存器的情况。在成功写寄存器时,波形图如图B4-1所示。
注:在ADIv6中,SWDIO的波形均被描述为上升沿时改变,这对调试器而言实际上不够好,见物理层部分的相应描述。
可以看到,在acknowledge response阶段,DP通过返回OK表明自己有能力接收新的数据。至于此次传输的数据是否被DP成功接收,则需要等待下一次传输的acknowledge response返回,其中:
若写的是DP寄存器,则通常可以直接获知是否成功传输,也就是说会在下一次传输时返回OK/FAULT或其它错误
若写的是AP寄存器,则由于可能需要等待上次传输完毕,可能需要等待一段时间才能获知传输是否成功,也就是说下一次传输时可能会返回WAIT,直到上次传输完毕
注:写AP寄存器在下一次传输返回OK并不代表已经成功写入到AP部分的相应寄存器,而只是表示已经写入到写缓冲(write buffering)区域。如果写操作进入到写缓冲但最终被丢弃,将会通过CTRL/STAT.WDATAERR标志位来表示。这一部分内容可以参考B4.2.7的SW-DP write buffering部分。
接下来是读寄存器的情况。在成功读寄存器时,波形图如图B4-2所示。
这里需要区分读DP寄存器和读AP寄存器的情况了。对于读DP寄存器,这种情况比较简单,只需要一次传输就能获取到acknowledge response和所需的状态;与之相对应的是,读AP寄存器需要考虑AP寄存器的延迟,需要两次传输才能获取到实际的数据。
读AP寄存器的流程如下:
第一次传输,需要在packet request指明传输的AP寄存器;在acknowledge response阶段,DP通过返回OK表明自己有能力处理此次请求;此时传输的数据内容无意义,应当丢弃。
第二次传输,需要在packet request指明读取DP寄存器中的RDBUFF寄存器;在acknowledge response阶段,DP通过返回OK表明自己已经从AP获取到新的数据并准备好回传给调试器;此时传输的数据即为所需的内容。如果数据没有准备好,DP会返回WAIT,需要重复第二次传输直到DP返回OK为止。
可以看到,读AP寄存器实际上需要分为先提交后接收的两个步骤。当然,如果需要多次读取AP寄存器,则提交和接收可以在同一次传输中交替完成(在ADIv6中被称为流水线化),即:
首先发起第1个AP寄存器的读取,并且丢弃此时返回的数据。
接下来发起第2个AP寄存器的读取,等待acknowledge response返回OK,此时返回的数据即为第1个AP寄存器的结果。
重复2的步骤,每次发起第n个寄存器的读取时,都会返回第(n-1)个寄存器的结果。
在所有AP寄存器均发起读取后,需要再额外发起一次传输,读取DP寄存器中的RDBUFF寄存器,以获取最后一次传输的结果。
到这里为止,我们就把成功传输时的处理方式介绍完了。但是,调试器的传输过程不可能做到尽善尽美,那么在遇到意外状况时,应该怎么处理呢?这里我们按照错误类型进行介绍:
WAIT:一般表示上一次读写AP寄存器的操作还未结束,这种情况下常规操作是继续发起相同的传输,直到响应OK为止;当然也可以通过ABORT寄存器终止传输,这个会在后续数据链路层中介绍。
FAULT:技术上说,返回FAULT表示的是CTRL/STAT寄存器有sticky flag被设为0b1,而这通常表示DP发现了一些错误,包括写寄存器时data packet phase的校验位出错等,感兴趣的读者可以参考数据链路层部分。
Protocol error:包含了一系列不符合传输协议的错误,例如packet request中的校验位出错、Stop和Park出错、不支持的turnaround周期数等。
大家可能会有些疑惑,为啥还没有看到错误发生时的波形图呢?这是因为,WAIT和FAULT时的波形与overrun detection有关。Overrun detection是DP的一个特性,针对调试器在高可靠性、高延迟、高吞吐量的场合使用,可以有效加快处理效率。当然,我们这里主要说明的还是打开和关闭overrun detection的不同之处。
注:针对overrun detection的特性,我这边举一个可能实用的例子。
对于FTDI这种只使用物理层的调试器,输出信号通常是bit-bang或类似的方案,这需要上位机发出一系列指令来模拟SWD协议。一个可能的使用方式是这样的(假设是写寄存器):
USB发送一个命令,写入8个bit,也就是packet request部分
USB发送一个命令,读取5个bit,包括了两个turnaround和acknowledge response部分
USB发送一个命令,写入33个bit,也就是data transfer phase部分
可以发现,在overrun detection关闭前,是否执行3依赖于2的结果,而相关的结果并不能在物理层中得到反馈,必须要回传到上位机,并由上位机来决定下一步的处理方式。这样的一大缺点是,2和3之间必然会有很大延迟(如果使用interrupt transfer,延迟通常是ms级的),这会严重制约SWD的实际读写效率。
对于这个问题,打开overrun detection就能得到有效缓解,原因是overrun detection打开后data transfer phase就是一直存在的,并不受到acknowledge response返回结果的影响,上位机完全可以在发起一系列传输后通过检查CTRL/STAT寄存器获取传输结果,也就是说上位机可以尽可能多的填充传输队列,从而提高传输效率。
当然,这么做也有一个显而易见的缺点:如果传输不稳定或成功率过低,则每次发起一系列传输后DP大概率会进入到需要从错误中恢复的状态,这也会导致效率下降。因此,overrun detection只适合在高可靠性、高延迟、高吞吐量的场合使用。
在关闭overrun detection时,如果DP返回WAIT或FAULT,则跳过接下来的data transfer phase,直接开始下次传输,如下图B4-3和B4-4所示。
但是,如果打开overrun detection,不论DP返回WAIT还是FAULT,接下来的data transfer phase都和成功传输一样进行,只是传输的数据无效,如图B4-6和B-7所示。
最后说说Protocol error。一般来说,protocol error的错误是比较严重的,通常意味着信号传输不稳定,导致调试器或DP读取到了错误的结果。这种情况下,DP的策略是比较保守的,一般是直接终止所有传输(除特定寄存器外),调试器需要尽快发起line reset以重置DP状态;因此,DP将会在检测到错误后释放对SWDIO的驱动,在调试器一端通常会读到0b111的响应,如下图B4-5所示。
对于protocol error,详细的处理方式可以参考ADIv6中的B4.2.5,这里不再赘述。
其它细节
从上面我们知道,SW-DP是有状态的,读写结果会和之前的传输有关,因此恢复到初始状态显得非常重要。
在ADIv6中,SWD有个名为line reset的特性,就是在必要的时候对SW-DP进行重置,以保证SW-DP能工作在确定的状态,这个特性会在以下场景使用:
SW-DP初始化:在首次连接到SW-DP时,需要在传输前先来一发line reset,以保证SW-DP不会受到上电时不定态或已传输数据的影响。
切换DP:无论是从JTAG-DP切换到SW-DP,还是从其它SW-DP切换过来,也都需要一次line reset。
错误恢复:前面提到的protocol error需要通过一次line reset才能恢复。
注意到line reset只重置SW-DP部分寄存器(DLCR和SELECT.DPBANKSEL),不影响SW-DP的其它寄存器、JTAG-DP、SWJ-DP和所有AP。
那么,line reset要怎么做到呢?其实很简单,就是传输以下序列即可:
首先,给至少50个周期的SWDIO高电平,此时SW-DP可以识别到line reset。
紧接着给至少2个周期的SWDIO低电平,让SW-DP做好准备。
最后正常传输即可。
Line reset的波形图如图B4-8所示。
可以看到,2的话并不影响结果,这实际上是SW-DP的一个特性:空闲周期(idle cycles)。回想起每次传输的Start信号为0b1,如果在此时传输的是0b0,则传输不会开始,SW-DP可以维持在空闲状态,等待SWDIO传输0b1后传输才正式开始。
注:CMSIS-DAP中,可以定义每次传输后附加的空闲周期数,这部分的内容并不需要修改DP和AP寄存器。合理使用空闲周期可以减少DP响应WAIT的次数,从而减少实际的传输时间。
JTAG-DP
对于JTAG,想必大家都不陌生(陌生的建议先看看IEEE Std 1149.1,逃),在其它器件上已经使用过。由于JTAG的引脚都是单向传输的(到了1149.7才有两线调试的方案,才会涉及到引脚传输方向切换),并且JTAG在协议层本质上就是一个状态机(见图B3-2),因此说明起来会比较容易。这里就尽量简明扼要地描述其中需要关注的部分。
传输格式
JTAG-DP和普通的JTAG状态机的用法基本一致,都是分为指令寄存器(Instruction Register,即IR)和数据寄存器(Data Register,即DR)。对于JTAG而言,一般是有一个IR和多个DR,其中:
IR用于选择和控制JTAG扫描链,位数是固定的
DR用于交换暴露在JTAG扫描链的信息,具体的信息一般由IR决定,位数是可变的
因此,一次传输需要先选择IR再向DR写数据同时读返回结果。具体的传输过程在B3.2.3中已有详细描述,这里不再赘述。
读写方式和错误处理
从ADIv6的表B3-3中,我们可以获知,标准IR指令如下:
ABORT
DPACC
APACC
IDCODE
BYPASS
其中,IDCODE和BYPASS是JTAG标准要求的部分,DPACC和APACC基本对应SW-DP中的DP和AP寄存器,而ABORT则是单独列出。后面主要提到DPACC和APACC部分。
注:
IEEE Std 1149.1要求IR全1时对应BYPASS指令。
IEEE Std 1149.1要求Test-Logic-Reset状态下IR对应的是IDCODE或BYPASS,JTAG-DP使用的是IDCODE。
DPACC和APACC的操作如B3.4.3的图所示。可以看到,这两个DR都是35位,数据结构如下:
对于TDO这一端,JTAG依次输出ACK[0:2]和ReadResult[0:31]
对于TDI这一端,JTAG依次输入RnW、A[2:3]和DATAIN[0:31]
相对于SW-DP,由于JTAG-DP的Capture-DR在Update-DR之前执行,而JTAG-DP的acknowledge response和ReadResult在Capture-DR阶段确定、packet request和DATAIN在Update-DR阶段生效,因此当前传输的数据包需要在下一次传输时给出。当然,和SW-DP中读AP寄存器类似,JTAG-DP也可以通过流水线执行的方式“重叠”这些命令,执行过程如下:
首先发起第1个寄存器的传输,并且丢弃此时返回的acknowledge response和ReadResult。
接下来发起第2个寄存器的传输,并且从acknowledge response的结果获知传输是否成功,如果第1个寄存器对应的传输是读取,则还需同时读取ReadResult并作为第1个寄存器的读取结果,否则直接丢弃。
重复2的步骤,每次发起第n个寄存器的传输时,都会返回第(n-1)个寄存器的acknowledge response,并根据需要判断是否需要读取ReadResult。
在所有寄存器均发起传输后,需要再额外发起一次传输,读取DPACC中的RDBUFF寄存器,以获取最后一次传输的acknowledge response。如果第n个寄存器对应的传输是读取,则还需同时读取ReadResult并作为第1个寄存器的读取结果,否则直接丢弃。
这里有一些需要注意的细节:
由于JTAG-DP对所有指令的写入和读取都是流水线化的,因此要确保此次传输被成功接受,就必须发起下一条指令来读取结果。可以通过读取DPACC寄存器的RDBUFF寄存器来获取acknowledge response,这是因为读取RDBUFF寄存器总是不会产生其它副作用。
当返回的结果为WAIT,或者有sticky flag为0b1时,此次传输将被丢弃,因此可以仅通过读取TDO输出的前3位(即ACK[0:2])来判断上一次传输是否成功进行,若非成功进行则可以直接结束传输。
JTAG-DP返回的ReadResult仅在上一个传输访问的是DPACC、APACC和BYPASS这三个DR时才有意义,因此不能在执行DPACC和APACC的传输过程中切换到其它DR。
注:注意第二点原理和SW-DP的overrun detection不同,JTAG可以在传输会被丢弃的情况读取任意位数(前提是不会影响扫描链上的其它设备,这可以通过将其它设备的IR均设为BYPASS来做到),这可以减少传输时间(在WAIT状态时尤其有用)。
另外,JTAG-DP在协议版本不同的时候acknowledge response的定义会有所不同,见表B3-6。在v0中,OK和FAULT合并为一个,即OK/FAULT,对应的ACK[2:0]为0b010,是否传输成功需要读取CTRL/STAT寄存器才能获知;而v1中,又将OK和FAULT分离。
其它细节
在Capture-IR阶段,JTAG扫描链会写入0b0001或0b00000001(取决于IR长度为4位或8位),并且最靠近TDO的是0b1,这个可以在后续更新IR时被移出,用来检查扫描链的连接是否正常。
注:根据IEEE Std 1149.1,JTAG扫描链需要保证在Capture-IR阶段写入到扫描链中最靠近TDO的2个bit为0b01,JTAG-DP显然符合此要求。
和SW-DP类似,JTAG-DP也有自己的idle cycles,不过这一定义借用了JTAG状态机中的Run-Test/Idle状态。除了和SW-DP类似用于减少实际执行时间的作用外,如果host需要在传输结束后停止TCK,需要保证在Update-DR后至少在Run-Test/Idle状态转8个周期,以保证传输结束(当然如果继续使用JTAG或者不需要最后一次传输结果时则不受此影响)。
注:一般来说,在最后一次传输发起后(无论读写),调试器会至少再发送一次读RDBUFF寄存器请求,确认传输是否成功进行,因此这个设定对正确进行的读写操作没有影响。
JTAG-DP和SW-DP的一大不同是没有line reset,这意味着JTAG-DP不能(其实也不需要)将传输恢复到初始状态。从ADIv6中,我们知道,JTAG-DP仅能在上电复位时重置DP寄存器,但是JTAG-DP不需要像SW-DP那样设置turnaround,因此初始化对于JTAG-DP来说只需要重新设置一遍寄存器就好,不会和当前的状态冲突。
SWJ-DP
在协议层,SWJ-DP主要做的事情就是处理SW-DP和JTAG-DP之间的切换。根据SWD协议版本不同,SWJ-DP最多有两套切换方式,分别是:
SWD和JTAG之间的切换
休眠状态和相关操作
接下来详细介绍这两种切换方式。
SWD和JTAG之间的切换
这种方式多用于SWD协议v1,v2也可以支持但被废弃(deprecated)。
先贴个状态转移图,见图B5-1。
从图上可以看出:
SWJ-DP的初始状态为JTAG-Sel TLR,也就是JTAG状态机中的Test-Logic-Reset状态
SWD和JTAG之间的切换需要在特定的状态完成,成功的话会切换到相应状态,失败的话则会保持在原有状态
当然,实际应用中,我们只需要使用JTAG-to-SWD和SWD-to-JTAG这两种序列就可以了。这部分是ARM规定好的,因此没啥好说的,照做就是了。
JTAG-to-SWD的引脚时序如图B5-2所示。
注:和正常的line reset不同,在JTAG-to-SWD序列中,最后不允许将SWDIOTMS拉低两个周期。
SWD-to-JTAG的引脚时序如图B5-3所示。
注:和正常的line reset不同,在SWD-to-JTAG序列中,在至少50个周期的SWDIOTMS高电平后,不存在将SWDIOTMS拉低两个周期。
休眠状态和相关操作
SWD协议v2引入了休眠状态(dormant state),所有的切换操作都需要途径dormant state状态进行,这有助于目标设备使用不同的混合协议。
原话如下:Using dormant state allows the target to be placed into a quiescent mode, allowing devices to inter-operate with other devices implementing other protocols. Those other protocols must also implement a quiescent state, with a mechanism for entering and leaving that state that is compatible, but not necessarily compliant, with the SWJ-DP and SW-DP protocols.
在引入休眠状态后,SWJ-DP的协议选择如图B5-4所示,注意到前面提到的JTAG-to-SWD和SWD-to-JTAG已被废弃。
对于SW-DP,相关状态转移图中JTAG相关状态被移除,且初始状态即为dormant state,如图B5-5所示。
JTAG-to-DS涉及到ZBS(zero-bit-DR-scan)序列,并没有统一的引脚时序,其中一个推荐的引脚时序如图B5-7。需要注意的是,这里需要事先将IR切换到IDCODE或BYPASS,否则行为无法预测。对ZBS有兴趣的同学可以参考B5.3.2。
SWD-to-DS则是固定序列,引脚时序如图B5-8所示。
从dormant state离开时,根据activation code确定下一个使用的协议,相关序列被称为Selection Alert sequence(这里不知道怎么翻译比较好),如图B5-9所示。Activation code的取值如表B5-2所示。
距离上次更新已经过了14个月了,还好最近又想起来了,闲话不多说,让我们继续之前的内容吧。
说到ARM的调试协议,必然绕不开ADI(ARM Debug Interface)相关的规范了。目前,ARM在新型号CPU上主要使用ADIv5和ADIv6这两个规范,两者之间互不兼容(主要是AP接口的区别),因此调试器这边需要分别支持。
根据规范,ADIv6(当然v5也是)由低到高可以分为以下层次:
物理层(Physical Layer):定义各种物理信号,包括SWD和JTAG
协议层(Protocal Layer):定义数据包的格式,维护SWD和JTAG的状态机
数据链路层(Data Link Layer):定义如何访问DP寄存器和AP寄存器,实现基本的调试功能
AP层(AP Layer):定义如何访问SoC上的一个或多个子系统
从这个角度来说,市面上已有的调试器方案可以按照使用的最高层次分为以下几类:
只使用物理层:FTDI家的所有方案,与操作GPIO无异,突出一个“又不是不能用”,效率通常最低,当然优势是比较灵活,只要改改上位机代码理论上就能支持所有协议。当然,除了大家熟知的bit-bang之外,也有像MPSSE这种效率比较高的方案,不过依然需要上位机赋予其“灵魂”。
支持协议层:ARM自家的CMSIS-DAP,为协议层访问做了一些优化,DAP_Transfer和DAP_TransferBlock命令了解一下?不过更高级的操作(例如访问SoC上的内存地址)单靠调试器本身做不来,需要上位机下发一系列命令来完成,没有上位机的配合基本只能歇逼。
支持所有层次:J-Link等商用调试器,为了功能和效率,通常在调试器上集成了各种高级操作,访问个内存地址之类的不在话下,当然调试器的实现上会比较复杂。开源的方案可以参考Black Magic Probe。
接下来我们按照由低到高的顺序介绍每个层次的相关规范。
物理层关心的部分如下:
信号名称及必要性
部分信号是可选的,例如JTAG中的TRST
信号的敏感沿
当前的调试接口都是带同步时钟的,需要定义信号在何时被采样
信号的传输方向
主要包括调试器到DP、DP到调试器和双向这三种情况,其中双向传输需要在协议层约定好传输方向的切换
信号的其它物理层需求
举个栗子,SWD要求给SWDIO一个上拉电阻,以保持该信号在未被驱动时的状态确定
SW-DP
SW-DP共有两个必需的引脚,分别是SWCLK和SWDIO,分别表示时钟和数据。
SWCLK没啥好说的,唯一需要说明的是该信号可以是门控时钟,这意味着SWCLK可以在不需要传输数据的时候停止翻转,这样可以节省功耗,并简化调试器的逻辑。
SWDIO是双向信号,这意味着信号的传输方向需要调试协议规定好,通过状态机的方式实现信号方向切换。对于调试器而言,通常需要额外输出SWDIO_TXEN信号(CMSIS-DAP中定义,表示当前调试器是否驱动SWDIO信号),以控制电平转换电路的工作方向,但这一信号并不包括在SW-DP内。
在SW-DP中,规定了DP在SWCLK信号上升沿的时候采样或切换数据(取决于当前状态是输入或输出)。对于调试器而言,这意味着需要在SWCLK信号下降沿的时候采样或切换数据(假设占空比是50%)。
另外,SW-DP要求对SWDIO信号上拉100 kΩ的电阻,以保持该信号在未被驱动时的状态确定。
JTAG-DP
JTAG-DP使用的引脚和普通的JTAG区别不大,最大的区别是修改了引脚名称。可以参考IEEE Std 1149.1获取更多信息。
JTAG信号和SPI Mode 0或3类似,都是在时钟信号下降沿改变数据、上升沿采样数据。
ADIv6并未对JTAG引脚的外部连接进行更多说明,不过根据IEEE Std 1149.1,还是建议在设备端对TMS和TDI等引脚上拉,以满足稳定性的需求。
SWJ-DP
前面已经介绍了SW-DP和JTAG-DP,那么这个SWJ-DP又是何物呢?看名字就知道,这个其实就是Serial Wire + J(TAG)的组合。
实际上,SWJ-DP并不负责具体的DP功能,其主要作用就是将SW-DP和JTAG-DP使用的引脚整合在一起,并且允许使用特定的序列切换实际使用的DP,这样便可使用相同的引脚和连接器定义(例如Coresight 10),节省引脚数量。
SWJ-DP定义的引脚名称如下表所示。需要说明的是,SWJ-DP可以只拉出SW-DP相关的引脚,并可在使用SW-DP时重新定义TDI、TDO和TRSTn这几个引脚的功能,当然在这种情况下就只能使用SWD进行调试了。
这个好,同理 高速DAP 也是可以的了
可以的,顺着Xilinx / XilinxVirtualCable的代码思路,用Python写了个XVC server to CMSIS-DAP,可以正常工作,不过目前性能有些感人,还需要再优化下才能见人。
免责声明:本文所记载的内容仅涉及技术科普和探讨,与具体代码和实现方式无关,作者不会对破解等敏感问题进行回应,请悉知。
IP核是在电路设计中不可或缺的组成部分。通常,IP核可以从FPGA厂商或专门的提供商获得。为了保护知识产权,这部分代码需要进行保护。
正如所猜测的那样,IP核的加解密工作是有专门的标准进行规范的,目的应该是保证各个EDA工具可以正确处理相关代码。这个标准也就是IEEE Std 1735,可以从这里获得标准的PDF文档。
总的来说,IP核的加解密算法和大家常用的算法其实区别不大,都是综合利用了非对称加密的安全性与对称加密的效率,是比较成熟的方案,可以很方面地使用市面上已有的加密库(比如OpenSSL cyrpto library,即libcrpyto)进行加解密。具体来说:
非对称加密可以通过对公钥和私钥的区分来实现很高的安全性。EDA工具厂商可以将公钥分发给需要加密的第三方厂商,而将私钥通过各种手段隐藏在自身代码中(或者通过远程服务器进行解密),从而降低了密钥流出的风险。
对称加密则用于对代码主体的加密。考虑到EDA工具对IP核的处理速度,这里可以使用更加高效的对称加密,典型的算法是AES。考虑到对称加密的加解密密钥是一致的,可以事先使用非对称加密对密钥进行处理,进一步提升安全性。
当然,以上提到的算法只是IP核加解密的一个重要环节,标准只能解决文本级别的加解密,目的主要是避免相关代码被直接暴露。这里还可以使用其它技术手段(如代码混淆)进行更深层次的加密,这对于隐藏具体实现方式和避免逆向设计来说更为有效。
以下文章主要探讨V1(也就是等级1)的加解密,V2可以参考上面给出的标准文档。
在加密IP核的时候,我们需要准备好以下内容(session key的定义可以见后文):
首先最重要的当然是RTL代码,目前在标准层面支持Verilog HDL和VHDL。
非对称加密(用于加密session key)和对称加密(用于加密代码块)的算法需要给出,目前常用的分别是RSA(推荐大于等于2048位)和AES(128位或256位,CBC)。
非对称加密使用的公钥,这部分通常由EDA工具或者代码加密工具提供。在加密时,可以同时使用多个公钥,工具将会为每个公钥生成对应的session key,这些公钥可以使用keyowner等字段区分。
其实还有个不大明显的部分,就是如何从session key中得到对称加密使用的密钥。为了增强安全性,我们可以通过加盐等方式让session key和AES的密钥有一个特定的生成关系。我们定义相关的处理函数为f: x ↦ y,其中函数f并不要求可逆。
其中,session key是一个重要的部分,它可以保证对每个IP核都生成一个专门的密钥,这可以获得以下好处:
每个IP核使用的session key都可以不同,从而提升了加密的有效性。
不同的RSA公钥可以用来加密同一个session key并获得不同的结果,可以避免对同一个代码块进行重复多次加密,节省了文件的体积。
加密流程如下:
确定需要加密的文本部分,并将其填充到AES要求的整数倍字节(例如128位)。这里使用的填充算法应该是PKCS#7 padding,也是OpenSSL等工具默认的填充算法。
生成session key,并使用函数f将其处理为AES使用的密钥。为了保证AES密钥的强度,session key最好使用较长的位数,并且可以使用加盐等方式进一步提升强度。
代码加密工具读取RSA公钥,对session key进行加密,使用Base64编码以将二进制映射到ASCII字符,并将其写入到key_block中。
代码加密工具读取AES密钥,对代码主体进行加密,使用Base64编码以将二进制映射到ASCII字符,并将其写入到data_block中。
可以发现,上述流程中生成的key_block和data_block是最重要的部分,分别记录了加密后的session key和代码块,而这些部分将会成为解密的关键。
在解密IP核的时候,我们需要准备好以下内容:
key_block,记录了加密后的session key。
data_block,记录了加密后的代码主体。
RSA的私钥,这个是整个环节中隐蔽性最高的部分,一般EDA工具都会将其写入到代码的特定位置,使用时经过特殊处理获取,防止被直接泄露。
在加密流程中定义的处理函数f。
解密流程如下:
分别读取key_block和data_block,并且使用Base64解码获取实际的二进制字符。
使用RSA私钥解密key_block,获得session key。
使用函数f将session key处理为AES使用的密钥。
使用AES解密data_block,并根据padding的数值去除padding部分,得到实际的代码块内容。
通过以上流程,我们就能从加密的IP核获得解密后的代码。在这其中,最重要的就是RSA和私钥和处理函数f,这两个部分需要在EDA工具中被重点保护。
可以看到,IP核的加解密过程其实并不神秘,其安全性主要依赖于对RSA私钥和处理函数f的保护程度。当然,V2规范还提到了多种加密方式,这些方式也离不开非对称加密和对称加密的组合,有兴趣的读者可以自行研究。
metro 说:之前在外网上看到SMT2的示意图,不过没试过,不知道是否可用。
https://whycan.cn/files/members/1510/JTAG-SMT2.png大佬,您这个图是从哪里看到的?可否给个连接?
多谢!
https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=114633&page=5
看到楼主的另一个回复了。有篇论文给出了几个IC的型号和一个稍作修改后的原理图,但没有直接给出SMT3-NC的原理图,可以参考一下。An Example of PCB Reverse Engineering – Reconstruction of Digilent JTAG SMT3 Sche.pdf
省流小助手:
GitHub - metro94/RV-DAP-Plus
######## 我是假装成注释的分割线 ########
简单来说就是在Sipeed RV-Debugger Plus(MCU是博流智能的BL702)上移植好了CMSIS-DAP。有一说一,USB协议栈写得不错,虽然不支持Microsoft OS 2.0 Descriptors有点小遗憾,不过自己魔改了SDK还是支持上了。
目前这个版本是基于CMSIS-DAP V2.1(也就是Bulk Transfer的版本)的代码移植的,支持SWD/JTAG的调试,但不支持虚拟串口和SWO。有兴趣的坑友可以自行移植串口部分。
固件和使用方法已经在GitHub的Releases里面有了,这里不再赘述,祝大家玩得开心。😋
Sipeed官方有下载链接的,地址是http://dl.sipeed.com/shareURL/MaixII/MaixII-A/HDK/2_Schematic
这个帖子是我开的,当时二楼的回复是兼容ARM的SWD,后面他们自己删了😅
接下来是尝试连接BL702的JTAG。虽然BL702的JTAG可以映射到任意引脚(经典IOMUX),但在上电时默认有4个引脚是使能为JTAG功能,因此调试时最好还是使用这几个引脚比较合适。
经过一番研究(还跑去官方论坛确认了一下😅),连接方式如下:
GPIO0 -> TMS
GPIO1 -> TDI
GPIO2 -> TCK
GPIO9 -> TDO
需要注意的是,RV-Debugger Plus的默认固件将这几个引脚复用了,因此需要在上电时按住Boot按键进入ISP模式才行(此时设备管理器可以发现一个虚拟串口设备);另外,由于RV-Debugger Plus将GPIO9用作LED,因此需要断开链接并且手动飞线。
首先用J-Link连接。J-Link更新到最新版本后是支持SiFive E24的,因此使用起来很方便,直接可以识别。
接下来使用OpenOCD搭配FT232H连接。最新的OpenOCD v0.11.0支持RISC-V,因此只需要为SiFive E24添加配置文件即可,当然你也可以使用SDK里面的配置。这里我贴一份从sifive-e31arty.cfg改过来的配置,使用方法见注释:
#
# Be sure you include the speed and interface before this file
# Example:
# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty.cfg"
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000E05
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME
$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
# flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000
init
# if {[ info exists pulse_srst]} {
# ftdi_set_signal nSRST 0
# ftdi_set_signal nSRST z
# }
halt
# flash protect 0 64 last off
echo "Ready for Remote Connections"
经过一番操作,OpenOCD也能正确连接上BL702了:
最后提一下,在SDK里面是有SVD文件的,虽然只有BL602,估计还需要等待进一步更新。
整理一下目前找到的资料:
Sipeed提供的资料(包括原理图、BSP和已经开发好的固件):sipeed/RV-Debugger-BL702
Bouffalo的GitLab:Bouffalo Lab
Bouffalo的Gitee:博流智能科技(南京)有限公司
官方文档:BL MCU SDK 开发指南
开发者社区(包括文档、论坛等):博流智能开发者社区
SiFive E24的相关文档:
最近Sipeed上线了一款调试器RV-Debugger Plus,这个调试器是模拟FT2232D,本身没啥好玩的;不过呢,这个调试器使用的MCU比较有意思,是博流智能的BL702,支持二次开发并且提供SDK,值得玩玩。
先列一下我觉得比较有趣的配置:
RISC-V(准确说是SiFive E24,四舍五入算是年轻人的第一个SiFive),指令集为RV32IMAFC,支持FPU(单精度),可以跑到144MHz
132KB RAM+192KB ROM,并且手头这个版本SiP了512KB的Flash,在QFN32的封装下算是不错了
2.4G,支持BLE 5.0和Zigbee 3.0,集成balun和PA/LNA
USB 2.0 FullSpeed Device
集成了DC-DC和LDO,只需要5V和3.3V两路供电即可
另外还有SiP PSRAM,EMAC和DVP的选项,但是和BL702无缘
拍一张图康康:
奇怪,我按楼主说的搜了一下ESP8266 D1 mini和ESP-01下载器,发现都是正确的脚位(5/6)。
http://www.weiguo.com.tw/d1-mini-esp8266mod.html
https://item.taobao.com/item.htm?id=623312189879
@Blueskull
Quartus默认不支持FTDI的芯片,不过我在网上看到一个号称可以通过替换dll支持的方法,链接如下:https://mil.ufl.edu/3701/docs/quartus/quartus18.1_installation.pdf。
手头没有Altera的FPGA板子(严格来说有但是板载了下载器233)所以没法测试,可以试一下好不好用。
ft232如何作为intel fpga的下载器比如ep4c系列
Quartus默认不支持FTDI的芯片,不过我在网上看到一个号称可以通过替换dll支持的方法,链接如下:https://mil.ufl.edu/3701/docs/quartus/quartus18.1_installation.pdf。
手头没有Altera的FPGA板子(严格来说有但是板载了下载器233)所以没法测试,可以试一下好不好用。
最近买了块Xilinx Kria KV260,发现底板板载的调试器是FT4232H,感觉有点意思,因此花了点时间把EEPROM的内容(俗称固件)dump出来并做了少许修改。在用于Xilinx调试器时,FT4232H的ChannelA是JTAG,ChannelB和ChannelC可用于串口,ChannelD可以忽略,因此是1xJTAG+2xUART,看起来性价比相对FT2232H做成的调试器(Digilent JTAG-SMT3-NC)更高。
亲测可用于Xilinx Vivado烧录任意器件,不过手头只有一个Memblaze(XC7K325T)可供测试,欢迎大家自行测试后反馈结果。如果需要原理图,可以参考KV260底板的原理图,Xilinx官网搜索XTP682就有。
晒张图证明可用:
最后贴一下工程和编译好的二进制文件:
FT4232H EEPROM Modify.zip
ARM调试接口(即ADI,ARM Debug Interface),定义了基于ARM的SoC中所有调试组件的功能;而我们常说的DAP(即Debug Access Port),可以认为是基于ADI标准的一个实现。
对于DAP,我们又可以进一步分为两个部分:
Debug Port:面向调试器的接口,主要用于接收来自调试器的请求,并将Access Port的数据和响应传回到调试器。
Access Port:面向SoC内各个组件的接口,主要用于将Debug Port传来的请求转换成对SoC内对应组件的传输操作,并且将结果返回到Debug Port。
DAP的基本架构如下图所示。
可以发现,对于一个部署了ADI的系统来说,通常会存在一个DP和若干个AP,并且DP通过选择AP的方式一次只和一个AP进行交互。一方面,DP与(外置的)调试器相连,并根据调试器的协议进行数据交换;另一方面,AP和系统中的某个组件(一般是总线之类的组件)相连,可以将DP传来的请求进一步翻译成系统可以处理的操作(一般是寄存器或内存的读写操作)。
下图展示了一种包含了DPv0 JTAG-DP和通用AP的示意图,可以一窥DAP的架构。
常见的DP包括:
JTAG-DP:使用了JTAG接口,一种四线(另有可选的TRST,加上之后有五线)的全双工同步协议。
SW-DP:使用了SWD接口,一种两线的半双工同步协议。
SWJ-DP:同时兼容JTAG-DP和SW-DP接口,并且包含了JTAG/SWD双协议切换的一种特殊协议。
常见的AP包括:
MEM-AP:包括一大类调试组件的AP,特点是通过内存映射(Memory-mapped)的方式进行访问,覆盖了SoC的各种功能。
JTAG-AP:一个面向传统JTAG接口的AP,可以外接系统中已经存在的包含JTAG接口的非ARM组件。
MEM-AP的一个实现如下图所示。可以看到,MEM-AP可以通过ROM Table获取其它调试组件的定义情况,并且通过访问特定的调试组件以实现特定的调试功能。
对调试架构感兴趣的同学,可以阅读ADIv5标准的Chapter A1部分;对各个AP和CoreSight各个调试组件感兴趣的同学,可以阅读ADIv5标准的Part C以及CoreSight的相关文档。在下文中,我们主要介绍DP,因为这与我们的调试器设计密切相关。
本作品采用知识共享署名 4.0 国际许可协议进行许可。
如标题所述,TinyDAP是一个在兼容8051的单片机上实现的CMSIS-DAP调试器,不仅可以用于调试和烧录ARM Cortex-M系列单片机,配合第三方工具还能支持RISC-V等其它单片机和SoC。可以说,CMSIS-DAP是最适合实现的开源调试器协议(个人认为没有之一),而TinyDAP的目标就是做CMSIS-DAP的最小实现方案(同样没有之一!)。
TinyDAP在软件和硬件两个层面都将做到极致:
在软件上,通过汇编级别的优化,将CMSIS-DAP协议的几乎所有功能一一实现在小于16KB的Flash中,可以兼容JTAG和SWD的调试线协议,还能通过支持CMSIS-DAP v2达到不输于闭源调试器(如ST-Link/V2)的速度
在硬件上,可以运行在CH551/552等超低价格(1.x RMB)的单片机上,芯片占用的面积可以低至4.9x3.0 mm²(CH552E),预计成品体积不大于STLINK-V3MINI,还能直接在开发板上板载。
当然,截止至今日,TinyDAP还在初步开发阶段,不过前期的验证工作已经结束(参见帖子:晒一下CH558跑的CMSIS-DAP v2调试器,下载速度可以达到70KB/s(Flash)和300KB/s(SRAM)),可以证明这个目标是能够实现的(无非就是多掉几根头发而已)。
除此之外,TinyDAP还将依赖于以下工作:
利用SPI等外设加快调试速度。由于SWD和JTAG都是属于类SPI协议(串行输入/输出,并且有独立时钟引脚),因此可以通过SPI等外设加快数据传输,从而加快总体的调试速度。
对CMSIS-DAP的算法进行深度优化。通过阅读代码发现,当前的CMSIS-DAP代码控制调试线时的算法在有些情况下不够高效,可能会导致性能降低。在CMSIS-DAP的代码之外,作者还会参考ARM的其它文档(见下文),重新整理CMSIS-DAP的算法,进一步提升调试的性能。
参考DAPLink的代码,实现更多定制的功能。DAPLink也是基于CMSIS-DAP协议的实现,在完全开源的基础上做出了虚拟串口、拖拽烧录等实用功能。在存储空间和外设允许的前提下,作者也会在项目后期尝试将这些功能加入到TinyDAP中。
由于作者已经工作(四舍五入996的那种),所以这个项目必然不会很快完成(否则也不会从去年鸽到现在),还请大家耐心等待。当然,由于TinyDAP是一个比较随性的项目,所以也不会给自己设定各种时间上的目标,但会借此机会尝试用文字等方式将自己的想法表述出来供大家参考,因此本帖会尽可能地持续更新(可以想起来的时候常来看看hhh)。
本文的目标是记录开发的过程,分享一些开发过程中遇到的问题和解决方法,也欢迎和大家一同探讨各种相关话题。
本文将会按照以下顺序编写文档:
ARM调试接口
CMSIS-DAP协议
USB设备的协议栈(包括HID和WinUSB等)
WCH CH54x/CH55x
TinyDAP的实现细节
参考代码以ARM官方维护的代码为主,包括:
CMSIS-DAP:ARM基于CMSIS-DAP协议的一个简单实现,集成在CMSIS Version 5中。这一版本的CMSIS-DAP使用RTX v5 RTOS和Keil提供的USB设备协议栈与驱动,其中后者似乎并不开源。
DAPLink:ARM基于CMSIS-DAP协议的另一个实现,加入了虚拟串口、拖拽烧录等实用功能,由ARM Mbed维护。这一版本的CMSIS-DAP使用RTX v4 RTOS和开源的USB设备协议栈与驱动,代码完全开源并且可以方便地添加新设备的支持。DAPLink的主要缺点是编译后二进制文件太大(完整配置超出STM32F103C8T6的Flash空间,只能上CBT6)。
DesignStart:ARM的一个项目,提供了Cortex-M0和M3的RTL代码(经过混淆处理),在实现调试接口时作为参考。
参考文档则是覆盖了上面所说的所有内容,包括:
CMSIS-DAP:ARM官方的CMSIS-DAP文档。CMSIS-DAP包括协议和实现两部分,这个文档主要覆盖了协议部分,重要性无需多言。
ARM Debug Interface Architecture Specification:ARM调试接口的文档,版本是ADIv5.2。需要注意的是,该文档的最新版本是ADIv6.0,但当前主流的ARM单片机似乎并不使用v6.0,所以v5.2已经够用(v5.x加入了很多实用功能)。
USB相关的各个标准,包括(除了最后一项外都可以在USB官网找到):
USB Specification 2.0:USB 2.0的主标准。
与BOS(Binary Device Object Store)描述符相关的补充标准:于Wireless USB Specification 1.0引入,在USB 3.0时被写入主标准中,主要用于实现WinUSB、WebUSB等功能。
USB Device Class Definition for Human Interface Devices (HID):HID类的标准,主要用于实现CMSIS-DAP v1的免驱动安装。
Microsoft OS 2.0 Descriptors Specification:MS OS描述符标准,主要用于实现CMSIS-DAP v2的免驱动安装(通过WinUSB),这里我们使用的是2.0的标准,可以兼容Windows 8.1和10。
8051的指令集和单片机的数据手册及相关文档。
2021/3/7:开坑,更新简介部分.
JTAG线也不是很多,自己杜邦线连一下也不麻烦。
我这边ARM的器件比较全,M0 M3 M4 M23都有,GD32的ARM芯片几乎所有型号都有。
RISC-V芯片比如VF103价格没有优势的前提下,实在找不到考虑它的理由。
调试方面,我基本只用USB和UART,其实SWD都很少用。metro 说:echo 说:所有IO都引出了呀。
话说JTAG现在还有人用么?我这里无论板子还是调试器,JTAG都拿掉了,只留SWD,管脚少就是好。不是的,GD32VF103(注意不是GD32F103)是RISC-V的CPU,不支持SWD,只支持四线的JTAG协议,所以要调试的话需要从两个地方都接出来,不是很方便。
至于CH32V103,沁恒实现了和SWD相似的RVSWD(只是引脚相同,协议应该不兼容),所以倒是不像GD32VF103那样有这个问题。不过看起来CH32V103在协议没公开之前只能用他家的调试器了。
话说GD32VF103的接口定义可以参考Sipeed Longan RV,两面共引出2x4p的2.54mm接口,不过接口稳定性堪忧,我的那块板子就被我把焊盘弄掉了
是的,现在新出的单片机很多都不支持JTAG,没记错的话GD32F系列也是全员不支持JTAG。RISC-V可能是个问题,因为没有占优势的两线协议,很多厂商还在用着四线JTAG。
至于价格,我记得CH32V103应该还不错(某宝上小于5块?),只不过去年才发布,用的人还不多。
所有IO都引出了呀。
话说JTAG现在还有人用么?我这里无论板子还是调试器,JTAG都拿掉了,只留SWD,管脚少就是好。metro 说:感觉应该也兼容CH32V103?另外GD32VF103的调试口是JTAG,好像不是很方便,可以考虑引出JTAG的所有接口。
不是的,GD32VF103(注意不是GD32F103)是RISC-V的CPU,不支持SWD,只支持四线的JTAG协议,所以要调试的话需要从两个地方都接出来,不是很方便。
至于CH32V103,沁恒实现了和SWD相似的RVSWD(只是引脚相同,协议应该不兼容),所以倒是不像GD32VF103那样有这个问题。不过看起来CH32V103在协议没公开之前只能用他家的调试器了。
话说GD32VF103的接口定义可以参考Sipeed Longan RV,两面共引出2x4p的2.54mm接口,不过接口稳定性堪忧,我的那块板子就被我把焊盘弄掉了
话不多说,先看效果:
两个屏幕都是ST7789,8位8080接口的屏幕,分辨率分别是240x240和240*280,刷新率拉到99Hz依然非常流畅(更高的刷新率似乎无法正常初始化,有些遗憾)。
为了同时驱动两个屏幕,这里让每个LCD都有一个对应的CPU进行刷新,并且由同一个PIO的不同状态机来驱动总线,两路总线可以同时传递不同的数据。状态机的频率被设置为5分频,因此总线上的WR信号的频率可达12.5MHz,可以满足99Hz刷新率的需求。
可以看到,树莓派Pico的PIO还是非常强大的,这里相当于只使用了状态机总数的四分之一(主要是引脚数量限制了发挥233),还是具有一定可玩性的。
Swd有专利吗 专利号是多少
搜了一下,能看到的最早专利似乎是这个:Communication Interface for Diagnostic Circuits of An Integrated Circuit,2023年8月到期,不过不清楚是否还存在后面改进的版本。
在中国的专利号是CN100487472C。
Pico镇楼
相信这个小玩意大家都知道了,双核Cortex-M0+,时钟频率133MHz(实际上保底可以超频到250MHz+),自带PIO、SIO等一系列有趣的外设,并且拥有2MB SPI Flash(自带16KB的cache)+264KB SRAM的内存.
那么问题来了,已知:
之前我在Nios II上移植过NES的模拟器,可以跑到20 fps左右(不包含索引色处理的部分,声音暂时也没做),而且当时没有用上汇编优化,(不排除超频的前提下)RP2040的性能应该足以模拟NES了。
RP2040有两个核心,可以像NES一样,一个模拟2A03(CPU+APU),另一个模拟PPU,两者可以同时工作。
RP2040的片上内存达到了264KB,不考虑显示部分的话应该够用了,而且显示部分可以由一个核心直接渲染,不需要把一整帧渲染后的RGB图像存储下来,大大节约了空间。
RP2040支持XIP,可以把Flash直接映射到内存空间,最大支持16MB,足以放下所有的NES游戏并且直接寻址,有cache的话速度应该还不错。
RP2040的PIO可以用来处理输出并且自带FIFO,根据别人的demo来看直接输出VGA应该没啥问题。
RP2040的SIO中的Interpolator应该很适合用来处理音频数据。
感觉经过以上分析,似乎在Pico(RP2040)上跑个NES模拟器是可行的?欢迎大家讨论。
George Hilliard(就是那个做 F1c100s 电子名片的)在博客上发表了 Mastering Embedded Linux 一系列的文章。我看着写的很不错,就把它翻译了过来,也作为一个英语翻译的练习吧。翻译的不好还请见谅。
- 精通嵌入式 Linux 第一章:概述
- 精通嵌入式 Linux 第二章:硬件
- 精通嵌入式 Linux 第三章:Buildroot
- 精通嵌入式 Linux 第四章:添加功能新的第五章还没翻译,等我有空再继续翻吧。
一直在等他关于F1C200s解码的文章,哈哈。
我的是287,也在吃灰,i.mx28x系列有主线linux吗
主线也就是mainline,是由Linus Torvalds本人维护的Linux内核,该内核将会作为其它发行者使用的基础。见https://www.kernel.org/doc/html/latest/process/1.Intro.html#the-importance-of-getting-code-into-the-mainline。
按我的理解,楼主的需求不是使用单一的Linux内核在不同CPU上执行不同的程序(即使CPU占用的资源是互相独立的,但依然是同一个内核调配的),而是在不同CPU上使用不同的Linux内核或者裸机和RTOS(此时CPU之间不受同一个内核控制)。
楼主的这个需求可以使用AMP(Asymmetric Multi Processing)实现。Linux基本上都是实现为SMP(Symmetric Multi Processing),如果要用AMP需要使用另外的框架,比如说https://github.com/OpenAMP/open-amp。
在FPGA等地方经常使用到异构计算,所以在这些平台上AMP还是常见的,可以参考Xilinx的相关文档。
不能打电话,只能上网,能不能收短信没测试,估计不行,无需实名认证,上电即开始激活,有效期貌似一年。
应该可以收发短信,官方提供了demo,见Luat_4G_RDA_8910/script_LuaTask/demo/sms/。
看到了
V3S 比超频到700M的F1C200S快了3倍X86锐龙2700(虚拟机里)跑 比V3S 快了70倍
看来架构很重要啊 频率次之
有没有STM32H7系列的测试数据啊?
参考List of ARM microarchitectures(需fq
F1C100s用的是ARM926EJ-S,大致是1.1 DMIPS/MHz,V3(Cortex-A7)是1.9 DMIPS/MHz,而Cortex-M系列最高端的Cortex-M7(对应STM32F7/H7系列)则达到了2.14 DMIPS/MHz。
如果 8N04 的 EH 不足以提供足够的驱动能力,那可以直接从天线上取电,一般读写器辐射的能力都有富余。
另外,还可以考虑用双界面安全芯片,比如 thd89, sle78 带有 spi master,可以驱动 e-paper。
微雪做了个完全靠NFC驱动的墨水屏,可以参考解决方案:
http://www.waveshare.net/shop/7.5inch-NFC-e-Paper-Eval-Kit.htm
Traceback (most recent call last):
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 223, in get_interface_and_endpoint
return self._ep_info[endpoint_address]
KeyError: 2During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\Administrator\Desktop\ch55x_dumper-master\ch55x_dumper-master\dump.py", line 9, in <module>
dev.write(0x02, bytearray([0xA7, 0, 0, 0x1F, 0]))
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 940, in write
intf, ep = self._ctx.setup_request(self, endpoint)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 102, in wrapper
return f(self, *args, **kwargs)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 215, in setup_request
intf, ep = self.get_interface_and_endpoint(device, endpoint_address)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 102, in wrapper
return f(self, *args, **kwargs)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 225, in get_interface_and_endpoint
for intf in self.get_active_configuration(device):
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 102, in wrapper
return f(self, *args, **kwargs)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 236, in get_active_configuration
self.managed_open()
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 102, in wrapper
return f(self, *args, **kwargs)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\core.py", line 120, in managed_open
self.handle = self.backend.open_device(self.dev)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 786, in open_device
return _DeviceHandle(dev)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 643, in __init__
_check(_lib.libusb_open(self.devid, byref(self.handle)))
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-packages\usb\backend\libusb1.py", line 593, in _check
raise NotImplementedError(_strerror(ret))
NotImplementedError: Operation not supported or unimplemented on this platform
可能是驱动问题。试试用最新版的Zadig安装WinUSB的驱动。
的确有可能,可是这边显示的是44.1kHz诶?
难道是驱动的问题吗?
http://ys-k.ys168.com/613493438/w732J3L2587N4lPnfgk/3.png
不好说,可以先播放其它采样率(比如32/48 kHz)的音频试试,看是不是还有相同问题。
歪个楼,现在通过CDC类实现串口的话要控制RTS/CTS信号似乎会比较困难,所以用作这类下载器的USB转串口芯片还是适合专用驱动的芯片。
见:http://www.wch.cn/bbs/thread-69122-1.html#2