杰理 SDK 文档中心
首页
首页
  • 概述与入门

    • 项目概览
    • 快速开始与开发环境
  • 应用与运行时

    • 应用入口与主循环
    • 按键驱动与用户消息处理
    • 消息系统
  • 固件升级

    • 双备份升级机制与状态机
    • UART 升级传输
    • 升级校验、启动信息与复位流程
  • 芯片与硬件支持

    • AC63 系列芯片 BSP 结构
    • 外设接口与驱动
    • 低功耗、RTC 与时基唤醒
  • 构建与工具

    • 构建系统与工作区
    • 烧写与量产工具
  • 参考资源

    • 数据手册与原理图
    • 双备份升级文档

构建系统与工作区

本页介绍 fw-AC63_GP_MCU 固件仓库的工作区目录组织与基于 Makefile 的多芯片构建体系,包括顶层总控 sdk/Makefile、各芯片 BSP 子工程 Makefile 的配置区(工具链、编译/链接参数、宏定义、源文件清单)、构建产物输出以及烧录后处理流程。

Purpose and Scope

本页覆盖的内容:

  • 仓库工作区的顶层目录结构(sdk/、apps/、bsp/ 及各芯片子工程)与各目录的职责边界;
  • 顶层 sdk/Makefile 如何统一调度 ac636n / ac638n / ac632n / ac635n 四个芯片子工程;
  • 单个 BSP 子工程 Makefile 的完整构建机制:平台工具链探测、clang(pi32v2 目标)编译参数、宏定义、源文件与静态库清单、LTO 链接参数;
  • 构建中间产物(objs/)与最终产物(output/sdk.elf / sdk.map / sdk.ld)的生成路径;
  • 构建后的烧录下载脚本(tools/download.sh / download.bat)的接入方式。

本页不涉及具体的外设驱动实现、应用业务逻辑、SDK 组件(VM、充电、升级等静态库)的内部机制——这些属于各自的目录页(例如 BSP 驱动、应用层、SDK 组件)。构建系统只是把这些模块"装配"起来的手段,本页聚焦装配过程本身。

Overview

fw-AC63_GP_MCU 是杰理(Jieli)AC63 系列通用 MCU 固件仓库,支持 AC632N、AC635N、AC636N、AC638N 四款芯片。整个固件采用 “单仓库、多芯片子工程” 的工作区布局:sdk/bsp/ 下每个芯片一个子目录,各自携带独立的 Makefile、板级文件(board/)、驱动源码(src/)和构建输出目录(output/),而 sdk/Makefile 作为唯一入口统一调度它们。

构建体系的关键设计意图:

  1. 多芯片复用同一套构建规则:四份子工程 Makefile 结构完全相同(差异只在源文件清单、头文件路径与芯片静态库),降低维护成本,也便于新增芯片时复制模板;
  2. 以 clang/LTO 为核心的现代工具链:目标架构为杰理私有 pi32v2,mcpu=r3,全程开启 LTO(-flto),链接时通过 lto-wrapper 的 --plugin-opt 系列参数做全局优化、段合并(--gc-sections)、内联阈值控制,以适配 MCU 的有限 Flash/RAM;
  3. 双平台支持:同一份 Makefile 通过 OS 变量区分 Windows(C:/JL/pi32/bin,clang.exe)与 Linux(/opt/jieli/pi32v2/bin,clang),并自动切换烧录脚本为 .bat 或 .sh;
  4. 静态库裁剪定制:芯片厂商提供的功能(printf.a、mkey.a、resfile.a、update.a、vm.a、chargestore.a 以及 agreement.a、memory.a、sfc_flash.a、efuse.a、clock.a、power.a、dac.a)以预编译 .a 形式参与链接,应用只需通过 --start-group/--end-group 按需引用。

使用本构建系统,开发者只需在仓库根目录的 sdk/ 下执行 make ac636n(或 ac638n / ac632n / ac635n)即可完成对应芯片固件的编译与下载;make clean 一键清理全部子工程的临时文件。

Architecture

下图展示工作区目录结构、构建调度关系与工具链/产物流向(节点均对应仓库中实际存在的文件或目录):

