IIC 通讯

写这篇文章的原因是本来我觉得IIC,SPI这种级别的协议早已了然于胸,直到今天在github被别人提醒,我才明白以前对着代码和各种中文资料知道的只是能凑合通讯,实际的规范中还有亿点点细节o.o

有点懒,基本协议内容就不再描述了(如果不了解可以看下下面规范原文),下面部分说明直接机翻

规范位置

比较重要的协议一览

  • 除了与高速模式相关的一种特殊情况外,不允许 I2C 设备驱动总线,即通过在总线上施加电压来发送 1。
    • 总线终止于高电平
  • Clock Stretching(不是所有从机都有这个功能,没有的话可以不实现)
    • 任何IIC总线设备(各个从机或主机)都可以要求延长SCL低电平时间甚至暂停通讯。
    • 规范中不包含等待超时(但是驱动中可能会有)
    • 一些从设备在超时一段时间之后会认为总线空闲
    • 这个功能对总线带宽有影响,使用时应当充分评估
    • 仅在 ACK 位之后(并且在下一个字节的第一个位之前)才允许在高速模式下进行时钟延长。位 2-9 之间的拉伸是非法的,因为这些位的边缘通过额外的电流源被提升。
  • i2c level shifting
  • Arbitration(单主机模式可以不实现)
    • 虽然看到协议想起来确实有这么回事,但是一般凑合用的时候就没实现过 😄
    • 能够遵循仲裁逻辑。如果两个设备同时开始通信,则向总线(或速度较慢的设备)写入更多零的设备赢得仲裁,而另一个设备立即停止总线上的任何操作。(这个没用过)
    • 总线繁忙检测。每个设备都必须检测正在进行的总线通信并且不得中断它。这是通过识别总线通信并在开始通信之前等待停止条件出现来实现的。(这个比较常见)
    • 如果使用多主机,那么所有主设备都应支持multimaster功能。
  • I2C标准定义了0.3 Vcc的低电平阈值,0.7 Vcc的高电平阈值。
  • 广播呼叫使用I2C 地址 0寻址总线上的所有设备。
  • 为了兼容淘汰的C-Bus协议,保留地址(’0000001X’)。I2C 设备必须忽略发往该地址的消息。
  • 地址“0000010X”旨在将 I2C 设备与在同一总线上使用不同协议的设备互连。只有能够使用这些协议运行的 I2C 设备才能回复消息。 (这个不太懂)
  • 10-bit-addressing
    • 为了防止地址冲突,由于 7 位地址的范围有限,引入了新的 10 位地址方案。此增强功能可以与 7 位寻址混合使用,并将可用地址范围增加约十倍。在开始条件之后,前导“11110”引入 10 位寻址方案。第一个字节的最后两个地址位与八位连接整个 10 位地址的第二个字节。仅使用 7 位寻址的设备只会忽略带有前导“11110”的消息。
  • auto-increment
    • eeprom什么的地址自动递增是协议的一部分
  • 速度(精度不重要)
    • 100k – 龟速(我起的名字) standard-mode
    • 400k – 快速 Fast Mode
    • 1 M – Fast Mode Plus (大部分都能在此频率工作,不过建议以各个设备datasheet为准)
    • 3.4M – high speed mode
    • 5M 超快速模式 ultra-fast-mode
      • 单向通信,从机不再发送ack
      • 可以多主机,但是没有仲裁机制
      • 推挽驱动
      • 多个设备可以通过共享 I2C UfM 总线进行寻址。112 个节点可用。
      • 超快速模式总线主要集中在 LED 设备。
高速模式
  • PC debug
  • Repeated Start Condition
    • 在发送地址字节(地址和读/写位)后,主机可以发送任意数量的字节,然后是停止条件。除了发送停止条件之外,还允许再次发送另一个开始条件,后跟地址(当然包括读/写位)和更多数据。这是递归定义的,允许发送任意数量的开始条件。这样做的目的是允许在不释放总线的情况下对一个或多个设备进行组合的写/读操作,从而保证操作不会中断。
    • 无论在一次传输期间发送了多少个开始条件,传输都必须恰好由一个停止条件结束。

