移植zephyr到AT32_SURF_F437开发板

感谢Artery公司提供开发板,以及Artery各位工程师的技术支持。

背景

今年上半年收到了Artery公司 木一川 先生的邀请,有幸白嫖到了AT32的开发板。开发板搭载的AT32F437ZMT7芯片和其他国内芯片公司的xx32产品类似,芯片内核采用ARM Cortex-M4,外设和STM32F1相似。

题外话: 在写这篇文章的时候,翻阅了以前写的GD32移植时候看到当时刚刚考完日语N2,一年半时间飞逝,N1考试因为疫情连续取消了三回。

zephyr移植

基础知识:

请参考gd32移植

对于传统的嵌入式软件开发,可能会使用IAR、KEIL等IDE,而绝大多数的芯片厂家默认提供的BSP也往往基于这些工具进行开发。 然而对于开源项目来说,这些工具费用高昂,并且对工作流的细节控制很难实现。因此,对于第一次接触zephyr项目的朋友优先理解编译器(和目标平台架构相关,对于at32来说是gcc)和构建系统(cmake)的作用。

zephyr系统利用了大量linux的开发工具:

  • 为了解决c语言大量宏(marco)的依存关系,zephyr使用linux的kconfig工具来管理宏。
  • 为了解决各个平台的硬件区别,zephyr基于使用linux的devicetree框架对硬件设备从Board,SOC,Arch三个层级对硬件平台进行描述。但是zephyr项目的设备树会生成c语言头文件而不是dtb

为了对开发平台进行调试,一般会使用pyocd或者OpenOCD这两个工具来建立JTAG或者SWD连接,配合gdb对芯片进行调试。 一般gdb不会单独运行,在命令行中调试即使配合tui也是十分痛苦的,但是对于一些高手,利用hook,可以打造出更顺手的调试环境。我个人一般会配合vscode或者gdbgui等工具一同使用,这些GUI界面一般也可以使用hook,并且使用gdb的终端。

以上工具,一般在zephyr项目中也不会直接调用,而是使用west命令进行操作。

AT32移植

zephyr项目支持多种架构和大量厂商的芯片,一般情况下,我们只需要制作最外层的Board级别的移植,即可完成。

但是本次Artery公司尚未被zephyr项目支持,但是arm cortex-m4是被zephyr项目支持的架构arch,所以需要SOC级别的移植。

如果你使用的是RenesasRH850或者infineonTriCore系列芯片,那么你将会面对一个arch级别的移植,这会面对很大的工作量,目前我也没有经历过这个级别的适配。

  • 供应商支持
    • zephyr会对供应商进行管理,只有记录在vendor-prefix.txt内的供应商名称,才可以作为vendor出现在设备树中。
  • 板极支持(boardat_surf_F437)
    • 板级设备树
      • 这里一般会描述LED、按键、串口等板级外设的配置。
    • 板级kconfig配置
      • 对一些设定进行配置,例如LOG等级,IP地址等。
    • 调试工具配置
      • openocdpyocd以及各个厂家特有的下载工具等进行配置,以便对目标设备进行调试和烧写。
    • 文档
      • 一般会描述开发板的功能和简单的编译烧写方法。
  • 芯片级支持(SOCAT32F437ZMT7)
    • soc启动代码(soc.c)
      • 对系统启动进行一些初期设定,arm架构一般会调用cmsis接口SystemInit
    • 芯片级dts
      • 对芯片级设备进行描述,例如定时器,flash等。
    • 芯片级KCONFIG
      • 对芯片系列进行定义。
    • 芯片片内外设驱动
      • 串口、定时器等外设驱动。
      • 这部分代码会大量利用c语言宏的一些特性,熟练掌握可以很大程度的提升c语言宏的使用技巧。
  • 供应商硬件抽象层(对于本次移植来说是hal_artery)
    • 在适配驱动的过程中,如果完全重新写一遍外设驱动的话会产生很大的工作量;同时一般芯片厂商会提供一定的代码以便加速开发。但是,这些代码的维护和zephyr之间关系不大,因此作为module存在。
    • 在使用这些代码的时候,我们需要十分小心。因为c语言没有package或者namespace这些方法对符号的作用域进行限缩,所以在引入供应商HAL代码的时候,符号会重名,这种时候需要对HAL名称进行修正。万幸是这些修正项目往往比较规则,即使在版本更新后,一般也只需要再做一遍即可。如果希望更加一劳永逸的办法,建议了解coccinelle
    • HAL库的另外一大工作量是芯片的引脚复用的管理(pinctrl)。一般情况下,我们对引脚的处理仅仅局限在某一个系列的兼容,然而在zephyr项目中,我们需要对整个供应商的引脚IP进行描述。并且,zephyr项目一般不允许手动修改这些描述,因此制作一个脚本程序是必要的,例如:hal_gigadevice: gd32pinctrl.py
    • 作为zephyr模块,根目录应当包含zephyr文件夹和module.yml文件。这些文件的修改可以参考west工具的说明。