flowchart TD
    Dev["开发者终端"] -->|"make ac636n / ac638n / ac632n / ac635n"| TopMK["sdk/Makefile<br/>顶层总控"]
    TopMK -->|"make -C bsp/AC636N -f Makefile"| BSPMK["bsp/AC636N/Makefile<br/>子工程构建"]
    TopMK -.->|"相同方式调度"| BSPMK2["bsp/AC638N / AC632N / AC635N<br/>子工程"]

    subgraph sg_BSP["BSP 子工程 Makefile 配置区"]
        TC["工具链路径<br/>clang / lto-wrapper / lto-ar"]
        CFLG["编译参数<br/>-target pi32v2 -mcpu=r3 -flto -Oz"]
        DEF["宏定义<br/>CONFIG_FREE_RTOS_ENABLE 等"]
        SRC["源文件清单<br/>apps/main.c + board/ + src/"]
        LFLG["链接参数<br/>LTO 插件选项 + sdk.ld 分散加载"]
    end

    BSPMK --> TC
    BSPMK --> CFLG
    BSPMK --> DEF
    BSPMK --> SRC
    BSPMK --> LFLG

    TC -->|"调用"| CC["pi32v2 工具链<br/>/opt/jieli/pi32v2/bin 或 C:/JL/pi32/bin"]
    CFLG --> CC
    SRC --> OBJS["objs/ 中间对象 .o / 依赖 .d"]
    LFLG --> LD2["lto-wrapper 链接<br/>--start-group 静态库 --end-group"]
    OBJS --> LD2
    LD2 --> OUT["output/sdk.elf / sdk.map / sdk.ld"]
    OUT -->|"tools/download.sh / download.bat"| FLASH["烧录下载"]

架构要点说明:

  • 顶层总控(sdk/Makefile):仅做两件事——把 all/clean 目标拆分为四个芯片目标,并用 $(MAKE) -C bsp/<chip> -f Makefile 递归进入子工程。它本身不定义任何编译规则,是纯粹的任务编排层。
  • 子工程 Makefile(sdk/bsp/<chip>/Makefile):定义全部构建细节,自上而下依次为:工具链路径 → 输出文件 → 编译路径 → 编译参数(CFLAGS/CXXFLAGS)→ 宏定义(DEFINES)→ 头文件路径(INCLUDES)→ 各语言源文件清单 → 链接参数(LFLAGS)→ 系统库 → 对象/依赖文件推导规则。
  • 工具链与产物:无论 Linux 还是 Windows,最终都使用同一套 pi32v2 clang 工具链;编译产物统一落在各子工程自己的 output/(链接脚本、ELF、MAP)与 objs/(中间对象)下,互不干扰。
  • 烧录后处理:链接完成后由 download.sh(Linux)或 download.bat(Windows)接管,实现"编译即下载"的一键流程。

工作区目录结构

仓库根目录仅包含 LICENSE、README.md、README-en.md 与 sdk/ 目录;全部固件源码都位于 sdk/ 之下。结合顶层 Makefile 的源文件清单与包含路径,可以还原出如下实际布局:

