# AGENTS.md ## 项目概述 本仓库是 **mothercup(母乳杯)** 产品的完整代码仓库,包含三大部分: 1. **设备固件** — 基于国民技术(Nations)**N32WB031 BLE SoC**(Cortex-M0,64MHz HSI,**板载硅片实测 256KB Flash**(0x01000000~0x0103FFFF,开发日志 §37),RAM 48KB+16KB): - **`mcm-ddc-ble/`** — 唯一活跃的应用固件工程(APP,链接在 APP1 bank `0x01008000`/112KB)。以 SDK rdtss 例程为蓝本,集成 FreeRTOS、UART CLI、BLE 自定义 GATT 服务(CLI 透传 / 设备信息查询 / BLE OTA 双 bank 直写升级)、bootsetting 与 APP_DATA 参数区结构化读写命令。当前版本 **V1.00.27**(`mcm-ddc-ble/inc/app_version.h`)。历史上曾有 `mcm-ddc-04/` 主工程,**已删除**,其功能已全部并入本工程。 - **`Boot/`** — 自写精简 bootloader(链接在 `0x01000000`/16KB):校验 bootsetting 记录自身完整性(magic + 结构体 CRC32)后按 active bank 的 `start_address` 直接跳转;**不校验镜像 CRC(CRC 校验在 OTA 升级过程中完成)**;记录无效或地址越界回退 APP1。 2. **手机 App `SmartAssiter/`** — uni-app **Vue3 + TypeScript** 工程(HBuilderX 项目管理,无 package.json),通过 BLE 连接设备:查看运行参数(温度/电压/转速/bank/堆等)、CLI 终端、参数读写(appget/appset)、OTA 升级页(e0005 锁步,已恢复)。另有登录/注册/用户信息等云端业务页面。 3. **PC 工具 `tools/`** — 整片烧录包制作/烧录脚本 + bleak 蓝牙测试客户端。 关键文档: - `docs/开发日志.md` — 固件全程开发日志(45 节,含所有踩坑根因与设计决策,排查问题先查这里) - `docs/ble_protocol.md` — CAIIC BLE 通信协议 V1.1(帧格式/GATT UUID/三类业务流程/维护命令/手机端开发指南) - `SmartAssiter/docs/修改记录_*.md` — App 侧每次改造的详细记录 ## 仓库顶层结构 ``` mothercup/ ├── mcm-ddc-ble/ # 应用固件工程(src/ inc/ MDK-ARM/) ├── Boot/ # bootloader 工程(src/ + MDK-ARM/caiic_boot.uvprojx) ├── SmartAssiter/ # 手机 App(uni-app vue3,HBuilderX 工程) ├── tools/ # merge_image.py / make_package.bat / flash_package.bat / ble_cli_test.py 等 ├── docs/ # 开发日志.md + ble_protocol.md(仓库级权威文档) ├── nations-tec/ # 厂商资源:SDK V2.0.0、DFP 器件包、STB 开发板资料、官方 PDF。**只读,不要修改** └── tools/out/ # 出包产物(mothercup_ble_prod.{hex,bin} 生产整包 + mothercup_ble_ota.bin 单文件升级包 + 调试用 _ota.bin/_ota_app2.bin 及 json) ``` SDK 源码(固件库、CMSIS、FreeRTOS V9.0.0、BLE 协议栈/profile/ns_library、启动文件)通过相对路径 `..\..\nations-tec\N32WB03x_SDK_V2.0.0` 被 uvprojx 引用,**不复制进工程**;Bootloader 共享代码(`Boot/src/dfu_layout.h`、`boot_crc32.c`)经 `..\..\Boot\src` 被 APP 工程引用。因此各工程目录不能脱离仓库根单独移动。 ## Flash / RAM 布局(铁律) > 板载硅片实测 **256KB** Flash(0x01000000~0x0103FFFF;曾按 512KB 规划,实测 0x01040000 起 CPU 读回绕、SWD fault,见开发日志 §37)。以下布局已按 256KB 重排(§38),双 bank 切换 `appsw` 实测通过。 Flash 布局(256KB,`Boot/src/dfu_layout.h` 为唯一权威定义;Boot/bootsetting/APP_DATA 保持 16/8/8KB,余下 224KB 均分双 bank): | 区域 | 地址 | 大小 | |---|---|---| | Bootloader | 0x01000000 | 16KB | | bootsetting | 0x01004000 | 8KB(用 1 个 4KB 扇区,结构体见 dfu_layout.h) | | APP_DATA | 0x01006000 | 8KB(区头为 `caiic_params_t` 参数记录,见 app_params.h) | | APP1 | 0x01008000 | 112KB(0x1C000) | | APP2 | 0x01024000 | 112KB(0x1C000) | - **RAM 铁律**:**低 16KB(0x20000000~0x20003FFF)由芯片 ROM/BLE 子系统占用**(rwip 堆描述符、patch 数组、中断中继表,由 ROM 启动代码预备),**任何工程的 IRAM 执行区必须从 0x20004000 起**(含 Boot 和任何小工具),否则 .data/.bss 初始化冲掉 ROM 数据,BLE init 必然 HardFault(实测根因,开发日志 §21)。**顶部同样悬崖(实测 SWD 探明,§47):0x2000C000 起访问即 fault,APP 可用 SRAM 实为 32KB(0x20004000~0x2000BFFF)**——IRAM 配置里的 0xC000(48KB)上限是虚的,**栈顶 `__initial_sp` 必须 < 0x2000C000**;`merge_image.py` 已加硬卡(出包时校验 bin 向量表首字,越线直接失败)。ZI 膨胀(加大缓冲/堆)把栈顶推过线会导致上电即 HardFault/Lockup(V1.00.24 的 2KB DMA ring 事故,heap 已降为 18KB 腾位)。注意:mcm-ddc-ble.uvprojx 里 `` 镜像元素显示 0x20000000 是过期显示值,实际生效的是 OCR_RVCT9=0x20004000/0xC000——以 `Listings/mcm-ddc-ble.map` 的 `RW_IRAM1 (Exec base: 0x20004000)` 为准。 - **VTOR**:Cortex-M0 无 SCB->VTOR,用 `PWR->VTOR_REG`(bit31=EN|[30:0]=基址)。规则:**BLE 初始化之前** VTOR 指向 APP 自身向量表(main 开头设 `0x80000000|0x01008000`,USART1 RX 中断需要);**`ns_ble_stack_init()` 之后 VTOR 必须为 0**,此后所有中断经芯片 ROM 跳板 + RAM 中继。**绝对不要在 BLE init 后重设 VTOR**(实测崩溃根因,开发日志 §18)。 ## 固件工程(mcm-ddc-ble) ``` mcm-ddc-ble/ ├── src/ │ ├── main.c # 入口:VTOR 预置 → USART+banner → LED → app_ble_init → app_params_init │ │ # → ns_sleep_lock_acquire(锁睡眠保 SWD) → 建 BLE 调度/LED/CLI 任务 → vTaskStartScheduler │ ├── bsp_usart.c # USART1(PB6/PB7, 460800 8N1, V1.00.26 起;IWDG 看门狗见 §50):fputc 重定向 + DMA TX(CH1) + RX DMA 循环环形缓冲(CH2, 3KB, IDLE 中断唤醒;擦扇区关中断期间不丢字节) + TX 互斥锁 │ ├── app_gpio.c # LED1(PB0)/LED2(PA6) │ ├── app_cli.c # CLI UART 前端:CliTask 行接收/编辑/历史/Tab/Ctrl+Z,提示符 caiic-> │ ├── cli_core.c # CLI 核心(命令表 s_cmds[]/handler/分词执行),输出经可切换 cli_out_fn │ │ # 命令:help / version / sysinfo / devinfo / blelog / led / appget / appset / │ │ # bsdump / bsset / appsw / reset / factory / uartrst / uartinfo │ ├── app_ble.c # BLE 栈初始化/广播(名 CAIIC-MCM-20260902)/连接事件 + BLE 调度任务 │ ├── app_ble_proto.c # 0xCA 帧协议:字节流重组、CLI_REQ/RSP、INFO_QUERY/RSP、OTA 帧分发、 │ │ # CLI 读写特征(...e0003) 与只读参数特征(...e0004) 的执行/应答 │ ├── app_info.c # 设备信息:ADC 芯片温度(CH7)/电压(CH6)、运行时长、堆剩余;风扇 weak 数据源 │ ├── app_ota.c # BLE OTA:双 bank 直写(惰性擦扇区,仅 4B 对齐暂存)+ CRC32 校验 + bootsetting 更新 + 复位 │ ├── app_params.c # APP_DATA 参数记录(caiic_params_t,magic+CRC)+ appget/appset 命令(led/pwm) │ ├── app_bootset.c # bootsetting 结构化读写 bsdump/bsset + appsw 切 bank(自动重算 CRC,防裸写变砖; │ │ # appsw 切前复算目标镜像 CRC32) │ ├── ble_up.c # CLI 应答的 BLE notify 上行(ke_msg 上下文约束:环形缓冲 + BLE 任务内发送) │ ├── n32wb03x_it.c # 异常处理(HardFault 栈帧打印)+ USART1_IRQHandler 转发 │ ├── app_usart.c # 遗留文件,已不在工程中编译(rdtss 原透传 FIFO,勿使用) │ ├── infra/ # vendored cJSON v1.7.18(MIT)+ infra_cjson.c(分配挂 pvPortMalloc, │ │ # 惰性初始化);供参数接口 JSON 化等使用,MicroLIB 下整数走 %d 快路径 │ └── app_profile/ # app_rdtss.c(GATT 服务实现,读请求按 att_idx 分发 CLI_VAL/INFO_VAL)等 ├── inc/ # 对应头文件 + FreeRTOSConfig.h(heap 20KB)+ app_user_config.h(广播名/连接参数) └── MDK-ARM/ # mcm-ddc-ble.uvprojx(target "N32WB03x" 为活跃 target,链接 APP1; # target "APP2" 为同源码链接 0x01024000 的 APP2 bank 构建(同版本), # 供 make_dual_package.bat 出双 APP 整包;OTA_IMG_1/2 是 rdtss 遗产,保留不用)、 # Objects/、Objects-app2/、bin/、Listings/、Listings-app2/ ``` 工程配置:器件 `N32WB031KEQ6-2`(实际硅片 256KB),IROM 0x01008000/0x1C000(APP1),IRAM **0x20004000/0xC000**,MicroLIB,全局宏 `N32WB03X, USE_STDPERIPH_DRIVER`;链接器 Misc 附加 BLE ROM 符号表 `symbol_g15.obj`(SDK `middlewares/Nationstech/ble_library/ns_ble_stack/symdef/`)。 ## 构建与烧录 工具链:Keil µVision5(ARMCC V5.06 update 6),安装于 `D:\Keil_v5`。 命令行构建(工作目录在对应工程的 `MDK-ARM/`): ```bash "D:\Keil_v5\UV4\UV4.exe" -b mcm-ddc-ble.uvprojx -j0 -o build.log # APP 增量构建 "D:\Keil_v5\UV4\UV4.exe" -b caiic_boot.uvprojx -j0 -o build.log # Boot 增量构建 ``` 要求保持 **0 Error(s), 0 Warning(s)**。当前基线(V1.00.27):`Code=49408 RO-data=5132 RW-data=2092 ZI-data=30140`。 **固件版本号约定(重要)**:每次修改固件代码必须递增 `mcm-ddc-ble/inc/app_version.h` 中的 `APP_FW_VERSION` 与 `APP_FW_VERSION_NUM`(格式 `0x00MMmmpp`,通常补丁位 +1),用于识别板上实际运行的固件;工程名与出包文件名保持不变。 **出包约定(重要)**:每次固件修改构建通过后,必须直接运行 `tools\make_package.bat` 重新生成整片包与 OTA 升级包到 `tools/out/`(与代码改动一起交付,不要只交付源码)。 出包与烧录: 1. `tools\make_package.bat` — 一键:`UV4 -r` **全量重建** Boot + APP1 + APP2 target(出包必须 `-r`,增量构建曾产生栈顶/ZI 不一致的砖包,见开发日志 §24)→ `merge_image.py` 合并。产物在 `tools/out/`: - `mothercup_ble_prod.hex/.bin` — 生产整片包(Boot + 缺省 bootsetting + APP1,只含一个 APP) - `mothercup_ble_ota.bin` — **OTA 单文件发布件**(52B 头含 version/总大小/总 CRC + 双 bank 载荷索引,格式见 ble_protocol.md §7);调试用单 bank 载荷 `mothercup_ble_prod_ota.bin`(bank1)/ `_ota_app2.bin`(bank2)+ json 也保留。**客户端按信息项 0x07 CUR_BANK 选对侧 bank 的载荷**;固件 OTA_END 有向量表防呆(status=6 bank_mismatch) - 注意:`merge_image.py` 不带参数运行时默认 app 路径仍指向已删除的 `mcm-ddc-04/`,**手动调用必须显式传参**:`python tools/merge_image.py mcm-ddc-ble/MDK-ARM/bin/mcm-ddc-ble.bin mothercup_ble_prod` 2. 首次/变砖恢复:`tools\flash_package.bat tools\out\mothercup_ble_prod.hex`(调 SDK 自带 NSpyocd,整片擦除 + 烧录;需 NS-LINK 接 SWD PA4/PA5 + 复位脚,先关闭 Keil;target 用 DFP pack 的 `n32wb031keq6_2` + `-O smart_flash=false`) - **双 APP 整包(appsw 测试)**:`tools\make_dual_package.bat` 出 `caiic_ble_dual.{hex,bin}`(Boot+bootsetting 双 bank 记录+APP_DATA 缺省记录+APP1/APP2 **同版本**双镜像,APP2 由 uvprojx target "APP2" 链接 0x01024000 构建;运行 bank 用信息项 0x07 CUR_BANK 识别);`flash_package.bat tools\out\caiic_ble_dual.hex` 烧录后可用 `appsw` 在两 bank 间切换(已实测双向切换)。 - **OTA 双 bank 选包**:OTA 写对侧 bank,载荷必须链接在目标 bank 地址;两份载荷见上,客户端按 CUR_BANK 选包(详见开发日志 §39)。 3. 日常开发调试:Keil F7 编译、F8 下载即可(Boot 不校验镜像 CRC,可直接下载 APP 调试);**Keil 下载选项必须是 "Erase Sectors",整片擦除会杀掉 Boot/bootsetting**(杀掉后需重烧整片包恢复)。板子上烧过其他 0x01000000 起步的程序同样会覆盖 Boot,恢复也是重烧整片包。 4. 日常固件升级设计路径是 BLE OTA(手机 App 或 PC bleak 客户端)。 验证运行:串口助手接 PB6(TX)/PB7(RX),460800 8N1(V1.00.26 起),复位后应看到 banner 与 `caiic->` 提示符(`help` 查看命令);手机应能搜到广播名 `CAIIC-MCM-20260902`。 ## BLE 接口与协议 协议权威文档:`docs/ble_protocol.md`(V1.1)。广播名 `CAIIC-MCM-20260902`,自定义 128-bit UUID 服务 `00002760-08c2-11e1-9073-0e8ac72e1001`(SDK rdtss 服务),特征: | 特征 UUID 尾段 | 属性 | 用途 | |---|---|---| | `...c72ee001` | Write Without Response | 0xCA 帧协议下行(CLI_REQ / INFO_QUERY / OTA_*) | | `...c72ee002` | Notify | 帧协议上行应答(CLI_RSP / INFO_RSP / OTA_RSP) | | `...c72ee003` | Read + Write(带响应) | **CLI 读写特征**:写原始命令行(≤63B)→ **分包读回**输出文本(每片 ≤att_mtu−2,0 长度包=结束,V1.00.13 起;此前单读 ≤512B),V1.00.02 新增 | | `...c72ee004` | Read | **只读参数特征**:读出全部信息项 TLV(同 INFO_RSP(all)),V1.00.04 新增 | | `...c72ee005` | Read + Write(带响应) | **OTA 专用特征**(V1.00.19 新增):写携带一帧 OTA 传输帧 → 读同一特征取回 OTA_RSP(轮询至非空),见 ble_protocol.md §6.6 | - **notify 上行已修复(V1.00.19)**:根因是固件帧 CRC16 漏算最后一个 payload 字节(3+payLen vs 协议规定的 4+payLen),所有帧被静默丢弃,与 notify 硬件链路无关(开发日志 §42)。帧协议通道(e0001/e0002)已实测恢复。App(SmartAssiter)走 `...e0003`/`...e0004` 读写特征 + `...e0005` OTA 特征(App 侧参考 `src/mcm/McmOta.ts`,PC 参考 `tools/ble_ota_update.py`)。 - 帧格式:`0xCA | TYPE | SEQ | LEN(LE16) | PAYLOAD | CRC16-CCITT(0x1021/0xFFFF, LE)`,**CRC 覆盖 TYPE..PAYLOAD 共 4+payLen 字节**;OTA 为双 bank 直写、END 整镜像 zlib CRC32 + 向量表 bank 校验后更新 bootsetting 并复位。OTA 传输层通道无关:BLE e0005(逐帧锁步)/ UART 二进制模式(CLI `ota`;V1.00.24 起**流式模式**:BEGIN 16B flags、8KB 窗口流水线、扇区边界 ack、go-back-N,旧固件自动回退锁步)/ 旧帧协议通道,详见 ble_protocol.md §6.6/§6.7。 - 连接后设备主动发起 MTU=247 交换;失败退化为默认 20B/包,协议按字节流重组,两种情形都正确。 - 信息项 id:0x01 固件版本 u32 / 0x02 芯片温度 i16(0.1°C,ADC CH7) / 0x03 风扇转速 u16(0xFFFF=无硬件,`app_fan_get_rpm()` 弱符号,产品板重写即可) / 0x04 电压 u16(mV,ADC CH6) / 0x05 运行时长 u32(s) / 0x06 剩余堆 u32(B) / 0x07 当前运行 bank u8(1=APP1,2=APP2,OTA 选包依据)。 - 调试手段:CLI 命令 `blelog on` 后,串口打印每个收/发协议帧 hex dump、连接/断开、CCCD 订阅事件(走 printf,不经 BLE 通道,避免自激)。 - **维护命令(V1.00.10 起)**:bootsetting 与 APP_DATA 参数区为**结构化**读写(`appget`/`appset`/`bsdump`/`bsset`,不暴露裸读写),UART 与 BLE CLI 读写特征 `...e0003` 均可调用;V1.00.11 起新增 `reset`(复位单板)/`factory`(恢复出厂设置)/`uartrst`(复位串口)/`uartinfo`(查询串口参数);V1.00.15 起新增 `appsw`(切换运行 bank,切前复算目标镜像 CRC32)。详见 `docs/ble_protocol.md` §6.5。 ## 手机 App(SmartAssiter) - uni-app **Vue3 + TypeScript**(`manifest.json` vueVersion 3,appid `__UNI__884AC41`),**HBuilderX 工程**(有 `.hbuilderx/`,无 package.json/vite 配置)——开发/运行/打包均在 HBuilderX IDE 内进行(运行→运行到手机或模拟器;发行→原生 App 云打包)。目标平台为 Android/iOS App(BLE 功能仅 App 端有效;manifest 里保留 mp-weixin 配置但蓝牙不依赖它)。 - 由 uni-app x(uvue/uts)+ 第三方蓝牙插件迁移而来,现蓝牙全部用 **uni 内置 BLE API**(vue3 App 端内置),标准基座即可运行(见 `SmartAssiter/docs/修改记录_2026-09-03_迁移uni-app-vue3与蓝牙去插件.md`)。 - 结构: - `src/BluetoothManager.ts` — 蓝牙管理核心(扫描/连接/服务发现/读写/MTU/RSSI;**读写按特征值独立通道**:读请求经 `onBLECharacteristicValueChange` 按 characteristicId 分发到各特征自己的队列/超时(3s),写无跨特征阻塞;链路未稳误报的 10007 读/写各延时重试一次;连接状态经 `uni.$emit("bleState", state)` 广播,0=已连接可用) - `src/mcm/` — 设备业务层:`McmCli.ts`(CLI 特征写命令/分包读应答——读到 0 长度包止,Promise 链串行)、`McmInfo.ts`(参数特征 TLV 解析,含 0x07 CUR_BANK)、`McmCommands.ts`(业务命令封装:sysinfo/devinfo/appget/appset 等)、`McmOta.ts`(combo 包解析 + e0005 锁步 OTA,重发/再同步/中止) - `pages/tabbar/` — home(设备连接+参数展示+APP_DATA 参数读写)、ota(升级页:选择 mothercup_ble_ota.bin→e0005 锁步 OTA→复位回连复核)、my;`pages/bleTest/bluetoothOperation/`(CLI 终端页);login/register/displayUserInfo 为云端账号业务 - `api/` — 云端 HTTP 封装(`httpInstance.ts` 含服务器列表 SERVER_LIST,正式/测试/DEBUG 三地址,token 鉴权);`common/auth.ts`(token 本地存储)、`common/bleInfo.ts`(已连设备名/MAC 记忆) - `uni_modules/` 仅 uni-icons、uni-scss(官方组件,无第三方插件) - App 侧错误码约定(BluetoothManager):0=成功,10000=连接失败,10001=已断开,10002=蓝牙未开,10003=无权限,10004/10005=服务/特征缺失,10008=读写/MTU 失败或超时。 ## PC 工具(tools/) **自包含生产包(§49)**:tools/ 内嵌 Python 运行时(`python-embed/`,bleak+pyserial 预装)+ NSpyocd 烧录器副本 + DFP pack,`make_release.bat` 一键打 zip 到 `out/mothercup_tools_<时间戳>.zip`——解压到任何 Windows 电脑即可用,无需安装 Python/任何环境。三件套不入库(gitignore):`python-embed/`、`NSpyocd/`、`N32WB03x_DFP.1.4.0.pack`;**bat 文件必须保持 CRLF 行尾**(LF 会导致 cmd 解析错乱)。Python 解析优先级:`python-embed` → `.venv-ble`(开发机自动建)→ 系统 Python。 - `merge_image.py` — 纯 Python 无三方依赖;合并 boot+bootsetting(缺省记录,脚本生成)+APP 为整片 hex/bin,同时产出 `_ota.bin`/`_ota.json`(bank1 载荷);`--ota-app2` 追加 bank2 载荷 `_ota_app2.bin/.json`;`--app2 --with-appdata` 生成双 bank 整包(make_dual_package.bat 使用);自动从 `app_version.h` 取 `APP_FW_VERSION_NUM` 写入清单(含 `target_bank` 字段);**出包硬卡:镜像初始 SP 必须在 (0x20004000, 0x2000C000](SRAM 悬崖,§47)** - `make_package.bat` / `flash_package.bat` — 一键出包 / NSpyocd 整片烧录(flash_package.py 流式转发输出并把厂商横幅替换为 "CAIIC NSLINK UMP") - `make_dual_package.bat` — 双 APP 整包(Boot+bootsetting 双 bank+APP_DATA+APP1+APP2,APP2 升一版链接 0x01024000),用于 appsw 切换测试 - `ble_cli_test.py` + `ble_cli.bat` — PC 端 bleak 蓝牙 CLI 测试客户端(帧协议模式 + `-rw` 读写特征模式,交互模式 `-i`,venv 在 `tools/.venv-ble`,不入库;首次运行 bat 按 `tools/requirements-ble.txt`(bleak+pyserial)自动创建) - `ble_ota_update.py` + `ble_ota.bat` — BLE OTA 升级器(解析单文件升级包 `mothercup_ble_ota.bin`、按 CUR_BANK 选对侧 bank 载荷、经 OTA 特征 `...e0005` 逐帧锁步、复位检测+重连校验;`--uart COMx` 走串口二进制模式(460800 8N1,V1.00.26 起):握手标记进入/ABORT 退出;V1.00.24 起默认流式(8KB 窗口+扇区 ack+go-back-N),`--lockstep` 或旧固件自动回退锁步)。**BLE 与 UART 双通道均已实测通过(§42/§44),流式见 §47/§48** - `ble_temp_watch.py` — 温度监测小工具 ## 实时架构约定(固件) - 使用 FreeRTOS V9.0.0 原生 API,**不使用 cmsis_os 封装**。 - **IWDG 看门狗(V1.00.27 起)**:4s 超时,idle hook 仅在 3s 内有任务心跳时喂狗(BLE/LED/CLI 任务循环打点 `app_wdt_heartbeat()`);SWD halt 时冻结(DBG_IWDG_STOP);banner 打印复位原因;`hang` 命令可验证点火。新增任务请在循环里打心跳。 - 任务:BLE 调度任务(栈 512 字,优先级 2,循环 `rwip_schedule(); vTaskDelay(1ms);`——**ke_msg/ke_timer 只允许在该任务上下文运行**);LED 任务(LED1 闪烁半周期读 APP_DATA 参数 `led1_blink_ms`);CliTask(优先级 3);CLI 输出经环形缓冲由 BLE 任务上下文发 notify(`ble_up.c`)。`configTOTAL_HEAP_SIZE = 18KB`(heap_4;SRAM 悬崖约束见 Flash/RAM 布局铁律)。 - SysTick 由 FreeRTOS port 接管:`main` 中不要手动 `SysTick_Config`,`n32wb03x_it.c` 中不要重复定义 SVC/PendSV/SysTick_Handler。 - USART1_IRQn 优先级为 3(最低),因 ISR 内调用 FreeRTOS FromISR API,必须 ≥ `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`(=3)。BLE_SW/FIFO IRQ 优先级 0,其 ISR 内禁止调用 FromISR API。 - 串口输出并发:多任务/CLI 输出分别持有 `bsp_usart_tx_lock()` 互斥锁;调度器启动前为空操作。不要在中断或多个任务里直接 printf。 - **不接 ns_sleep 低功耗**(与 FreeRTOS tick 冲突):`main.c` 里 `ns_sleep_lock_acquire()` 永久锁睡眠,SWD 全程可调试;ns_sleep.c 仍需编译(ns_ble.c 引用其符号)。 ## 硬件引脚约束(重要) - **SWD 调试管脚 SWCLK=PA4 / SWDIO=PA5:应用程序绝对禁止占用**,否则下载/调试失效。 - 板载 LED:LED1=PB0(跳线 J21)、LED2=PA6(跳线 J22),蓝色,4.7K 限流。 - USART1:TX=PB6 / RX=PB7,复用 AF4,经排针 J3 引出。 - PB8/PB9 默认接 32.768K 晶振;PB3 有下拉注意事项(用户手册 5.2.4)。 - 新增 GPIO 前必须核对开发日志第 4 节引脚分配表。 - **寄存器级勘误修复必须先在 SDK 源码交叉验证地址用途**——曾按勘误表写 `0x40011004 |= 0x40`(AFEC 寄存器,与 BLE 协议栈共享)导致 BLE 射频挂死,已撤回(开发日志 §28 教训)。 ## 代码风格 - 固件为 C(ARMCC,MicroLIB):文件头/函数头用 Doxygen 注释(`@file`/`@brief`),**注释用英文**;BSP 层函数 `bsp__`;引脚/时钟等硬件参数集中在头文件顶部宏定义;使用 SDK 标准外设库 API,不要直接操作寄存器(确有例外需交叉验证,见上)。 - App 为 TypeScript/Vue3:注释用中文;BLE 通信统一走 `src/BluetoothManager.ts` 的 `MyApiResult` 回调约定,设备业务封装在 `src/mcm/`;不改 uni_modules 官方组件。 ## 测试策略 无自动化测试框架;验证方式为: 1. Keil 命令行构建必须保持 0 Error / 0 Warning;出包必须 `UV4 -r` 全量重建,并核对 map 的 `__initial_sp` 与 bin 向量表初始 SP 一致; 2. 烧录后通过串口输出(banner/`caiic->`/`devinfo`)、LED 行为人工确认; 3. BLE 链路用 `tools/ble_cli_test.py`(PC bleak)或手机 App 实测,配合固件 `blelog on` 串口抓帧对照 `docs/ble_protocol.md` §8.3 示例帧; 4. App 侧改动记录写入 `SmartAssiter/docs/修改记录_日期_主题.md`(沿用现有命名格式)。 ## 其他注意事项 - `nations-tec/` 下的 SDK、器件包与 PDF 为第三方只读资料,改动应只发生在 `mcm-ddc-ble/`、`Boot/`、`SmartAssiter/`、`tools/`、`docs/` 内。 - 固件重大改动应同步追加 `docs/开发日志.md` 新章节(现有格式:`## N. 标题(日期)`),协议改动同步 `docs/ble_protocol.md`。 - 每改固件必递增版本号(`mcm-ddc-ble/inc/app_version.h`),否则无法识别板上实际固件。