Sipeed R329 主线 armbian 内核、系统、驱动的开发方法

我的开发环境是 ubuntu20.04 ,请在具备以下文章的开发基础上,再继续往下会比较好。

Allwinner & Arm 中国 & Sipeed 开源硬件 R329 SDK 上手编译与烧录!

选用官方版型:MaixSense 简介

首先拿到原始镜像 sipeed-r329-maixsense-armbian-maixpy3-0.4.0.img ,用 dd 烧录到大于 4G 的卡里就行,我丢群里了。

2022-03-03 本次更新只是包含了 maixpy3 所需要的所有基础环境,并在里面放了一个 resnet50 和 人脸检测关键点供参考测试,加入了 uart 和 i2c 设备,aipu 未更新。

sipeed 用户镜像 root 账号没有 root 密码,输入 root 直接进入系统,自带 maixpy3 0.4.0 所需的基础环境,仅用于用户参考。

原始镜像为 Armbian_21.08.0-trunk_Maixsense_bullseye_edge_5.14.1.img.xz (700M) 自行下载站的 sipeed 企业盘中获取。

镜像编辑和导出的方法

在 ubuntu 上可以直接使用 disk 装载镜像编辑文件(disk)。

  • 挂载到 loop 设备和加载到文件系统

sudo losetup -P /dev/loop404 ./r329-armbian-maixpy3-0.4.0-20220223.img && sudo mkdir -p ./r329 && sudo mount /dev/loop404p1 ./r329 && ls ./r329

  • 卸载的文件系统,并删除目录。

sudo umount /dev/loop404p1 && sudo losetup -d /dev/loop404 && rm -rf ./r329

卸载后会自动同步,此时烧录即可使用。

扩容文件系统的方法

注意分区的损坏了就不能挂载,分区的大小改变不代表文件系统大小改变,所以需要以下代码检查和扩容文件系统。


e2fsck -f /dev/loop404p1 && sudo resize2fs -p /dev/loop404p1

在 armbian 里可以用这个进行扩容 /usr/lib/armbian/armbian-resize-filesystem start ,注意该操作会改变分区表,也会影响尾部的分区大小,慎用。

参考文章:修改R329的Armbian镜像包

修改 boot.cmd 的方法

比如改变 uboot 的一些启动配置,就可以通过这个方式进行修改,修改 boot.cmd 后可以直接系统里运行完成更新。

mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr

主线 linux 都会有类似的配置供你使用,可能是文件可能是分区,最简单得到就是改个波特率。

例如把 115200 改成 1152000 就可以得到 1500000 的波特率串口交互 shell 了(R329 现在的一个可爱的 bug)。

这里 armbian 系统额外写了一种加载配置的方法,如这里我改变了串口为我定义的方法(把 console=serial 改成 none 之类就意味着采用 consoleargs 的配置 ),设置串口为 1152000 (实际上测量的结果为 1.5M )。

verbosity=1
bootlogo=true
console=serial
consoleargs=console=ttyS1,1152000 
disp_mode=1920x1080p60
overlay_prefix=sun50i-r329
rootdev=UUID=9b82c7b2-8d5f-45cc-8fb9-883bd5e1d219
rootfstype=ext4
usbstoragequirks=0x2537:0x1066:u,0x2537:0x1068:u

Linux 内核、驱动、设备树的相关用法方法

可以参考 Sipeed Lichee 进行学习,这部分为通用基础,而 armbian 不需要自己去手工编译。

准备环境 sudo apt install git wget make gcc flex bison libssl-dev bc kmod

前置知识:

  1. 主线Kernel基础编译
  2. 主线Linux编译

修改设备树配置的方法

获取 git clone https://github.com/sipeed/linux.git 切到 r329-wip 分支

编译链工具可以用系统自带的 通用编译链 或 gcc-linaro,看自己喜好,我们用的是这个 gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu.tar.xz 版本

前置知识:设备树简介

