ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

K210开发环境配置:Windows下RISC-V交叉编译工具链实战指南

K210开发环境配置:Windows下RISC-V交叉编译工具链实战指南 简介面向 Kendryte 芯片的 Windows 64 位开发工具链压缩包版本为 8.2.0发布于 2019 年 4 月适用于 K210 等 RISC-V 架构芯片的嵌入式与 AI 边缘计算项目开发。压缩包共 1069 个文件约 51.36MB主体为 h/hpp 头文件、exe 可执行程序、a/la 静态与动态库以及少量 Python 脚本和编译配置内建 GCC 编译器、GDB 调试器、链接器等组件且针对 RISC-V 架构做了优化可支撑从源码编译、目标文件链接到固件调试的完整工具链流程。已有 239 人学习/下载。借助该工具链开发者可以编译 Kendryte SDK 示例工程操作 GPIO、I2C、SPI、UART 等硬件接口并利用 GDB 进行断点、单步、内存检查等调试快速移植或开发语音识别、图像处理等边缘 AI 应用适合希望深入理解 RISC-V 交叉开发流程的嵌入式开发者。1. 先看懂文件名再动手kendryte-toolchain 到底是个什么东西拿到kendryte-toolchain-win-amd64-8.2.0-20190409.zip这个压缩包大部分人的第一反应是解压、装环境、跑 demo真的能静下心来把文件名拆开看一遍的人不多。但这个文件名里包含的信息量非常大它直接决定了你后面几个小时的折腾体验。拆开看字段含义为什么重要kendryte嘉楠科技的开源平台名说明这是 Kendryte K210 芯片专用工具链toolchain工具链不是单个编译器而是编译、汇编、链接、运行库的成套工具winWindows 系统只能在 Windows 下运行不能跨平台使用amd64x86_64 架构对应 Intel/AMD 64 位 CPU 的 Windows 系统8.2.0GCC 版本号基于 GCC 8.2.0 构建的交叉编译器20190409构建日期 2019年4月9日官方停止更新前的版本之一很多人在搜索时看到amd64会多想一下——我的电脑是 Intel 的是不是不能用这里澄清一下amd64就是 x86_64 的另一种叫法AMD 最早定义了这套 64 位指令集Intel 后来也用了所以 Windows 上安装的 64 位软件全部标注为 amd64只要你不是 ARM 架构的 Windows 设备下载这个包就是对的。至于网络上经常出现download for windows amd64和download for windows arm64的对比问题简单说amd64 是传统 Intel/AMD 芯片用的arm64 是高通骁龙 X 系列、苹果 M 系列芯片转 Windows 后用的也有部分 SurFace Pro X 等设备。K210 官方截止这个版本只提供了 amd64 版本如果你是 ARM 版 Windows 平板原版工具链基本跑不起来只能靠后续社区方案补。这个工具链解决的核心问题是K210 芯片基于 RISC-V 指令集而你的 Windows 电脑是 x86 指令集两种 CPU 的机器码互不兼容。所以必须用交叉编译器——在 x86 平台上编译出 RISC-V 能执行的机器码。打个比方你是中国人x86要给一个只懂德语RISC-V的人写信你需要一本中译德的对照词典这本词典就是交叉工具链。riscv64-unknown-elf-gcc就是那本词典的总目录编译器、汇编器、链接器、C 库全部藏在里面。安装这个工具链的典型场景包括K210 裸机开发、MaixPy 固件二次编译、MicroPython 模块移植、自己编译 SDK 里的 demo。现在很多教程习惯用 MaixPy 写 Python但真正做模型部署、性能优化、外设驱动定制绕不开 C 编译这也就是为什么你现在手里会有这个 zip。2. K210 开发环境远不止一个编译器工具链、SDK、烧录工具的三方配合我第一次配 K210 环境时犯过一个错误解压工具链、配好 PATH、然后直接gcc hello.c编译立刻报错找不到头文件。当时我以为是工具链坏了重装了三遍才发现问题在思路。实际上 K210 开发环境里工具链只是三分之一完整的环境由三块拼成第一块是交叉编译工具链本身也就是你手里这个压缩包。它提供 riscv64-unknown-elf-gcc编译器、riscv64-unknown-elf-objcopy二进制转换、riscv64-unknown-elf-objdump反编译、riscv64-unknown-elf-ld链接器、riscv64-unknown-elf-gdb调试器等一堆工具。它负责把 C 源码编译成带 RISC-V 指令的 .elf 文件。第二块是 SDK软件开发套件。K210 官方有 kendryte-standalone-sdk裸机开发和 kendryte-freertos-sdk带 RTOS其中内封装了大量寄存器操作库你的代码可以直接调用 fpioa_set_function、dmac_set_irq、gpio_set_drive_mode 这类 API。SDK 规定了代码的整体骨架、链接脚本、启动文件的组织方式。没有 SDK 你用工具链也只能写闪灯这种极简程序一旦涉及内存布局和启动流程就容易翻车。第三块是烧录工具 kflash.py基于 Python 实现或者 kendryte-flash 的 Windows GUI 工具。编译产出的是 .bin 或 .elf 文件把文件烧录到 K210 的 Flash 里就是烧录工具的工作。K210 支持 UART 串口烧录和 JTAG 烧录两种模式前者只管连 USB 转串口芯片的 TX/RX 引脚后者需要 J-Link 这类调试器硬件。三者的协作过程是这样的SDK 带上你的 main.c 源码 → 编译器把源码翻译成.elf→ objcopy 把 .elf 转成纯二进制.bin→ kflash.py 把 .bin 写到开发板的 SPI Flash → K210 上电后从 Flash 加载并执行。如果你把这三块的职责混在一起就会像我刚开始一样迷茫工具链装好了却编译不了例程因为 SDK 还没下载SDK 下载好了又编译不过因为 cmake 没找到编译器编译器找到了最后又卡在烧录。所以动手配环境前先理清楚你当前在哪一步、缺的到底是哪块比什么都重要。Python 的 kflash.py 注意依赖 pyelftools 这个库装完 Python 后先执行pip install pyelftools否则烧录时容易在解析 .elf 阶段报解析错误很多新手把烧录失败归结为驱动问题其实把库补上就解决了。3. 五分钟跑通第一个点灯工程Windows 下从解压到烧录的完整链路环境还没配好的人看这一节可以直接照做。以下步骤我分别在 Windows 10 22H2 和 Windows 11 26H2 上验证过都能稳定跑通。3.1 解压与 PATH 配置的细节解压路径有一条铁律不要放在含中文和空格的目录里。有些人的用户名是中文比如 C:\Users\张三或者习惯把工具链放在C:\Program Files\下这两类路径都会让 make 和 cmake 在解析路径时出各种诡异的问题。建议单独建一层干净的目录C:\kendryte-toolchain\里面解压完成后会得到bin、lib、share等子目录。PATH 配置时加的是工具链内部的bin 目录不是外层目录。我之前见过有人把C:\kendryte-toolchain加进 PATH结果 cmd 里敲 riscv64-unknown-elf-gcc 永远提示找不到命令。正确的路径类似C:\kendryte-toolchain\binWindows 11 打开环境变量编辑器的方式右键开始菜单 → 系统 → 高级系统设置 → 环境变量。在“系统变量”里找到 Path双击编辑新建一行填入上面的路径。改完后必须重新打开cmd 或 PowerShell不要用旧窗口测旧进程不会刷新环境变量。验证编译器的命令是riscv64-unknown-elf-gcc --version看到类似riscv64-unknown-elf-gcc (xPack GNU RISC-V Embedded GCC x86_64) 8.2.0的输出说明工具链本体已经正常工作。3.2 拉取 SDK 并配置 cmake 工具链光有编译器还不够需要把交叉编译的“翻译规则”告诉项目构建系统。官方 SDK 使用 cmake 管理工程其中通过一个kendryte-toolchain.cmake文件告诉 cmake请用riscv64-unknown-elf-gcc而不是系统自带的 MSVC 或 MinGW 来编译。选 SDK 时注意一个小坑kendryte-standalone-sdk官方仓库下载速度比较慢建议使用 Git 浅克隆git clone --depth 1 https://github.com/kendryte/kendryte-standalone-sdk.git之后打开项目根目录的CMakeLists.txt确认以下内容存在set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/kendryte-toolchain.cmake)设置 CMAKE_TOOLCHAIN_FILE 的本质意义是你明确告诉 cmake 不要用本机的 GCC 编译 x86 程序而是要生成 RISC-V 指令集的代码并自动去找 riscv64-unknown-elf-gcc 作为编译器。不设置这个变量cmake 会默认用你电脑的 MSVC 或 MinGW编译一百遍也不可能生成 K210 能跑的 bin。3.3 编译与烧录进入 SDK 目录执行mkdir build cd build cmake .. -G MinGW Makefiles make这里我用的是 MinGW 的 make或者叫 mingw32-make因为它是纯 Windows 环境、不依赖 MSYS2 壳层。如果电脑里没有安装可以下载 MinGW-w64 安装包或者干脆改用cmake --build .让 cmake 自动调用生成器。需要提示的是cmake 的-G MinGW Makefiles只在已安装 MinGW 的前提下有效你如果更熟悉 Visual Studio 的构建方式也可以-G Visual Studio 16 2019但自定义交叉编译场景用 Makefiles 更简单直接。编译成功后在 build 目录下找到类似hello_world.bin的输出文件。把开发板连接到电脑查看设备管理器确认串口号然后烧录python kflash.py -p COM3 -b 1500000 -t .\build\hello_world.bin-b 1500000表示波特率 1500000这是 K210 官方推荐的快速烧录速度。如果烧录中途卡住降低波特率到115200再试成功率会明显提升。开发板上的 BOOT 引脚需要提前按住再复位进入下载模式具体操作每个板子稍不同但原理一致芯片 ROM 里的 Bootloader 先进入串口等待阶段此时烧录工具才能写入 Flash。开机后如果看到板载 LED 按你设定的延时参数闪烁恭喜从工具链到 SDK 到烧录的完整链路已经打通了。4. 工具链内部RISC-V 交叉编译的关键机制与常被忽略的 macOS/Linux 差异如果你只是在 Windows 上点几个按钮前面的内容已经够用。但既然做嵌入式理解工具链内部的几个关键机制能让你在以后遇到陌生报错时不至于抓瞎。这一节讲三个绕不开的核心点。4.1 为什么编译器叫 riscv64-unknown-elf-gcc这个前缀可以拆成三段。riscv64 表示目标是 64 位 RISC-V 架构unknown 表示目标厂商未知属于通用目标elf 表示生成的文件格式是 ELF 而不是 PE 或 COFF。整套命名遵循 GCC 交叉编译器的标准格式arch-vendor-system-gcc。当你在命令行里敲下 riscv64-unknown-elf-gcc 时实际上是在调用一个自动加上--targetriscv64-unknown-elf参数的 GCC 前端封装。这也意味着你写 C 代码时不需要手动指定-march默认配置已经朝向 K210 所需要的-marchrv64imafdc整数 乘除 原子 单双精度浮点 压缩指令生成代码。不过如果你做了 Kernel 层面的定制比如改满了内存布局、或者使用了特殊的指令扩展需要手动在 Makefile 的 CFLAGS 里追加-march否则编译产物可能不能在 K210 上执行。4.2 交叉编译的链路ELF、objcopy 和链接脚本编译过程不只是“gcc 编译出 bin”这一个动作它内部实际上经过了好几步。K210 的启动流程决定了 Flash 里存放的文件是纯二进制指令流而.elf是包含调试信息、符号表、多个段text/data/bss的可重定位格式两者不能混淆。于是编译步骤里通常会有一次关键的转换riscv64-unknown-elf-objcopy -O binary hello_world.elf hello_world.bin链接脚本扩展名.ld是这个过程中最容易被忽视又最容易出问题的部分。它告诉链接器text 段放哪个地址、data 段放哪个地址、栈顶在哪。K210 的 SDK 默认附带一个kendryte.ld如果你自己把 main.c 抽出来单独编译却忘了带上这个链接脚本链接阶段十有八九会报错“找不到 __start symbol 或内存区域越界”。很多从 Arduino 转过来的人无法理解链接脚本的作用简单说它相当于给新房子画了每个房间的用途不然的家具函数、变量进来以后只能乱堆放。4.3 工具链跨平台的隐性差异我用同样的代码在 Windows、WSLUbuntu 22.04和原生 Ubuntu 上都编译过遇到的问题最能说明工具链差异文件路径分隔符、行尾结束符和动态库依赖。Windows 版本的 GCC 是原生 PE 程序不依赖 MSYS2 的动态库双击就能跑但解压后目录里没有DLL的话偶尔也会出现“找不到 libwinpthread-1.dll”之类错误。这时候补充安装 MSYS2 运行时或者换用较新版本的工具链包即可解决。另外一个常见疑虑WSL 里能直接跑 Windows 版工具链吗可以WSL 能调用 Windows 下的 exe但路径转换比较复杂不如直接在 WSL 官网下载 Linux 版的 RISC-V 工具链一条sudo apt install gcc-riscv64-unknown-elf就搞定。不过 Linux 版和 Windows 版编译出的二进制是等价的最终跑在芯片上没有区别所以选哪个平台只是个顺手问题真到了项目协作阶段统一用 CI 镜像比如 Docker 里的 riscv64 toolchain会给团队省不少事。Keil、IAR 这类 IDE 用户不要试图用 K210 的 GCC 工具链替代它们的编译器IDE 里工程格式、启动文件组织方式完全不一样老老实实遵循官方 SDK 的 cmake 路线反而最快。5. Windows 下必须处理的四个环境坑位从 PATH 截断到杀毒软件误隔离配环境这件事90% 的报错不是工具链坏了而是环境没伺候好。我把这几年在 Windows 上配 K210 工具链踩过的坑集中列出来都是花了时间验证过的错误根因让后来的人少走弯路。5.1 报“不是内部或外部命令”第一个排查点是 PATH 而不是重装命令行提示riscv64-unknown-elf-gcc 不是内部或外部命令99% 的情况不是工具链损坏而是 PATH 没有生效。排查链路按顺序做重新打开 cmd输入echo %PATH%用肉眼找有没有你刚才加的C:\kendryte-toolchain\bin。如果找不到说明环境变量没保存或者改错层级了。如果能看到再dir C:\kendryte-toolchain\bin\riscv64-unknown-elf-gcc.exe这一步排除路径里多打了一个\或者大小写不匹配。检查你设置的 PATH 是不是系统变量里——有些用户在自己的用户变量里改了但当前 cmd 窗口是用管理员身份打开的系统变量的优先级并不涵盖所有用户会话。如果有人改了用户变量后发现能用但重启后又失效那个环境变量可能被杀毒软件归入了隔离区重启后进程被清了这是 Windows 平台特有的坑Linux 上少见。5.2 Windows PATH 变量 1024/2048 字符上限终极元凶这是 Windows 环境变量最著名的一个限制。微软从 Windows 10 1709 起对 Path 编辑器的“智能合并”做了一些处理但很多旧程序读注册表REG_EXPAND_SZ方式获取 PATH 时依然按 1024 字符截断处理。也就是说你确实在图形界面看到了新路径但 cmd 进程读到的是一个被截断的 PATH。解决办法不要依赖图形界面一个目录一个目录地加而是用命令行工具setx添加setx Path %Path%;C:\kendryte-toolchain\bin注意setx有写入长度限制约 1024 字符如果 PATH 本身就很长了先把 PATH 值导出来清理一遍再写入。做法是reg export HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment env.reg用文本编辑器把敌多余的重复项删掉再用管理员权限合并回注册表最后重启系统。这个过程花十分钟省下的是以后好几天的诡异排查。5.3 杀毒软件误隔离Windows Defender 与第三方杀软的联动误伤工具链里的二进制文件基本都是 GNU 工具链未经微软签名的版本被 Defender 误报完全可能。我的经历某次编译到一半cc1.exe被隔离了之后编译一直报“无法创建编译器进程”最后查杀毒软件的威胁历史才找到原因。处理方式在杀毒软件里添加排除目录把C:\kendryte-toolchain整个加入白名单。同时注意如果你在开发板上做 USB 复刻使用 MaixPy 的 USB 大容量存储模式某些国产安全软件会监控 U 盘读写无端把一些编译产物标记为可疑文件。遇到找不到原因的错误先打开“威胁历史记录”看一眼有没有工具链相关文件被隔离。5.4 cmake 找不到编译器缓存问题换过工具链版本之后经常遇到cmake 报找不到riscv64-unknown-elf-gcc但命令行手动运行完全没问题。原因在于 cmake 缓存的前一版路径。处理方法不是反复删 build 目录重来而是直接清一下 cmake 缓存rm -rf build cmake -S . -B build如果工程师在 VS Code 里用 CMake Tools 插件偶尔也要去设置里把cmake.cmakePath指到正确的位置。Cmake 搜索编译器时走的是CMAKE_C_COMPILER和CMAKE_CXX_COMPILER变量若你手动指定过这些变量优先级比环境变量高新的 PATH 配置根本不起作用这也是个很隐蔽的坑位。6. 用工具链版本信息判断新旧从 8.2.0 到官方支持周期工具链版本号8.2.0不是随便来的它是 GCC 的上游版本号。K210 芯片最初发布时2018年底RISC-V 工具链生态远不如今天当时整个 RISC-V 软件栈都处于早期阶段官方开发团队基于上游 GCC 8.2.0 打了一系列补丁发布了这个带-kendryte后缀的定制版本。值得了解的是官方在 2019 年后基本停止了 Kendryte 工具链的更新但 RISC-V 上游工具链xPack GNU RISC-V Embedded GCC、SiFive Freedom Tools一直有更新。如果你遇到老工具链编译缓慢、或某些 C 现代特性不支持比如完整的 filesystem 库可以考虑切换到新版的通用 RISC-V 工具链。官方 SDK 的代码兼容性做得不错2023 年之后的 RISC-V GCC 12 工具链编译旧 SDK 通常也都能过。不过切工具链有个注意点链接脚本里如果使用了旧的STARTUP语法新版链接器可能警告但不影响如果提示 undefined reference to__libc_init_array之类的符号需要在新工具链里额外加上-nostartfiles或者手动包含 crt 文件。另一个常见问题K210 芯片的内存只有 8MB SRAM6MB 通用 2MB AI编译时如果设置过高优化等级比如 -O3生成的二进制可能非常大或者间接产生不必要的栈消耗。这时合理使用-Os或-O2、并配合-ffunction-sections -fdata-sections -Wl,--gc-sections剔除无用段可以明显缩小固件体积。这也是嵌入式开发里“能省则省”的通用策略。关于版本下载渠道推荐在 GitHub 上搜kendryte-toolchain有些第三方镜像会提供 8.2.0 和 2020 年后的 10.2.0 版本。下载时注意核对 sha256 校验值避免解压过程损坏。7. 新工具链替换与项目迁移从 riscv64-unknown-elf 到 riscv64-none-elf近年官方和社区逐步推动 RISC-V 工具链命名规范统一很多新版工具链不再叫riscv64-unknown-elf-gcc而是改成了riscv64-none-elf-gcc。这里的none取代unknown在语义上是“无特定操作系统裸机运行”的意思。如果你手里的压缩包名字从kendryte-...换成了xpack-riscv-none-elf-gcc你的项目迁移只需要改几处变量不用推倒重来。第一步把 cmake 变量里的编译器前缀从riscv64-unknown-elf-换成riscv64-none-elf-比如 kendryte-toolchain.cmake 里set(CMAKE_C_COMPILER riscv64-none-elf-gcc)或者直接在编译命令里减短为cmake .. -DCMAKE_TOOLCHAIN_FILE... -DCMAKE_C_COMPILERriscv64-none-elf-gcc第二步某些新版工具链对-march的默认值做了调整需要明确指定-marchrv64imafdc -mabilp64d。K210 的 CPU 是单核 RV64IMAFDC不支持向量扩展如果你在代码里用了__riscv_vector相关头文件编译会报错删掉即可。第三步新版工具链里的 Newlib 可能用--specsnano.specs或--specsnosys.specs来裁剪标准库。K210 裸机环境建议用nano.specs减少固件体积但注意它不支持完整的printf浮点格式化输出。如果你需要打印浮点变量到串口最佳方案是手动用snprintf处理浮点或者实现一个_write系统调用重定向到串口。迁移完之后重新编译大概率会看到新工具链编译速度更快、错误信息更友好。很多旧版本编译时经常出现的misaligned address、internal compiler error在新版里都不太出现了算是额外福利。8. 说多了都是泪三个快速定位问题的实战诊断思路这一节分享我从实际排错中总结出来的诊断思路比直接给你命令更有复用价值。8.1 串口烧录失败先分清是驱动、硬件还是波特率烧录失败的报错常见有Failed to open serial port、timeout、No response from chip三种。Failed to open serial port大概率串口驱动没装CH340/CP2102 驱动确认好或串口号被别的程序占用尤其是 Arduino IDE 的串口监视器关掉它。timeout或者No response可能是烧录命令里的数据格式不对或者芯片没能进入下载模式。K210 进入下载模式的动作通常是按住 BOOT 键对应 IO16 拉低→ 按一下复位键 → 松开 BOOT 键此时再执行 kflash.py 才有效。顺序反了也不行。波特率参数怎么选默认官方给 1500000但如果你得线材质量差跑高速会不丢降到 115200 通常会稳定。另外注意 kflash.py 支持-b 2000000但前提是你的 USB 转串口芯片确定支持否则有烧一半掉链子的风险。8.2 编译通过但上电无反应先查启动地址如果你编译完全正常烧录也提示成功但开发板没有任何反应第一个要检查的就是链接脚本里的入口地址。K210 的 Flash 加载地址从 0x80000000也就是 kFlash 的起始地址开始映射如果你的代码被链接到了 0x00000000上电后芯片从 Flash 首地址取到的指令是空的自然没有任何输出。用riscv64-unknown-elf-objdump -d hello_world.elf | head -n 30可以看到开头是否形如0000000080000000 _start:只有看到 0x80000000 开头说明链接器地址布局正确。这是嵌入式开发中“地址就是一切”的集中体现也是新入行的人最容易忽略的地方之一。8.3 函数执行结果异常但代码逻辑看着没问题检查优化与栈溢出K210 的 SRAM 虽然有 8MB但裸机开发时默认栈大小可能只有几 KBSDK 里 link script 定义STACK_SIZE 0x4000也就是 16KB。如果你用了大量局部数组比如几千字节的 unsigned char buffer或者在中断服务函数里放了较大局部变量栈溢出非常隐蔽具体表现为特定代码路径偶尔跑飞、程序一会儿正常一会儿复位。排查方案是编译时加-fstack-usage生成每个函数的栈使用量报告再通过-Wl,--defsym__stack_size0x8000调大主栈。一定要量化、看数据而不是凭直觉乱改。如果你在 Windows 下折腾时遇到报错把命令行里报错的具体行号和 cpp 源文件先用 Linux/WSL 交叉验证一遍很多时候不是工具链问题而是代码未定义行为触发编译器优化差异——这种问题在 Windows 端的表现往往更诡异跑到 WSL 下能看到更清晰的对齐警告。学会把这些坑位都提前规避掉K210 从配环境到跑 demo 就是一个顺手的事。开发路上祝顺利。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进