1. 中科蓝讯RV32开发环境搭建:从选型到跑通的完整思路
中科蓝讯的RV32系列芯片在蓝牙音频、TWS耳机、智能穿戴这些领域出货量非常大,很多做嵌入式音频产品的团队都在用它。但第一次接触这套工具链的人,十有八九会在环境搭建这一步卡住——不是编译器找不到,就是CodeBlocks启动报错,再不然就是编译出来的固件烧进去没反应。我自己前前后后搭过五六套中科蓝讯的开发环境,从最早的纯命令行到后来配CodeBlocks做IDE,踩过的坑基本能写一本小册子。这篇内容就是把这些经验整理出来,给正在折腾RV32-Toolchain和CodeBlocks 17.12的朋友一个可以直接抄的作业。
先说清楚这套环境到底解决什么问题。中科蓝讯的RV32内核用的是RISC-V 32位指令集,官方提供的工具链是基于GCC的定制版本,包含riscv32-unknown-elf-gcc、objcopy、objdump、gdb这些标准组件。CodeBlocks 17.12在这里的角色是一个轻量级的C/C++ IDE,它本身不参与编译,只是调用外部工具链来完成构建。所以整个环境的核心其实是两件事:第一,把RV32-Toolchain正确安装并让系统能找到它;第二,把CodeBlocks配置成能调用这套工具链的编辑器。听起来简单,但实际操作中,路径里的空格、中文目录、环境变量顺序、CodeBlocks自带的MinGW冲突,每一个都能让你折腾半天。
适合谁来参考这篇内容?如果你是中科蓝讯方案开发的初学者,或者从其他MCU平台(比如STM32、ESP32)转过来做RISC-V音频开发,又或者你已经在用命令行编译但想换成IDE提高效率,那这篇内容基本能覆盖你90%的需求。我假设你用的是Windows系统,因为CodeBlocks 17.12在Windows下的坑最多,Linux下反而简单很多。下面我会按照“先理清思路,再拆解细节,然后完整实操,最后排查问题”的顺序来讲,每一部分都尽量把“为什么这么做”说清楚,而不是只给一堆步骤让你照抄。
2. 工具链与IDE的选型逻辑:为什么是CodeBlocks 17.12加RV32-Toolchain
2.1 为什么不用官方推荐的IDE或者VS Code
中科蓝讯官方其实提供过基于Eclipse的定制IDE,但那个版本比较老,界面卡顿不说,有时候还会和Windows的杀毒软件打架。VS Code虽然现在很流行,但配置RISC-V工具链需要装一堆插件,对于只想快速编译烧录的音频方案开发者来说,学习成本偏高。CodeBlocks 17.12的好处是它足够轻量,安装包不到100MB,启动速度快,而且它的自定义编译器功能非常直接——你只需要告诉它编译器路径、编译参数、链接参数,它就能干活。对于RV32这种需要频繁修改Makefile或者自定义编译选项的场景,CodeBlocks的“自定义编译器”配置比VS Code的tasks.json要直观得多。
还有一个很实际的原因:很多中科蓝讯的方案商提供的SDK里,示例工程就是基于CodeBlocks的.cbp文件组织的。你直接用CodeBlocks打开就能看到完整的工程结构,编译按钮一点就出固件,省去了自己写构建脚本的麻烦。当然,如果你习惯用Makefile,CodeBlocks也支持自定义Makefile构建,灵活性是够的。
2.2 RV32-Toolchain的版本选择与来源
中科蓝讯的RV32-Toolchain通常随SDK一起提供,文件名类似riscv32-unknown-elf-gcc-xxx-windows.zip。这里有一个关键点:不要自己去RISC-V官网下载通用的工具链,因为中科蓝讯的芯片在指令集扩展和链接脚本上有定制,通用工具链编译出来的固件可能跑不起来。我试过一次用官方开源工具链编译,结果链接阶段就报错,提示找不到某些符号,后来换回SDK自带的工具链才解决。
工具链的版本号一般对应GCC的版本,比如gcc version 8.3.0或者10.2.0。不同SDK版本可能要求不同的工具链版本,这个在SDK的Release Note里通常会写。如果你拿到的工具链和SDK不匹配,最常见的表现是编译通过但运行异常,或者链接时提示relocation truncated to fit之类的错误。所以第一步一定是确认SDK文档里指定的工具链版本,不要随意混用。
2.3 CodeBlocks 17.12的安装包选择:带不带MinGW
CodeBlocks的下载页面会给你两个选项:带MinGW的版本和不带MinGW的版本。这里我的建议非常明确:下载不带MinGW的版本。原因很简单,中科蓝讯的RV32-Toolchain本身就是一套完整的GCC工具链,它包含了编译器、链接器、标准库。如果你装了带MinGW的CodeBlocks,系统里就会有两套GCC,环境变量一冲突,CodeBlocks可能调用到MinGW的gcc而不是RV32的gcc,编译出来的就是x86代码,烧到芯片上肯定跑不了。
不带MinGW的CodeBlocks安装包大概30MB左右,安装过程也很干净,不会往系统里塞一堆你不需要的东西。安装路径建议用纯英文,比如C:\CodeBlocks,不要放在Program Files下面,因为路径里的空格有时候会让工具链的参数解析出问题。我遇到过有人装在C:\Program Files (x86)\CodeBlocks,结果编译时提示找不到crt0.o,折腾了一下午才发现是路径空格导致的。
3. 安装过程中的核心细节与避坑要点
3.1 RV32-Toolchain的解压与路径设置
拿到工具链的压缩包后,解压到一个纯英文、无空格的路径下,比如C:\RV32-Toolchain。解压完成后,目录结构通常是这样的:
C:\RV32-Toolchain\ ├── bin\ │ ├── riscv32-unknown-elf-gcc.exe │ ├── riscv32-unknown-elf-objcopy.exe │ ├── riscv32-unknown-elf-objdump.exe │ └── ... ├── lib\ ├── include\ └── ...接下来要把C:\RV32-Toolchain\bin添加到系统的PATH环境变量里。这一步的目的是让命令行和CodeBlocks都能直接找到riscv32-unknown-elf-gcc这个命令,而不需要写完整路径。添加方法:右键“此电脑”->属性->高级系统设置->环境变量->在“系统变量”里找到Path->编辑->新建->填入C:\RV32-Toolchain\bin->确定。
注意:添加PATH之后一定要重启CodeBlocks,如果CodeBlocks已经打开,它不会自动刷新环境变量。更稳妥的做法是添加完PATH后重启一次电脑,确保所有进程都能读到新的环境变量。
验证工具链是否安装成功:打开命令提示符(cmd),输入riscv32-unknown-elf-gcc -v,如果能看到GCC的版本信息,说明PATH设置正确。如果提示“不是内部或外部命令”,那就是PATH没生效,检查路径是否写错,或者有没有多余的空格。
3.2 CodeBlocks 17.12的安装与首次启动配置
CodeBlocks的安装基本是下一步下一步,但有两个地方要注意。第一,安装组件选择时,只勾选“Code::Blocks主程序”和“中文语言包”(如果需要汉化),不要勾选任何编译器相关的组件。第二,安装完成后首次启动,CodeBlocks会弹出一个“编译器自动检测”的对话框,它会扫描系统里的编译器。这时候你可能会看到它检测到了MinGW或者Visual Studio的编译器,不要选这些,直接点“Skip”跳过。因为我们后面要手动配置RV32的工具链,自动检测的编译器对我们没用。
跳过自动检测后,进入CodeBlocks主界面。如果是英文界面,可以通过Settings -> Environment -> View -> Internationalization选择中文语言包来汉化。汉化包通常在安装目录的share\CodeBlocks\locale\zh_CN下,如果没有,可以去CodeBlocks的官方论坛找对应的语言包文件。
3.3 那个烦人的“thesaurus files not found”报错怎么处理
很多人第一次启动CodeBlocks 17.12时会看到一个弹窗,提示thesaurus files '\spellchecker\th_en_us.idx' not found。这个报错不影响编译,但每次启动都弹出来很烦人。它的原因是CodeBlocks的拼写检查插件找不到英语词库文件。解决方法有两个:一是直接禁用拼写检查插件,在Plugins -> Manage plugins里找到SpellChecker,把它禁用;二是下载对应的词库文件放到指定目录。我一般直接用第一种方法,因为写嵌入式代码根本用不到拼写检查,禁用掉最省事。
如果你不想禁用插件,也可以去CodeBlocks的安装目录下,找到share\CodeBlocks\SpellChecker文件夹,把th_en_us.idx和th_en_us.dic两个文件放进去。这两个文件在网上可以找到,但要注意版本匹配,不然还是会报错。
4. 在CodeBlocks中配置RV32自定义编译器的完整实操
4.1 新建自定义编译器配置
打开CodeBlocks,进入Settings -> Compiler,在“Selected compiler”下拉框里选择GNU GCC Compiler,然后点“Copy”按钮,给它起个名字,比如RV32-GCC。这一步的目的是基于GCC的默认配置创建一个副本,我们在这个副本上修改,不会影响原来的GCC配置。
创建完成后,切换到Toolchain executables标签页。这里是最关键的地方,需要把每个工具的执行文件路径指向RV32-Toolchain的bin目录。具体配置如下:
| 配置项 | 填写内容 |
|---|---|
| Compiler's installation directory | C:\RV32-Toolchain |
| C compiler | riscv32-unknown-elf-gcc.exe |
| C++ compiler | riscv32-unknown-elf-g++.exe |
| Linker for dynamic libs | riscv32-unknown-elf-g++.exe |
| Linker for static libs | riscv32-unknown-elf-ar.exe |
| Debugger | riscv32-unknown-elf-gdb.exe |
| Resource compiler | 留空 |
| Make program | mingw32-make.exe(如果SDK用Makefile构建) |
注意“Compiler's installation directory”只需要填到工具链的根目录,CodeBlocks会自动去bin子目录下找对应的可执行文件。如果你填了C:\RV32-Toolchain\bin,反而可能找不到,因为CodeBlocks会再拼一次bin。
4.2 编译选项与链接参数的设置
切换到Compiler settings标签页,这里需要根据中科蓝讯SDK的要求来设置。一般来说,RV32的编译选项包括:
-march=rv32imc:指定指令集架构,rv32imc表示支持整数、乘除法、压缩指令-mabi=ilp32:指定ABI,ilp32表示int、long、pointer都是32位-mcmodel=medany:指定代码模型,medany适合大多数嵌入式场景-Os:优化等级,音频方案通常用Os平衡性能和体积-ffunction-sections -fdata-sections:把每个函数和数据放到独立的段,方便链接器裁剪-Wall:打开常用警告
链接参数通常包括:
-T linker_script.ld:指定链接脚本,这个文件在SDK的工程目录里-Wl,--gc-sections:回收未使用的段,减小固件体积-nostartfiles:不使用标准启动文件,因为RV32的启动代码是SDK自己提供的-Wl,-Map=output.map:生成map文件,方便分析内存布局
这些参数不是固定的,具体要看SDK里的Makefile或者工程配置。我的建议是先把SDK自带的示例工程编译一遍,看看它的编译命令是什么,然后把这些参数原样填到CodeBlocks里。
4.3 头文件与库文件的搜索路径
在Search directories标签页里,需要添加SDK的头文件路径和库文件路径。头文件路径通常包括:
- SDK的
include目录 - SDK的
components目录下的各个子模块 - 工程自身的
inc目录
库文件路径通常是SDK的lib目录,里面会有libaudio.a、libbt.a之类的静态库。添加完路径后,在Linker settings里把这些库文件按依赖顺序列出来。注意顺序很重要,被依赖的库要放在后面,比如libbt.a依赖libaudio.a,那就要写成-lbt -laudio。
5. 编译、烧录与调试的完整流程
5.1 用CodeBlocks打开SDK示例工程
中科蓝讯的SDK通常会提供一个.cbp文件,这就是CodeBlocks的工程文件。直接双击打开,CodeBlocks会自动加载工程结构。如果SDK没有提供.cbp文件,你也可以新建一个空工程,然后把源文件手动添加进去。新建工程时选择Empty project,编译器选择刚才创建的RV32-GCC。
工程打开后,先别急着编译。检查一下Project -> Build options里的编译器配置是否继承了我们刚才设置的RV32-GCC。有时候工程文件里会硬编码编译器名称,如果和你设置的不一致,需要手动改过来。
5.2 编译过程中的常见报错与解决
第一次编译大概率不会一帆风顺,下面这几个报错是我遇到最多的:
报错1:riscv32-unknown-elf-gcc: command not found
这个说明CodeBlocks没找到编译器。检查Toolchain executables里的路径是否正确,以及PATH环境变量是否生效。如果PATH没问题,试试在CodeBlocks的Compiler settings -> Other settings里,把Compiler's installation directory的路径手动写死,不要用相对路径。
报错2:cannot find -lxxx
链接阶段找不到某个库。检查Linker settings里的库文件名是否正确,以及Search directories -> Linker里的库路径是否包含了库文件所在的目录。注意库文件名要去掉lib前缀和.a后缀,比如libaudio.a要写成-laudio。
报错3:relocation truncated to fit: R_RISCV_HI20 against symbol xxx
这个通常是代码模型或者链接脚本的问题。试试把-mcmodel=medany改成-mcmodel=medlow,或者检查链接脚本里的内存区域定义是否超出了芯片的实际地址范围。
报错4:undefined reference to '_start'
链接器找不到入口点。检查链接脚本里是否定义了ENTRY(_start),以及启动文件start.S是否被正确编译和链接。有时候是因为-nostartfiles参数导致标准启动文件被排除,但SDK的启动文件又没被加进来。
5.3 烧录工具的使用与注意事项
编译生成的固件通常是.bin或者.elf格式。中科蓝讯的烧录工具一般叫Downloader或者BurnTool,具体名称看SDK版本。烧录时需要注意:
- 芯片要进入烧录模式,通常是按住某个按键再上电,或者通过串口发送特定命令
- 烧录工具的串口号要选对,波特率一般是115200或者921600
- 烧录前最好先擦除芯片,避免旧固件残留导致异常
- 烧录完成后要复位芯片,有些工具会自动复位,有些需要手动断电再上电
提示:如果烧录后芯片没反应,先用
riscv32-unknown-elf-objdump -d output.elf反汇编一下,看看入口地址的指令是否正确。有时候是链接脚本里的地址写错了,导致固件被烧到了错误的Flash位置。
6. 常见问题速查与独家避坑经验
6.1 环境搭建阶段的高频问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| CodeBlocks启动报thesaurus文件缺失 | 拼写检查插件找不到词库 | 禁用SpellChecker插件或放入词库文件 |
| 编译提示找不到riscv32-unknown-elf-gcc | PATH未生效或路径错误 | 检查PATH,重启CodeBlocks或电脑 |
| 编译通过但烧录后无反应 | 工具链版本不匹配或链接脚本错误 | 换回SDK自带工具链,检查链接脚本 |
| 链接报relocation truncated to fit | 代码模型或内存地址范围问题 | 改-mcmodel参数,检查链接脚本 |
| 找不到-lxxx库 | 库路径或库名错误 | 检查Linker settings和搜索路径 |
| CodeBlocks调用到了MinGW的gcc | 系统里有多个GCC,PATH顺序问题 | 把RV32的bin目录移到PATH最前面 |
| 中文注释导致编译报错 | 文件编码不是UTF-8 | 把源文件保存为UTF-8无BOM格式 |
| 工程打开后编译器显示为GNU GCC | 工程文件里硬编码了编译器名称 | 在Project build options里改成RV32-GCC |
6.2 那些文档里不会写的实操心得
第一个心得:工具链路径千万不要有中文和空格。我见过有人把工具链解压到“D:\新建文件夹\RV32工具链”下面,结果编译时各种奇怪的报错,折腾了半天才发现是路径问题。Windows下虽然理论上支持中文路径,但GCC的工具链对路径的处理有时候会出问题,尤其是涉及到临时文件生成的时候。所以从一开始就用纯英文路径,能省掉后面很多麻烦。
第二个心得:CodeBlocks的工程文件不要放在SDK的只读目录下。有些SDK是从压缩包里直接打开的,目录属性是只读的。CodeBlocks在编译时会生成.o文件和.d依赖文件,如果目录只读,编译就会失败。把整个SDK复制到一个可读写的目录下再打开工程。
第三个心得:编译参数里的优化等级不要随便改。音频方案对实时性要求高,-O0编译出来的代码体积大、运行慢,可能导致音频卡顿。-O3又可能因为过度优化导致某些时序敏感的代码出问题。SDK默认给的-Os是经过验证的,没有特殊需求不要动。
第四个心得:善用map文件分析内存占用。编译时加上-Wl,-Map=output.map,然后打开map文件,可以看到每个函数和变量占用了多少空间,Flash和RAM的剩余量是多少。如果RAM快满了,就要考虑优化数据结构或者把一些常量放到Flash里。
第五个心得:调试时优先用串口打印,不要一上来就上GDB。RV32的GDB调试需要JTAG调试器,而且配置起来比较麻烦。大多数情况下,在代码里加几个printf,通过串口输出调试信息,效率反而更高。中科蓝讯的SDK通常已经封装好了串口打印函数,直接调用就行。
6.3 关于CodeBlocks汉化和插件的一些补充
CodeBlocks 17.12的汉化包在网上有很多版本,建议去官方论坛下载对应版本的汉化文件,不要随便找个汉化包就用。版本不匹配的汉化包可能导致菜单显示不全或者CodeBlocks崩溃。汉化方法:把zh_CN文件夹放到CodeBlocks安装目录\share\CodeBlocks\locale\下,然后在Settings -> Environment -> View里选择中文。
插件方面,CodeBlocks自带的Code completion插件对RISC-V的头文件支持一般,有时候补全不准。如果你需要更好的代码补全,可以试试Clangd插件,但配置起来稍微复杂一些。对于大多数嵌入式开发场景,自带的补全够用了,不用折腾。
7. 从命令行到IDE:两种构建方式的取舍与配合
7.1 命令行构建的优势与适用场景
虽然这篇内容主要讲CodeBlocks,但我想说的是,命令行构建在某些场景下反而更方便。比如你要做持续集成,或者需要在多台机器上批量编译,命令行一条make命令就能搞定,不需要打开IDE。中科蓝讯的SDK通常都带Makefile,直接在SDK根目录下执行make就能编译。
命令行构建的另一个好处是错误信息更清晰。CodeBlocks的编译输出窗口有时候会把错误信息截断,或者因为编码问题显示乱码。命令行下直接看gcc的输出,什么问题一目了然。我一般是在CodeBlocks里写代码,遇到编译错误时切到命令行跑一遍make,看完整的错误信息。
7.2 在CodeBlocks中调用外部Makefile
如果你既想用CodeBlocks的编辑器,又想用SDK自带的Makefile,可以在CodeBlocks里配置“自定义Makefile”。具体做法:Project -> Properties -> Build targets,把Type改成Makefile,然后在Make commands里填写make命令。这样点击编译按钮时,CodeBlocks会调用外部make程序来构建,而不是用它自己的构建系统。
这种方式的优点是兼顾了IDE的编辑体验和Makefile的灵活性。缺点是CodeBlocks的语法检查和高亮可能不完全准确,因为它不知道Makefile里定义的那些宏和包含路径。不过对于写代码来说,影响不大。
7.3 两种方式的配合使用建议
我的习惯是:日常开发用CodeBlocks,因为编辑、跳转、补全方便;发布版本或者排查编译问题时用命令行,因为输出信息完整、可脚本化。具体来说,在CodeBlocks里写好代码后,按Ctrl+S保存,然后切到命令行执行make clean && make,确认编译通过后再回到CodeBlocks里做其他操作。这样既享受了IDE的便利,又保证了构建的可靠性。
还有一个小技巧:可以在CodeBlocks的Tools菜单里添加一个自定义工具,命令填cmd /c "cd /d $(PROJECT_DIR) && make",这样在CodeBlocks里点一下就能调用命令行编译,输出会显示在CodeBlocks的日志窗口里。配置方法:Settings -> Tools -> Add,填好名称和命令即可。
8. 环境验证与固件运行确认
8.1 用最小工程验证工具链是否正常
在正式开发之前,建议先建一个最小工程验证工具链是否工作正常。这个工程只需要一个main.c和一个链接脚本,main.c里写一个空循环:
int main(void) { volatile int i = 0; while (1) { i++; } return 0; }链接脚本里定义好Flash和RAM的地址范围,入口点设为main。编译这个工程,如果能在output目录下生成.elf和.bin文件,说明工具链基本正常。然后用objdump反汇编一下,看看main函数的指令是不是RISC-V指令(指令编码以0x开头的32位或16位数据)。如果反汇编出来是x86指令,那说明CodeBlocks调用错了编译器。
8.2 烧录后的运行确认方法
固件烧录后,怎么确认它真的在运行?最直接的方法是看串口输出。在main函数开头加一句串口打印,比如printf("RV32 boot ok\n"),然后打开串口助手,波特率设成和代码里一致,复位芯片,看能不能收到打印信息。如果收到了,说明固件至少跑到了main函数。
如果串口没输出,先检查硬件连接:TX和RX是不是接反了,波特率是不是对,串口助手是不是打开了正确的串口号。硬件没问题的话,再检查软件:时钟初始化是不是正确,串口引脚配置是不是对,打印函数是不是被优化掉了(用volatile修饰或者降低优化等级试试)。
8.3 性能与资源占用的初步评估
固件跑起来之后,可以进一步评估资源占用。用riscv32-unknown-elf-size output.elf命令查看Flash和RAM的使用量:
text data bss dec hex filename 12345 678 9012 22035 5613 output.elftext是代码段大小,data是已初始化数据段,bss是未初始化数据段。Flash占用通常是text + data,RAM占用是data + bss。对比芯片的Flash和RAM容量,看看还剩多少余量。如果余量不足10%,后续加功能就要小心了。
音频方案还要关注CPU占用率。中科蓝讯的SDK通常提供了CPU负载统计的接口,可以在主循环里定期打印出来。如果CPU占用率长期超过80%,音频播放可能会出现卡顿或断音,需要优化代码或者降低采样率。
9. 一些关于版本管理和团队协作的建议
9.1 工具链和SDK的版本锁定
团队开发时,工具链和SDK的版本一定要统一。我见过因为两个人用的工具链版本不一样,导致同一個工程一个人编译通过另一个人编译报错的情况。建议在项目文档里明确记录工具链的版本号、SDK的版本号、CodeBlocks的版本号,最好把工具链的压缩包也放到版本控制里(如果体积允许的话)。
如果工具链太大不方便入库,至少要把版本号和下载链接记录下来。新成员加入时,按照文档一步步装,能避免很多“我这里怎么不行”的问题。
9.2 CodeBlocks工程文件的版本控制
CodeBlocks的.cbp文件和.layout文件是可以入库的,但.depend和.o文件不要入库。.cbp文件里记录了工程的源文件列表、编译选项、搜索路径等信息,入库后其他成员拉下来就能直接打开。.layout文件记录了窗口布局,入不入库都行,看团队习惯。
需要注意的是,.cbp文件里的路径如果是绝对路径,换一台电脑可能就失效了。建议在CodeBlocks里把路径设置成相对路径,具体做法:Project -> Properties -> Build targets,把Output filename和Objects output dir改成相对路径,比如bin\output.elf和obj\。这样工程在不同电脑上都能正常编译。
9.3 团队共享的编译脚本
如果团队里有人用命令行、有人用IDE,可以写一个统一的编译脚本,比如build.bat,里面封装好工具链路径和编译参数。CodeBlocks里配置调用这个脚本,命令行下也执行这个脚本,保证两边编译结果一致。脚本内容大概是这样:
@echo off set TOOLCHAIN=C:\RV32-Toolchain\bin set PATH=%TOOLCHAIN%;%PATH% riscv32-unknown-elf-gcc -march=rv32imc -mabi=ilp32 -Os -c main.c -o main.o riscv32-unknown-elf-gcc -T linker.ld main.o -o output.elf riscv32-unknown-elf-objcopy -O binary output.elf output.bin这个脚本虽然简单,但能保证编译环境的一致性。新成员只需要改一下TOOLCHAIN变量指向自己的工具链路径就行。
10. 后续扩展:从环境搭建到量产固件
环境搭好只是第一步,后面还有很长的路要走。比如怎么优化音频算法的CPU占用,怎么配置蓝牙协议栈的参数,怎么做OTA升级,这些都需要在稳定的开发环境基础上逐步深入。我的建议是,环境搭建完成后,先花时间把SDK里的示例工程都跑一遍,理解每个模块的初始化和调用流程,然后再动手改代码。不要一上来就大改,那样出了问题很难定位是环境问题还是代码问题。
另外,中科蓝讯的芯片型号很多,不同型号的RV32核配置可能略有差异,比如有的带FPU,有的不带,有的Flash大有的Flash小。在搭建环境时,要确认工具链的编译参数和芯片型号匹配。比如带FPU的型号需要加-march=rv32imfc,不带FPU的就不能加f扩展,否则编译出来的指令芯片不认。
我在实际项目中的体会是,环境搭建这件事,第一次做最痛苦,但只要把工具链路径、编译参数、链接脚本这三个东西搞清楚了,后面换芯片型号或者换SDK版本,基本就是改几个参数的事。所以第一次搭建时不要怕麻烦,把每个配置项都弄明白为什么这么设,后面会省很多时间。