简单来说,设备树就是用户定义的需要选配的驱动功能,用户在设备树里定义并启用的树结点,就是要匹配使用的驱动。

R329 的设备树在 linux/arch/arm64/boot/dts/allwinner/ 路径下,和 r329 相关的设备树有

  • sun50i-r329-maix-iia.dtsi
  • sun50i-r329-maixsense.dts
  • sun50i-r329.dtsi

目前的主线配置 linux/arch/arm64/configs/defconfig 导入它。

make ARCH=arm64 defconfig

开始完整编译。

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8 INSTALL_MOD_PATH=out modules
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8 INSTALL_MOD_PATH=out modules_install

啥都不清楚的情况下,一路确认键按下去,直到开始编译,导出 modules 是非必要操作,但对应一些外置 ko 模块需要导出拷入 /lib/modules/ 中,在 menuconfig 中设置为 M 就可以编译出 ko 模块从外部插入系统。

编译成功后,生成文件所在位置:

内核 Image 文件: ./arch/arm64/boot/Image 对应 armbian 目录下的 boot/Image
设备树 dtb 文件: ./arch/arm64/boot/dts/allwinner/sun50i-r329-maixsense.dtb 到 boot/dtb/allwinner/
modules 文件夹: ./out/lib/modules

将 Image 与 dtb 文件放入 boot 目录下重启即可完成内核的更新(armbian 特有)。

上述内容测试过后,你就可以开始自定义自己的主线内核了,但这个并不是主要目的,只是说一些基础用法。

单独编译 dtb 文件加入设备。

通常来说,在不了解如何编译整体的情况下,只需要通过简单的设备树替换就可以完成驱动适配。

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs -j8

参考文章:总结一次为R329开启uart的经历

参考文章:为R329添加i2c设备

将编译得到的 dtb 文件 cp linux/arch/arm64/boot/dts/allwinner/sun50i-r329-maixsense.dtb /boot/dtb

2022-08-31 用这个直接替换吧 sshpass -p root scp ./arch/arm64/boot/dts/allwinner/sun50i-r329-maixsense.dtb root@192.168.0.234:/boot/dtb/allwinner/sun50i-r329-maixsense.dtb 相对快一点,路径也有些变化。

最终提交由开源社区的 冰淇淋 和 灯鼠 完成,感谢他们。

为主线加入外部模块并编译使用。

这里仅供学习参考,Sipeed 内部已经包含了 /usr/lib/modules/5.14.0-rc4-sun50iw11/kernel/drivers/net/wireless/rtl8723ds/8723ds.ko 模块。

上述方法出来的内核不是我们提供的,因为配置项的不同所以会缺少一些驱动,需要你自行加入,如 8723ds 非主线所使用的 wifi 模块。

获取 git clone https://github.com/Icenowy/rtl8723ds 切到 newest-kernel

放到 linux/drivers/net/wireless/realtek/ 下

编辑 drivers/net/wireless/Kconfig 添加 source "drivers/net/wireless/realtek/rtl8723ds/Kconfig",清理错误的语法,只留最简单的部分即可。

config RTL8723DS
	tristate "Realtek 8723D SDIO or SPI WiFi"

编辑 linux/drivers/net/wireless/realtek/Makefile 添加 obj-$(CONFIG_RTL8723DS) += rtl8723ds/ 使得模块参与编译。

通过 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8 menuconfig 按 / 搜索 8723ds 把它配上编译即可。

配好直接 make 编译就行,在 sipeed 的 armbian 这里不需要,仅告知如何加入非主线模块,如特殊的 TP 触摸屏、ADC 按键驱动、I2C 传感器驱动等。

编译 armbian 系统*

自行准备良好的网络环境,相关问题不做解答,默认懂得都懂,编不出来也很正常,不用太在意。

上述开发的内核模块在 sipeed 提供的 armbian 镜像中都是无用的,仅用于测试和确认开发环境,所以要进一步把 armbian 编译出来才是最终用户所用的环境。

