mothercup/docs/开发日志.md

776 lines
44 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 帧即可对话。
## 23. BLE 三业务补齐:OTA + 设备信息查询 + CLI 透传(2026-09-03)
mcm-ddc-04 目录已由用户删除,mcm-ddc-ble 成为唯一应用工程。本轮把 BLE 通道
从"仅 CLI 透传"补齐为协议 V1.1 的三业务:CLI 透传(已有)、设备信息查询
(新增)、双 bank 直写 OTA(从 04 git 历史 3135722 移植 app_ota.c/h)。
### 23.1 协议升级 V1.1(docs/ble_protocol.md 重写)
- 适配本工程实际:rdtss 服务(`...E0001` 下行写 / `...E0002` 上行 notify)、
广播名 `CAIIC-MCM-20260902`。
- 新增信息查询帧:INFO_QUERY(0x20, {item_id}*n,空/0xFF=查全部) /
INFO_RSP(0x21, TLV {id,len,value}*n)。信息项:0x01 固件版本 u32、
0x02 芯片温度 i16(0.1°C)、0x03 风扇转速 u16(0xFFFF=无硬件)、
0x04 电源电压 u16(mV)、0x05 运行时长 u32(s)、0x06 剩余堆 u32(B)。
- OTA 帧 0x10~0x12/0x1F 从"保留"变为实现,流程与 04 一致(扇区级 ack 流控、
END 时整镜像 CRC32 校验 + 更新 bootsetting + 200ms 后复位)。
### 23.2 OTA 移植(app_ota.c/h,368 行原样搬入)
- 4KB 扇区 RAM 缓存攒满即擦写对侧 bank,无 flash 中转区;`Image$$ER_IROM1$$Base`
判定当前 bank(本工程链接 0x01008000 = APP1,OTA 写 APP2 0x01040000)。
- `app_ble_proto_send_frame()` 由 static 改为导出供 OTA/INFO 应答;
OTA 状态码 BLE_OTA_ST_* 移入 app_ble_proto.h。
- 断连即 `app_ota_abort()`(挂在 app_ble_proto_on_disconnect)。
- uvprojx:USER 组加 app_ota.c / app_info.c / `..\..\Boot\src\boot_crc32.c`,
IncludePath 追加 `..\..\Boot\src`(dfu_layout.h / boot_crc32.h)。
与 app_ble_proto.c 一样只加 target "N32WB03x"。
### 23.3 设备信息查询(新模块 app_info.c/h)
- 温度:ADC CH7 内置温度传感器(`ADC_EnableTS` + 单发轮询 + 超时保护,
`ADC_ConverValueToTemperature` 用出厂 trim),参考 SDK 例程
`peripheral/ADC/ADC_Temperature`。
- 电压:ADC CH6(VCC),`ADC_ConverValueToVoltage`(600~3600mV 档 trim)。
- ADC 懒初始化(AUDIOPLL 时钟源 + bypass filter + 过采样 3),首次查询时配好。
- 风扇转速:`__weak app_fan_get_rpm()` 默认返回 0xFFFF(本板无测速电路),
产品代码重写该函数即可,协议不变。
- CLI 新增 `devinfo` 命令打印同组数据(方便无手机时串口验证)。
### 23.4 MTU 协商
- `app_ble_connected()` 里设备主动 `ns_ble_mtu_set(247)`(ns_ble 库提供,
官方 DFU 的 OTA_CMD_MTU_UPDATE 同款调用)。MTU 247 时一次写入 244B,
OTA_DATA 单帧可带 233B 数据;MTU 协商失败则退化为 20B/写(协议按字节流
重组,两种情形都正确)。上行 notify 仍固定 20B 块,兼容任意对端。
### 23.5 产物
- 构建 0E/0W:`Code=34488 RO-data=3592 RW-data=2004 ZI-data=31012`
(含 4KB OTA 扇区缓存;用户 RAM 48KB 占用 33016B)。
- APP bin = 39616B(≈38.7KB,bank 上限 224KB)。
- 整包:`tools\out\caiic_ble_full.{hex,bin}`(Boot + 缺省 bootsetting + 本工程
APP1,bootsetting crc32=0x69A005D5)。
- 待上板验证:BLE 连接后 MTU 交换、INFO_QUERY 应答、OTA 全流程(写 APP2 →
复位 → Boot 跳 APP2)。
## 24. OTA 去 4KB 扇区缓存,改直写(2026-09-03)
- 背景:23 节版本整包烧录后不运行。静态校验发现该包 APP1 向量表初始 SP 仍停在
旧版栈顶 0x2000B0D0,而新增 4KB OTA 缓存已把 ZI 顶到 0x2000B8F8——栈顶落在
ZI/堆区域内,启动即崩(增量构建产物不一致所致;教训:出包一律 `UV4 -r`
全量重建,并核对向量表 SP 与 map 的 `__initial_sp` 一致)。
- 应用户要求去掉 4KB 扇区 RAM 缓存设计,app_ota.c 重写为**直写**:
- 惰性擦除:数据首次落入某扇区时先擦该扇区(`ota_erase_up_to`);
- 收到 OTA_DATA 立即 `Qflash_Write` 写入(bulk 对齐部分直接用帧 payload,
不再经过大缓冲);
- 仅保留 4 字节对齐暂存(Qflash 写要求 4B 对齐,尾部 OTA_END 时 0xFF 补齐);
- 流控/进度不变:每写满一个 4KB 扇区回一帧 OTA_RSP(ok, offset)。
- 效果:ZI 从 31012 降回 26912(-4KB),本版 `Code=34564 RO=3592 RW=2016
ZI=26912`,APP bin 39692B,栈顶 0x2000B100 与 map `__initial_sp` 一致。
- 整包:`tools\out\caiic_ble_full.{hex,bin}`(bootsetting crc32=0xF15790D8)。
- 协议文档 §6 已同步直写描述(对外流程与帧格式不变)。
- 上板验证:整包烧录后正常启动,串口 banner + `caiic->` 正常(2026-09-03 确认)。
## 25. 出包流程同时产出 OTA 镜像(2026-09-03)
- `tools/merge_image.py` 扩展:每次生成整包时同步输出
`<包名>_ota.bin`(OTA 载荷 = APP bin 本体)和 `<包名>_ota.json`
(清单:file/size/crc32/version,手机端 OTA_BEGIN 直接取用;
version 用第三个命令行参数指定,如 `0x00010001`,缺省 0)。
- 本版产物:`caiic_ble_full_ota.bin`(39692B,crc32=0xF15790D8)+ json,
已校验与 Keil 产物 bin 逐字节一致;`make_package.bat` 流程自动获得同样产物。
- 协议文档 §7 已补充 OTA 产物说明。
## 26. 协议文档补齐手机端开发指南(2026-09-03)
- 用户将文档目录移到仓库根 `docs/`(mcm-ddc-ble/docs 已删除,以根目录为准)。
- `docs/ble_protocol.md` 新增第 8 节"手机端开发指南":
- 8.1 连接初始化步骤(扫描名/服务 UUID → CCCD 使能 notify → MTU 协商);
- 8.2 参考实现:CRC16-CCITT、组帧、字节流解帧(含坏帧重同步)、zlib CRC32,
Python 版可直接对照移植 Kotlin/Swift/JS;
- 8.3 字节级完整示例表(CLI/INFO/OTA 全业务,CRC 均为真实计算值);
- 8.4 时序与异常处理:CLI 串行执行、OTA 滑动窗口流控与断点重同步、
notify 跨包重组要求、温度/风扇特殊值约定。
## 27. BLE 打印开关 + 收发报文打印(2026-09-03)
- 新增 `blelog [on|off]` CLI 命令(缺省关),开关状态只存 RAM(复位即关)。
- 打开后:
- 每个完整收/发协议帧在串口 hex 打印:`[BLE RX]/[BLE TX] type= seq= len= + payload
预览(超 24B 截断打 ...`);RX 在 CRC 校验通过分发前打印,TX 在组帧入队前打印;
- 连接/断开事件打印(`[BLE] connected` / `disconnected, advertising restarted`)。
- 打印走 printf(fputc 轮询 UART),不经过 BLE 通道,避免 CLI-over-BLE 自激。
- 用途:手机 APP 联调时对照 ble_protocol.md §8.3 的示例帧逐字节核对。
- 本版 `Code=35104 RO=3672 RW=2016 ZI=26912`,整包/OTA 镜像已重新生成
(_ota.bin 40312B,crc32=0xCAE8E135),SP=0x2000B100 与 map 一致。
## 28. CLI 读写特征 + 只读参数特征 + 温度采样修复(2026-09-04,V1.00.02~V1.00.08)
- **CLI 读写特征 `...c72e0003`(V1.00.02)**:RD + WRITE_REQ(带响应写)。手机写原始
命令行(≤63B,不套 0xCA 帧),设备执行后读同一特征取回输出文本(≤512B,
ATT long read 由协议栈自动分段)。`app_ble_proto_cli_exec()` 捕获输出到静态缓冲,
`rdtss_value_req_ind_handler` 按 att_idx 分发读请求。整条链路不依赖 notify。
- **blelog 可见性增强(V1.00.02)**:rdtss 写回调原始 dump 从编译期剔除的
NS_LOG_DEBUG 改为 blelog 门控 printf(`[BLE] write ind: att_idx= len= ...`),
新增 CCCD 订阅/退订打印(`[BLE] notify enabled/disabled`);修正 CCCD 值解析
(`value[0]+value[1]` → 小端合成)。
- **只读参数特征 `...c72e0004`(V1.00.04)**:读出为全部信息项 TLV,与
INFO_RSP(all) 一致;`app_info.c` 抽出 `app_info_tlv_snapshot()` 与帧应答共用组包。
- **温度采样修复(V1.00.03/05/08)**:现象 `devinfo` 显示 287.6°C。定位过程:
首版加 5ms 稳定+丢弃首次转换(05 加到 20ms)无效;devinfo 加 `(adc= trim=)`
诊断后确认 adc≈115(贴近地的浮空读数,trim=681 正常)——**规律是每次开机后
第一次 TS 采样为垃圾值,之后全部正常**(V1.00.05 稳态 272 采样点 20~26°C)。
最终修复:ADC 初始化时做预热转换并丢弃(`info_adc_init` 尾部)。
- **教训记录(V1.00.06/07 → 08 撤回)**:曾按勘误表 7.1 条加
`*(uint32_t*)0x40011004 |= 0x40`(HSI 设计 ADC 时钟修复),但该地址是
AFEC+0x04,与 BLE 协议栈共享(rwip_driver.c 写 0x20,ns_sleep.c 保存/恢复,
pwr.c 的 bit6 是无 HSE 睡眠唤醒专用),误写导致首次 ADC 读取后 BLE 射频挂死、
设备停止广播。V1.00.08 已撤回该写操作。寄存器级勘误修复必须先在 SDK 源码
交叉验证地址用途。
- **工具**:新增 PC 端 bleak 测试客户端 `tools/ble_cli_test.py`(帧协议/读写特征
两种方式,venv `tools/.venv-ble`)、一键启动器 `tools/ble_cli.bat`、温度监测
`tools/ble_temp_watch.py`;`make_package.bat` 改指 mcm-ddc-ble(mcm-ddc-04 已删);
`merge_image.py` 出包自动从 `app_version.h` 取 `APP_FW_VERSION_NUM` 写入 OTA 清单。
- **版本号约定**(已写入 AGENTS.md):每次修改固件递增 `app_version.h` 的
`APP_FW_VERSION`/`APP_FW_VERSION_NUM`(0x00MMmmpp 补丁位 +1),文件名不变。
- 本版 V1.00.08 `Code=35864 RO=3760 RW=2020 ZI=27532`,整包/OTA 镜像已重新生成
(_ota.bin 41168B,crc32=0x26056D5B)。
- **已知未决**:notify 上行链路不通(帧协议 CLI/INFO_QUERY/OTA 应答收不到),
下行写入正常;新读写/只读特征已绕开 notify,OTA 仍依赖它,待后续定位。
## 29. bootsetting 读写 + APP_DATA 参数区(结构化命令,CLI + BLE,2026-09-04,V1.00.09)
需求:维护期读写 bootsetting 记录与 APP_DATA 保留区(0x01006000/8KB)。
**本次只提供结构化访问,不暴露任何裸读写命令**;经 CLI 命令实现,UART 与
BLE(CLI 读写特征 ...c72e0003,写命令行读应答)双通道可用。
- **新模块 `app_params.c/h`(APP_DATA 参数记录)**:区头放 `caiic_params_t`
(magic 0xCA12DA7A + layout_ver + led1_blink_ms + flags + pwm_duty_pct +
reserved[8] + crc32,52B)。`app_params_init()` 开机校验 magic+CRC,无效则
RAM 载入缺省(不落盘);`param set` 改 RAM 副本后重算 CRC、擦首扇区、编程、
读回校验。命令:`param`(打印全部+valid/default 状态)、
`param set <led1_blink_ms|pwm_duty_pct> <val>`、`param save`。
PWM 占空比本版只存参数不接外设;LED1 闪烁半周期由 led_task 每循环读参数
生效(另有 <50ms 兜底回 500ms,参数区为全 0xFF 时 magic 不匹配直接走缺省)。
- **新模块 `app_bootset.c/h`(bootsetting 结构化读写)**:`bsdump` 逐字段打印 +
magic/CRC 校验结果;`bsset <field> <val>`(active/b1addr/b2addr/b1size/b2size/
b1crc/b2crc/b1ver/b2ver)单字段修改后整记录重写(无效记录先清零重建),流程与
`app_ota.c::ota_update_bootsetting()` 一致。addr 钳位只允许 APP1/APP2 基址,
size ≤224KB,active 只允许 1/2。写错 active/addr 会导致 Boot 跳错,恢复靠
SWD 重烧整片包。
- Qflash 使用模式与 OTA 相同:各模块 static flag 保证 `Qflash_Init()` 只调一次;
擦写关中断数十 ms/扇区,BLE 靠 5s supervision timeout 维持。
- 构建 0 Error/0 Warning,V1.00.09 `Code=38352 RO=4192 RW=2028 ZI=27580`,
整包/OTA 镜像已生成(_ota.bin 44088B,crc32=0xE246E2B2)。