3. 开发环境搭建:ARM GCC工具链、OpenOCD调试器、VS Code工程配置

好,咱们正式开始动手了。这一章我带你搭开发环境。说实话,很多初学者把精力都花在写代码上,结果环境没配好,一编译全是红字,心态直接崩了。我当年刚入行时也踩过这个坑,折腾了一整天发现是路径配错了。

嵌入式开发的环境搭建,说白了就是三样东西:编译器(把C代码变成机器码)、调试器(把程序烧进去并跟踪运行)、编辑器(你写代码的地方)。咱们一个一个来。

3.1 ARM GCC工具链:从源码到二进制

ARM GCC,全称是 GNU Arm Embedded Toolchain。它是专门为ARM Cortex-M系列芯片准备的免费编译器。为什么不用Keil或IAR?因为咱们要做RTOS移植,需要完全掌控编译选项,而GCC是开源的,想怎么改都行。

我个人习惯用 gcc-arm-none-eabi 这个版本。注意名字里的「none」和「eabi」——「none」表示没有操作系统(bare-metal),「eabi」是嵌入式应用二进制接口标准。

3.1.1 下载与安装

去ARM官网下载最新版。我建议选 9.3.110.3-2021.10 这两个版本,稳定,踩坑少。下载后解压到一个没有中文和空格的路径,比如:

C:\arm-gcc\gcc-arm-none-eabi-10.3-2021.10

然后把 bin 目录加到系统环境变量 PATH 里。验证方法:打开命令行,输入:

arm-none-eabi-gcc --version

如果看到版本号,说明装好了。嗯,这里要注意:Windows用户记得用管理员权限打开命令行,否则环境变量可能不生效。我曾经因为这个浪费了半小时。

3.1.2 编译选项说明

咱们的牙刷主控是STM32F103系列,Cortex-M3内核。编译时常用的选项我列个表:

选项 说明 我的推荐值
-mcpu=cortex-m3 指定CPU内核 必须加,否则生成错误指令
-mthumb 使用Thumb指令集 Cortex-M只支持Thumb
-O2 优化等级 调试用-Og,发布用-O2
-ffunction-sections 每个函数独立段 配合链接器垃圾回收用
-fdata-sections 每个数据独立段 同上
小技巧: 调试阶段用 -Og 优化等级,它不会过度优化导致调试时变量值看不到。我刚开始用 -O2 调试,单步执行时变量全被优化掉了,查了半天才发现是优化等级的问题。

3.2 OpenOCD调试器:烧录与调试的瑞士军刀

OpenOCD(Open On-Chip Debugger)是一个开源调试工具。它支持各种调试器硬件(比如ST-Link、J-Link、CMSIS-DAP),也支持各种芯片。说白了,它就是你的电脑和芯片之间的翻译官。

3.2.1 安装OpenOCD

Windows用户建议直接下载预编译的二进制包。我常用的是 xpack-openocd 版本,更新及时,配置也简单。解压后同样把 bin 目录加到PATH。

验证方法:

openocd --version

3.2.2 配置文件编写

OpenOCD需要两个配置文件:一个是调试器接口配置,一个是目标芯片配置。咱们用ST-Link调试器,连接STM32F103,配置文件长这样:

# stlink.cfg
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/stm32f1x.cfg]

启动OpenOCD的命令:

openocd -f stlink.cfg

如果看到 Info : Listening on port 3333 for gdb connections,说明连接成功了。这时候芯片已经通过SWD接口和电脑连上了。

注意: 连接牙刷的PCB板时,一定要确认SWD接口的电压匹配。STM32F103是3.3V,ST-Link V2默认也是3.3V,但有些山寨调试器输出5V,直接烧芯片。我曾经烧坏过一块板子,就是因为没检查电压。

3.3 VS Code工程配置:让写代码变成享受

VS Code本身只是一个编辑器,但配上插件后,它就是最强的嵌入式IDE。我个人觉得比Keil好用多了——免费、轻量、插件生态丰富。

3.3.1 必备插件

  • C/C++(微软官方):语法高亮、智能提示、调试支持
  • Cortex-Debug:专门调试ARM芯片,配合OpenOCD使用
  • Makefile Tools:方便编译和构建
  • Hex Editor:查看二进制文件,调试时很有用

3.3.2 工程目录结构

我习惯这样组织代码:

toothbrush_rtos/
├── .vscode/          # VS Code配置
│   ├── launch.json   # 调试配置
│   ├── tasks.json    # 构建任务
│   └── c_cpp_properties.json  # 编译器路径
├── src/              # 源代码
│   ├── main.c
│   ├── rtos/         # RTOS内核源码
│   └── drivers/      # 外设驱动
├── startup/          # 启动文件
├── linker/           # 链接脚本
├── Makefile          # 构建脚本
└── openocd.cfg       # OpenOCD配置

3.3.3 launch.json配置

这是调试配置的核心。我直接贴一份能用的:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Cortex Debug",
            "type": "cortex-debug",
            "request": "launch",
            "servertype": "openocd",
            "cwd": "${workspaceRoot}",
            "executable": "./build/toothbrush.elf",
            "configFiles": [
                "openocd.cfg"
            ],
            "svdFile": "./STM32F103.svd"
        }
    ]
}

这里有个关键点:svdFile 是芯片的寄存器描述文件,有了它,调试时可以直接看外设寄存器的值,不用翻手册。STM32的SVD文件可以从ST官网下载。

3.3.4 tasks.json配置

Ctrl+Shift+B 就能编译,配置如下:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "make",
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}
核心思路: VS Code + Makefile + OpenOCD 这套组合,本质上就是把编译、烧录、调试三个环节串起来。你只需要按一个键(F5),代码自动编译、烧录、停在main函数入口。这才是嵌入式开发的正确姿势。

3.4 验证环境:点亮第一颗LED

环境搭好了,咱们写个最简单的程序验证一下。让牙刷上的LED闪烁:

#include "stm32f1xx.h"

void delay(void) {
    for(int i = 0; i < 1000000; i++);
}

int main(void) {
    // 使能GPIOC时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
    // 配置PC13为推挽输出
    GPIOC->CRH &= ~(0xF << 20);
    GPIOC->CRH |= (0x2 << 20);
    
    while(1) {
        GPIOC->BSRR = GPIO_BSRR_BS13;  // 亮
        delay();
        GPIOC->BSRR = GPIO_BSRR_BR13;  // 灭
        delay();
    }
}

编译、烧录、运行。如果LED开始闪烁,恭喜你,环境搭建成功了!

你想想看,从零开始,到LED闪烁,其实就三步:装编译器、配调试器、写代码。但每一步都有细节,稍不注意就卡住。我当年第一次配OpenOCD,折腾了整整一个周末,最后发现是配置文件里少写了一个 source 命令。

好了,环境搭好了,下一章咱们开始真正移植RTOS内核。到时候你会看到,这些工具会发挥巨大的作用。