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这种频繁上下文切换的场景,优化效果很明显。

我的建议: 如果你刚开始学,先用Keil。它的界面更友好,工程配置更直观。等你把RTOS跑通了,再试试IAR,感受一下差异。

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 安装步骤(精简版)

  1. 双击安装包,一路Next,注意安装路径不要有中文
  2. 安装完成后,打开Pack Installer,下载你需要的DFP包
  3. 配置License:File → License Management,输入你的激活码
  4. 验证:新建一个空工程,编译一下,不报错就OK
注意: 我曾经遇到过一个问题——装完Keil后,调试器死活连不上板子。查了半天,发现是驱动没装。如果你用J-Link,记得单独装SEGGER的驱动;用ST-Link的话,装STM32 ST-LINK Utility里的驱动。

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的文件夹结构保持一致
小技巧: 在IAR里,你可以把常用的工程配置保存为「模板工程」。下次新建项目时,直接复制这个模板文件夹,改个名字就能用。我手头有十几个不同芯片的模板,随用随取。

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 };
避坑指南: 我曾经在IAR里犯过一个低级错误——把CSTACK(调用栈)的大小设得太小,结果RTOS一跑多任务就死机。调试了整整两天,最后发现是栈溢出。所以,建议把CSTACK和HEAP都设大一点,比如CSTACK设0x1000(4KB),HEAP设0x2000(8KB)。等系统稳定了再慢慢调小。

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代码。先跑一个简单的「点灯」程序,验证整个工具链是否通畅。

  1. 新建工程,选好芯片
  2. 写一个main.c,里面就一个while(1)循环,翻转GPIO
  3. 编译,下载,看LED闪不闪
  4. 如果闪了,恭喜你,环境OK
  5. 如果不闪,检查:调试器驱动、芯片型号、下载算法、复位配置
我的习惯: 我会在工程模板里预置一个「硬件检测」函数,上电后自动检测LED、按键、串口。这样每次换板子,只要改一下BSP文件,就能快速验证硬件和软件环境是否匹配。

好了,这一章的内容就到这。环境搭好了,下一章我们就可以正式开始RTOS的移植了。记住,磨刀不误砍柴工,花点时间把开发环境整利索,后面会顺畅很多。