路径角色依据(Makefile 中的引用)
sdk/Makefile顶层总控,调度四个芯片子工程全部 -C bsp/<chip> 规则
sdk/apps/main.c应用层入口(与具体芯片无关)c_SRC_FILES 首项 ../../apps/main.c
sdk/bsp/include/跨芯片共享头文件INCLUDES 的 -I../../bsp/include
sdk/bsp/include/liba/<chip>/芯片厂商预编译静态库(printf.a、mkey.a、resfile.a、update.a、vm.a、chargestore.a)LFLAGS 中 --start-group 的库路径
sdk/bsp/<chip>/Makefile芯片子工程构建脚本顶层 -f Makefile 调用
sdk/bsp/<chip>/board/板级文件(board_demo.c、test.c)c_SRC_FILES 引用
sdk/bsp/<chip>/src/芯片驱动源码(adc.c、boot.c、uart.c、spi.c、timer.c、wdt.c 等)与汇编入口(startup.S、upgrade.S)c_SRC_FILES / S_SRC_FILES
sdk/bsp/<chip>/src/*.a芯片级链接库(agreement.a、memory.a、sfc_flash.a、efuse.a、clock.a、power.a、dac.a)LFLAGS --start-group 列表
sdk/bsp/<chip>/output/构建产物:sdk.elf、sdk.map、sdk.ld(链接脚本)OUT_ELF 与 -T/-M 参数
sdk/bsp/<chip>/tools/烧录后处理脚本 download.sh / download.batPOST_SCRIPT / RUN_POST_SCRIPT
sdk/bsp/dual_bank_update.c、sdk/bsp/msg.c、sdk/bsp/sdk_version.c跨芯片共享的 BSP 层源码c_SRC_FILES 尾部引用

设计意图:把"与芯片无关"的代码(apps/、bsp/ 顶层共享文件)与"芯片相关"的代码(bsp/<chip>/)分离,使新增芯片时只需复制一个子工程目录并调整 Makefile 中的清单,应用层与共享 BSP 无需改动。

顶层构建入口(sdk/Makefile)

顶层 Makefile 是一个纯调度器。它声明了 10 个 PHONY 目标:all、clean 以及四个芯片目标(ac636n、ac638n、ac632n、ac635n)和对应的 clean_<chip>。核心实现如下:

.PHONY: all clean ac636n ac638n ac632n ac635n clean_ac636n clean_ac638n clean_ac632n clean_ac635n

all: ac636n ac638n ac632n ac635n
	@echo +ALL DONE

clean: clean_ac636n clean_ac638n clean_ac632n clean_ac635n
	@echo +CLEAN DONE

ac636n:
	$(MAKE) -C bsp/AC636N -f Makefile

clean_ac636n:
	$(MAKE) -C bsp/AC636N -f Makefile clean

Source: sdk/Makefile

要点解读:

  • all 与 clean 都是并行无关的聚合目标:all 顺序构建全部四个芯片,clean 逐个清理,最后各打印 +ALL DONE / +CLEAN DONE 作为完成标记;
  • 单芯片构建使用 $(MAKE) -C bsp/<chip> -f Makefile 递归调用——-C 切换工作目录,-f 显式指定 Makefile 文件名,子进程 make 继承环境(PATH 等由子工程 Makefile 自行导出);
  • 顶部注释明确了 Linux 下的前置条件:从 http://pkgman.jieliapp.com/doc/all 下载工具链并解压到 /opt/jieli,保证 /opt/jieli/common/bin/clang 存在;且 ulimit -n 需大于 8096,否则链接阶段会因打开文件数超限失败。

核心构建流程

一次 make ac636n 的完整执行路径如下(依据 sdk/Makefile 与 sdk/bsp/AC636N/Makefile 的实际代码):

flowchart TD
    Start([make ac636n]) --> Top["sdk/Makefile 目标 ac636n"]
    Top --> Sub["make -C bsp/AC636N -f Makefile"]
    Sub --> OS{"OS == Windows_NT ?"}
    OS -->|"是"| Win["TOOL_DIR=C:/JL/pi32/bin<br/>CC=clang.exe LD=pi32v2-lto-wrapper.exe<br/>POST_SCRIPT=tools/download.bat"]
    OS -->|"否"| Lin["TOOL_DIR=/opt/jieli/pi32v2/bin<br/>CC=clang LD=lto-wrapper<br/>EXT_CFLAGS=-D__SHELL__<br/>POST_SCRIPT=tools/download.sh"]
    Win --> Cmp["clang -target pi32v2 -mcpu=r3 -flto -Oz 编译<br/>c/S/cpp 各源文件 → objs/ 下 .o 与 .d"]
    Lin --> Cmp
    Cmp --> Lnk["lto-wrapper 链接<br/>--start-group 静态库 --end-group<br/>-T output/sdk.ld -M output/sdk.map"]
    Lnk --> Elf["生成 output/sdk.elf"]
    Elf --> Dn{"RUN_POST_SCRIPT 存在?"}
    Dn -->|"是"| Dl["执行 download.sh / download.bat 烧录"]
    Dn -->|"否"| Done([结束])
    Dl --> Done

流程说明:

  1. 入口:make ac636n 命中顶层目标,递归进入 bsp/AC636N;
  2. 平台分支:子工程 Makefile 用 ifeq ($(OS), Windows_NT) 区分平台——这决定了工具链目录、可执行文件后缀(.exe)、系统库目录(pi32v2-lib/r3)以及烧录脚本类型,同时 Windows 分支不追加 -D__SHELL__(注释明确说明该宏用于 Linux 下正确处理 download.c);
  3. 编译:每个源文件独立编译为 objs/ 下的对象文件,路径映射规则为 $(addprefix $(BUILD_DIR)/, $(OBJS:$(ROOT_PREFIX)/%=%)),即去掉 ../../ 前缀后平铺到 objs/,同时生成 .d 依赖文件;
  4. 链接:lto-wrapper 按 LFLAGS 执行 LTO 全局优化、--gc-sections 裁剪未用段、按 --start-group/--end-group 解析静态库循环依赖,产出 sdk.elf、sdk.map(内存映射,供排查 Flash/RAM 占用)与链接脚本 sdk.ld;
  5. 后处理:若 RUN_POST_SCRIPT 已定义(两个平台都会定义),链接后自动执行烧录脚本完成下载。

BSP 子工程 Makefile 深度剖析

以 sdk/bsp/AC636N/Makefile 为例(其余三芯片结构相同),自上而下剖析六个配置区。这是整个构建系统的核心。

1. 工具链路径与平台探测

# 工具路径设置
ifeq ($(OS), Windows_NT)
# Windows 下工具链位置
TOOL_DIR := C:/JL/pi32/bin
CC    := clang.exe
CXX   := clang.exe
LD    := pi32v2-lto-wrapper.exe
AR    := llvm-ar.exe
MKDIR := mkdir_win -p
RM    := rm -rf

SYS_LIB_DIR := C:/JL/pi32/pi32v2-lib/r3
SYS_INC_DIR := C:/JL/pi32/pi32v2-include
EXT_CFLAGS  := # Windows 下不需要 -D__SHELL__
export PATH:=$(TOOL_DIR);$(PATH)

Source: sdk/bsp/AC636N/Makefile

设计意图:

  • 依赖环境变量 OS 而非 make 内置变量:make 在 Windows 下同样可以定义 OS=Windows_NT(由 cmd 环境注入),这是最廉价的跨平台判定方式;
  • 目录统一在变量层收敛:TOOL_DIR、SYS_LIB_DIR、SYS_INC_DIR 全部在文件头一次性确定,后续 CFLAGS/INCLUDES/LIBPATHS 直接引用,避免散落的硬编码路径;
  • export PATH:把工具链目录注入子进程环境,使 download.sh 等后处理脚本也能直接找到工具;
  • 编译完成后统一追加绝对路径前缀:CC := $(TOOL_DIR)/$(CC),保证即使 PATH 被污染也使用正确工具。

Linux 分支(sdk/bsp/AC636N/Makefile 第 34-54 行)使用 /opt/jieli/pi32v2/bin,并额外导出 OBJDUMP、OBJCOPY、OBJSIZEDUMP 三个工具供链接后分析使用,同时追加 EXT_CFLAGS := -D__SHELL__。

2. 编译参数(CFLAGS / CXXFLAGS)

CFLAGS := \
	-target pi32v2 \
	-mcpu=r3 \
	-integrated-as \
	-flto \
	-Wuninitialized \
	-Wno-invalid-noreturn \
	-fno-common \
	-Oz \
	-g \
	-fallow-pointer-null \
	-fprefer-gnu-section \
	-Wno-shift-negative-value \
	-Wframe-larger-than=256 \
	-Werror=implicit-function-declaration \
	-Werror=macro-redefined \
	-Werror=return-type \
	-Werror=int-conversion \
	-Werror=incompatible-pointer-types \
	-Werror=undef \
	-fms-extensions

Source: sdk/bsp/AC636N/Makefile

参数意图逐条说明:

参数作用
-target pi32v2 -mcpu=r3指定杰理私有 32 位 DSP 架构及 R3 内核变体,clang 据此生成指令集
-integrated-as使用 clang 内置汇编器,无需外部 as,保证与 LTO 中间表示兼容
-flto全程链接时优化(配合 lto-wrapper),跨编译单元内联/常量传播,显著压缩代码体积
-Oz以代码尺寸为优先的优化等级——MCU Flash 有限,体积优先于速度
-g保留调试信息,配合 sdk.map 定位问题
-fno-common未初始化全局变量不合并为 common,避免链接期符号冲突
-fprefer-gnu-section每个函数/变量独立成节,是 --gc-sections 能裁剪的前提
-Wframe-larger-than=256栈帧超过 256 字节告警,MCU RAM 紧张的早期预警
-Werror=... 系列隐式函数声明、宏重定义、返回类型、整型转换、指针类型不匹配、未定义宏一律升级为错误,把"野指针/类型错误"挡在编译期
-fms-extensions兼容 MS 风格扩展语法(如匿名 struct/union),匹配厂商 SDK 代码风格

3. 宏定义(DEFINES)

DEFINES := \
	-DSUPPORT_MS_EXTENSIONS \
	-D__GCC_PI32V2__ \
	-DCONFIG_OS_ENABLE=0 \
	-DAPP_USE_SOFT_SPI_ACCESS_VM \
	-DCONFIG_FREE_RTOS_ENABLE \
	-DCONFIG_RELEASE_ENABLE \
	-DCONFIG_MMU_ENABLE

DEFINES += $(EXT_CFLAGS) # 额外的一些定义

Source: sdk/bsp/AC636N/Makefile

这些宏是芯片级功能开关:CONFIG_FREE_RTOS_ENABLE 决定是否启用 FreeRTOS(同时 CONFIG_OS_ENABLE=0 表示关闭厂商自有 OS)、CONFIG_MMU_ENABLE 开启 MMU、CONFIG_RELEASE_ENABLE 进入发布模式、APP_USE_SOFT_SPI_ACCESS_VM 表示用软件 SPI 访问 VM 存储。注意 DEFINES += $(EXT_CFLAGS) 把平台分支追加的 -D__SHELL__ 合入,即 Linux 构建天然多一个编译宏——这是平台差异在源码层的体现,改动宏定义即可切换芯片/功能组合,而无需改动源码。

4. 源文件清单与对象推导

c_SRC_FILES 列出应用入口(apps/main.c)、板级文件(board/board_demo.c、board/test.c)、芯片驱动(src/ 下约 30 个 .c)以及跨芯片共享的 bsp/dual_bank_update.c、bsp/msg.c、bsp/sdk_version.c;S_SRC_FILES 仅两项汇编入口 src/startup.S 与 src/upgrade.S(启动与升级引导)。随后统一推导对象与依赖文件:

c_OBJS    := $(c_SRC_FILES:%.c=%.c.o)
S_OBJS    := $(S_SRC_FILES:%.S=%.S.o)
OBJS      := $(c_OBJS) $(S_OBJS) $(s_OBJS) $(cpp_OBJS) $(cxx_OBJS) $(cc_OBJS)
DEP_FILES := $(OBJS:%.o=%.d)

OBJS      := $(addprefix $(BUILD_DIR)/, $(OBJS:$(ROOT_PREFIX)/%=%))
DEP_FILES := $(addprefix $(BUILD_DIR)/, $(DEP_FILES:$(ROOT_PREFIX)/%=%))

Source: sdk/bsp/AC636N/Makefile

机制说明:六类源文件(c/S/s/cpp/cc/cxx)分别做模式替换生成对象名(.c → .c.o,避免同名 .c 与 .cpp 冲突),再统一推导 .d 依赖文件;最后用 $(addprefix $(BUILD_DIR)/, ...) 与 $(ROOT_PREFIX)/%=%(去掉 ../../ 前缀)把对象平铺映射到 objs/ 目录下——这样无论源文件在哪个子目录,中间产物都集中在构建目录,make clean 只需删除 objs/。

5. 链接参数(LFLAGS)与静态库装配

LFLAGS := \
	--plugin-opt=-pi32v2-always-use-itblock=false \
	--plugin-opt=-enable-ipra=true \
	--plugin-opt=-pi32v2-merge-max-offset=4096 \
	--plugin-opt=-pi32v2-enable-simd=true \
	--plugin-opt=mcpu=r3 \
	--plugin-opt=-global-merge-on-const \
	--plugin-opt=-inline-threshold=5 \
	--plugin-opt=-inline-max-allocated-size=32 \
	--plugin-opt=-inline-normal-into-special-section=true \
	--plugin-opt=-dont-used-symbol-list=malloc,free,sprintf,printf,puts,putchar \
	--plugin-opt=save-temps \
	--plugin-opt=-pi32v2-enable-rep-memop \
	--plugin-opt=-warn-stack-size=256 \
	--sort-common \
	--dont-complain-call-overflow \
	--gc-sections \
	--start-group \
	../../bsp/include/liba/AC636N/printf.a \
	../../bsp/include/liba/AC636N/mkey.a \
	../../bsp/include/liba/AC636N/resfile.a \
	../../bsp/include/liba/AC636N/update.a \
	../../bsp/include/liba/AC636N/vm.a \
	../../bsp/include/liba/AC636N/chargestore.a \
	../../bsp/AC636N/src/agreement.a \
	../../bsp/AC636N/src/memory.a \
	../../bsp/AC636N/src/sfc_flash.a \
	../../bsp/AC636N/src/efuse.a \
	../../bsp/AC636N/src/clock.a \
	../../bsp/AC636N/src/power.a \
	../../bsp/AC636N/src/dac.a \
	--end-group \
	-T../../bsp/AC636N/output/sdk.ld \
	-M=../../bsp/AC636N/output/sdk.map \
	--plugin-opt=mcpu=r3 \
	--plugin-opt=-mattr=+fprev1

Source: sdk/bsp/AC636N/Makefile

设计意图:

  • --plugin-opt 系列是 LTO 插件的细粒度控制:-enable-ipra(跨过程寄存器分配)、-global-merge-on-const(常量段全局合并)、-inline-threshold=5 与 -inline-max-allocated-size=32(严格限制内联规模,防止代码膨胀)、-warn-stack-size=256(链接期栈用量预警)、-pi32v2-merge-max-offset=4096(寻址偏移合并,配合 R3 内核的 12 位立即数寻址);
  • --dont-used-symbol-list:显式告知链接器 malloc/free/sprintf/printf/puts/putchar 等标准库函数即使被引用也不作 LTO 内联,避免厂商库与 libc 的符号冲突;
  • --start-group/--end-group:让 13 个静态库互相解析循环引用(例如 vm.a 依赖 chargestore.a,agreement.a 又引用 update.a),这是厂商库装配的标准手法;
  • -T sdk.ld -M sdk.map:使用芯片分散加载脚本(output/sdk.ld)布局 Flash/RAM 段,并输出内存映射表供分析;
  • 系统库(libm.a、libc.a、libcompiler-rt.a)来自 SYS_LIB_DIR(-L 指定),与厂商库分开管理。

6. 构建产物与清理

产物统一输出到 ../../bsp/AC636N/output/:

产物说明
sdk.elf最终固件 ELF(含调试信息)
sdk.ld链接脚本(分散加载描述,位于 output 目录)
sdk.map链接内存映射,用于排查 Flash/RAM 占用与符号地址
objs/*.o / *.d中间对象与自动依赖文件(make clean 删除)

Makefile 头部注释同时声明了三个常用目标:make(编译并下载)、make VERBOSE=1(显示编译详细过程)、make clean(清除编译临时文件)。

使用示例

示例 1:编译并下载指定芯片固件

在 sdk/ 目录下执行(all 目标会依次构建全部四款芯片):

.PHONY: all clean ac636n ac638n ac632n ac635n clean_ac636n clean_ac638n clean_ac632n clean_ac635n

all: ac636n ac638n ac632n ac635n
	@echo +ALL DONE

ac636n:
	$(MAKE) -C bsp/AC636N -f Makefile

clean_ac636n:
	$(MAKE) -C bsp/AC636N -f Makefile clean

Source: sdk/Makefile

# 编译并下载 AC636N 固件(等价于进入 bsp/AC636N 执行 make)
make ac636n

# 显示详细编译过程(透传 VERBOSE 到子工程)
make VERBOSE=1

# 只编译不下载/清理
make -C bsp/AC636N -f Makefile clean

# 一次构建全部芯片,或全部清理
make all
make clean

示例 2:Linux/Windows 双平台工具链分支

同一份 Makefile 依据 OS 变量选择工具链目录与烧录脚本,这是整个构建系统跨平台工作的核心:

ifeq ($(OS), Windows_NT)
# Windows 下工具链位置
TOOL_DIR := C:/JL/pi32/bin
CC    := clang.exe
CXX   := clang.exe
LD    := pi32v2-lto-wrapper.exe
AR    := llvm-ar.exe
...
POST_SCRIPT     := ../../bsp/AC636N/tools/download.bat
RUN_POST_SCRIPT := ..\..\bsp\AC636N\tools\download.bat
else
# Linux 下工具链位置
TOOL_DIR := /opt/jieli/pi32v2/bin
CC    := clang
CXX   := clang
LD    := lto-wrapper
AR    := lto-ar
...
POST_SCRIPT     := ../../bsp/AC636N/tools/download.sh
RUN_POST_SCRIPT := bash $(POST_SCRIPT)
endif

Source: sdk/bsp/AC636N/Makefile

差异汇总:Windows 使用 C:/JL/pi32/bin、clang.exe、llvm-ar.exe、download.bat,且不追加 -D__SHELL__;Linux 使用 /opt/jieli/pi32v2/bin、clang、lto-ar、download.sh,追加 -D__SHELL__ 并额外导出 OBJDUMP/OBJCOPY/OBJSIZEDUMP。

示例 3:通过宏定义切换功能组合

修改 DEFINES 即可在编译期切换芯片功能,无需改动任何 C 源码:

DEFINES := \
	-DSUPPORT_MS_EXTENSIONS \
	-D__GCC_PI32V2__ \
	-DCONFIG_OS_ENABLE=0 \
	-DAPP_USE_SOFT_SPI_ACCESS_VM \
	-DCONFIG_FREE_RTOS_ENABLE \
	-DCONFIG_RELEASE_ENABLE \
	-DCONFIG_MMU_ENABLE

DEFINES += $(EXT_CFLAGS) # 额外的一些定义

Source: sdk/bsp/AC636N/Makefile

例如:去掉 -DCONFIG_FREE_RTOS_ENABLE 可编译无 RTOS 的裸机版本;平台分支自动注入的 -D__SHELL__ 会让 download.c 在 Linux 下走正确的下载逻辑。

配置选项

以下为 sdk/bsp/<chip>/Makefile 中可直接修改的构建配置(变量名即选项名,均为字符串/路径类型):

选项类型默认值(AC636N / Linux)说明
TOOL_DIR路径/opt/jieli/pi32v2/bin(Win: C:/JL/pi32/bin)工具链根目录
CC / CXX命令clang(Win: clang.exe)C/C++ 编译器
LD命令lto-wrapper(Win: pi32v2-lto-wrapper.exe)LTO 链接器
AR命令lto-ar(Win: llvm-ar.exe)归档工具
SYS_LIB_DIR路径/opt/jieli/pi32v2/lib/r3系统库目录(libc/libm/compiler-rt)
SYS_INC_DIR路径/opt/jieli/pi32v2/include系统头文件目录
EXT_CFLAGS宏-D__SHELL__(Win: 空)平台附加宏定义
OUT_ELF路径../../bsp/AC636N/output/sdk.elfELF 输出路径
BUILD_DIR路径objs中间对象目录
ROOT_PREFIX路径../..源路径前缀(对象映射时剥离)
CFLAGS参数列表-target pi32v2 -mcpu=r3 -flto -Oz -g ...编译参数
DEFINES宏列表CONFIG_FREE_RTOS_ENABLE、CONFIG_MMU_ENABLE、CONFIG_RELEASE_ENABLE 等功能开关
INCLUDES路径列表-I../../bsp/include -I../../bsp/AC636N/include -I$(SYS_INC_DIR)头文件搜索路径
c_SRC_FILES / S_SRC_FILES 等文件列表见上节清单参与编译的源文件
LFLAGS参数列表LTO 插件选项 + --gc-sections + 库组 + -T sdk.ld -M sdk.map链接参数
LIBS文件列表libm.a、libc.a、libcompiler-rt.a链接的系统库
POST_SCRIPT / RUN_POST_SCRIPT命令tools/download.sh / bash $(POST_SCRIPT)构建后烧录脚本

顶层 sdk/Makefile 的配置面更小:新增芯片时只需仿照现有目标追加一个 <chip> 与 clean_<chip> PHONY 目标(并加入 all/clean 依赖列表)。

命令参考

命令(在 sdk/ 下执行)行为
make ac636n / make ac638n / make ac632n / make ac635n编译并烧录对应芯片
make all依次构建全部四款芯片
make clean清理全部芯片的临时文件
make clean_ac636n仅清理 AC636N 子工程
make VERBOSE=1显示详细编译过程(透传至子工程)
make -C bsp/AC636N -f Makefile clean绕过顶层直接操作子工程

失败模式与边界情况

以下问题均能在 Makefile 注释或参数中直接找到依据:

工具链缺失或路径错误

  • 现象:make 报 clang: command not found 或找不到 /opt/jieli/pi32v2/bin/clang;
  • 依据:sdk/Makefile 顶部注释要求工具链从 http://pkgman.jieliapp.com/doc/all 下载并解压到 /opt/jieli,且必须保证 /opt/jieli/common/bin/clang 存在(注意目录层次);
  • 处置:检查 TOOL_DIR 是否正确,Linux 下确认解压层次为 /opt/jieli/pi32v2/bin/clang。

链接期打开文件数超限

  • 现象:链接阶段失败,报 "too many open files" 类错误;
  • 依据:顶层 Makefile 注释明确要求 ulimit -n 大于 8096,原因在于 LTO 链接需要同时打开大量中间文件;
  • 处置:执行 ulimit -n 8096(或更大)后重新 make。

平台分支不一致

  • 现象:Windows 下烧录脚本执行失败,或 Linux 下 download.c 行为异常;
  • 依据:Makefile 通过 ifeq ($(OS), Windows_NT) 分支,且 EXT_CFLAGS 在 Linux 下追加 -D__SHELL__(注释说明"Linux 下需要这个保证正确处理 download.c");
  • 边界:若在非 Windows 环境误设 OS=Windows_NT,会选错工具链后缀与脚本类型,导致构建失败——平台切换只应通过真实环境变量进行。

编译警告升级为错误

  • 现象:implicit-function-declaration、macro-redefined、return-type、int-conversion、incompatible-pointer-types、undef 任一出现即终止编译;
  • 依据:CFLAGS 中 -Werror= 系列参数;
  • 设计意图:MCU 固件对代码正确性要求苛刻,这类错误一旦混入固件会导致难以调试的运行时崩溃,因此从源头阻断。

栈/内存超限预警

  • 现象:编译告警 -Wframe-larger-than=256、链接告警 --plugin-opt=-warn-stack-size=256;
  • 依据:两个阈值均为 256 字节;
  • 说明:这只是告警(除非配合 -Werror),提示栈帧可能超出 R3 内核的可用栈空间,属于早期风险信号而非硬失败。

性能与运维注意事项

  • 全量 LTO 的代价:-flto + --gc-sections + 13 个静态库的 --start-group 解析,使链接阶段计算量大、打开文件多——这正是 ulimit -n 必须调大的原因;增量开发建议只构建目标芯片(make ac636n)而非 make all;
  • 中间产物可复用:objs/ 下的 .o/.d 支持增量编译,make clean 只清理该目录;output/ 下的 sdk.elf/sdk.map 是链接产物,建议纳入版本管理审查以跟踪固件体积变化;
  • 体积优化是显式目标:-Oz、-fprefer-gnu-section、-global-merge-on-const、-inline-threshold=5 组合表明该平台以 Flash 容量为首要约束;引入新代码时优先复用 include/liba/<chip>/ 中的厂商库,避免重复实现导致体积膨胀;
  • 后处理脚本可旁路:若只需编译不烧录,可临时注释 RUN_POST_SCRIPT 或在链接后中断,避免开发机上反复占用下载工具。

扩展点

  1. 新增芯片子工程:复制 bsp/AC636N 为 bsp/ACxxxxN,替换 output/sdk.ld 链接脚本、board/ 板级文件、src/ 驱动与 include/liba/<chip>/ 库路径,再在顶层 sdk/Makefile 追加 acxxxxn: / clean_acxxxxn: 目标并登记到 all/clean(注意同步 AC636N → 新芯片名的路径替换)。
  2. 追加源文件:向 c_SRC_FILES(或 S_SRC_FILES/cpp_SRC_FILES 等)追加路径即可,对象映射规则会自动把它平铺到 objs/ 并生成 .d 依赖;跨芯片共享代码应放在 bsp/ 顶层(如 dual_bank_update.c、msg.c),芯片相关代码放 bsp/<chip>/src/。
  3. 调整功能宏:增删 DEFINES 中的 CONFIG_* 宏切换 RTOS/MMU/Release 等特性;新增平台相关宏可仿照 EXT_CFLAGS 机制按 OS 分支注入。
  4. 替换/扩展烧录流程:POST_SCRIPT 与 RUN_POST_SCRIPT 是两个独立变量——前者记录脚本路径,后者定义实际执行命令(Linux 为 bash $(POST_SCRIPT)),可替换为自定义脚本或 CI 上传命令。

Related Links

  • sdk/Makefile(顶层构建总控)
  • sdk/bsp/AC636N/Makefile(子工程构建模板)
  • sdk/bsp/AC638N/Makefile
  • sdk/bsp/AC632N/Makefile
  • sdk/bsp/AC635N/Makefile
  • 仓库根目录 README.md 与 README-en.md

相关主题提示:芯片驱动实现(bsp/<chip>/src/)与 SDK 组件(VM、充电、升级等静态库)的内部机制不属于本页范围,详见各自的 BSP 驱动与 SDK 组件页面。

Next
烧写与量产工具