Zig 工具链编译 STM32 开发指南

Zig 工具链编译 STM32 开发指南

参考仓库 :ZigEmbeddedGroup/stmicro-stm32

本项目为 STM32 提供 Zig 嵌入式开发支持,全程使用 Zig 原生工具链,无需额外安装 ARM GCC 交叉编译器。

目录

  1. 环境准备
  2. [仓库与 build.zig 简介](#仓库与 build.zig 简介)
  3. 编译官方示例工程
  4. 固件烧录(ST-Link)
  5. [基于 build.zig 创建自定义工程](#基于 build.zig 创建自定义工程)
  6. [调试:OpenOCD + Zig GDB](#调试:OpenOCD + Zig GDB)
  7. 常见问题
  8. 参考资料

1. 环境准备

1.1 安装 Zig

访问 Zig 官网下载对应操作系统的 Zig 二进制包,推荐使用仓库兼容的稳定版本。

Zig 内置交叉编译能力,不需要单独安装 arm-none-eabi-gcc。

验证安装:

bash 复制代码
zig version

1.2 克隆 stmicro-stm32 仓库

bash 复制代码
git clone https://github.com/ZigEmbeddedGroup/stmicro-stm32.git
cd stmicro-stm32

仓库目录结构:

text 复制代码
stmicro-stm32/
├── build.zig           # 核心构建脚本
├── build.zig.zon       # 依赖清单
├── src/                # 芯片寄存器定义、启动文件、底层支持
├── examples/           # 示例项目(blink 点灯等)
└── README.md

2. 仓库与 build.zig 简介

build.zig 是 Zig 的构建脚本,作用等同于 C/C++ 开发中的 CMakeLists.txt 或 Makefile。仓库内 build.zig 主要完成以下工作:

  • 定义嵌入式目标架构 :ARM Cortex-M(thumbv7m-none-eabi)
  • 加载链接脚本 :引入 .ld 文件,配置 Flash、RAM 内存地址布局
  • 引入底层文件:加载芯片启动汇编文件、寄存器定义
  • 设置编译选项:配置无标准库(freestanding)、优化等级、链接垃圾回收
  • 自动生成固件 :输出 .elf 和 .bin 文件

注意:嵌入式环境为 freestanding,不依赖 libc。


3. 编译官方示例工程

bash 复制代码
# 指定示例 blink + 指定芯片 stm32f103c8t6
zig build -Dexample=blink -Dchip=stm32f103c8t6

参数说明:

  • -Dexample=xxx:选择 examples/ 目录下的示例名称
  • -Dchip=xxx:指定 STM32 芯片型号

3.2 编译产物说明

编译输出目录位于 zig-out/firmware/:

  • firmware.elf:带调试信息的 ELF 文件,用于 GDB 调试
  • firmware.bin:纯二进制固件,用于烧录到芯片 Flash

查看产物命令:

bash 复制代码
ls zig-out/firmware/

4. 固件烧录(ST-Link)

安装 stlink 工具集后,使用 st-flash 进行烧录。

bash 复制代码
# 将 bin 固件烧录到 STM32 Flash 起始地址 0x08000000
st-flash write zig-out/firmware/firmware.bin 0x8000000

# 复位芯片,运行程序
st-flash reset

备选方案:也可以使用 OpenOCD 进行烧录。


5. 基于 build.zig 创建自定义工程

新建工程最简 build.zig 模板如下:

zig 复制代码
const std = @import("std");

pub fn build(b: *std.Build) void {
    // 嵌入式目标配置 Cortex-M3
    const target = b.standardTargetOptions(.{
        .default_target = .{
            .cpu_arch = .thumb,
            .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m3 },
            .os = .freestanding,
            .abi = .eabi,
        },
    });
    const optimize = b.standardOptimizeOption(.{ .default = .ReleaseSmall });

    // 创建可执行固件
    const exe = b.addExecutable(.{
        .name = "my_firmware",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .strip = false,
    });

    // 嵌入式关键配置
    exe.setLinkerScript(b.path("stm32f103.ld"));
    exe.addAssemblyFile(b.path("src/startup_stm32f103.s"));
    exe.link_gc_sections = true;
    exe.link_data_sections = true;

    // 生成 .bin 文件
    const bin = b.addObjCopy(exe, .{
        .format = .bin,
    });
    bin.step.dependOn(&exe.step);
    b.installArtifact(bin);

    // 安装 ELF
    b.installArtifact(exe);
}

6. 调试:OpenOCD + Zig GDB

第一步:启动 OpenOCD

在新终端中运行以下命令:

bash 复制代码
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg

第二步:启动 Zig GDB

在另一个终端中运行:

bash 复制代码
zig gdb zig-out/firmware/firmware.elf

第三步:GDB 调试指令

进入 GDB 交互界面后,依次执行:

text 复制代码
(gdb) target remote :3333
(gdb) monitor reset halt
(gdb) load
(gdb) continue

7. 常见问题

7.1 链接报错:找不到内存区域

原因 :检查链接脚本 .ld 中的 Flash/RAM 大小是否和你实际使用的芯片匹配。

7.2 烧录成功,芯片不运行

原因:

  • 确认启动文件 startup 汇编、中断向量表配置是否正确。
  • 确认 Flash 起始地址是否为 0x08000000。

7.3 编译提示无法使用 libc 函数

原因:嵌入式是 freestanding 环境,没有 libc,必须使用 Zig 无标准库写法。


8. 参考资料

相关推荐
wuyk55511 小时前
防逆向基础:在量产固件中关闭调试接口并设置读保护(RDP)的正确姿势
stm32·单片机·嵌入式硬件·性能优化·重构
zhangrelay14 小时前
单片机原理与接口技术-2026融合版-从MEGA2560-ESP32与Wokwi到ROS2-Lyrical与具身智能栈
单片机·嵌入式硬件
lhbweilai15 小时前
分析FreeRTOS内核对象API的源码实现(八)
c语言·开发语言·stm32·单片机
艾络迅Acceleronix15 小时前
环境监测终端:STM32+EG800Z AT+ 艾络迅平台实战|多传感器采集联动全流程
c语言·stm32·单片机·嵌入式硬件·物联网·1024程序员节
涂山苏苏⁠16 小时前
stm32复习总结
stm32·单片机·嵌入式硬件
苏格拉真没有底16 小时前
ESP32 AI MCP调试器
stm32·单片机·嵌入式硬件
硅基造物主17 小时前
STM32 从 0 到 1 做智能家居(二):把开发环境一次配好
stm32·mqtt·智能家居·hal库·esp-12f
zhangzhangkeji19 小时前
stm32, HAL 库,PVD 与低功耗:
stm32
创界工坊工作室20 小时前
50-基AT89C51的自动窗帘控制系统的设计
stm32·单片机·嵌入式硬件·51单片机·proteus
xiangw@GZ20 小时前
SD / eMMC / SDIO 总线接口技术对比
单片机·嵌入式硬件