# AGENTS.md ## 项目概述 本仓库是基于国民技术(Nations)**N32WB031 BLE SoC** 的嵌入式固件工程集合。实际芯片型号 **N32WB031KEQ6-2**(Cortex-M0,64MHz HSI,**Flash 512KB**,RAM 48KB+16KB)。 当前活跃工程: - **`mcm-ddc-04/`** — 主工程(APP,链接在 APP1 bank `0x01008000`/224KB):UART(printf 重定向 + DMA 发送 + RX 中断)、CLI 命令框架(UART + BLE 双通道)、FreeRTOS 多任务、GPIO 点灯、BLE 协议栈(自定义 GATT 透传服务 CLS)、BLE OTA 双 bank 直写升级(见开发日志第 15/16 节、`docs/ble_protocol.md`)。 - **`Boot/`** — 自写精简 bootloader(链接在 `0x01000000`/16KB):校验 bootsetting 自身完整性(magic + 结构体 CRC32)后按 active bank 的 `start_address` 直接跳转;**不校验镜像 CRC(在 OTA 升级过程中校验)**;记录无效或地址越界回退 APP1(开发日志第 19/21 节)。 - **`mcm-ddc-ble/`** — 独立 BLE 工程(基于 SDK rdtss 例程 + FreeRTOS,睡眠已锁保 SWD):当前链接在 `0x01008000`/0x38000 作为 APP1,与 Boot 组成整包 `caiic_ble_full.*`;单跑时把 IROM1 改回 `0x01000000, 0x40000`。日志在 `mcm-ddc-ble/docs/开发日志.md`。 仓库顶层目录: - `mcm-ddc-04/` — 主工程(应用代码、MDK 工程文件、开发日志) - `mcm-ddc-ble/` — 独立 BLE 工程(rdtss 蓝本 + FreeRTOS,APP1 链接形态) - `Boot/` — bootloader 工程(`src/main.c`、`dfu_layout.h`、`boot_crc32.c`;后两个被 APP 工程以相对路径 `..\..\Boot\src` 共用) - `tools/` — 烧录包工具:`merge_image.py`(合并 boot + bootsetting 缺省记录 + APP 为整片 hex/bin,支持 `merge_image.py [app_bin] [输出名]`)、`make_package.bat`(一键全量重建 `-r` + 合并)、`flash_package.bat`(NSpyocd 整片烧录),产物在 `tools/out/` - `nations-tec/` — 厂商资源:SDK V2.0.0、DFP 器件包、STB 开发板资料、官方 PDF 文档。**这些内容为只读参考资料,不要修改。** - `app/`、`docs/` — 顶层空目录,预留占位 关键参考路径(相对仓库根): - SDK:`nations-tec/N32WB03x_SDK_V2.0.0`(固件库 `firmware/`、中间件 `middlewares/Nationstech/ble_library` 与 `middlewares/Third_Party/FreeRTOS`、官方例程 `projects/n32wb03x_EVAL/`、DFU 工具 `utilities/dfu`) - 官方例程:USART printf `projects/n32wb03x_EVAL/peripheral/USART/Printf`、点灯 `peripheral/GPIO/LedBlink`、FreeRTOS `application/FreeRTOS/FreeRTOS_ThreadCreation` - 开发日志与详细设计决策:`mcm-ddc-04/docs/开发日志.md` ## 工程结构(mcm-ddc-04) ``` mcm-ddc-04/ ├── app/ │ ├── main.c # 入口:VTOR 重映射 → USART 初始化+banner → LED 初始化 → app_ble_init → 建队列/任务/CLI → vTaskStartScheduler │ ├── bsp_usart.c/.h # USART1 初始化(PB6/PB7,115200 8N1)+ fputc 重定向('\n' 前自动补 '\r')+ DMA TX(CH1,轮询完成)+ RXDNE 中断字节队列 + TX 互斥锁 │ ├── bsp_led.c/.h # LED1(PB0)/LED2(PA6) 初始化、on/off/toggle │ ├── app_tasks.c/.h # 3 个 FreeRTOS 任务 + 日志队列(生产者-消费者模型)+ 主动打印开关(默认关) │ ├── app_cli.c/.h # CLI UART 前端:CliTask 行接收/编辑/历史/Tab/Ctrl+Z,分行后交 cli_core 执行 │ ├── cli_core.c/.h # CLI 核心(命令表/handler/分词执行),输出经可切换 cli_out_fn(默认 UART DMA);命令:help/version/sysinfo/log/led/bankinfo │ ├── app_ota.c/.h # BLE OTA 接收器:4KB 扇区缓冲直写对侧 bank + CRC32 校验 + bootsetting 更新 + 复位切换 │ ├── app_version.h # 固件版本号 APP_FW_VERSION │ ├── n32wb03x_it.c/.h # NMI / HardFault 异常处理 + USART1_IRQHandler(转发到 bsp_usart_rx_isr_handler) │ ├── FreeRTOSConfig.h # heap 22KB,SVC/PendSV/SysTick 映射给 FreeRTOS port │ └── ble/ │ ├── app_ble.c/.h # BLE 栈初始化/广播/连接事件 + BLE 调度任务 + notify 发送与下行回调 + app_ble_max_payload/is_connected │ ├── app_ble_proto.c/.h # BLE 帧协议前端:字节流重组、CLI_REQ/CLI_RSP 传输、OTA 帧分发、pending 重试(BleTask 上下文) │ ├── app_user_config.h # 广播名 CAIIC-MCM、连接参数、profile/日志开关(被 SDK rwip_config.h 包含) │ └── app_profile/ │ ├── rwapp_config.h # CFG_APP_* → BLE_APP_* 映射 │ └── app_cls.c/.h # 自定义 128-bit UUID GATT 服务(写 + notify 两特征,基于 SDK rdtss profile 引擎) ├── MDK-ARM/ │ ├── embeddedSrc.uvprojx / .uvoptx # Keil µVision5 工程文件(含 DFU 组:..\..\Boot\src\boot_crc32.c) │ ├── Objects/ # 编译产物(embeddedSrc.axf / .hex) │ ├── bin/ # fromelf 生成的 embeddedSrc.bin │ └── build.log └── docs/开发日志.md ``` 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` 引用。因此 `mcm-ddc-04` 目录不能脱离仓库根单独移动。 工程配置:器件 `N32WB031KEQ6-2`(512KB Flash),IROM 0x01008000 / 0x38000(APP1 区,前 32KB 留给 Bootloader),**IRAM 0x20004000 / 0xC000**(低 16KB 保留给芯片 ROM/BLE,见下),MicroLIB,全局宏 `N32WB03X, USE_STDPERIPH_DRIVER`;链接器 Misc 附加 BLE ROM 符号表 `symbol_g15.obj`。 ## 构建与烧录 工具链:Keil µVision5(ARMCC V5.06 update 6),安装于 `D:\Keil_v5`。 命令行构建(工作目录必须为 `mcm-ddc-04/MDK-ARM`): ```bash "D:\Keil_v5\UV4\UV4.exe" -b embeddedSrc.uvprojx -j0 -o build.log ``` 构建成功后自动执行 `fromelf --bin --output=.\bin\embeddedSrc.bin .\Objects\embeddedSrc.axf`。 当前基线结果:**0 Error(s), 0 Warning(s)**,体积 `Code=38348 RO-data=6932 RW-data=10600 ZI-data=36128`(RW+ZI≈45.7KB < 48KB 可用窗口,heap 22KB)。 烧录与运行: 1. Keil 打开 `MDK-ARM/embeddedSrc.uvprojx`,F7 编译 2. NS-LINK 接 SWD(PA4/PA5),F8 下载——Boot 跳转不校验镜像 CRC,Keil 直接下载 APP 即可正常启动调试;**但 Keil 下载选项必须是"Erase Sectors",整片擦除会杀掉 Boot**(杀掉后独立运行不启动,需重烧整片包恢复) 3. 独立运行(脱调试器)需烧整片包:`tools\flash_package.bat tools\out\caiic_full.hex`(改代码后先 `make_package.bat` 重新出包)。**板子上烧过其他 0x01000000 起步的程序会覆盖 Boot/bootsetting,恢复靠重烧整片包** 4. 串口助手接 PB6(TX)/PB7(RX),115200 8N1,复位后应看到启动 banner 与 `caiic->` CLI 提示符(输入 `help` 查看命令;LED 滚动日志默认关闭,用 `log on` 打开) 5. BLE:手机 nRF Connect 应能搜到并连接 `CAIIC-MCM`,可见自定义服务(写特征 + notify 特征) ## 硬件引脚约束(重要) - **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)。 ## 实时架构约定 - 使用 FreeRTOS V9.0.0 原生 API(`xTaskCreate` / `vTaskDelay` / `xQueue`),**不使用 cmsis_os 封装**。 - 任务模型:LedTask(LED1,500ms)、LedTask2(LED2,1000ms)为生产者,只向日志队列投递 `LogMsg_t`;PrintTask(优先级 3,栈 1024 字)消费队列并 printf。**主动日志打印由 `AppTasks_SetLogEnabled()` 控制,默认关闭**(CLI 命令 `log on|off` 切换)。新增需要打印的任务时沿用此生产者-消费者模式,不要在中断或多个任务里直接 `printf`。 - CLI 任务(优先级 3,栈 1024 字,见 `app_cli.c`):从 USART1 RXDNE 中断的字节队列取输入,行结束符 `\r\n` / `\n\r` / `\r` / `\n` 均识别;解析-执行-应答一体化,应答走 `bsp_usart_write_dma`(DMA_CH1)。新命令在 `s_cmds[]` 命令表中注册。支持 Tab 命令补全、上下方向键历史回翻(8 条环形缓冲)、Ctrl+Z 关闭主动打印。 - 串口输出并发:PrintTask 的整条 printf 与 CLI 的整段应答分别持有 `bsp_usart_tx_lock()` 互斥锁,避免字节级交错;调度器启动前该锁为空操作。 - SysTick 由 FreeRTOS port 接管(`FreeRTOSConfig.h` 中 `xPortSysTickHandler → SysTick_Handler` 映射):`main` 中不要手动 `SysTick_Config`,`n32wb03x_it.c` 中不要重复定义 SVC/PendSV/SysTick_Handler。 - USART1_IRQn 中断优先级为 3(最低),因 ISR 内调用 FreeRTOS FromISR API,必须 ≥ `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`(=3)。 - `configTOTAL_HEAP_SIZE = 22*1024`(4 个任务栈各 1024 字 + BLE 任务 512 字,另加队列/TCB/空闲任务开销),使用 heap_4。 ## BLE 架构约定(重要) - **RAM 布局(铁律)**:本芯片 SRAM 为 48KB+16KB。**低 16KB(0x20000000~0x20003FFF)由芯片 ROM/BLE 子系统占用**(rwip 堆描述符 0x20000118 起、patch 数组、中断中继表,由 ROM 启动代码预备,全 SDK 无源码重写)。任何工程的 IRAM 执行区必须从 **0x20004000** 起(含 Boot 和任何小工具),否则启动时代的 .data/.bss 初始化会冲掉 ROM 数据,BLE init 必然 HardFault(实测根因,开发日志第 21 节)。 - **VTOR**:Cortex-M0 无 SCB->VTOR,向量重映射用 `PWR->VTOR_REG`(bit31=EN|[30:0]=基址)。规则:**BLE 初始化之前** VTOR 指向 APP 自身向量表(`0x80000000|0x01008000`,main 开头设置,USART1 RX 中断需要);**`ns_ble_stack_init()` 之后 VTOR 必须为 0**——此后所有中断经芯片 ROM 跳板 + RAM 中继(`ns_ble_stack_vtor_init` 把 APP 的 `__Vectors` 拷到 0x200000e8/0x200009c0 并把 BLE_FIFO/BLE_SLP/EXTI4_12 指向 ROM/RAM handler)。绝对不要在 app_ble_init() 后重设 VTOR,否则 BLE FIFO 中断落入 weak Default_Handler 死循环(实测崩溃根因,见开发日志第 18 节)。 - **BLE 调度任务**(`app/ble/app_ble.c`,栈 512 字,优先级 2):循环 `rwip_schedule(); vTaskDelay(1ms);`。**ke_msg/ke_timer 只允许在该任务上下文运行**(SDK 约束),不要在其他任务或中断里直接调用。 - BLE 中断向量不在 `n32wb03x_it.c` 定义:启动文件中 BLE_*IRQHandler 为 weak,真正 handler 由 `symbol_g15.obj`(ROM)+ SDK RAM 重映射(0x200000e8/0x200009c0)提供。BLE_SW/FIFO IRQ 优先级 0,其 ISR 内禁止调用 FreeRTOS FromISR API。 - GATT 服务:自定义 CLS 服务(`app/ble/app_profile/app_cls.c`),复用 SDK rdtss profile 引擎;notify 发送为单包接口(忙返回 -1,上层重试)。**ns_sleep 低功耗不接**(与 FreeRTOS tick 冲突),NS_LOG/LPUART 不接。 ## 代码风格 - 语言为 C(ARMCC,C 库 MicroLIB),文件头与函数头使用 Doxygen 风格注释(`@file` / `@brief`),注释用英文。 - 命名:BSP 层函数 `bsp__`;应用层聚合函数 `AppTasks_*` / `AppCli_*`;引脚/时钟等硬件参数集中在头文件顶部宏定义。 - 使用 SDK 标准外设库 API(如 `RCC_EnableAPB2PeriphClk`、`GPIO_InitPeripheral`、`USART_Init`),不要直接操作寄存器。 - 新增 GPIO 前必须核对开发日志第 4 节引脚分配表,避开 PA4/PA5。 ## 测试策略 无自动化测试框架;验证方式为: 1. Keil 命令行构建必须保持 0 Error / 0 Warning; 2. 烧录后通过串口输出与 LED 行为人工确认。 ## 其他注意事项 - `nations-tec/` 下的 SDK、器件包与 PDF 为第三方只读资料,改动应只发生在 `mcm-ddc-04/`(或新增工程目录)内。 - BLE 协议栈(`middlewares/Nationstech/ble_library`)已接入(开发日志第 15 节);CLI-over-BLE 协议与 BLE OTA 为后续任务。