可以看文档 https://docs.armbian.com/Developer-Guide_Build-Preparation/ 说明,虽然也没什么好看的。

安装 apt install dialog psmisc acl uuid-runtime curl gnupg gawk 准备环境

获取 https://github.com/sipeed/armbian-build.git 切到 r329-wip 分支,可以在 6ba70ed1f0acabb48c7072e044b62d3439374996 提交获取到配置,最后通过 compile.sh 完成编译。

将根据以下配置在 armbian-build 中进行编译。

  • config/boards/maixsense.wip
  • config/bootscripts/boot-sun50iw11.cmd
  • config/kernel/linux-sun50iw11-edge.config
  • config/sources/families/sun50iw11.conf

运行 ./compile.sh 选择 会自动拉取所有相关的东西,即可编译出来,接下来就是漫长的等待。

注意 maixsense 并非为最终 conf 版本,你需要在 底下的 show WIP 中选择 agree 后就可以看到 maixsense 了,配置可以是 bullseye 和 minimal 就好。。

编译期间会在 armbian-build/cache/sources 下 git clone 在 config/sources/families/sun50iw11.conf 指定的仓库和分支。

完成后输出如下:

[ o.k. ] Building kernel splash logo [ bullseye ]
[ .... ] Installing extras-buildpkgs [  hostapd htop mmc-utils sunxi-tools ]
[ o.k. ] Calling image customization script [ customize-image.sh ]
[ o.k. ] No longer needed packages [ purge ]
[ o.k. ] Unmounting [ /home/juwan/R329/armbian-build/.tmp/rootfs-c735dfca-9977-402a-a68b-b4529b5aac8f ]
[ o.k. ] Preparing image file for rootfs [ maixsense bullseye ]
[ o.k. ] Current rootfs size [ 780 MiB ]
[ o.k. ] Creating blank image for rootfs [ 984 MiB ]
[ .... ] dd:  984MiB [ 136MiB/s] [================================================================>] 100%
[ o.k. ] Creating partitions [ root: ext4 ]
[ .... ] Creating rootfs [ ext4 on /dev/loop40p1 ]
[ .... ] Copying files to [ / ]
[ .... ] Copying files to [ /boot ]
[ .... ] Updating initramfs... [ update-initramfs -uv -k 5.14.0-rc7-sun50iw11 ]
[ o.k. ] Updated initramfs. [ for details see: /home/juwan/R329/armbian-build/output/debug/install.log ]
[ .... ] Re-enabling [ initramfs-tools hook for kernel ]
[ o.k. ] Unmounting [ /home/juwan/R329/armbian-build/.tmp/mount-c735dfca-9977-402a-a68b-b4529b5aac8f/ ]
[ o.k. ] Free SD cache [ 8% ]
[ o.k. ] Mount point [ 91% ]
[ o.k. ] Writing U-boot bootloader [ /dev/loop40 ]
[ o.k. ] SHA256 calculating [ Armbian_21.08.0-trunk_Maixsense_bullseye_edge_5.14.0_minimal.img ]
[ warn ] GPG signing skipped - no GPG_PASS [ Armbian_21.08.0-trunk_Maixsense_bullseye_edge_5.14.0_minimal.img ]
[ o.k. ] Done building [ /home/juwan/R329/armbian-build/output/images/Armbian_21.08.0-trunk_Maixsense_bullseye_edge_5.14.0_minimal.img ]
[ o.k. ] Runtime [ 350 min ]
[ o.k. ] Repeat Build Options [ ./compile.sh  BOARD=maixsense BRANCH=edge RELEASE=bullseye BUILD_MINIMAL=yes BUILD_DESKTOP=no KERNEL_ONLY=no KERNEL_CONFIGURE=no COMPRESS_OUTPUTIMAGE=sha,gpg,img  ]

把 Armbian_21.08.0-trunk_Maixsense_bullseye_edge_5.14.0_minimal.img 拿来烧录就行。

