这块板子到手的时候,我其实挺兴奋的。KICKPI K11,RK3566 主控,4GB 内存加 128GB eMMC,带一块 8 寸 1280x800 的屏幕,预装 Android 12,开机就能当个小主机玩。但真正开始做环境搭建,才发现问题比想象中多:Rockchip 的 Linux SDK、Buildroot、U-Boot、内核编译,整套工具链几乎都是按 Linux 环境设计的。我日常主力机是 Windows,又不想折腾双系统,VMware 里跑编译实在憋屈。最后选定 Windows + WSL2 方案,把 SDK 拉取、交叉编译、镜像打包全部丢进 WSL2 里跑。这篇文章就是把从安装 WSL2 到第一次成功编译出 RK3566 镜像的过程中踩过的坑,一条条完整记录下来,给同样想在 Windows 平台上开发 RK 系列板卡的朋友做个参考。
1. 为什么是 WSL2:三种方案对比后我做了什么选择
很多人在 Windows 上做嵌入式开发,第一反应是装 VMware 或者 VirtualBox。我一开始也这么想,后来把三种方案放在一起对比,才发现 WSL2 在当前这个场景下确实是最省心的。
1.1 传统虚拟机、双系统、WSL2 的取舍
先说 VMware。它能跑完整的图形化 Ubuntu,兼容性也确实好,但代价是给虚拟机分配的内存和 CPU 要被固定占走。RK3566 的 SDK 编译时,Buildroot 那种全量编译非常吃 CPU,虚拟机方案在 IO 和调度上总有损耗,而且每次用 Windows 端的烧录工具、串口终端,还得在两个系统间来回切窗口,体验很割裂。
再说双系统。性能确实是最接近物理机的,但切换成本太高。开发 RK3566 的过程中,你需要频繁在烧录工具、串口调试、源码编译之间横跳。我经常是编译完一个内核镜像,马上要去 Windows 端用 RKDevTool 烧录,双系统意味着每次都要重启,半小时就烦了。
WSL2 的优势在于它不是一个"翻译层",而是一个基于 Hyper-V 的轻量虚拟机,跑的是真正的 Linux 内核。RK 系列的 SDK 编译脚本里大量用到挂载、设备节点、符号链接这些底层操作,WSL1 那种 API 翻译的方式在这种场景下容易出幺蛾子,WSL2 就没有这个问题。而且 WSL2 的 ext4 磁盘 IO 性能接近原生,只要文件不放在 /mnt/c 下,编译速度完全能接受。
1.2 WSL2 对 RK3566 SDK 的适配性分析
Rockchip 官方的 Linux SDK 包含 Bootloader、Kernel、Buildroot/Debian rootfs、各种打包脚本。这套东西在 Ubuntu 下跑得最顺,文档里基本都写着"推荐 Ubuntu 18.04/20.04"。WSL2 里装的就是标准 Ubuntu 发行版,所以 SDK 拿到手之后几乎不需要为"这不是真 Linux"做额外适配。
我实测下来,只有两类操作 WSL2 做不了或者做得不稳:一类是牵扯到 kernel module 加载和硬件直通的操作,另一类是高实时性的 USB 烧录时序。前者本来也不需要,后者我后面专门用一节来讲怎么分工。
提示:如果你的 Windows 版本支持,建议优先确认 Windows 10 2004 以上或者 Windows 11。老版本系统装 WSL2 需要手动开启两个 Windows 功能,新版本一条 wsl --install 就能搞定。
2. WSL2 安装与配置:三个绕不开的坑
WSL2 的安装网上教程满天飞,但真正落到 RK3566 开发这个场景,有几个细节是教程里不会写的。这里只讲我实际踩到的,顺序按安装流程来。
2.1 安装卡住时的排查链路
我第一次装 WSL2 时,wsl --install 执行完,重启进终端,Ubuntu 卡在"Installing, this may take a few minutes..."界面超过半小时没动静。这问题一般不是网络,而是 Windows 服务没起来。
排查路径建议按这个顺序:
- 确认 BIOS 里虚拟化开关已经打开,任务管理器 -> 性能 -> CPU,能看到"虚拟化: 已启用"。
- 打开服务管理器,检查 LxssManager 和 vmcompute 两个服务状态,vmcompute 经常是手动模式,卡住时先把它启动。
- 如果安装了 VMware/VirtualBox 且开着 Hyper-V,会有冲突,必要时关掉旧虚拟机软件的服务再重试。
另外,wsl --install 默认装的是比较新的 Ubuntu 版本,安装完成后建议顺手跑一下 wsl --update,把内核组件升到最新,避免后续 USB 透传时出现内核模块版本对不上的问题。
2.2 Ubuntu 版本选择的版本匹配问题
Rockchip 官方 SDK 的历史包袱比较重。很多脚本和工具链是照 Ubuntu 18.04 时代写的,尤其依赖 python2、openssl 1.1、libncurses5 这些老组件。Ubuntu 20.04 最稳妥,但要装 python2 得走 deadsnakes PPA,Ubuntu 22.04 更要手动处理 openssl 3.0 和 libncurses5 缺失的问题。
我最终选了 Ubuntu 22.04,理由是它对新版工具链支持更好,后续如果想在板子上跑新版本内核或者用更新的交叉编译器,22.04 的库依赖不容易出问题。缺的组件单独补齐就行。
补依赖时最需要注意的是 libssl-dev。22.04 默认是 openssl 3.0,但 SDK 里某些 host 端工具(比如 mkimage、firmware 打包脚本)是按 openssl 1.1 写的,编译时会报一些结构体字段找不到的错误。我的处理方式是直接安装旧版本兼容包,然后让编译脚本通过环境变量去指定头文件路径。如果你不想折腾这个,老老实实用 20.04 是最省事的。
2.3 网络模式选择:NAT 和 mirrored 的实际差异
WSL2 默认的 NAT 模式下,WSL2 里的 Linux 可以访问外网,也能主动访问局域网里的开发板,这在大多数情况下够用。但有一个场景很别扭:板子上的系统要通过 NFS 或者 TFTP 挂载你 WSL2 里编译好的内核和根文件系统时,NAT 模式下 WSL2 的 IP 每次启动都会变,而且宿主机和 WSL2 的关系是端口转发,板子想主动连进来非常费劲。
Windows 11 较新版本支持 mirrored 镜像网络模式,它让 WSL2 和 Windows 共享同一套网络接口,IP 也就是同一个。对开发板调试来说,这意味着你在板子上可以直接 ssh 或者 nfs 挂载到 WSL2 里的固定地址,不用再关心端口转发。
配置文件在用户目录下新建 .wslconfig:
[wsl2] networkingMode=mirrored dnsTunneling=true firewall=false dhcp=false需要提醒的是,mirrored 模式在某些版本的 Windows 上对 localhost 转发的行为和 NAT 模式不一致,如果发现 WSL2 里访问 Windows 上跑的服务不稳定,切回 NAT 模式再排查。
3. RK3566 SDK 拉取与编译链路
这一步是整个环境搭建的核心。SDK 拉不下来、编译环境缺包、工具链路径没配好,每一个都是真实消耗过时间的坑。
3.1 目录规划与 repo 初始化
RK3566 的 Linux SDK 用 repo 管理,由几十个 git 仓库组成,包含 U-Boot、内核、Buildroot、Debian 打包脚本、rockdev 输出目录等。拉取前务必确认目录规划,我的建议是直接放在 WSL2 的原生文件系统里,比如 ~/rk3566/rk3566-sdk,绝对不要放在 /mnt/c 或者 /mnt/d 下。
原因有三个:第一,/mnt 下的跨文件系统 IO 性能折损非常严重,全量编译时间可能差出 30% 以上;第二,Windows 的 NTFS 权限模型和 Linux 不一致,SDK 里大量需要可执行权限的脚本会偶发权限错乱;第三,路径转换的坑太多,后面有一节专门讲。
拉取 SDK 前先确认基础工具:
sudo apt update sudo apt install -y git git-lfs python3 python3-pip ssh \ build-essential gcc g++ make cmake automake autoconf \ libssl-dev libncurses5-dev libncursesw5-dev device-tree-compiler \ u-boot-tools zip unzip bzip2 lz4 expectrepo 工具本身建议用官方方式安装到用户目录:
mkdir -p ~/bin curl -sS https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo chmod a+x ~/bin/repo export PATH=~/bin:$PATH然后初始化 SDK 仓库:
mkdir -p ~/rk3566/rk3566-sdk cd ~/rk3566/rk3566-sdk repo init -u 你的SDK清单仓库地址 -b 你要的分支 repo sync -c --no-tags这里第一次容易踩的坑是 repo sync 到一半中断。具体表现是某个仓库 clone 到 99% 就挂起,重新跑一遍能续上但下次还会在别的地方断。我的处理是加参数控制并发:
repo sync -c --no-tags -j4并发调到 4 反而比默认高并发稳定,中断概率明显下降。同步完成后务必 git lfs install 跑一遍,SDK 里有些大文件是通过 Git LFS 托管的,漏了这步后面编译到一半会跳出找不到文件。
3.2 交叉编译工具链的路径问题
RK3566 是 64 位 ARM 架构,交叉编译工具链用的是 aarch64-linux-gnu 系列。SDK 里通常会自带预编译工具链,位置在 prebuilts/gcc/linux-x86/aarch64/ 下,或者你需要单独下载 Rockchip 提供的 gcc-linaro 版本。
我自己遇到的问题是编译 U-Boot 和内核用的工具链版本不一致导致的各种诡异报错。U-Boot 编译时看的是环境变量里的 CROSS_COMPILE,内核编译有时会走 SDK 脚本里硬编码的路径。排查时先确认:
which aarch64-linux-gnu-gcc echo $CROSS_COMPILE如果系统里没装,要么把 SDK 自带的工具链路径加到 PATH,要么用 apt 装交叉工具链:
sudo apt install -y gcc-aarch64-linux-gnu但注意 apt 版本和 SDK 自带的版本可能有差异,如果遇到"internal compiler error"这种莫名其妙的崩溃,优先换成 SDK 自带的工具链再试。
3.3 从编译脚本入口到第一个镜像
SDK 的编译入口一般是 build.sh,按顺序编译 u-boot、kernel、rootfs 再打包。正确的方式是分步编译,不要一上来就跑全量脚本,否则日志刷屏后根本定位不了错误。
./build.sh lunch ./build.sh uboot ./build.sh kernel ./build.sh rootfs ./build.sh firmware每一步完成后检查输出目录,确认中间产物正常再走下一步。我第一次跑 ./build.sh uboot 时就卡了很久,后来发现是环境变量 PATH 里缺少 SDK 自带的工具链目录,脚本找不到编译器,报错信息又藏在几百行日志里。
4. USB 透传与烧录:Windows 和 WSL2 该怎么分工
开发板调试绕不开 USB:ADB 调试、fastboot、loader 模式烧录、串口日志。在这一步,WSL2 的短板开始暴露,但也并非无解。
4.1 usbipd-win 的安装与 USB 透传原理
usbipd-win 是个开源工具,原理是把 Windows 上的 USB 设备通过 usbip 协议共享给 WSL2,让 Linux 侧直接识别底层 USB 设备。安装很简单:
winget install usbipdWSL2 内部需要装配套内核模块:
sudo apt install linux-tools-generic hwdata然后 Windows 上管理员 PowerShell 执行:
usbipd list usbipd bind --busid 你的设备busid usbipd attach --wsl --busid 你的设备busidattach 之后,WSL2 里输入 lsusb 就能看到设备。RK3566 芯片的 USB Vendor ID 是 2207,看到对应记录就说明透传成功。
4.2 RKDevTool 与 Linux 烧录工具的实际分工
这里要给个明确建议:RK 板卡的烧录操作,尤其是进入 Maskrom/Loader 模式的烧录,建议留在 Windows 端用 RKDevTool,不要指望 WSL2 透传后用 rkdeveloptool 搞定一切。
原因在于烧录过程中 USB 通信时序要求很高,透传链路多了一层 usbip 的封装,Windows 上 1 秒内完成的握手动作到了 WSL2 里可能超时。我实际测试过,rkdeveloptool 的 ld 命令在透传环境下经常卡在"Waiting for device",而同一个设备在 Windows 上被 RKDevTool 秒识别。不是工具不行,是透传场景的时序损耗。
USB 透传真正好用的场景是 ADB。把开发板通过 USB 连到电脑,透传到 WSL2 后,你可以在 Linux 侧直接执行 adb shell、adb logcat、抓取内核日志,配合 SDK 里的调试脚本非常顺手。注意开发板首次连接时需要授权,确认板子上弹出的 RSA 指纹提示后再执行 adb devices。
4.3 串口调试的稳定方案
嵌入式开发离不开串口。KICKPI K11 这类板子一般会引出 UART 调试串口,通过 USB 转串口适配器(常见 CH340、CP2102)连接到 Windows。我的建议是串口调试完全留在 Windows 端,用 MobaXterm 或者 PuTTY 连接,波特率默认 115200,不要为了"统一到 Linux"而强行透传串口设备。
理由很简单:串口是排错时最后的救命稻草,如果板子起不来,你只能靠串口看启动日志。这种场景下任何不稳定的中间链路都是风险。WSL2 透传串口设备虽然也能用,但驱动兼容性和流控行为偶尔飘,关键时刻掉链子就得不偿失了。
提示:实际开发调试时,我常用的组合是——Windows 端开一个 MobaXterm 挂着串口,看 U-Boot 和内核的启动 log;WSL2 里跑 ADB 和交叉编译;烧录镜像时切到 Windows 用 RKDevTool。三个窗口各司其职,比任何"全家桶"方案都省心。
5. 踩坑实录:KICKPI K11 环境搭建中最典型的 6 个问题
这一节把我踩过最典型的 6 个坑完整复盘一下,每一个都是现象、排查过程、最终解决一条龙写出来。
5.1 问题一:repo sync 中断到怀疑人生
现象:repo sync 跑几十分钟,某个仓库到 99% 突然挂住,ctrl+c 重跑又继续,过会儿再挂,尤其是带 LFS 文件的仓库。
排查过程:一开始怀疑是网络问题,但同一个仓库手动 git clone 又能完整拉下来,说明不是断网。后来对比了日志,发现高并发时多个仓库同时拉取 LFS 文件,Windows 宿主机的文件系统 IO 和 WSL2 的 9P 协议偶发死锁。虽然推荐把 SDK 放在 WSL2 原生文件系统,但我的 SDK 初始是放在 /mnt/d 下的,所以卡得更明显。
解决:把 SDK 目录迁移到 ~/rk3566 下,同时降低 repo sync 并发到 4。迁移后中断概率大幅下降。
补充一层:如果同步的是带 LFS 的仓库,在 repo 初始化之后先在仓库目录执行一次git lfs install --local,确保 LFS 过滤器正确注册。
5.2 问题二:SDK 目录放 /mnt/c 引发编译权限翻车
现象:build.sh 编译到打包步骤时,脚本老是报 permission denied,或者生成出来的镜像文件在 Windows 里打开正常,但拿到 Linux 下格式又是坏的。
排查过程:看脚本执行到哪一行,用 bash -x 打开详细日志,发现是 mkenvimage 这类工具生成的临时文件没有可执行权限。因为文件在 /mnt/c 下,Windows 的 NTFS 不认 Linux 的权限位,SDK 里部分脚本 chmod +x 后执行还是没有权限。
解决:彻底放弃在 /mnt/c 下放代码,全部迁移到 WSL2 ext4 文件系统。这算是最痛的教训,如果你看到 SDK 里有任何 mount 操作或者对设备节点文件的操作,基本可以断定它不适合放到 NTFS 上。
5.3 问题三:git autocrlf 把脚本搞成了 CRLF
现象:SDK 从仓库拉下来后,运行 build.sh 报 /bin/bash^M: bad interpreter,或者脚本里出现诡异的语法错误,vi 里能看到行尾有 ^M。
排查过程:第一反应是拉取过程文件损坏,删掉重新 checkout 还是一样。后来意识到是 git 的 core.autocrlf 默认在 Windows 环境被设置成了 true,导致 checkout 时把 LF 转成了 CRLF。
解决:
git config --global core.autocrlf false然后重新 checkout 所有文件。最稳的做法是在 WSL2 里针对 SDK 仓库单独设置:
git config core.autocrlf input这个坑很容易被忽略,而且一旦发生,报错信息五花八门,特别误导人。
5.4 问题四:usbipd attach 后设备在 WSL2 里消失
现象:usbipd attach --wsl 成功,lsusb 也能看到设备,但拔插一次或者板子重启后再执行 adb devices,设备不见了,lsusb 也看不到。
排查过程:看 usbipd list,发现设备状态已经从 Attached 变回 Not attached。这是因为开发板 USB 断开后,usbip 会话没有自动重连,需要重新 attach。更麻烦的是,板子重启后 busid 可能变化,之前 bind 的 busid 对应的设备已经不存在。
解决:整理成一个固定的操作流程,板子每次重启后重新执行一次 bind + attach。另外,把常用板卡设备的 Vendor ID 在 WSL2 里加到 udev 规则,避免 adb 识别时因权限问题被忽略:
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="2207", MODE="0666", GROUP="plugdev"' | sudo tee /etc/udev/rules.d/51-rockchip.rules sudo udevadm control --reload-rules5.5 问题五:Windows Defender 实时扫描拖慢编译
现象:同样的 SDK、同样的并发参数,WSL2 里编译速度比预期慢很多,top 看 CPU 占用不高但编译就是跑不快。
排查过程:观察 Windows 端的 Defender 进程,发现它一直在扫描 WSL2 的 vhdx 文件。WSL2 的虚拟磁盘在 Windows 看来就是一个大文件,每次 WSL2 写入,Defender 都要实时扫描,IO 全面拖慢。
解决:在 Windows 安全中心的排除项里,加入 WSL2 的发行版存储目录,一般是%LOCALAPPDATA%\Packages\CanonicalGroupLimited.Ubuntu*下的 ext4.vhdx 文件路径。加完排除项后,全量编译时间大概缩短了 15% 到 20%,效果非常明显。
5.6 问题六:WSL2 磁盘空间告急与发行版迁移
现象:SDK 全量拉下来加编译产物,WSL2 虚拟磁盘占用轻松超过 50GB。C 盘告急,虚拟机磁盘文件还在不断膨胀。
排查过程:du -sh *定位大目录,发现 buildroot 输出和内核编译中间产物占了大头。清理后依然空间紧张,因为 C 盘本来就不宽裕。
解决:两个手段并行。一个是把整个 WSL2 发行版迁移到 D 盘:
wsl --export Ubuntu-22.04 D:\wsl-backup\ubuntu.tar wsl --unregister Ubuntu-22.04 wsl --import Ubuntu-22.04 D:\wsl\ubuntu D:\wsl-backup\ubuntu.tar注意 unregister 会删掉发行版内所有数据,迁移前务必确认编译产物和代码已经备份。另一个手段是定期清 SDK 中间产物,make clean配合rm -rf buildroot/output/*一类的操作,不要舍不得删,反正能重新编译。
6. 日常开发工作流与效率心得
坑踩得差不多了,最后分享一下这套方案磨合稳定之后的日常工作流,以及一些提高效率的细节。
6.1 目录规划与跨系统文件访问
我的目录规划是固定的:
- WSL2 内:~/rk3566/rk3566-sdk 放 SDK 源码和编译产物
- WSL2 内:~/share 放编译好的镜像文件、脚本、补丁
- Windows 端:D:\board-tools 放 RKDevTool、串口驱动、固件备份
Windows 访问 WSL2 文件,直接在资源管理器地址栏输入 \wsl$\Ubuntu-22.04\home\你的用户名,把这个路径映射成网络驱动器,日常拷贝编译产物到 Windows 桌面就很方便。反过来,WSL2 访问 Windows 文件就通过 /mnt/d。
6.2 编译效率的细节优化
WSL2 里编译并行度可以按 CPU 核数减半设置。我的机器是 8 核 16 线程,用 -j8 跑全量编译比较稳,-j16 反而因为内存不够导致 OOM。如果编译过程中卡死或报 cannot allocate memory,优先调低并行度,再考虑关掉 Windows 端的浏览器。
对于内核和 U-Boot 这种反复编译的场景,我习惯用 ccache 加速。SDK 默认可能没开,手动安装并配置:
sudo apt install ccache export USE_CCACHE=1 export CCACHE_DIR=~/ccache ccache -M 20G实测二次编译内核时,ccache 命中率能到 60% 以上,编译时间缩短一半。唯一要注意的是 ccache 目录也会膨胀,定期 ccache -C 清理就好。
6.3 环境备份与迁移
WSL2 环境最大的风险是误操作。比如 apt 装包时手滑卸载了系统库,或者 SDK 目录被误删。我的备份策略是:SDK 源码用 git 管理还好说,关键是编译好的镜像和 toolchain 不能动不动就重新搞一遍。所以每周做一次 WSL2 发行版的全量导出:
wsl --export Ubuntu-22.04 D:\wsl-backup\ubuntu-weekly.tar全量导出文件比较大,但是恢复了真的能救命。有一次我在 WSL2 里配环境时误删了 /usr/lib 下的一个符号链接,导致整个系统半瘫,直接导入备份半小时就回到了正常状态,比自己排查快得多。
根据我个人使用RK3566这块板子的经验,Windows + WSL2 这套组合完全可以支撑日常的嵌入式开发,前提是把那几个结构性的问题提前规避掉:SDK 必须放 WSL2 原生文件系统、烧录留在 Windows 端、串口独占 Windows、USB 透传只用于调试场景。这套流程稳定跑下来之后,我反而觉得比直接用 Linux 物理机还方便,因为 Windows 端那些图形化的烧录和串口工具,确实比命令行版本顺手。最后再给一个小技巧:把上面提到的几个命令写成 Windows 批处理和 WSL2 里的 shell 脚本,一键完成环境检查和 USB 透传,省得每次开发板重启都要敲一遍命令。