4、开发环境搭建:Keil MDK/IAR EWARM安装、工程模板创建、Linker Script配置
好,咱们正式开始动手了。
做RTOS移植,第一件事不是写代码,而是把家伙事儿备齐。我见过不少新手,上来就撸代码,结果编译不过、下载不了、调试器连不上,折腾半天发现是环境没配好。嗯,这其实挺浪费时间的。
这一章,我就带你一步步把Keil MDK和IAR EWARM这两个主流IDE装好,再建一个干净的工程模板,最后把Linker Script(链接脚本)也配明白。说白了,就是给你搭一个「想怎么折腾就怎么折腾」的开发基地。
4.1 为什么选Keil和IAR?
你可能会问:「用GCC不行吗?」当然行。但在我做过的几十个量产项目中,90%的客户都指定用Keil或IAR。原因很简单——调试体验好、编译优化成熟、技术支持到位。
我个人习惯是:Keil MDK 用来做ARM Cortex-M系列的快速原型验证,IAR EWARM 用来做最终产品的性能调优。为什么?因为IAR的编译器在代码密度和执行效率上确实有一手,尤其对FreeRTOS这种频繁上下文切换的场景,优化效果很明显。
4.2 Keil MDK安装与配置
Keil MDK的安装其实没什么玄学,但有几个坑我得提前跟你说。
4.2.1 版本选择
目前主流版本是MDK 5.38或5.39。别追最新版,有时候最新版对某些老芯片支持不好。我建议用5.36~5.38之间的版本,稳定。
- MDK-Core: 必装,这是IDE本体
- Device Family Packs: 根据你的芯片选,比如STM32F4系列就装Keil.STM32F4xx_DFP
- ARM Compiler: 默认会装AC6(基于LLVM),但如果你要做老项目兼容,可以保留AC5
4.2.2 安装步骤(精简版)
- 双击安装包,一路Next,注意安装路径不要有中文
- 安装完成后,打开Pack Installer,下载你需要的DFP包
- 配置License:File → License Management,输入你的激活码
- 验证:新建一个空工程,编译一下,不报错就OK
4.3 IAR EWARM安装与配置
IAR的安装比Keil稍微「矫情」一点。它的许可证管理比较严格,而且不同版本之间不能混用。
4.3.1 版本选择
我目前用的是IAR EWARM 9.40.1,对Cortex-M4/M7支持很好。如果你用M33或M55,建议上9.50以上版本。
4.3.2 安装要点
- 许可证: IAR有「节点锁定」和「浮动许可证」两种。个人开发用节点锁定就行
- 编译器选项: 安装时建议勾选「IAR C-SPY Debugger」,这是它的调试器,很好用
- 路径问题: 同样,不要有中文路径。IAR对路径里的空格也敏感,最好全英文
我记得有一次帮客户调一个RTOS任务优先级反转的问题,用Keil怎么都复现不了,换成IAR一跑就出来了。后来发现是Keil的优化选项把某些时序逻辑给「优化」掉了。所以,调试疑难杂症时,换个编译器往往有奇效。
4.4 工程模板创建
这一步很关键。一个好的工程模板,能让你后续的移植工作省下一半时间。
4.4.1 Keil工程模板结构
我个人习惯这样组织文件夹:
Project/
├── User/ # 用户代码(main.c, app.c等)
├── BSP/ # 板级支持包(GPIO, UART, SPI等驱动)
├── RTOS/ # RTOS源码(FreeRTOS或uC/OS)
├── CMSIS/ # CMSIS核心文件(core_cm4.h, system_stm32f4xx.c等)
├── Startup/ # 启动文件(startup_stm32f4xx.s)
├── Linker/ # 链接脚本(.icf或.sct文件)
└── Output/ # 编译输出(.hex, .bin, .map等)
在Keil里新建工程时,选择对应的芯片型号,然后把上述文件夹添加到工程组里。注意:启动文件和链接脚本一定要放在正确的位置,否则编译会报错。
4.4.2 IAR工程模板结构
IAR的工程管理方式和Keil略有不同。它用.ewp文件管理工程,用.eww文件管理工作空间。
我的做法是:
- 先创建一个空工作空间(.eww)
- 再添加一个工程(.ewp)
- 在工程选项里配置好芯片型号、编译器、调试器
- 然后手动添加源文件组,和Keil的文件夹结构保持一致
4.5 Linker Script配置
Linker Script,说白了就是告诉编译器:你的代码该放哪,数据该放哪,堆栈该放哪。
很多初学者觉得这步可以跳过,用默认的就行。但做RTOS移植时,链接脚本必须自己配。为什么?因为RTOS需要精确控制内存布局,比如任务栈放在哪里、MPU保护区域怎么划分。
4.5.1 Keil下的Linker Script(.sct文件)
Keil使用分散加载文件(Scatter File),后缀是.sct。默认情况下,Keil会自动生成一个,但我们需要手动修改。
一个典型的.sct文件长这样:
LR_IROM1 0x08000000 0x00100000 { ; 加载区,起始0x08000000,大小1MB
ER_IROM1 0x08000000 0x00100000 { ; 执行区,和加载区重叠(代码在Flash中运行)
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00020000 { ; RAM区,起始0x20000000,大小128KB
.ANY (+RW +ZI)
}
}
这里要注意:RTOS的任务栈通常放在RW_IRAM1区域。如果你用MPU,还需要单独划分出特权级和非特权级区域。
4.5.2 IAR下的Linker Script(.icf文件)
IAR用的是.icf文件,语法和.sct不同,但逻辑一样。
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__ = 0x080FFFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x2001FFFF;
place at address mem:__ICFEDIT_region_ROM_start__ { readonly section .intvec };
place in ROM_region { readonly };
place in RAM_region { readwrite, block HEAP, block CSTACK };
4.5.3 针对RTOS的特殊配置
做FreeRTOS移植时,链接脚本里需要额外注意两点:
- 堆空间: FreeRTOS的动态内存分配(heap_1到heap_5)都依赖一个大的堆区域。这个堆通常在链接脚本里定义为`__heap_start`和`__heap_end`,或者直接用`HEAP`段
- 中断向量表: 必须放在Flash的起始地址(0x08000000),且4字节对齐。如果用了Bootloader,向量表要重映射到RAM里
嗯,说到这里,我想起一个项目。当时做一款分拣机的控制板,用的STM32F407,FreeRTOS跑了8个任务。一开始链接脚本用的是默认配置,结果系统运行半小时后必死。后来用.map文件一查,发现是堆和栈重叠了。重新调整了.icf里的区域划分,问题解决。
所以,学会看.map文件,是调试链接问题的基本功。
4.6 验证环境是否搭好
环境搭完,别急着写RTOS代码。先跑一个简单的「点灯」程序,验证整个工具链是否通畅。
- 新建工程,选好芯片
- 写一个main.c,里面就一个while(1)循环,翻转GPIO
- 编译,下载,看LED闪不闪
- 如果闪了,恭喜你,环境OK
- 如果不闪,检查:调试器驱动、芯片型号、下载算法、复位配置
好了,这一章的内容就到这。环境搭好了,下一章我们就可以正式开始RTOS的移植了。记住,磨刀不误砍柴工,花点时间把开发环境整利索,后面会顺畅很多。