以下是我的配置:(如果你连这个都没编译出来就不要操作了)

# Allwinner R329 dual core 256M RAM WiFi USB-C
BOARD_NAME="MaixSense"
BOARDFAMILY="sun50iw11"
BOOTCONFIG="sipeed_maixsense_defconfig"
MODULES_BLACKLIST="lima"
DEFAULT_CONSOLE="serial"
BUILD_DESKTOP="no"
BOOT_LOGO="yes"
SERIALCON="ttyS0"
KERNEL_TARGET="edge"
OFFLINE_WORK="yes"
CLEAN_LEVEL=""


# ./compile.sh EXPERT=yes BUILD_STABILITY=stable BOARD=maixsense BRANCH=edge RELEASE=bullseye BUILD_MINIMAL=yes BUILD_IMAGE=yes BUILD_DESKTOP=no KERNEL_ONLY=no KERNEL_CONFIGURE=yes COMPRESS_OUTPUTIMAGE=sha,gpg,img CLEAN_LEVEL=""

# ./compile.sh OFFLINE_WORK="no" EXPERT=yes BUILD_STABILITY=stable BOARD=maixsense BRANCH=edge RELEASE=bullseye BUILD_MINIMAL=yes BUILD_IMAGE=no BUILD_DESKTOP=no KERNEL_ONLY=yes KERNEL_CONFIGURE=yes COMPRESS_OUTPUTIMAGE=sha,gpg,img CLEAN_LEVEL=""

必须经过第一次完整编译才能用 OFFLINE_WORK 加快仓库的拉取检查。

看 BOOT_LOGO="yes" 和替换图片文件自动打包编译到二进制文件。

配置开机启动服务脚本

  • /etc/rc.local
#!/bin/sh

# your cmd.

exit 0

#!/bin/sh 没有就会报 Failed to execute /etc/rc.local: Exec format error

系统默认已经不启动 /etc/rc.local 了,所以需要启动一下再往里面编辑脚本,一定要挂在 & 后台,不然就看不到交互终端了。

创建文件 sudo nano /etc/systemd/system/rc-local.service 后编辑如下内容:

[Unit]
 Description=/etc/rc.local Compatibility
 ConditionPathExists=/etc/rc.local

[Service]
 Type=forking
 ExecStart=/etc/rc.local start
 TimeoutSec=0
 StandardOutput=tty
 RemainAfterExit=yes
 SysVStartPriority=99

[Install]
 WantedBy=multi-user.target

配置服务即可。

sudo systemctl enable rc-local

最后把要启动的命令放里面然后 chmod -x /etc/rc.local 给权限即可重启确认效果。

sudo systemctl start rc-local.service

sudo systemctl status rc-local.service

删除用户密码并关闭控制台输出到屏幕上和闪烁光标

查询服务 systemctl status 禁用服务 systemctl disable getty@tty1.service 即可关闭开机终端。

删除密码 sudo passwd -d root 之后输入 root 自动进入系统。

使用 echo 0 > /sys/class/graphics/fbcon/cursor_blink 关闭终端的光标闪烁(cursor_blink),对应实现 drivers/video/console/fbcon.c 。

编译 aipu.ko 主线模块并加入 armbian 系统

2022年02月28日 待编辑,需要结合上下两节食用。没有 linux 外部编译模块基础的,要先简单看过这篇 https://www.kernel.org/doc/Documentation/kbuild/modules.txt 知道怎么添加外部模块参与编译(*.ko)

https://github.com/junhuanchen/linux/commit/efb74da10966ceaa994dfcce3d3e550d8e356ef4

这里我提供了一份包含编译 aipu 的分支,你也可以在 linux 目录下外部编译 aipu.ko 模块出来。

https://github.com/junhuanchen/linux/commits/r329-wip

将其替换掉 armbian-build/config/sources/families/sun50iw11.conf 里的 KERNELSOURCE="https://github.com/sipeed/linux" 即可采用新源进行 armbian 的编译。

