移植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也挺好玩的,能看到调查这堆东西花了多少时间:

FT4232H体验记录

体验背景

对于单片机来讲,串口通信是比较方便的接口了,打印log什么的不需要自己写上位机,网上串口助手一大把,随便找个就行,比较适合嵌入式项目的前期调试使用。

但是,随着嵌入式芯片的速度不断提高,产生的log越来越多,串口也需要比较高的速度,前段时间给mcu的串口终端通信压力测试时候,用国产山寨pl2303把速度设到921600才能给mcu一点压力。

并且新的项目需要更加快速的log速度,于是我开始寻找更加快速的串口。首先想到的是以前玩px4时候用的ft232高贵的三十多块钱的串口,速度好像3m左右来着,当年也没什么特殊需求,也没在速度这边做研究。于是打开FTDI的官网,发现最大速度12m,而且还有更加高贵的版本,70多块的ft4232,相当于4个ft232的版本。更加新一代的产品ft4233在当前(2020/5/1)还没有发售,比ft232支持了typec的pd功能(其实这个更符合我的需求,奈何淘宝没有,之后联络供应商可能会有其他回答)

体验(踩坑)历程

  1. 淘宝卖家发来的是没有焊接引脚的版本,对于我这种手残党,直接翻车。
正面
背面

清晰可见电容扭曲,因为我焊接引脚时候焊锡落在在电容上,两个电容是我后焊上去的,折腾了好久。如果不是测试用,强烈不建议购买这种,做工很差,pcb特别薄,而且明显的拼版,掰开后没打磨,在从usb拔出时候极易割伤手指(我已经被割伤了)。四周尖角,扎人。非要买的话,建议一起买个锉刀,打磨下。

2. 驱动的话,windows 10manjaro linux基本都能自己驱动,不用折腾,连接在PC上4个COM口,linux的话lsusb出现一个设备,/dev/ttyUSB出现4个,在我这边测试都是从小到大对应ABCD,没有出现反人类情况。

3. 新的FTDI芯片可以通过FT PROG对eeprom进行配置。这个软件只能windows运行。

FT Prog

这个软件在点击扫描时候有可能闪退(比如我这),通过上面命令行执行SCAN命令,可以看到错误

对这个错误进行搜索,可以查询到这是一个已知的问题,https://www.ftdicommunity.com/index.php?topic=39.0

简单来说就是和我的鼠标冲突(因为我键盘使用ps2接口,不使用USB HID协议),于是拔下鼠标,按F5然后再把鼠标插上就可以正常工作了,这里根据需要设置即可,不过感觉设置没什么作用,可能是因为我还没有测试D2XX接口。

4 通过串口助手进行发送测试,波特率直接测试12000000,通信没什么问题,回环和逻辑分析仪都没什么问题,但是循环发送速度特别慢,约几kb/s,让人难以接受,在网络上搜索没什么有效的结果,于是上逻辑分析仪进行测试。

overview
两包数据间隔时间

可以看到每次传输都是比较快的,但是在中间等待了很长时间才进行下一次传输,于是猜测串口助手影响,使用golang写(抄)了如下测试代码。

package main

import (
    "flag"
    "github.com/tarm/goserial"
    "github.com/larspensjo/config"
    "os"
    "log"
)

var (
    conFile = flag.String("configfile","/config.ini","config file")
)

var TOPIC = make(map[string]string)

func main() {
    file, _ := os.Getwd()
    cfg, err := config.ReadDefault(file + *conFile)

    id, err := cfg.String("COM","COMID")
    baud, err := cfg.Int("COM","BAUD")
    c := &serial.Config{Name: id, Baud: baud}
    s, err := serial.OpenPort(c)

    if err != nil {
        log.Fatal(err)
    }

	data := []byte("0")

	for i:=0; i< 1000000; i++ {
		_, err := s.Write(data)
		
		if err != nil {
			log.Fatal(err)
		}
	}

}
[COM]
COMID=COM17
BAUD=12000000

依旧间隔很久,肉眼可见的等待时间,怀疑驱动层或者goserial或者windows系统对串口处理有问题(linux尚未测试,c语言串口也需要测试一下),于是对每次传输字节数量进行增加,得到下面波形,可见大数据是可以高速通信的。

传输大byte
放大一点

接收的话12m的波特率没什么问题,可以正常看到数据,没发现丢包情况,不过看串口助手cpu占用率挺高,快占满一个核心了,估计自制串口通讯工具时候也需要注意这一点,把串口接收单独一个线程,防止丢数据。

启动电平时间

这方面应该跟板载电容大小有关,但是作为淘宝货,应该也是直接抄的公版电路,所以对启动电平的测量也能在一定程度上说明一定问题,对今后串口下载电路的实现可以起到一定的借鉴作用.因为这个板子没有usb的电压接口,只能采取测量ldo的3v3输出.

可以看到上电初期时序,做下载电路的话,dtr时间最长.适合作为rst使用.大约40us左右,rts可以作为类似与stm32的boot0一样的存在,用于选择引导位置.