今天要聊的这块KICKPI K11开发板,主控是瑞芯微RK3566。这颗SoC大家应该不陌生:四核Cortex-A55,带G52 GPU,还有0.8T算力的NPU,主打AIoT和边缘计算。板子本身很有意思,4GB内存加128GB eMMC,扩展接口也齐全。但真正让很多人在开局阶段就卡住的,反而是Windows主机下的开发环境搭建。我一开始在Win10上直接裸装Linux工具链,折腾一通发现能编译但调试痛苦,后来换成了Windows + WSL2混合方案,才算把编译、烧录、串口调试这几个环节理顺。这篇东西就写给准备在这块板子上做开发、又不想折腾双系统的人,算是把这几个月踩过的坑一次性摆出来。
有这块板子的朋友应该都有体会,说它是“桌面安卓电脑”其实有点低估了。RK3566这颗芯片能被拿来玩出花的地方不少,但前提是把环境先伺候舒服。尤其是Windows用户,光是想在宿主机和Linux开发环境之间传文件、跑编译脚本、再处理USB设备透传这些问题,就能消耗掉大半天。我最终敲定的方案是:Windows负责图形化烧录工具和部分驱动,WSL2里面跑Ubuntu 22.04承载编译链和SDK。这样两边各干各擅长的事,省心不少。
我知道有人会说,搞个VMware或者VirtualBox不是更简单?我后面也会聊为什么WSL2比传统虚拟机更适合这个场景,以及它有哪些必须提前埋单的坑。
1. 整体设计与思路拆解
1.1 为什么是WSL2而不是虚拟机或双系统
RK3566的开发环境绕不开Linux,但Windows用户面临一个选择:双系统、传统虚拟机、还是WSL2。
双系统的问题在于切换成本高。开发过程中经常需要Windows这边开串口终端、看PDF、挂微信,同时Linux那边挂着编译任务。来回重启不仅浪费时间,编译到一半切走还可能出各种意外。虚拟机(VMware/VirtualBox)倒是能同时跑,但传统虚拟机的文件系统开销大、磁盘镜像体积不可控,而且对USB设备的透传处理远不如WSL2那边的usbip方案干净。我最初用VMware试过一版Ubuntu 20.04,编译时明显感觉磁盘IO拖后腿,整机响应都变肉。
WSL2不是虚拟机,也不是传统意义的容器。它是基于轻量级实用工具构建的完整Linux内核,跑在Hyper-V平台上。跟宿主机共享网络、文件系统、剪贴板,调用GPU也有微软官方支持。最关键的一点是,它的文件系统访问速度和兼容性比前面两个方案高一大截,对本项目的交叉编译场景尤其友好。
1.2 Windows + WSL2 双环境的分工逻辑
这块板子的开发流程,其实可以拆成两类任务。
编译类任务放WSL2里做:RK3566的SDK源码同步、DTS编译、u-boot内核镜像构建、根文件系统打包,全部在WSL2的Linux文件系统下完成。理由很朴素:源码和编译产物对大小写、软链接、文件权限、符号链接这些属性要求严格,而Windows文件系统在这些方面天生不友好。我第一次把AOSP源码放在/mnt/c盘符下编译,跑了一会儿直接因为符号链接权限问题崩掉,后来改成放在WSL2的ext4虚拟磁盘里面,问题消失。
调试与烧录类任务放Windows侧做:RKDevTool的烧录工具、瑞芯微的DriverAssistant驱动安装工具、ADB调试、串口终端(MobaXterm或者Windows Terminal + WSL)都跑在Windows侧。原因是板子的USB设备识别机制在Windows驱动层更成熟可靠,而且很多上位机图形工具只有Windows版本。
1.3 我手头的环境参考
给一个可以对照的参考配置。主机是i5-12400F + 32GB内存 + 1TB NVMe固态,Windows 11 22H2版本。WSL2内安装Ubuntu 22.04 LTS,/opt下挂SDK目录,/home下放着编译工具。这套配置编译RK3566的AOSP系统固件,首次全量编译实测约80分钟,增量编译在10到15分钟上下。如果内存小于16GB,我建议至少加一条虚拟内存配置项,不然编译大工程会因为OOM被内核杀掉。
2. WSL2 底座搭建与基础坑位
2.1 安装WSL2和Ubuntu版本选择的注意事项
WSL2的安装现在很简单,管理员权限的PowerShell里执行两条命令就完了:
wsl --install wsl --set-default-version 2几条命令背后的逻辑值得说一下。wsl --install在Win10 2004以上版本会自动启用Windows虚拟机平台和Hyper-V相关组件,然后安装默认的Ubuntu发行版。不用手动打开“启用或关闭Windows功能”里的复选框,省得自己点了半天还搞不清缺哪个模块。
版本选择上,Ubuntu 22.04 LTS是一个稳妥的决定。原因有三点:一是RK3566生态里的SDK脚本和依赖包列表大多基于Ubuntu 18.04到22.04验证过;二是18.04已经接近EOL,用apt装软件经常遇到旧源失效问题;三是22.04的GCC和内核工具链版本可以兼容瑞芯微提供的预编译交叉工具链,不会出现glibc版本过低无法运行的问题。
如果还在用Win10老版本(比如20H2之前),需要手动安装WSL2内核更新包。这个包在微软官网有,安装完再执行wsl --set-version Ubuntu-22.04 2把发行版从WSL1切到WSL2。检查是否切换成功,在WSL里跑uname -a,内核版本号中能看到microsoft-standard-WSL2字段就算正常。
2.2 文件系统与磁盘空间的硬性教训
WSL2的虚拟磁盘是ext4文件系统,以vhdx文件的形式存放在Windows侧。这个设计让Linux侧的文件权限、软链接、inode语义都得以完整保留,但同时也带来两个常见的坑。
第一,虚拟磁盘默认不会自动收缩。你在WSL里编译了上百GB的中间产物,删除之后,C盘的那个ext4.vhdx文件仍然占据了同样大的物理空间。解决办法是定期用diskpart的compact功能收缩磁盘:管理员PowerShell执行diskpart,select vdisk file="C:\Users\你的用户名\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu22.04LTS_xxx\LocalState\ext4.vhdx",然后compact vdisk,可以释放空间。注意执行前先在WSL里运行sudo fstrim /。
第二,千万千万不要把源码放在/mnt/c、/mnt/d这样的Windows挂载目录下编译。道理在于,WSL2的9P文件系统协议访问Windows目录,每次读文件都经过协议转换,和原生ext4的速度差好几倍。更麻烦的是,Windows的NTFS对硬链接、大小写敏感的支持是模拟出来的,AOSP这类工程编译时对文件路径大小写敏感,很容易在链接阶段爆出一堆找不到文件类报错。我见过有人在/mnt/d下放SDK硬是编译了4个小时还没跑完。
我的做法是在WSL内创建一个专用目录,然后把SDK和源码都放这里。同时把WSL的虚拟磁盘迁移到D盘(如果有第二块硬盘),避免C盘空间被大幅挤占。迁移方法不复杂:wsl --shutdown后,用wsl --export导出发布版为tar文件,再wsl --import到新的位置。导入后需要设置默认用户为root再改回,或者用wsl --manage指定用户,细节可以查微软文档。
2.3 systemd、网络与包管理器的实用调优
Ubuntu 22.04在WSL2里默认不启用systemd,对嵌入式开发来说主要是两个影响:某些服务脚本(比如systemctl start xxx)不能直接跑;其次,一些SDK里的服务管理脚本会误判环境。解决办法是在WSL的/etc/wsl.conf里添加以下内容并重启WSL:
[boot] systemd=trueWSL2的NAT网络模式对外能出去(需要宿主机有网),但出现DNS解析异常是高频问题。症状是sudo apt update报“Temporary failure resolving”,解决办法是手动指定DNS服务器,编辑/etc/resolv.conf,把nameserver改成223.5.5.5或119.29.29.29。不过要注意,文件可能被WSL自动覆盖,需要在/etc/wsl.conf里加[network]下面的generateResolvConf=false来禁止自动生成。
包管理器方面,建议在安装依赖之前先把apt源替换为国内镜像。方法不复杂,Ubuntu 22.04的源文件是/etc/apt/sources.list,把archive.ubuntu.com替换成镜像域名即可。这一步能显著减少后续装依赖时的等待时间。
3. RK3566 编译环境的重点配置
3.1 依赖安装:一长串apt包的坑与解法
RK3566的SDK编译,无论你跑的是AOSP还是Buildroot或Debian镜像,依赖包列表都长得吓人。我整理了一份经过实际验证、可直接复制粘贴的安装名单:
sudo apt update sudo apt install -y git gnupg flex bison gperf build-essential zip curl \ zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses-dev \ x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils \ xsltproc unzip fontconfig liblz4-tool libssl-dev python3 python3-pip \ openjdk-8-jdk repo bc cpio device-tree-compiler u-boot-tools \ libncurses5-dev libncursesw5-dev lzop python2 dosfstools mtools pigz有几个包在纯Ubuntu桌面或者WSL默认安装里是缺失的,少了它们编译一定报错:liblz4-tool用于lz4压缩格式,python2在AOSP 12的某些脚本里会用到,u-boot-tools提供mkimage命令,lzop是内核压缩出lzo格式镜像的工具。缺这些包时,编译日志里会出现command not found或“Can't locate module”的提示。
特别提醒两点。第一,RK3566 SDK如果编译Android 12,需要OpenJDK 8。但Ubuntu 22.04默认源里已经移除openjdk-8,需要额外从openjdk-r/ppa或者手动下载Oracle JDK 8。我建议直接用apt安装openjdk-11,在很多脚本里也能兼容,但如果非要按瑞芯微的官方步骤来,稳妥做法是从Azul或OpenLogic下载JDK 8的Linux x64包,放到/usr/lib/jvm/手动配置。第二,编译过程中如果报错提示缺少/usr/bin/ld: cannot find -lncurses,说明缺32位libncurses库,需要sudo dpkg --add-architecture i386 && sudo apt update && sudo apt install libncurses5-dev:i386。
3.2 交叉编译工具链与SDK目录规划
瑞芯微的SDK分几类。如果是编译u-boot和内核,只需要ARM64交叉编译工具链。官方一般在SDK里自带了预编译的gcc-linaro工具链,但有的裁剪版SDK只提供脚本,依赖你自己装。
推荐直接在Ubuntu 22.04上安装标准交叉编译工具链:
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu然后在SDK的Makefile或build脚本里指定CROSS_COMPILE=aarch64-linux-gnu-。内核编译命令示例:
export ARCH=arm64 export CROSS_COMPILE=aarch64-linux-gnu- make rockchip_linux_defconfig make -j$(nproc) uImage dtbs编译整个SDK时,目录结构建议这样规划:
/opt/rk3566/ ├── sdk/ # 全量SDK源码(u-boot、kernel、app等) ├── output/ # 编译产物 ├── tools/ # 交叉工具链、打包脚本、固件签名工具 └── images/ # 最终生成的img/img.gz文件这里有个实际教训:不要在快接近磁盘满的路径上编译。SDK目标编译一次全量AOSP,光是out目录就接近50GB加中间临时文件,加内核、u-boot、dtb等还得再占10GB到15GB。确保WSL虚拟磁盘所在物理盘至少留出150GB空闲空间,不然编译到一半磁盘满了,前面所有时间全打水漂。
3.3 AOSP/Ubuntu镜像编译的耗时与资源实测
KICKPI K11的厂商支持做得还行,官方SDK里既有Android 12的AOSP工程,也有Ubuntu的根文件系统构建工程。我实际跑过两者的编译,说点具体数据。
AOSP工程,用make -j$(nproc)全量编译,32GB内存的机器上,swap没开的情况下,内存峰值大概在20GB左右,属于能扛住的范畴。如果内存只有16GB,建议给WSL2设置8GB到12GB的虚拟机内存上限,并在WSL内部配置8GB的swapfile,否则gcc/clang会OOM被杀。设置WSL虚拟内存上限可以在%UserProfile%\.wslconfig里写:
[wsl2] memory=24GB swap=8GB processors=8 localhostForwarding=trueUbuntu根文件系统构建相对轻量,主要是交叉编译一系列deb包,C代码居多,CPU占用拉满的同时内存需求不高,8GB也能跑。
编译完成后,产物是rockdev/目录下的Image文件集合,包括boot.img、dtb.img、vendor.img、system.img等。打包一个完整烧录镜像时,SDK里通常会调用./mkimage.sh脚本,生成一个类似RK3566-xxx-xxx.img的完整固件包,这个文件最终给Windows侧烧录工具使用。
4. 从WSL2到板子:USB透传与刷机协作
4.1 usbipd-win:把串口和ADB设备透传给WSL2
嵌入式开发的日常离不开串口和ADB。虽然在WSL2里能直接跑adb命令,但前提是把USB设备从Windows透传到WSL2中。这个能力在WSL2里默认不开启,需要装微软官方推荐的工具usbipd-win。
安装分两步。在Windows侧以管理员身份运行PowerShell,执行:
winget install usbipd然后在WSL里安装客户端支持:
sudo apt install linux-tools-generic hwdata sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-tools/*-generic/usbip 20USB设备透传的核心命令不多:
# Windows PowerShell(管理员) usbipd list # 找到开发板的串口或ADB设备,记录BUSID,比如 2-1 usbipd bind --busid 2-1 usbipd attach --wsl --busid 2-1绑定前最好把板子的USB线先拔插一次,确保设备处于Driver Assistant正确识别的状态。绑定后,在WSL里执行lsusb能看到对应的VID/PID,比如瑞芯微的VID是2207。此时ls /dev/ttyUSB*或ls /dev/ttyACM*应该出现对应串口设备。
有个经验之谈:不是所有USB设备都能透传成功。某些USB转串口芯片(比如CH340/CP2102)在绑定后需要在WSL里用chmod 666 /dev/ttyUSB0或者把当前用户加入dialout组才能正常读写。ADB设备透传后还需要在WSL里执行adb kill-server && adb start-server,否则adb会报“no devices”。
4.2 刷机时Windows与WSL2的分工协作
刷机这个环节,我最推荐的策略是:编译在WSL2,烧录命令在Windows的RKDevTool里操作。
具体流程是这样。在WSL2里完成镜像编译后,把生成的完整固件包拷贝到Windows侧的刷机目录,比如C:\rk3566_images\。然后板子进入Loader模式(按住板子的recovery键再上电,或者执行adb reboot loader),打开RKDevTool选择对应的镜像文件进行烧录。
RKDevTool的配置要点有两个。第一,烧录前要安装瑞芯微驱动DriverAssistant,否则Windows设备管理器里板子显示为未知设备,工具会一直停在“等待设备”状态。安装驱动的过程里如果杀毒软件拦截,需要临时关闭实时防护。第二,在RKDevTool的“高级功能”或“下载镜像”页签里,如果烧录整个固件包,要选择“按地址烧写”而不是“按文件烧写”。两者的区别在于后者只会把镜像写入指定分区,而前者是擦除后整包写入,更干净。
这个流程最省心的地方在于:Windows端的烧录工具不需要自己写脚本,图形界面操作一目了然;WSL2里编译生成的镜像文件只需要通过/mnt/c路径共享出来就行。
4.3 Loader模式进不去或驱动失败的排查经验
烧录失败,九成是设备根本没进入Loader模式或Windows驱动没识别。排查顺序按下面这个来:
第一,确认板子供电正常且没有连接外接电源异常。某些扩展板的电源指示灯正常不代表主控已经刷进Loader固件,最好先拿一个已经能运行的固件确认板子能正常开机进系统,再谈烧录。
第二,进入Loader模式的操作要在上电后的前5秒内完成。方法是:拔掉Type-C数据线,按住板子上的recovery键不松手,再插上USB线,保持按键按下2秒后松开。如果板子有OLED或LCD屏显,屏幕上会显示Loader模式的提示;如果没屏,看Windows设备管理器里是否出现“Rockchip USB”相关设备。
第三,驱动安装失败时试试离线安装模式。DriverAssistant的正确安装姿势是,解压之后以管理员身份运行DriverInstall.exe,点击“驱动安装”,等待提示成功。如果中途提示驱动未签名或Windows安全策略拒绝安装,需要进入Windows高级启动,选择“禁用驱动程序强制签名”后再试一次。
如果还是不行,换一根USB线。这不是玄学,USB线只走电源线不走数据线的问题在嵌入式调试里非常常见。
5. 开发调试日常:串口、ADB、文件共享
5.1 一套顺手的多窗口配法:Windows Terminal + WSL + MobaXterm
环境搭好之后,日常开发我习惯开三个窗口。第一个窗口是Windows Terminal的WSL页签,用来跑编译命令和查看构建日志。第二个窗口是Windows Terminal的PowerShell页签,跑usbipd attach、adb shell这类需要与Windows侧设备交互的命令。第三个窗口是专门的串口工具,我推荐MobaXterm,它自带串口会话能力,连接板子的调试串口很方便。
串口参数值得记一下:波特率通常是1500000,部分SDK版本用115200。数据位8、停止位1、无校验。连接上之后按回车应当出现Rockchip相关开机日志或shell提示符。如果回车无反应,先确认接线,GND、TX、RX三根线不能错,TX接RX、RX接TX。
串口用途上多说一句:除了看开机日志,串口实际上是进入Rockchip MaskRom模式或U-Boot交互模式的门户。在U-Boot启动阶段连续按ctrl+c可以进入u-boot命令行,在这里能执行mmc、ums、fastboot等操作,比在系统里敲命令灵活得多。
5.2 源码管理、文件双向拷贝与编译产物传递
源码管理这块,建议在WSL里直接git clone和repo sync,不要在Windows侧用TortoiseGit拉完再复制进来。原因还是文件系统兼容性,git仓库里的符号链接和权限位在NTFS上会丢。
文件双向拷贝,我最常用的三种方式:
一是/mnt/c路径共享,适合拷单个镜像文件。比如在WSL里执行cp rockdev/update.img /mnt/c/rk3566_images/,直接在Windows资源管理器里能看到。
二是Windows侧直接拖拽。WSL2支持把Windows文件拖进WSL的explorer窗口,但文件会经过9P协议转换,几百MB的大文件传输会比较慢。
三是scp或samba。如果文件特别多,建议直接在WSL里跑samba服务或用python3 -m http.server临时起一个下载服务,然后用Windows浏览器访问下载。用轻量级方法拷贝比拖拽稳定得多。
整个流程我踩过最深的一个坑是:更新SDK后,旧的编译产物没删干净,结果mkimage把新旧混合的镜像打包了。烧进板子后系统起不来,日志一直停在u-boot阶段。查了半天发现SDK里make clean没有清理干净out目录,必须手动删除out目录再重新编译。所以每次切换SDK分支或大版本更新后,rm -rf out/是必要动作,不要心疼编译时间。
5.3 需要GUI时:Xvfb和Windows侧显示工具备用
说实话,RK3566的开发大部分时间不需要GUI。但有个场景例外——跑某些图形相关的测试程序,或者需要用GUI配置工具检查框架渲染效果。WSL2里本身没有直接显示的机制,Windows侧需要装一个X Server,比如VcXsrv或X410,然后在WSL里设置export DISPLAY=:0,就能把WSL内Linux程序的图形界面显示到Windows桌面。
如果只是跑自动化测试,不想开整个X Server,另一个思路是用Xvfb创建一个虚拟显示器:
sudo apt install xvfb xvfb-run -a ./一道测试命令程序这种方式在无人值守构建和渲染冒烟测试里很管用。
不过要注意,WSLg在Windows 11里已经默认支持WSL内GUI程序直接显示到Windows桌面,无需再手动配置X Server。如果还在用Win10,就需要VcXsrv方案。启动VcXsrv时建议关闭“Native opengl”选项,否则部分基于OpenGL的测试程序会闪退。
6. 高频报错与排查速查表
6.1 冷启动阶段最容易翻车的几件事
我把实际遇到的问题整理成了一张表,方便对照自查。
| 报错或症状 | 原因 | 解决办法 |
|---|---|---|
sudo apt update报Temporary failure resolving | WSL2 DNS解析异常 | 修改/etc/resolv.conf,或禁用自动生成并指定DNS |
repo sync提示python3版本不对 | AOSP脚本需要python2或特定版本 | 安装python2及整理PATH,或使用SDK自带的虚拟环境脚本 |
编译报错/bin/bash: lz4: command not found | 缺lz4压缩工具 | sudo apt install liblz4-tool |
编译报错cannot find -lncurses | 缺32位ncurses库 | 启用i386架构安装libncurses5-dev:i386 |
| 烧录时RKDevTool一直等待设备 | 设备未进入Loader模式或驱动未装好 | 重按recovery进Loader,重装DriverAssistant |
| 板子插上USB但Windows不识别 | USB线只通电不传数据 | 换线,测试先用手机连PC验证数据线正常 |
| WSL里adb找不到设备 | 设备未透传或adb server过时 | usbipd bind/attach,WSL内重启adb server |
| u-boot启动卡住不动 | 镜像分区错乱或entry配置错误 | 编译前清理out目录,重新整包烧录 |
6.2 三个只有实际折腾过才懂的经验
第一,给WSL2的虚拟磁盘分区预留余量。编译SDK有时候不光是out目录占空间,~/下的ccache缓存也能轻松吃掉20GB。我的习惯是在/etc/profile里加一行export USE_CCACHE=1,同时把缓存目录指到磁盘空间更宽裕的路径,比如export CCACHE_DIR=/opt/ccache。ccache对重复编译的加速非常明显,尤其是改一行代码就要重新编内核的时候,能省几分钟到十几分钟不等。
第二,不要在主分支上直接拉远端SDK仓库的最新代码就跑。KICKPI相关的SDK源码本身有多个分支,有的分支跑Android 12,有的跑Debian/Ubuntu镜像,有的只含适配某个屏的DTS。如果你只按README默认操作,拉到默认分支的结果往往不是板子当前硬件版本能直接驱动的固件。建议先核对SDK里README或芯片手册中关于硬件版本与BSP分支的对应关系,再决定用哪个分支。我曾经直接编默认分支,烧进去后触摸屏驱动不生效,排查了两天才发现分支对不上。
第三,把WSL2当作一个需要维护的Linux发行版来对待。定期apt update && apt upgrade,磁盘空间不足时清理apt缓存和journalctl日志,这样能避免一些莫名其妙的构建报错。WSL2毕竟不是真机,它的内核模块数量是裁剪过的,如果SDK里有一些需要加载特定内核模块的操作,先确认这个模块在WSL2里是否可用。比如某些SDK脚本会尝试加载fuse或nbd模块,而默认WSL内核不一定包含,可以尝试通过/etc/wsl.conf的内核启动参数加载,不行就换个思路绕过。
6.3 性能调优:编译提速与资源占用的平衡
最后聊一点性能调优的心得。
WSL2的I/O性能和原生Linux还是有点差距,主要体现在大量零碎文件的读写场景。规避方式是尽量合并写操作,比如编译时使用make -j$(nproc)的并行度不能盲目拉满,并行度过高会造成大量进程同时写out目录,反而让磁盘IO成为瓶颈,编译时间可能不降反升。
有个实测数据供参考:32线程的CPU(8核16线程),-j16编译AOSP和-j8编译时间差距很小,但CPU占用天差地别。如果想边编译边做其他事情,建议-j8,机器的交互响应会好很多。磁盘方面,如果Windows和WSL2在同一个物理硬盘上,编译的同时不要做大量Windows文件复制,会显著拖慢编译速度。
另外,WSL2的localhost转发功能默认开启,板子和WSL之间如果通过ADB over Network方式调试(比如板子连Wi-Fi,IP是192.168.1.100),在WSL里直接adb connect 192.168.1.100:5555就能连上,不需要做端口转发。但如果想从Windows侧的RKDevTool或某些工具连接板子上的服务(比如SSH),需要在WSL里执行netsh interface portproxy或者在Windows防火墙里放行对应端口。这块内容比较零散,出问题时优先查看Windows Defender防火墙的入站规则。
回头再看这套环境,其实最核心的体会就一句话:Windows和WSL2不是对立关系,而是分工关系。开发板编译这种重活交给WSL2,烧录和驱动这种跟硬件强耦合的环节留在Windows侧,各取所长。WSL2不像传统虚拟机那么重,但也不是完全透明,DNS、文件系统、USB透传这几个点都得提前安排明白。如果非要给后来的朋友一个建议,我的经验是:环境搭建阶段多花半天时间把目录规划、磁盘空间和驱动提前确认清楚,后面编译调试能省下无数个加班的夜晚。