偷懒就用我的临时配置好的 https://github.com/junhuanchen/armbian-build 仓库。

给镜像中添加自定义模块(deb)

kernel 的模块(.ko)由 kernel 添加,如果没有发生改变则删除 armbian-build/output/debs/linux-image-edge-sun50iw11_21.08.0-trunk_arm64.deb 即可,可手工可命令。

这里说一下 armbian 的 deb 手工打进去,因为有时候可能不是所有东西都需要,而云端下载太久,就需要提前下好包进去。

在 armbian-build/config/cli/bullseye/main/config_cli_standard/packages.additional 的末尾添加一下包就可以编译进去,其他的类似有 desktop 目录之类的。

打包某些 deb 包的时候经常会出现 apt Hash Sum mismatch 问题,设置成 apt-get -o Acquire-by-hash=yes --fix-missing 可以解决大部分问题。

devmem 的寄存器读取应用

如果想要跳过驱动层直接获取芯片寄存器数据,可以用 busybox devmem 来读写

比如 读取 adc 数值,根据数据手册可知。

https://whycan.com/files/members/3907/R329_User_Manual_V1.0.pdf

image

根据起始地址 base 0x07030800 加上 adc 的 data 0x0c 通道即可获取数据,具体配置已经在 kernel 里完成了,虽然我们也可以跳过驱动,通过 devmem 一个个配置寄存器,但那会有点愚蠢。

所以 busybox devmem 0x0703080c 可以读取到 adc 按键变化的值。

image

这里接到了按键事件驱动上,可以直接 rmmod sun4i_lradc_keys 关掉按键驱动防止意外,驱动实现在 linux/drivers/input/keyboard/sun4i-lradc-keys.c 受到 linux/scripts/dtc/include-prefixes/arm64/allwinner/sun50i-r329-maixsense.dts 的 lradc 节点绑定。

uboot 开发示例

一般开发流程:

git clone https://github.com/sipeed/u-boot

cd u-boot

git checkout r329-wip

make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- sipeed_maixsense_defconfig

make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- menuconfig

make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- -j8

这样就会编译出 u-boot-sunxi-with-spl.bin 了,而在 armbian 中通常 kernel 和 rootfs(ramdisk) 的文件存放在 /boot/ 目录下。

root@maixsense:/# ls -l /boot/
total 45468
-rw-rw-r-- 1 root root      240 Aug 30 09:17 armbianEnv.txt
-rw-rw-r-- 1 root root     1536 Mar  2 06:24 armbian_first_run.txt.template
-rw-rw-r-- 1 root root   230454 Mar  2 06:24 boot.bmp
-rw-rw-r-- 1 root root     3132 Mar  2 06:22 boot.cmd
-rw-rw-r-- 1 root root     3204 Mar  2 06:25 boot.scr
-rw-r--r-- 1 root root   194136 Mar  1  2022 config-5.14.0-rc7-sun50iw11
lrwxrwxrwx 1 root root       24 Mar  2 06:23 dtb -> dtb-5.14.0-rc7-sun50iw11
drwxr-xr-x 3 root root     4096 Mar  2 06:23 dtb-5.14.0-rc7-sun50iw11
lrwxrwxrwx 1 root root       28 Mar  2 06:23 Image -> vmlinuz-5.14.0-rc7-sun50iw11
-rw-r--r-- 1 root root  9522761 Aug 29 10:49 initrd.img-5.14.0-rc7-sun50iw11
-rw-r--r-- 1 root root  4627090 Mar  1  2022 System.map-5.14.0-rc7-sun50iw11
lrwxrwxrwx 1 root root       28 Aug 29 10:49 uInitrd -> uInitrd-5.14.0-rc7-sun50iw11
-rw-r--r-- 1 root root  9522825 Aug 29 10:49 uInitrd-5.14.0-rc7-sun50iw11
-rw-r--r-- 1 root root 22431752 Mar  1  2022 vmlinuz-5.14.0-rc7-sun50iw11
root@maixsense:/# 

