2. 开发环境搭建:Keil/IAR工程配置、链接脚本修改、启动文件定制
好,咱们正式开始动手。这一章我带你把开发环境搭起来。别小看这一步,我见过太多人代码写好了,结果工程配置不对,链接脚本没改,启动文件还是原厂的——最后Bootloader跑不起来,还以为是代码有bug。
说白了,环境搭对了,后面就顺了。搭不对,你查三天都查不出问题。
2.1 开发工具选择与版本说明
我个人习惯用Keil MDK做ARM Cortex-M系列的开发。IAR也不错,但咱们课程以Keil为主,IAR的配置我会在关键地方提一下差异。
| 工具 | 推荐版本 | 说明 |
|---|---|---|
| Keil MDK | 5.38 及以上 | 支持AC6编译器,代码密度更好 |
| IAR EWARM | 8.50 及以上 | 优化能力强,调试体验好 |
| STM32CubeMX | 6.10 及以上 | 用于生成初始化代码和链接脚本模板 |
2.2 Keil工程配置要点
创建一个Bootloader工程,和普通应用工程不一样。你需要关注几个关键点。
2.2.1 目标芯片与Flash分区
先确定你的芯片型号。我用STM32F103C8T6举例,它有个特点:Flash只有64KB,但实际能用到128KB(嗯,这是ST的"福利")。不过咱们按64KB来规划。
- Bootloader区:0x08000000 ~ 0x08003FFF,16KB
- 应用区:0x08004000 ~ 0x0800FFFF,48KB
- 参数区:0x0800FC00 ~ 0x0800FFFF,1KB(存升级标志和校验值)
2.2.2 编译器选项设置
在Keil里,点开Options for Target,这几个地方必须改:
- Target标签:ROM1起始地址填0x08000000,大小0x4000(16KB)。RAM不用动。
- C/C++标签:Optimization选-O2或-Oz。我建议用-Oz,代码更小。
- Linker标签:取消勾选"Use Memory Layout from Target Dialog",改用自定义链接脚本。
关键一步:取消"Use Memory Layout from Target Dialog"后,Keil会使用工程目录下的.sct文件作为链接脚本。这个文件你得自己改。
2.3 链接脚本修改(.sct / .icf)
链接脚本决定了你的代码和数据怎么放。Bootloader的链接脚本和普通应用不一样,因为它的起始地址不是0x08000000吗?不对,Bootloader的起始地址就是0x08000000,但应用的要偏移。
咱们先看Bootloader的链接脚本。
2.3.1 Keil的.sct文件
; Bootloader链接脚本 - STM32F103C8T6
; Flash: 0x08000000 ~ 0x08003FFF (16KB)
; RAM: 0x20000000 ~ 0x20004FFF (20KB)
LR_IROM1 0x08000000 0x00004000 { ; load region
ER_IROM1 0x08000000 0x00004000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00005000 { ; RW data
.ANY (+RW +ZI)
}
}
这段脚本干了三件事:
- 把代码放在0x08000000开始的16KB空间
- 中断向量表放在最前面(RESET段)
- 可读写数据放在RAM里
2.3.2 IAR的.icf文件
IAR的语法不太一样,但逻辑相同:
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__ = 0x08003FFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x20004FFF;
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 };
2.4 启动文件定制
启动文件(startup_xxx.s)是芯片上电后执行的第一段代码。它做了三件事:
- 设置栈指针
- 初始化中断向量表
- 跳转到main函数
对于Bootloader,启动文件基本不用改。但有一个地方要注意:堆栈大小。
Bootloader的堆栈不需要太大,因为它的功能简单。我一般把堆设成0x200(512字节),栈设成0x400(1KB)。省下来的RAM可以给应用用。
; 修改启动文件中的堆栈大小
Stack_Size EQU 0x400
Heap_Size EQU 0x200
2.5 知识结构总览
下面这张图把整个环境搭建的脉络理清楚了。你照着这个顺序做,不会乱。
2.6 验证环境是否搭对
工程配好了,怎么知道对不对?我教你一个快速验证的方法。
- 编译工程,看生成的.hex文件大小。Bootloader应该在16KB以内。
- 用调试器下载,看芯片是否停在main函数入口。
- 查看反汇编,确认复位向量指向的是你的Reset_Handler。
快速检查:在Keil里按Ctrl+D进入调试模式,打开Disassembly窗口。看PC指针是不是停在0x08000000附近的Reset_Handler里。如果是,说明启动文件和链接脚本都对了。