应用篇 (zephyr-SUMP

谈论了很久的移植,最后来聊一下产品的开发。本节将简单的说明下zephyr应用开发的方式,并做一个简单的逻辑分析仪。为了简单起见,本次没有采用out-of-tree的开发方式,而是将代码放在了app文件夹内。

SUMP与SIGROK

  • sigrok
    • 这是一个支持大量设备的开源逻辑分析仪程序(也支持示波器、电源等设备)。
  • SUMP
    • SUMP是一个基于串口(UART/USBCDC)的逻辑分析仪传输协议。

基于这两个工具,我们实现逻辑分析仪的技术准备就基本完成了。

开发APP

为了获得更高的采样速度,需要在APP层级重新定义端口驱动,以绕开zephyr的IO驱动,较少操作系统抽象造成的性能损失。

  • sample文件夹下有大量例子,可以简单的复制出来,作为我们开发的基础。
  • APP KCONFIG设置
    • 对于app级别的宏进行描述,这些宏可以根据实际使用的目标平台进行调整。例如:采样频率,采样数据长度等。
  • 板级设备树覆写
    • 对于逻辑分析仪来说,为了更快的采样速度,我们需要更快的GPIO驱动,而zephyr提供的接口由于抽象,会损失些许性能。
  • app层驱动
    • 这里是对于不同芯片的端口驱动。不同芯片根据资源不同,可能会提供不同数量的端口数和采样方法。例如:
      • Zephyr GPIO方法
      • 汇编方法(目前只实现了ARM)
      • Timer + DMA方法(目前没有做)
  • app
    • 启动了一个测试用pwm(绿灯)
    • SUMP协议的处理
  • 文档
    • 一些文档更加利于别人理解这个项目的用途
  • todos
    • 这个app是我头脑一热做的,还有很多不完善的地方,暂时记录在这里

图片

开发板照片

PulseView采样

WIFI+USBIP+MCU=无线USB设备

请注意,本文提供方法基于zephyr OS制作,由于目前zephyr项目的USB子系统处于大规模重构状态,所以本方案不受zephyr正式支持。详细请参考:

https://github.com/zephyrproject-rtos/zephyr/pull/46862

背景

目前,我们有许多MCU项目利用USB协议与PC进行通信,绝大多数使用USB从机协议,随着Wifi协议的广泛使用以及速度的提升,我认为绝大多数的USB设备都可以经由网络协议而渐渐变得无线化。

但是,如果完全将协议栈转换为网络,会导致一系列兼容软件或驱动需要再次适配,较大的开发量和不明显的收益使得各大厂商在这方面进展缓慢。

本文介绍一种基于USBIP的USB设备无线化方法,希望能够推进设备线束的无线化进程。

USB with WIFI

灵感来源(废话部分,技术无关,可以跳过😄)

前段时间有幸从artery公司木一川先生处得到一片at32 demo板,正巧促使我简单的学习了一下openocd和cmsisdap。发现cmsis-dap协议很容易就可以在zephyr中引用,以获得大量开发板支持。

但是如果只是制作一个普通的dap仿真器,比较缺少挑战性,因此我决定尝试制作无线的仿真器。

最初的目标是通过TCP转发cmsis-dap协议,修改openocd以支援网络设备,但是后面我意识到这会导致windows的KEIL和IAR等IDE环境难以运用。

因此,我将目标转向USB设备的网络访问,因此了解了USBIP协议,并且偶然发现zephyr OS中对USBIP是有部分实现的,我只需要简单的将他扩展到其他设备即可,因此便有了本文。

方案介绍

再次提示,本方案虽然基于zephyr OS制作,但是由于zephyr OS的USB subsystem处于大规模重构状态,所以不受zephyr主线支持!

实现代码请参考:https://github.com/zephyrproject-rtos/zephyr/pull/46862

实际在下面设备中运行通过:

传统USB程序结构

这里指的传统zephyr USB 设备程序(因为zephyr系统目前没有host设备,这也是大规模重构的原因)。

如果您的程序目前采用其他方式架构(可能大部分程序都是吧),您首先需要将其移植到zephyr OS。(目前USB subsystem处于不稳定状态,商业用户需要谨慎考虑)

zephyr OS USB DEVICE

USBIP 网络USB设备

本方案工作在UDD层,通过注册zephyr USB device驱动,并将其转换为USBIP协议。因此没有虽然没有USB硬件,但是在操作系统看来和有USB驱动是一样的。

示意图

注意:

  • 这不是标准USBIP Server的实现,但是我认为对于绝大多数的USB设备已经足够实现功能

使用

MCU程序

建议创建如下application

  • 启动后的wifi配置:帐号,密码,功耗等(有线网络可忽略)
  • 静态IP或DHCP服务

简单使用教程

  • 使用usbip客户端,确认基本通信
usbip list -r FEILONG-CMSIS-DAP
  • 挂载usbip设备
sudo usbip attach -r FEILONG-CMSIS-DAP -b 1-1
  • 调试可以使用wireshark,内置有USBIP协议。

windows

请参考

https://github.com/cezanne/usbip-win

有些功能可能需要使用zadig安装驱动:

https://zadig.akeo.ie/

linux

linux用户应该不需要多说,参考archlinux wiki即可使用。

https://wiki.archlinux.org/title/USB/IP

注意:

在linux上使用时,如果在使用过程中,没有detach直接复位、断电等,会造成linux内核出现异常,重启后即可解决。(windows没有发现此类问题)

参考链接

移植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

使用vscode作为zephyr调试环境(基于stm32f746g-discovery)

前提条件west debug能正常工作,如果不能的话,请参考官方文档进行配置.

安装插件,大概下面这些.

cortex-debug,C/C++, Native Debug,arm

配置cortex-debug

settings.json里面加上下面两行

{
    "cortex-debug.armToolchainPath": "/opt/zephyr-sdk/arm-zephyr-eabi/bin/",
    "cortex-debug.armToolchainPrefix": "arm-zephyr-eabi"
}

工程配置

下面这些参考了github,各种文档汇总而成.

launch.json

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "cortex-debug",
            "request": "launch",
            "servertype": "openocd",
            "cwd": "${workspaceRoot}",
            "executable": "${workspaceFolder}/build/zephyr/zephyr.elf",
            "name": "stm32f746g-discovery",
            "device": "STM32F746NG",
            "configFiles": [
                "${workspaceFolder}/boards/arm/stm32f746g_disco/support/openocd.cfg"
            ]
        }
    ]
}

c_cpp_properties.json

{
    "env": {
        "myZephyrSourcePath": "/home/feilong/workspace/zephyrproject/zephyr/",
        "myZephyrSDKPath": "/opt/zephyr-sdk"
    },
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${myZephyrSourcePath}/include/",
                "${myZephyrSourcePath}/lib/libc/minimal/include/",
                "${myZephyrSourcePath}/arch/arm/include/",
                "${myZephyrSourcePath}/build/zephyr/include/generated/"
            ],
            "compilerPath": "${myZephyrSDKPath}/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "gcc-x64"
        }
    ],
    "version": 4
}

west build之后f5就可以了.