系统启动脚本受到 boot.cmd 控制,看最初的修改 boot.cmd 的方法可知,通常类似如下:

load ${devtype} ${devnum} ${ramdisk_addr_r} ${prefix}uInitrd
load ${devtype} ${devnum} ${kernel_addr_r} ${prefix}Image
booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}

而 uboot 的稍微有点不同,在 armbian 编译 uboot 后可以得知:

juwan@juwan-n85-dls:~/R329/armbian-build/cache/sources/u-boot/r329-wip$ ls -l u-boot-sunxi-with-spl.bin
-rw-rw-r-- 1 root root 585855 8月  31 15:01 u-boot-sunxi-with-spl.bin

/home/juwan/R329/armbian-build/cache/sources/u-boot/r329-wip/u-boot-sunxi-with-spl.bin 对应替换系统里的 /usr/lib/linux-u-boot-maixsense-edge_21.08.0-trunk_arm64/u-boot-sunxi-with-spl.bin 即可。

使用 sshpass -p root scp u-boot-sunxi-with-spl.bin root@192.168.0.234:/usr/lib/linux-u-boot-maixsense-edge_21.08.0-trunk_arm64/u-boot-sunxi-with-spl.bin 进行替换,结果如下。

电脑上

uwan@juwan-n85-dls:~/R329/u-boot$ pwd
/home/juwan/R329/u-boot
juwan@juwan-n85-dls:~/R329/u-boot$ sha256sum u-boot-sunxi-with-spl.bin
bd634560c632429811bd46c377607da5e52f596d072f9c0044039c670e75788d  u-boot-sunxi-with-spl.bin
juwan@juwan-n85-dls:~/R329/u-boot$ 

板子上

root@maixsense:~# sha256sum /usr/lib/linux-u-boot-maixsense-edge_21.08.0-trunk_arm64/u-boot-sunxi-with-spl.bin 
bd634560c632429811bd46c377607da5e52f596d072f9c0044039c670e75788d  /usr/lib/linux-u-boot-maixsense-edge_21.08.0-trunk_arm64/u-boot-sunxi-with-spl.bin

至于怎么修改 pinmux 和调试新节点(每个芯片都可能会有一点点不太一样),在主线设计里 uboot 的 pinmux 通常影响引脚资源是否存在且分配,而 kernel 的设备树 dts 影响这个引脚的功能选择,不过经我发现全志提供的 sdk 设备树的设计有一点不同,可以在 kernel 完成硬件的引脚配置 pinctrl 和 pinmux 功能选择,而不需要经过 uboot 的配置,我猜想可能只需要把引脚时钟分配对了就可以吧。

现在 uboot 也开始支持 dts 设备树的概念了,理论上以后应该就可以不用编辑 .h 的方式配置 pinmux 了,以后可能都会转到设备树定义的方式。

常见问题后记

boot 就不提了,看 https://github.com/sipeed/u-boot 就行,实际上全部交给 armbian-build 仓库就行,这样就具备了基础环境,要编辑的部分自然就很少了。

如果你发现模块加载不成功,可能是 version magic '5.14.0-rc4-sun50iw11 SMP mod_unload aarch64' should be '5.14.0-rc7-01557-gd78f1b75fd69-dirty SMP preempt mod_unload aarch64' 错误。

这是模块加载不成功的常见 version magic 错误,简单的处理方法是修改 linux/include/linux/vermagic.h 直接怼到 #define VERMAGIC_STRING "5.14.0-rc7-01557-gd78f1b75fd69-dirty"

想要彻底解决上述这个问题,只能重新编译 armbian-build 导出镜像改变 kernel version 。

如果还有遗漏可以 @ 我补充。

posted @ 2022-02-24 10:57  Juwan  阅读(2661)  评论(0编辑  收藏  举报