mothercup/mcm-ddc-ble/docs/开发日志.md

610 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# N32WB031 基础工程开发日志
日期:2025-06-09
工程:`H:\caiic_workspace\mothercup\embeddedSrc`
目标芯片:N32WB031(国民技术 BLE SoC,Cortex-M0,64MHz,Flash 256KB,RAM 48KB)
## 1. 任务目标
基于 N32WB03x SDK V2.0.0 新建裸工程,实现:
- UART 串口打印(printf 重定向)
- 集成 FreeRTOS,构建实时多任务架构
- GPIO 点灯(LED 周期翻转)
- 引脚分配不得与 SWD 调试管脚冲突
## 2. 参考资料
| 资料 | 路径 |
|---|---|
| SDK V2.0.0 | `nations-tec/N32WB03x_SDK_V2.0.0` |
| 器件包 | `nations-tec/N32WB03x_DFP.1.4.0.pack` |
| 用户手册 | `nations-tec/CN_UM_N32WB03X_Series_User_Manual_V1.5.pdf` |
| 硬件设计指南 | `nations-tec/CN_DG_N32WB03x_Series_Chips_Hardware_Design_Guide_V1.4.pdf` |
| STB 开发板资料 | `nations-tec/N32WB031_STB_V1.3` |
参考例程:
- 串口:`projects/n32wb03x_EVAL/peripheral/USART/Printf`
- 点灯:`projects/n32wb03x_EVAL/peripheral/GPIO/LedBlink`
- FreeRTOS:`projects/n32wb03x_EVAL/application/FreeRTOS/FreeRTOS_ThreadCreation`
## 3. 关键硬件结论
- **SWD 调试管脚:SWCLK=PA4,SWDIO=PA5**(复位后默认 AF0)——本工程所有 GPIO 分配均避开这两个脚
- STB 开发板板载 LED:LED1=PB0(跳线 J21)、LED2=PA6(跳线 J22),蓝色 LED,4.7K 限流
- 串口排针 J3 已引出 PB6/PB7
- 注意:PB8/PB9 默认接 32.768K 晶振;PB3 有下拉注意事项(手册 5.2.4)
## 4. 引脚分配表
| 功能 | 引脚 | 复用 | 说明 |
|---|---|---|---|
| USART1_TX | PB6 | AF4 | 115200 8N1 |
| USART1_RX | PB7 | AF4 | |
| LED1 | PB0 | GPIO 推挽输出 | 板载 D1 |
| LED2 | PA6 | GPIO 推挽输出 | 板载 D2 |
| SWDCLK | PA4 | AF0 | 调试占用,应用程序禁用 |
| SWDIO | PA5 | AF0 | 调试占用,应用程序禁用 |
## 5. 工程结构
```
embeddedSrc/
├── app/
│ ├── main.c # 入口:时钟更新 → USART 初始化+banner → LED 初始化 → 建队列/任务 → vTaskStartScheduler
│ ├── bsp_usart.c/.h # USART1 初始化 + fputc 重定向('\n' 前自动补 '\r')
│ ├── bsp_led.c/.h # LED1/LED2 初始化、on/off/toggle
│ ├── app_tasks.c/.h # 3 个 FreeRTOS 任务 + 日志队列
│ ├── n32wb03x_it.c/.h # NMI / HardFault 异常处理
│ └── FreeRTOSConfig.h # heap 8KB,SVC/PendSV/SysTick 映射给 FreeRTOS port
├── MDK-ARM/
│ ├── embeddedSrc.uvprojx
│ └── embeddedSrc.uvoptx
└── docs/
└── 开发日志.md(本文件)
```
SDK 源码(固件库、CMSIS、FreeRTOS V9.0.0、启动文件)以相对路径 `..\..\nations-tec\N32WB03x_SDK_V2.0.0` 引用,不复制到工程内。
工程配置:器件 N32WB031,IROM 0x01000000 / 0x40000,IRAM 0x20000000 / 0xC000,MicroLIB,宏定义 `N32WB03X, USE_STDPERIPH_DRIVER`。
## 6. 实时多任务架构
使用 FreeRTOS 原生 API(xTaskCreate / vTaskDelay / xQueue),不用 cmsis_os 封装。
| 任务 | 功能 | 周期/触发 | 栈(字) | 优先级 |
|---|---|---|---|---|
| LedTask | 翻转 LED1,向日志队列发送 LogMsg_t | 500ms | 128 | 2 |
| LedTask2 | 翻转 LED2,向日志队列发送 LogMsg_t | 1000ms | 128 | 2 |
| PrintTask | xQueueReceive 阻塞取消息并 printf | 队列驱动 | 256 | 3 |
生产者-消费者模型:LED 任务只负责投递消息,打印任务独占串口输出,避免多任务直接 printf 造成的输出交错。
调度相关:
- SysTick 由 FreeRTOS port 接管(FreeRTOSConfig.h 中 `xPortSysTickHandler → SysTick_Handler` 映射),main 中不再手动 `SysTick_Config`
- `configTOTAL_HEAP_SIZE = 8*1024`(48KB RAM 余量充足)
## 7. 编译验证
- 工具链:Keil µVision5(`D:\Keil_v5\UV4\UV4.exe`,ARMCC V5.06 update 6)
- 命令行:`UV4.exe -b embeddedSrc.uvprojx -j0 -o build.log`(工作目录 `embeddedSrc/MDK-ARM`)
- 结果:**0 Error(s), 0 Warning(s)**
- 体积:`Code=8248 RO-data=724 RW-data=100 ZI-data=10532`
- 产物:`Objects/embeddedSrc.axf`、`Objects/embeddedSrc.hex`、`bin/embeddedSrc.bin`
- 自查:全工程无 PA4/PA5 占用;SVC/PendSV/SysTick_Handler 无重复定义
## 8. 烧录与运行
1. Keil 打开 `embeddedSrc/MDK-ARM/embeddedSrc.uvprojx`,F7 编译
2. NS-LINK 接 SWD(PA4/PA5),F8 下载
3. 串口助手接 PB6(TX)/PB7(RX),115200 8N1
4. 复位后预期输出:启动 banner + `LED1 toggled, count = N` / `LED2 toggled, count = N` 滚动日志
注意:未在真实硬件上运行验证。若 LED 不亮,检查 STB 板 J21/J22 跳线;若串口无输出,检查 J3 排针接线。
## 9. 后续计划
- 板卡实测验证 LED 与串口日志
- 按需接入 BLE 协议栈(SDK ble 例程为裸机 rwip_schedule 调度,与 FreeRTOS 架构需做整合设计)
---
日期:2026-09-01
## 10. UART DMA 发送 + 日志开关 + CLI 命令框架
### 10.1 DMA 可行性结论
N32WB031 具备 DMA 外设(5 通道),固件库支持 `USART_EnableDMA` 与通道重映射
(`DMA_RequestRemap`),USART1_TX 可映射到 DMA_CH1(参考官方例程
`projects/n32wb03x_EVAL/peripheral/USART/DMA_Interrupt`)。**硬件支持,已实现 DMA 发送。**
### 10.2 串口驱动扩展(bsp_usart)
- TX 双通道并存:`fputc` 轮询发送保留给调度器启动前的 banner 与 PrintTask;
新增 `bsp_usart_write_dma(buf, len)` 走 DMA_CH1(每次发送重新 `DMA_Init`,轮询
`DMA_FLAG_TC1` 完成标志 + 等 `USART_FLAG_TXC` 移位寄存器排空),供 CLI 输出使用。
- RX 新增 RXDNE 中断:`USART1_IRQHandler`(n32wb03x_it.c)→ `bsp_usart_rx_isr_handler()`,
字节经 `xQueueSendFromISR` 投递到 64 字节接收队列;应用侧用
`bsp_usart_read_byte(ch, timeout_ms)` 阻塞取字节。NVIC 优先级 = 3(最低,满足
`configMAX_SYSCALL_INTERRUPT_PRIORITY` 约束)。
- 新增 TX 互斥锁 `bsp_usart_tx_lock/unlock`:调度器未运行时为空操作;
PrintTask 的整条 printf 与 CLI 的整段应答各持锁一次,避免 log 开启后两类输出字节级交错。
### 10.3 主动打印开关
`app_tasks` 新增 `AppTasks_SetLogEnabled()/AppTasks_GetLogEnabled()`,**默认关闭**。
LED 任务照常翻转,仅在开关打开时才向日志队列投递消息。运行时通过 CLI
`log on|off` 切换,`log` 无参数查询当前状态。
### 10.4 CLI 框架(app_cli)
- 独立任务 `CliTask`(栈 256 字,优先级 3),独占完成:行接收 → 解析 → 执行 → 应答,
应答全部走 DMA TX(`cli_write`/`cli_printf`,需显式带 `\r\n`)。
- 命令表 `CliCmd_t s_cmds[]`(name/help/handler),新增命令只需在表中加一项。
- 行结束符兼容 **`\r\n`、`\n\r`、`\r`、`\n`** 四种:首个 `\r` 或 `\n` 触发分发,
紧跟的互补字符被吞掉一次。支持退格(0x08/0x7F)编辑,行缓冲 64 字节,超长响铃。
- 内置命令:`help`、`version`、`log [on|off]`、`led <1|2> <on|off|toggle>`。
- 提示符 `n32> `,空行仅重显提示符。
### 10.5 编译验证
- `UV4.exe -b embeddedSrc.uvprojx -j0 -o build.log`:**0 Error(s), 0 Warning(s)**
- 体积:`Code=14712 RO-data=944 RW-data=112 ZI-data=10696`(Flash/RAM 余量仍充足)
- 新增源文件:`app/app_cli.c/.h`;uvprojx 的 FWLB 组加入 `n32wb03x_dma.c`
- 烧录后预期:banner 之后出现 `CLI ready. Type 'help' for commands.` 与 `n32> ` 提示符;
默认无 LED 滚动日志,`log on` 后恢复。
- 注意:尚未上板实测,DMA 与中断路径需硬件验证。
---
日期:2026-09-01
## 11. 任务栈统一调整为 1024 字
- 上板实测 DMA/CLI/日志开关运行正常后,4 个任务栈统一调整为 1024 字(4KB/任务):
`LED_TASK_STACK` / `PRINT_TASK_STACK`(app_tasks.c)、`CLI_TASK_STACK`(app_cli.c)。
- 4 任务共 16KB 栈,超出原 8KB heap,故 `configTOTAL_HEAP_SIZE` 由 8KB 调至 20KB
(含队列、TCB、空闲任务栈 128 字的开销)。
- 编译:0 Error / 0 Warning;体积 `Code=14712 RO-data=944 RW-data=112 ZI-data=22984`,
ZI 约占 48KB RAM 的 47%,余量充足。
---
日期:2026-09-01
## 12. CLI 增强:Ctrl+Z 关日志、Tab 补全、命令历史
均在 `app_cli.c` 的 CliTask 中实现:
- **Ctrl+Z(0x1A)**:立即 `AppTasks_SetLogEnabled(0)` 关闭主动打印,打印 `[log off]`
并重绘当前输入行。用于 log 滚动刷屏时快速停止。
- **Tab(0x09)自动补全**:仅补全行首命令名(已含空格则不动作)。唯一匹配则补全
并追加空格;多个匹配则先扩展公共前缀,无法扩展时列出候选并重绘输入行。
- **命令历史**:环形缓冲 8 条 × 64 字节(`s_history`),提交时去重(空行、与上一条
相同不入队);上/下方向键(`ESC [ A` / `ESC [ B` 转义序列状态机解析)回翻历史,
越过最新一条回到空行。回翻采用"清行重绘"(`\r` + 提示符 + 空格擦除 + 重显)。
- `help` 输出末尾附按键说明。
- 编译:0 Error / 0 Warning;体积 `Code=15688 RO-data=944 RW-data=112 ZI-data=23496`。
---
日期:2026-09-01
## 13. CLI 提示符修改
- 命令行提示符由 `n32> ` 改为 `caiic->`(`app_cli.c` 中 `CLI_PROMPT` 宏)。
- 编译:0 Error / 0 Warning;体积 `Code=15692 RO-data=944 RW-data=112 ZI-data=23496`。
---
日期:2026-09-01
## 14. 软件版本号 + sysinfo 系统信息命令
- 新增 `app/app_version.h`:`APP_FW_VERSION "V1.00.01"`,启动 banner 与 `version`
命令均输出版本号。
- 新增 CLI 命令 `sysinfo`:输出运行时间(tick/秒)、任务数、heap 总量/当前空闲/
历史最小空闲,以及 `vTaskList` 任务表(名称/状态/优先级/栈高水位/编号,
栈单位为字)。`vTaskList` 行尾自带 `\r\n`,直接 DMA 输出。
- `FreeRTOSConfig.h` 新增 `configUSE_STATS_FORMATTING_FUNCTIONS 1`(`vTaskList`
依赖,同时需要 `configUSE_TRACE_FACILITY 1`,已具备)。
- 编译:0 Error / 0 Warning;体积 `Code=16944 RO-data=1020 RW-data=112 ZI-data=23880`。
---
日期:2026-09-01
## 15. BLE 接入:自定义 GATT 透传服务(CLS)+ FreeRTOS 整合
### 15.1 工程与链接布局
- 器件由 `N32WB031` 改为 `N32WB031KEQ6-2`(512KB Flash 型号);APP 链接到
**APP1 = 0x01008000,大小 0x38000(224KB)**(uvprojx 的 Cpu/IROM/OCR_RVCT4、
FlashDriverDll `-FL080000`、RegisterFile/SFDFile 同步修改)。IRAM 保持
`0x20000000/0xC000`。
- LDads Misc 加入 BLE ROM 符号表 `symbol_g15.obj`(相对路径
`..\..\nations-tec\N32WB03x_SDK_V2.0.0\middlewares\Nationstech\ble_library\ns_ble_stack\symdef\`)。
- 新增源码组:BLE_STACK(lib_att.c / rwip.c / rwip_driver.c)、BLE_PROFILE
(prf.c / prf_utils.c / rdtss.c / rdtss_task.c / rdts_common.c)、NS_LIB
(ns_ble.c / ns_ble_task.c / ns_sleep.c / ns_sec.c / ns_timer.c / ns_error.c)、
BLE_APP(app_ble.c / app_cls.c);FWLB 追加 `n32wb03x_qflash.c`(OTA 备用)与
`n32wb03x_exti.c`(ns_ble.c 的 EXTI_* 调用需要)。NS_LOG/LPUART、Crypto、
NS_DFU 未接入。
- Cads IncludePath 参照 rdtss.uvprojx 移植全部 BLE 相关目录(前缀改 2 层
`..\..`),`..\inc`→`..\app\ble`、`..\inc\app_profile`→`..\app\ble\app_profile`。
### 15.2 BLE 应用层(app/ble/)
- `app_user_config.h` / `app_profile/rwapp_config.h`:由 rdtss 精简。广播名
`CAIIC-MCM`;广播数据 = 128-bit 服务 UUID 列表(LSB first),扫描应答留空由
协议栈自动附加设备名(attach_name);连接参数 15/30ms、latency 0、超时 5000ms;
仅启用 `CFG_PRF_RDTSS`(复用 SDK rdtss profile 引擎),NS_LOG 全关。
- `app_profile/app_cls.c/.h`:自定义服务 CAIIC Link Service(属性表仿 app_rdtss.c):
- service `0000CA10-CA11-4B11-8000-CA11CA11CA11`
- 下行写特征(Write Without Response)`0000CA11-CA11-4B11-8000-CA11CA11CA11`
- 上行 notify 特征(Notify + CCCD)`0000CA12-CA11-4B11-8000-CA11CA11CA11`
沿用 SDK prf 框架(GAPM_PROFILE_TASK_ADD_CMD 建库、`ns_ble_prf_task_register`
注册消息表、`prf_get_itf_func_register` 挂 `rdtss_prf_itf_get`)。notify 发送为
单包接口:忙(上一包未收到 RDTSS_VAL_NTF_CFM)或未订阅时返回 -1,由上层重试。
- `app_ble.c/.h`:`ns_ble_stack_init`(注册 ble 消息回调)+ GAP/安全/广播参数 +
profile 注册 + `ns_ble_adv_start()`;连接/断开/MTU 更新事件经
`bsp_usart_tx_lock` 保护的 printf 输出;断开后自动重新开广播。对外接口:
`app_ble_init()` / `app_ble_notify_send()` / `app_ble_set_rx_callback()`。
- **BLE 调度任务**:`app_ble_init()` 内创建(栈 512 字、优先级 2),循环
`rwip_schedule(); vTaskDelay(pdMS_TO_TICKS(1));`。ke_msg/ke_timer 只允许在该
任务上下文运行(SDK 约束)。
- **不接 ns_sleep 低功耗**(与 FreeRTOS tick 冲突,代码内留 TODO);ns_sleep.c
仍需编译(ns_ble.c 引用 `ns_sleep_lock_acquire` 等符号),只是主循环不调用。
### 15.3 VTOR 处理(关键)
Cortex-M0 无 SCB->VTOR,本芯片用 `PWR->VTOR_REG`(bit31=EN,[30:0]=向量基址)。
APP 链接在 0x01008000,但 SDK `SystemInit()` 写成 0x81000000(指向 0x01000000
bootloader 区),`ns_ble_stack_init()` 内部(`NS_BLE_STACK_INIT`)又清 0。
处理:`main` 在 SystemCoreClockUpdate 之后、任何 NVIC 中断使能之前先设
`PWR->VTOR_REG = 0x80000000 | 0x01008000`;`app_ble_init()` 之后再重设一次
(`main.c` 中 `APP_VTOR_VALUE`)。
另:SDK 的 `ns_ble_stack_vtor_init()` 会把 `__Vectors`(本 APP 的 flash 向量表,
含 FreeRTOS 的 SVC/PendSV/SysTick 映射与 USART1_IRQHandler)复制到 RAM 重映射区
(0x200000e8 系统异常 / 0x200009c0 用户 IRQ),并把 BLE_FIFO/BLE_SLP/EXTI4_12
指向 ROM/RAM 内部 handler;rdtss 例程在栈初始化后保持 VTOR=0 即依赖该 RAM 重映射。
**本工程按设计要求重设 VTOR 到 flash;若实测 BLE 中断异常,回退方案是
app_ble_init 后保持 VTOR=0(RAM 重映射已覆盖全部中断向量)。** 见 15.5 风险。
BLE 中断不定义在 n32wb03x_it.c:启动文件的 BLE_*IRQHandler 均为 weak
Default_Handler,真正的 handler 由 symbol_g15.obj(ROM)+ RAM 重映射提供;
与 FreeRTOS 的 SVC/PendSV/SysTick 映射无冲突。BLE_SW/FIFO IRQ 优先级 0,
ISR 内不得调用 FreeRTOS FromISR API(本工程 BLE 事件均在 BLE 任务上下文处理)。
### 15.4 编译验证
- `UV4.exe -b embeddedSrc.uvprojx -j0 -o build.log`:**0 Error(s), 0 Warning(s)**
- 体积:`Code=34828 RO-data=6788 RW-data=8820 ZI-data=25572`
- RW+ZI = 34392 字节 < 48KB(0xC000),`configTOTAL_HEAP_SIZE` 保持 20*1024 不变;
剩余约 14.4KB 供 MSP 主栈。BLE ROM 栈变量经 symbol_g15.obj 绝对符号落在低地址
RAM,其占区由 rwip_driver.o/ns_ble.o 等的 .data 段原位保留(与 rdtss 布局一致)。
- 上板预期:复位后 banner(含 BLE 行)→ `caiic->` CLI 正常;手机 nRF Connect
能搜到并连接 `CAIIC-MCM`,可见自定义服务的写/notify 两个特征。**尚未实测。**
### 15.5 遗留风险
- VTOR 与 BLE 中断的最终取指向量路径需上板确认(见 15.3,回退方案已备)。
- `app_ble_notify_send()` 会从非 BLE 任务上下文触发 ke_msg_send(SDK 未保证
跨上下文安全),后续 CLI-over-BLE 协议接入时应评估改为向 BLE 任务投递消息。
- ns_sleep 低功耗未接;广播常开,功耗未优化。
---
日期:2026-09-01
## 16. CLI 传输解耦 + BLE 帧协议 + BLE OTA 接收器
### 16.1 CLI 核心与传输解耦
- 新增 `app/cli_core.c/.h`:命令表、全部命令 handler、分词执行从 app_cli.c 迁入。
输出经可切换的 `cli_out_fn` 回调(`cli_set_output`,NULL=默认 UART DMA)。
`cli_exec_line()` 返回 0/1(未知命令)。对外另有 `cli_cmd_count/cli_cmd_name`
供 UART 前端 Tab 补全。
- `app/app_cli.c` 保留 UART 前端(CliTask、行编辑、历史、Tab、Ctrl+Z、提示符),
分发前 `cli_set_output(NULL)` 再 `cli_exec_line`;前端自身的提示符/回显/重绘
固定走 UART(`cli_uart_write`),不受回调切换影响。
- 并发约定:UART 与 BLE 两个前端共用全局 out 回调与 TX 缓冲,采用"执行前设置、
执行完恢复"的简单保护(两端并发概率低,代码内已注释说明)。
- 新增 CLI 命令 `bankinfo`:打印当前运行 bank(经 armlink 符号
`Image$$ER_IROM1$$Base` 判定)与 bootsetting 记录内容。
- UART CLI 行为不变(回归项)。
### 16.2 BLE 帧协议前端(app/ble/app_ble_proto.c/.h)
帧格式(小端):`[0]=0xCA SOF, [1]=TYPE, [2]=SEQ, [3:4]=LEN(LE), [5..]=PAYLOAD,
末尾 CRC16-CCITT(初值 0xFFFF, poly 0x1021) 2 字节 LE,覆盖 TYPE..PAYLOAD`。
帧开销 7 字节(头 5 + CRC 2)。
- 帧类型:0x01 CLI_REQ / 0x02 CLI_RSP / 0x03 CLI_RSP_END{status} /
0x10 OTA_BEGIN{size,crc32,version} / 0x11 OTA_DATA{offset+data} /
0x12 OTA_END{crc32} / 0x1F OTA_RSP{cmd_echo,status,offset}。
OTA_RSP status:0 ok / 1 bad_frame / 2 bad_state(seq) / 3 size_too_big /
4 crc_fail / 5 flash_fail。
- 接收:字节流状态机(找 SOF→5 字节头→payload+CRC),接收缓冲 512 字节
(payload 上限 480);CRC 错误的帧静默丢弃(OTA 靠 offset/ack 重同步)。
- CLI_REQ:payload ≤63 字节拷入行缓冲,置 out 为 BLE 帧输出后 `cli_exec_line`,
结束发 CLI_RSP_END(status=cli_exec_line 返回值)。
- 发送分块:单帧 payload 上限 = min(att_mtu-3, 244) - 7;新增
`app_ble_max_payload()`(未连接返回 17)与 `app_ble_is_connected()`。
- notify 忙重试:512 字节 pending FIFO 存整帧,`app_ble_proto_poll()` 挂进
BleTask 循环每轮冲刷;FIFO 满则丢弃并计数;断连清空。
- 全部运行在 BleTask 上下文(rx 经 CLS 写指示 handler,poll 在任务循环),无锁。
### 16.3 OTA 接收器(app/app_ota.c/.h)
- 静态 4KB 扇区缓冲;`Image$$ER_IROM1$$Base` 判定当前 bank,目标=对侧 bank。
- OTA_BEGIN:校验 4..0x38000(否则 status=3)、首次 `Qflash_Init()`、记录会话、
回 OTA_RSP(0x10,ok,0)。
- OTA_DATA:offset 必须等于期望值(否则 status=2 附期望 offset,状态保持供重发);
攒满 4KB → 擦扇区+写 4KB → 回 OTA_RSP(0x11,ok,已写 offset) 作扇区级流控;
未满不回包。Qflash 操作内关中断数十 ms,BLE 靠 5s supervision timeout 容忍。
- OTA_END:残余 0xFF 补齐到 4 字节倍数后擦写该扇区;整镜像 `caiic_crc32` 回读校验
(同时比对 BEGIN 与 END 的 crc32);失败 status=4 中止不复位。成功则更新
bootsetting(无效记录清零重建、写 active_bank/bank{size,crc,version}/重算结构
CRC、擦写+回读比对),回 OTA_RSP(0x12,ok),vTaskDelay 200ms 后
`NVIC_SystemReset()`。
- 断连(`app_ble_proto_on_disconnect`)中止会话并清空 pending;OTA 仅在连接态有效。
- uvprojx:新增 DFU 组(`..\..\Boot\src\boot_crc32.c`),IncludePath 加
`..\..\Boot\src`。
### 16.4 编译验证
- `UV4.exe -b embeddedSrc.uvprojx -j0 -o build.log`:**0 Error(s), 0 Warning(s)**
- 体积:`Code=38000 RO-data=6856 RW-data=10600 ZI-data=31008`
- RW+ZI = 41608 字节 < 48KB,`configTOTAL_HEAP_SIZE` 保持 20*1024 不变。
- 上板预期:UART CLI 回归正常;nRF Connect 连接后发 CLI_REQ("help") 应收
CLI_RSP 分块 + CLI_RSP_END;OTA_BEGIN/DATA/END 把新 bin 写入对侧 bank 并复位,
bootloader 校验跳转后 `version`/`bankinfo` 显示新 bank。**尚未实测。**
---
日期:2026-09-01
## 17. 整片烧录包(bootloader + APP 合并)
新增顶层 `tools/` 目录:
- `merge_image.py` — 纯 Python(无第三方依赖)合并镜像:`Boot/MDK-ARM/bin/caiic_boot.bin`
(0x01000000)+ `mcm-ddc-04/MDK-ARM/bin/embeddedSrc.bin`(0x01008000,APP1)→
输出 `tools/out/caiic_full.hex`(Intel HEX,稀疏地址)与 `caiic_full.bin`
(0x01000000 起,空隙补 0xFF)。已做回读校验:hex 中 boot/APP 段与源 bin 逐字节一致。
- `make_package.bat` — 一键:UV4 构建 bootloader → UV4 构建 APP → 合并。任一步 0E0W
校验失败即中止。本机 `python` 是商店占位 stub,脚本自动回退到 Python312 全路径。
- `flash_package.bat` — 调 SDK 自带 `NSpyocd.exe`:`erase --chip` 后 `load` 合并 hex
(目标 n32wb031)。需 NS-LINK 接 SWD(PA4/PA5)+ 复位脚。
烧录流程:**首次**整片烧录用 `tools\flash_package.bat`(或 Keil 分工程分别烧录);
之后日常升级走 BLE OTA。bootsetting 首次为空,bootloader 向量检查后直接跳 APP1。
---
日期:2026-09-01
## 18. 修复 app_ble_init 崩溃(VTOR 根因)+ heap 调整
### 18.1 现象与根因
上板实测:程序在 `app_ble_init()` 中崩溃(卡死)。排查后确认**不是 heap 不足**,而是 VTOR:
- 该芯片 BLE 协议栈的中断分发机制:`ns_ble_stack_vtor_init()`(ns_ble.c)把 APP 的
`__Vectors`(链接器符号,即我们 0x01008000 处的向量表)拷贝到 RAM 中继区
(系统异常 → 0x200000e8 起,用户 IRQ → 0x200009c0 起 31 项),再把
BLE_FIFO/BLE_SLP/EXTI4_12 槽位改写为 ROM/RAM handler(BLE FIFO handler 是运行时
拷贝到 RAM 的代码 `rwip_fifo_isr_codeArray`,不可能出现在 flash 静态向量表里)。
- 因此 BLE 栈初始化后 **VTOR 必须保持 0**(走芯片 ROM 跳板 + RAM 中继),
这也是 rdtss/app_ota 等所有官方例程的实际状态。
- 此前我们在 `app_ble_init()` 之后把 VTOR 重设为 `0x80000000|0x01008000`,
导致 BLE FIFO 中断直接查 APP 的 flash 向量表 → weak `Default_Handler` 死循环 → 卡死。
### 18.2 修复
- 删掉 `main.c` 中 `app_ble_init()` 之后的 VTOR 重设(保留 main 开头那一次——
BLE 初始化前 USART1 RX 中断需要查 APP 自己的向量表)。
- 规则:**BLE init 前 VTOR=APP 基址;BLE init 后 VTOR=0,不再动**。
### 18.3 heap 检查与调整
核算 FreeRTOS heap(20KB)占用:5 个任务栈(1024×4 + 512 字 = 18944B)+ 6 个 TCB
(≈552B)+ 队列/互斥锁(≈370B)≈ 19.9KB,剩余仅 ~600B——未耗尽但余量偏小。
`configTOTAL_HEAP_SIZE` 由 20KB 调至 **22KB**(RW+ZI=43656B,主栈余量约 5.4KB)。
编译:0 Error / 0 Warning,`Code=37996 RO-data=6856 RW-data=10600 ZI-data=33056`。
---
日期:2026-09-02
## 19. Boot 跳转策略调整:校验移到升级过程,解决 Keil 下载无法调试
### 19.1 现象与根因
加了诊断代码重新编译后,Keil 下载/调试**能连上但全速跑永远到不了 main**。根因:
- Keil 下载只写 APP1 区(0x01000000 起的镜像由 Keil 的 FLM 按 axf 地址 0x01008000 写入),
**不会更新 bootsetting(0x01004000)里记录的 APP1 CRC32**——那是上次 `merge_image.py`
打整片包时算的。
- 复位链路:芯片 ROM → Boot → 校验 bootsetting → 校验 APP1 镜像 CRC → **不匹配,拒绝跳转**,
CPU 停在 Boot 的 `for(;;)`。Keil 的 "Run to main" 走的是自然启动,自然卡在 Boot。
- 所以任何一次 Keil 重新下载(不只是诊断代码)都会触发;引入 Boot 之前没有这层校验,故以前正常。
验证方法:调试状态 halt 看 PC,落在 0x01000000~0x01003FFF 即 Boot 空转。
### 19.2 调整内容
- **Boot(`Boot/src/main.c`)改为跳转时不校验镜像 CRC**:只检查 bootsetting 扇区自身完整性
(magic + 自身 CRC32)选出 active bank,再做向量表 sanity(MSP 在 SRAM、复位向量在 bank 内)
兜底后直接跳转;bootsetting 无效时默认 APP1。删除 `bank_crc_ok()` 及双 bank CRC 回退。
- **镜像 CRC 校验职责完全在升级过程**:`app_ota.c` OTA_END 已对新镜像整体 CRC32 比对,
通过才写 bootsetting 切 bank 复位——OTA 链路安全性不变。
- 新增 `MDK-ARM/debug_app.ini` 并挂到工程调试配置(uvoptx `<tIfile>`):调试器下载后强制
`SP/PC = APP1 向量表`,跳过 Boot 直进 APP。Boot 不校验后该脚本已非必需,保留为纯调试可选旁路。
- Boot 重建 0E0W(`Code=1352`,bin 2032B),`tools/make_package.bat` 重新出整片包
(caiic_full 79464B)。
### 19.3 影响与注意
- Keil 直接下载 APP 即可启动和调试,开发节奏恢复。
- 代价:OTA 流程之外的镜像损坏(如 Keil 下载中途断电)不再被 Boot 拦截——向量检查只能挡
全空/乱码。这是"简单"换来的取舍。
- **在板子上烧过其他 0x01000000 起步的程序(SDK 例程 / mcm-ddc-ble)会覆盖 Boot 和
bootsetting**,恢复方法:`tools\flash_package.bat tools\out\caiic_full.bin` 重烧整片包。
---
日期:2026-09-02
## 20. 串口波特率提升到 1Mbps
### 20.1 可行性核实
- USART1 挂 APB2=64MHz(`n32wb03x_usart.c` 中 USART1 取 Pclk2),波特率发生器为
16 倍过采样 + 小数分频(同 STM32F1 算法)。
- 1Mbps 分频值 = 64MHz / (16 × 1M) = **4.0,误差 0%**(2M/4M 同样零误差)。
- 驱动断言上限 `IS_USART_BAUDRATE` = 4Mbps(`n32wb03x_usart.h`),1Mbps 远在范围内。
### 20.2 改动
- `bsp_usart.h`:`BSP_USART_BAUDRATE` 115200 → **1000000**,相关注释与 AGENTS.md 同步。
- 构建 0E0W(`Code=38080 RO-data=6932 RW-data=10600 ZI-data=33056`)。
- 注意:串口助手需切到 1000000;USB 转串口适配器需支持 1Mbps(CH340/CH343/FTDI 均可)。
### 20.3 决策:RX 暂不切 DMA
评估了 RX 由 RXDNE 逐字节中断改为 DMA 循环缓冲 + IDLE 中断的方案,结论**维持现状**:
- CLI 是人工输入速度,1Mbps 下逐字节中断负载可忽略;RX DMA 的收益只在串口灌大数据
(有线烧录/批量注入)时才存在,属出现需求后再做。
- DMA RX 引入循环缓冲管理、IDLE 中断、4 通道合一的 DMA IRQ 与 FromISR 优先级约束等
新出错点;现 RXDNE 方案已上板验证。
- 对 CLI 语义无影响(保持 `bsp_usart_read_byte()` 字节流接口即可),但无收益不改动。
### 20.4 后续:波特率回退
实测后决定**改回 115200**(`BSP_USART_BAUDRATE` 恢复,注释与 AGENTS.md 同步还原)。
本节 20.1 的核实结论仍然有效:该芯片串口支持 1Mbps 且零误差,需要高速时随时可再开。
---
日期:2026-09-02
## 21. Boot 跳转后 BLE 失败的最终定位与修复 + bootsetting 携带跳转地址
### 21.1 根因(两层叠加,均已修复)
1. **PRIMASK 中断状态**:旧 Boot 在 `jump_to_app()` 里 `__disable_irq()`,APP 继承中断全关。
全 SDK 应用代码从不自己 `__enable_irq()`(自然复位 PRIMASK=0),FreeRTOS 要到
`vTaskStartScheduler()` 才开中断,而 `app_ble_init()` 在调度器之前跑,其中的 ROM 初始化
(如 LSI 校准 `calib_lsi_clk`,7.5ms)需要中断推进 → 卡死。修复:Boot 跳转前
`__enable_irq()`(Boot 自身无中断源,安全)。
2. **RAM 起始地址踩 ROM 保留区(主因)**:N32WB031 SRAM 为 **48KB+16KB** 结构,低 16KB
(0x20000000~0x20003FFF)由芯片 ROM/BLE 子系统占用——ROM 启动代码在其中预备好
rwip 堆描述符(0x20000118 起,全 SDK 无任何代码写它们)、patch 数组、中断中继表。
SDK 例程(rdtss/mcm-ddc-ble)RAM 执行区从 **0x20004000** 起;而 mcm-ddc-04 和 Boot
之前错配成 0x20000000 起(器件切到 KEQ6-2 时被 pack 默认值带偏),`__main` 的
.data/.bss 初始化把低 16KB 冲掉 → BLE 栈拿垃圾描述符初始化堆 → HardFault。
修复:两个工程 IRAM 全部改 **0x20004000/0xC000**(应用可用 48KB,
APP RW+ZI≈46.7KB 放得下)。
- 佐证:故障时打印的堆描述符为乱码(`env=4622910E/30777...`);官方 masterboot 的
`ns_dfu_boot_jump` 不动 VTOR/PRIMASK 只设 MSP,行为与我们修复后的 Boot 等效。
- 教训:**任何工程(包括裸机小工具)链接到本芯片都必须从 0x20004000 起**。
### 21.2 辅助手段
- `n32wb03x_it.c` 的 HardFault_Handler 增加异常栈帧打印(R0-R3/R12/LR/PC/xPSR,
EXC_RETURN bit2 选 MSP/PSP;ARMv6-M 无 CFSR/HFSR)。
- 恢复 main 开头 2s 上电延时(与官方例程一致,兼作 SWD 附着窗口)。
- `debug_app.ini` 已由用户移除,调试不再需要旁路。
### 21.3 bootsetting 携带跳转地址
- `dfu_layout.h`:`caiic_bank_t` 新增 `start_address`(结构体 44 字节)。
- Boot:校验 bootsetting 自身完整性(magic + 结构体 CRC32)后按 active bank 的
`start_address` 跳转;地址越界或记录无效回退 APP1。
- `app_ota.c`:OTA 写记录时填 `start_address`;`bankinfo` 命令同步打印。
- `tools/merge_image.py`:**生成缺省 bootsetting** 打进 0x01004000(magic、active=APP1、
bank1={start=0x01008000,size,crc32,version=0}、bank2 空、结构体 CRC32,与
`boot_crc32.c` 同为 IEEE CRC32,脚本用 zlib 实现);支持 `merge_image.py [app_bin]
[输出名]` 参数化。
- `tools/make_package.bat`:构建改 `-r` 全量重建,杜绝陈旧中间产物进产线包。
### 21.4 产物(均逐字段校验:向量表 / 结构体 CRC / bank1 CRC 与镜像吻合)
- `tools/out/caiic_full.{hex,bin}`(79732B)= Boot + mcm-ddc-04(APP1 46964B)
- `tools/out/caiic_ble_full.{hex,bin}`(62480B)= Boot + mcm-ddc-ble(APP1 29712B,
该工程已重链接到 0x01008000/0x38000)
---
日期:2026-09-02
## 22. mcm-ddc-ble 工程:创建、FreeRTOS、CLI 搬迁与 BLE 帧协议落地
mcm-ddc-04 在 Boot 跳转路径下仍有问题期间,新建 `mcm-ddc-ble/` 作为可工作的基座
工程并逐步补齐功能。本节汇总其全部演进。
### 22.1 工程创建(rdtss 蓝本)
- 以 SDK `projects/n32wb03x_EVAL/ble/rdtss` 为蓝本整目录复制(BLE 原始数据透传服务,
128-bit UUID,下行写 + 上行 notify,与 CLI-over-BLE 形态最接近)。
- uvprojx/uvoptx 中 SDK 相对路径全部重定向到 `..\..\nations-tec\N32WB03x_SDK_V2.0.0\`,
`nations-tec/` 只读未动。OTA_IMG_1/2 两个 target 保留不用。
- 引脚核对:LED1=PB0、LED2=PA6、USART1=PB6/PB7、LPUART 日志=PB1,无 PA4/PA5(SWD)
占用。
- `main.c` 加 `ns_sleep_lock_acquire()` 永久锁睡眠,SWD 全程可调试(例程默认进
deep sleep 会断开 SWD)。
### 22.2 FreeRTOS 接入 + 点灯任务
- SDK 自带 FreeRTOS V9(tasks/queue/list/timers + heap_4 + RVDS/ARM_CM0 port)加入
工程;`FreeRTOSConfig.h` 从 mcm-ddc-04 移植。
- 任务化:`ble_schedule_task`(512 字,优先级 2,rwip_schedule 循环,rwip 单上下文
约束)、`led_task`(128 字,LED1 500ms 翻转)。
- 踩坑:脚本写 uvprojx 路径时 `\t` 被 Python 解释成制表符(`Source\tasks.c` 变成
`Source<TAB>asks.c`),Keil 报 `cannot create command input file`;另 `<FileName>`
必须写纯文件名。
### 22.3 从 mcm-ddc-04 搬迁 CLI 框架 + UART 驱动
- 搬入:`bsp_usart.c/h`(printf 重定向 + DMA TX + RXDNE 中断队列 + TX 互斥锁,
新增 `bsp_usart_rx_inject()`)、`cli_core.c/h`、`app_cli.c/h`(提示符 `caiic->`、
Tab 补全、历史、四种行结束符)、`n32wb03x_it.c`(USART1_IRQHandler 转发 +
HardFault 栈帧打印)、`app_version.h`(V1.00.01)、新写 `ble_up.c/h`(CLI 应答的
BLE notify 上行:ke_msg 只允许 BLE 任务上下文,故 CLI 任务入队 512B 环形缓冲,
BLE 调度任务 20B/notify、cfm 节流发送)。
- 命令集:`help`/`version`/`sysinfo`/`led`(`log`、`bankinfo`、Ctrl+Z 依赖 04 的
日志/OTA 系统,未搬)。
- 拆除:`app_usart.c`(原透传 FIFO)、`ns_log_lpuart.c`(占用 `fputc` 与 bsp_usart
冲突;`NS_LOG_LPUART_ENABLE` 置 0)。
- main.c 增加 VTOR 预置(`0x80000000|0x01008000`,BLE init 前 USART1 RX 中断需要,
BLE init 后 VTOR 归 0 不动)与启动 banner。
- 踩坑:µVision 在 uvoptx 缺失/不同步时会把多个 target 的同名组文件清单合并,从
target 1 删掉的文件仍被编进链接——三个 target 的条目需全部删除;以
`Objects/*.lnp` 链接清单无残留为验证。
### 22.4 实现 ble_protocol.md 帧协议
- 新增 `app_ble_proto.c/h`(从 04 移植适配 rdtss 服务):字节流重组状态机
(SOF 0xCA → 头 → payload → CRC16-CCITT,跨多次 BLE 写入重组,坏帧静默丢弃并
重新找 SOF);CLI_REQ 执行命令,输出组帧 CLI_RSP 若干 + CLI_RSP_END{status}。
- 通道隔离:串口输入只回串口,BLE 帧输入只回 BLE 帧(set/exec/restore 输出切换)。
- OTA 帧类型(0x10~0x1F)保留不应答(本工程无 flash 升级)。
- CRC16 已用标准向量("123456789" → 0x29B1)验证。
- 协议文档 `docs/ble_protocol.md` 增加 1.2 节(rdtss 服务 UUID 表、差异点:默认
MTU 下每帧 payload 13B、OTA 不支持)与 `help` 命令线上字节示例
(`CA 01 00 04 00 68 65 6C 70 16 EC`)。
### 22.5 产物与测试入口
- 构建 0E/0W:`Code=31184 RO-data=3504 RW-data=1968 ZI-data=26912`(heap 20KB)。
- 整包:`tools\out\caiic_ble_full.{hex,bin}`(Boot + 缺省 bootsetting + 本工程 APP1)。
- 串口(115200):banner + `caiic->`;BLE:`CAIIC-MCM-20260902`,订阅 `...E0002`
notify 后往 `...E0001` 写 CLI_REQ 帧即可对话。