移植zephyr到GD32E103_EVAL板子

背景

终于考完日语了,虽然够呛能过 o.o 105分飘过了o.o

不过也算是有点空闲时间能随便玩玩了.迫于近年来半导体价格飞涨, 国产MCU的应用也越来越广(大部分是替代STM32的样子)

整个移植过程可以看出GD32和STM32高度相似.

具体代码参考: https://github.com/zephyrproject-rtos/zephyr/pull/36833 PR的使用方法请参考后面

本次移植大概花费三四天,本文不会记录详细的移植过程(因为代码在上一行)只会记载几个移植中的小问题.

主要参考资料:https://docs.zephyrproject.org/latest/guides/porting/index.html

基础知识

为了能够移植zephyr系统,下面知识是我认为必须要先了解的,可能会有些不全,仅供参考,如有不足欢迎补充

  • 最低限度的计算机组成原理以及单片机构成常识(一般来说MCU由内核(arm,risk-v等,执行指令,提供中断系统)存储(flash, ram等)外设(gpio,uart,can,ethernet等),一般芯片是要放在电路板上才能工作,综上zephyr的硬件驱动划分为arch, soc, board)
  • cmake(虽然使用west命令进行编译,但是实际的构建环境是cmake,因此在移植前,我建议了解最低限度的cmake知识)
  • kconfig(官方仓库https://github.com/ulfalizer/Kconfiglib,用于配置内核宏, 会影响构建过程以及C程序)
  • dts(devicetree 设备树)(zephyr系统通过设备树对arch,soc,board进行抽象,类似linux设备树,但是系统调用方式不同,zephyr通过将dts编译为宏,在程序和构建过程中调用)
  • linux(虽然据说windows也可以使用,但是我建议如无特殊原因,请尽量养成在linux或mac中开发程序,避免各种麻烦)
  • openocd(MCU调试工具) 这个东西的使用的话相对简单,但是编写tcl脚本需要对jtag/swd的底层原理比较熟悉.一般的MCU openocd中都包含了支持文件, 但是不巧的是GD32E103_eval的这款板子和芯片均不在支持范围内.
  • yaml(一种配置文件格式,类似json/xml)简单了解即可
  • git(zephyr版本通过git管理)
  • C Marco (C语言宏)
    • 虽然因为zephyr项目使用C语言编写,为了移植掌握C语言是必要的无需多做说明,但是在处理设备树的过程中,会用到极其复杂的宏调用,数十层的宏包装人脑展开已经极为困难,有些时候只能根据编译器预编译结果来检查问题. 所以如果您是C语言新手或关于预编译器工作原理不是很清楚的话,强烈建议您补全此处知识,包括但不限于宏拼接(##运算),可变参数列表宏(__VA_ARGS__)
  • vscode调试和编译的配置方法(可能经常使用keil,iar等IDE环境的朋友会比较陌生)

相关文件

zephyr的移植主要设计下面文件(module需要单独建立仓库,可以参考https://github.com/feilongfl/hal_gd32, 仓库内GD32E1的支持包来自gigadevice官网)

  • boards(板级外设)
  • socs(芯片外设)
  • drivers(驱动)
  • west.yml(module)

绝大多数都可以参考STM32F1x的芯片进行移植,其实从手册来看,驱动也可以共用, 但是为了避免STM32的驱动应用在其他厂家的芯片上所产生的法律和道德问题, 我主要使用GD32官方提供的代码.

主要问题

  • arm mpu可能在移植初期带来一些问题,所以在初期最好关闭
  • zephyr使用systick定时器运行,所以在开始配置时,我们可以不用从时钟系统开始.我认为从gpio led灯开始会比较容易.
  • 我的移植顺序(目前只做了这些,至此芯片基本功能已经完成,但是我适配的串口只能支持基本的收发,如果要应用console或其他subsys可能还要支持中断和DMA):
    • 已实现
      • led灯(GPIO的输出)
      • RCU时钟树
      • 按键(GPIO输入)
      • 串口(GPIO pinmux, uart外设)
    • 计划中
      • 串口(runtime config)
      • 串口(中断驱动)
      • 串口(DMA)
      • CAN
      • USB
  • openocd 这个是移植过程中比较头痛的,因为虽然会使用openocd调试一些芯片,但是编写tcl脚本适配芯片debug系统确实没怎么研究过.只了解一些边界扫描之类的理论知识.这个位置氛围两个部分,一个是debugger,另一部分是debugger和MCU间的通讯支持
    • debugger
      • GD32开发板接入pc,执行 lsusb,可以得到Bus 001 Device 006: ID 28e9:058f GDMicroelectronics CMSIS-DAP,因此debugger是CMSIS-DAP,这部分驱动openocd内提供.
    • debugger和MCU间的通讯支持
      • 因为GD32基本与STM32相似, 仔细调查发现是与STM32F1x系列相似(新系列例如G4等不兼容), 于是常识STM32F1的openocd配置,发现jtag和swd的ID芯片信息需要修改,修改后即可工作.
  • west.yaml 这个和android的repo命令所使用的manifest原理很相似,看来大家都觉得git submodule不好用
  • 感觉GD32的EVAL板质量一般
    • 目前手中的板子信号振铃极其严重,串口波特率115200就已经开始乱码了,有点怀疑是不良品
      • 也可能是usb串口不良,因为我没想到只有两个DB9的串口接口可以使用,用的淘宝8元包邮的那种,后续可能会更换usb串口测试下
      • 印象里CMSIS DAP是自带虚拟串口的,不清楚为啥GD的这个调试器没有接串口.像ST-link一样调试串口可能更友好一些.
    • 吐嘈下,好多年没用锉刀打磨PCB板子边角了o.o
    • 从手册来看,芯片支持CANFD协议,但是PHY芯片手册标识最高速率1M,不是CANfd应该使用的PHY芯片.
      • 后续不稳定可能要自己更换
      • 不过确实是第一次见国产CAN phy,以前只用过NXP的产品,不知道国产芯片是否能有超越数据手册的性能 o.o
      • 我猜GD是不想管理太多芯片,整个eval系列物料共用了
  • 移植过程中发现STM32的官方支持确实很到位, GD32就没有找到太多的支持.

写完之后再看感觉会移植的人也不需要看了,不会的可能看完还是看不会 o.o

PR用法

动图如下(顺便发现了termtosvgasciinema这几个好玩的工具):

https://asciinema.org/a/443449

boox max2 更换电池

平时看漫画和anki的主力工具,用了两三年,电池有点不行了.

翻遍了国内各种网站,竟然没有任何拆解相关的内容, 我掰了掰侧面,感觉不像卡扣的.问淘宝电池卖家也没有拆解方案,最终在youtube上找到了前人的拆解视频,才恍然大悟,正面竟然只是一层贴纸,螺丝密密麻麻排在贴纸下.

拆解视频

注意,贴纸很薄,但很结实,感觉像是某种塑料,能割伤手指!!拆机一定要小心.

电池更换

和视频说明区别不大,换上电池满血复活 🙂

IAR (RH850) (V2.21.1)破解笔记

很久没有研究逆向了,最近研究编译器的起因也是因为被瑞萨的CS+恶心坏了。然而目标设备还是RH850这种非ARM芯片(内核是瑞萨自主的G3KH),可以换用的编译器选择很少,所以研究下破解IAR。

之前在公司邮箱的时候收到过IAR的邮件,发现RH850这个系列可以使用IAR作为开发环境,但是价格么印象里ARM系列貌似5万多一个加密狗,瑞萨系列的没有询价,估计这么小众的,几乎没有竞争对手的可能还会更贵。

本来目标是找一个现成的破解版,体验一下,但是搜索发现,IAR由于更换了License算法,所以以前的License都不可用了。于是自己动手一下。

破解结果

个人破解能力比较有限,注册机之类的基本不会,所以只能爆破。

通过尝试,发现应该是只需要破解iccrh850.exe即可。其他exe在运行时候都不会检查License。

首先,使用了 http://imyoung.ys168.com/ 提供的IAR破解工具, 虽然备注了新版无法使用,但是还是用了一下,确实不能用。

但是,这个时候编译错误已经出现了变化,说生成器的版本不符。为了让他符合,爆破一下0xCB319BJGE修改为JL,然后就成功了。

上图其他几处修改是想尝试没有License的时候能否破解,但是没成功,后面突然发现了捷径 🙂

LLVM学习笔记(1. 环境构建)

构建环境基于Manjaro20.2

系统配置

  1. 虚拟内存

本以为之前32G内存编译爆内存,扩展到64就不会了,结果证明我想多了。当初直接扩展到128好了,最近(2021.2)内存价格比去年双十一贵了不少。

所以还是需要虚拟内存,为了方便使用, 写了个简单脚本,保存在gist上面。

#!/usr/bin/env fish
set swap_file /home/feilong/Program-ext/swap/swapfile
fallocate -l 100G $swap_file
chmod 600 $swap_file
mkswap $swap_file
swapon $swap_file
# swapoff -v $swap_file
# rm $swap_file
view raw swap_make.fish hosted with ❤ by GitHub
#!/usr/bin/env fish
set swap_file /home/feilong/Program-ext/swap/swapfile
# fallocate -l 100G $swap_file
# chmod 600 $swap_file
# mkswap $swap_file
# swapon $swap_file
swapoff -v $swap_file
rm $swap_file
swap Create/remove

没有仔细测算,看SWAP的情况,内存大概少了20G左右。

2. 工具链

对于使用yay来说的arch系来说,工具链基本缺什么装什么就可以。

比较有用的是lld,可以让内存占用稍微小一点。

编译指令

  1. 贴一下官方描述(2021.2)
-G Ninja Setting this option will allow you to build with ninja instead of make. Building with ninja significantly improves your build time, especially with incremental builds, and improves your memory usage.

-DLLVM_USE_LINKER Setting this option to lld will significantly reduce linking time for LLVM executables on ELF-based platforms, such as Linux. If you are building LLVM for the first time and lld is not available to you as a binary package, then you may want to use the gold linker as a faster alternative to GNU ld.

-DCMAKE_BUILD_TYPE
 	
Debug — This is the default build type. This disables optimizations while compiling LLVM and enables debug info. On ELF-based platforms (e.g. Linux) linking with debug info may consume a large amount of memory.
Release — Turns on optimizations and disables debug info. Combining the Release build type with -DLLVM_ENABLE_ASSERTIONS=ON may be a good trade-off between speed and debugability during development, particularly for running the test suite.
-DLLVM_ENABLE_ASSERTIONS This option defaults to ON for Debug builds and defaults to OFF for Release builds. As mentioned in the previous option, using the Release build type and enabling assertions may be a good alternative to using the Debug build type.

-DLLVM_PARALLEL_LINK_JOBS Set this equal to number of jobs you wish to run simultaneously. This is similar to the -j option used with make, but only for link jobs. This option can only be used with ninja. You may wish to use a very low number of jobs, as this will greatly reduce the amount of memory used during the build process. If you have limited memory, you may wish to set this to 1.

-DLLVM_TARGETS_TO_BUILD Set this equal to the target you wish to build. You may wish to set this to X86; however, you will find a full list of targets within the llvm-project/llvm/lib/Target directory.

-DLLVM_OPTIMIZED_TABLEGEN Set this to ON to generate a fully optimized tablegen during your build. This will significantly improve your build time. This is only useful if you are using the Debug build type.

-DLLVM_ENABLE_PROJECTS Set this equal to the projects you wish to compile (e.g. clang, lld, etc.) If compiling more than one project, separate the items with a semicolon. Should you run into issues with the semicolon, try surrounding it with single quotes.

-DCLANG_ENABLE_STATIC_ANALYZER Set this option to OFF if you do not require the clang static analyzer. This should improve your build time slightly.

-DLLVM_USE_SPLIT_DWARF Consider setting this to ON if you require a debug build, as this will ease memory pressure on the linker. This will make linking much faster, as the binaries will not contain any of the debug information; however, this will generate the debug information in the form of a DWARF object file (with the extension .dwo). This only applies to host platforms using ELF, such as Linux.

2. 根据上面信息,提取出比较适合平时开发使用的命令:

cd llvm-project
mkdir build
cd build
# 上面都是废话 🙂
cmake -G Ninja -DLLVM_USE_LINKER=lld ../llvm
ninja

如果内存较小,不希望swap过大拖累编译速度,可以尝试设置 -DLLVM_PARALLEL_LINK_JOBS 或 -DLLVM_USE_SPLIT_DWARF

如果设置 -DLLVM_USE_SPLIT_DWARF 的话,内存占用会缩小至15G左右

参考链接

仓库位置:

https://github.com/llvm/llvm-project

参考文献

https://llvm.org/docs/GettingStarted.html

C语言函数体变化点抽出

前段时间出了几个坑人的bug(都不是我的)需要做Coverity检查,对同事引入的指摘进行修正.因为同事没有用VCS找出修改点变成了活生生的体力活.

正好今天想研究下Antlr,顺便做了个工具(golang),生成函数签名和函数体hash列表,这样不同版本的code就可以比较差分了.(即使函数位于不同文件,或注释不一致)

项目地址

https://github.com/feilongfl/CCodeHash

主要原理

代码十分少,只有几行,算是Antlr入门作了,利用FunctionDefinition定义对函数体进行分析,获得函数签名和实体,并对整个函数进行hash计算生成hash.

第一个是原文件,第二个只修改了注释,第三个对函数代码进行了修改.

配合Shell,以后再有这种坑人事也有对策了.

存在缺陷

对于#if还没做考虑

CAN232/CANUSB调查

最近研究了一下廉价CAN分析设备的原理,顺便明白了和CAN-OE设备的差距真的是天上地下.不过存在着不少优点还是可以学习的.下面是商品链接:

https://www.can232.com/

从名字上就可以看出这是一个串口到can数据包的转换工具,但是搜索很久都没找到通信协议,插在电脑上也不会主动发送消息,正在我百思不得其解的时候,发现了Linux内核里面有个叫做slcan的驱动模块,里面写着CAN232设备的网址.于是先调查下slcan是个什么东西.

slcan

全名 serial line CAN interface driver ,正好是CAN232设备的支持模块,需要配合slcand来使用(位于can=utils程序中).

初始化slcan很简单,正常初始化即可,但是如果我们把CAN232换成普通串口进行抓包,也是可以初始化的o.o

因此在打开设备时候可以捕获到下面数据(结尾均为0x0d,即’\r’):

C
S6
F
O

根据slcand的代码,可以判断相应字母(区分大小写)的意思,每个命令0x0d结尾

C -> 关闭
S6 -> 速度500k (参考: https://elinux.org/Bringing_CAN_interface_up#SLCAN_based_Interfaces)
F ->  获取状态
O -> 打开设备
// 下面这些也是代码中描述的协议
L -> 只听模式
s -> 设置波特率

//数据报文(大写代表扩展帧,小写代表数据帧)
t 数据帧
r 远程帧

//回复结尾
0x0d 正常
            异常(我忘了o.o,回头再试一下)

z 发送成功

因此,随便一个串口只要按照上面格式发送数据就可以被linux转换为CAN消息.当然这样的协议存在明显的缺点,即抗干扰能力差(不过CAN232采用了FTDI的串口芯片,一般实验室情况下稳定性足够了).

最后补上一张串口助手模拟的CAN.

slcanfd

这个串口模块非常古老,因此不支持CAN-FD的协议,但是内核驱动写的很清晰易懂,配合虚拟串口回环和cangen工具,制作了一个支持CAN-FD的驱动https://github.com/feilongfl/slcanfd.

首先模块名字改成了slcanfd,编译安装并手动加载即可使用slcand进行启动.(注意卸载slcan模块,否则会冲突)

后续可以考虑修改下slcand工具,增加下数据速度设置.在stm32G431上配合usb cdc跟fdcan做个usbcanfd(淘宝好像也有现成的,不过我想玩玩画板子,4层板都快成白菜价了)

发送接收展示:

pc发送不加速canfd
pc发送加速canfd
pc发送普通CAN(兼容原格式)
串口发送(CANFD Only)
串口发送(CANFD+CAN)

顺便wakatime也挺好玩的,能看到调查这堆东西花了多少时间: