999 lines
59 KiB
Markdown
999 lines
59 KiB
Markdown
# 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)。
|
||
|
||
## 30. 参数命令改名 appget/appset(2026-09-04,V1.00.10)
|
||
|
||
`param [set <led1_blink_ms|pwm_duty_pct> <val>|save]` 拆成两条短命令,参数名缩短:
|
||
|
||
- `appget` — 打印全部参数(led = LED1 闪烁半周期 ms,pwm = PWM 占空比 %)+ 记录状态。
|
||
- `appset <led|pwm> <val>` — 修改并立即落盘(led 50~10000;pwm 0~100)。
|
||
取消独立 save 子命令(每次 set 即保存)。
|
||
- 构建 0 Error/0 Warning,V1.00.10 `Code=38224 RO=4232 RW=2028 ZI=27580`,
|
||
整包/OTA 镜像已生成(_ota.bin 44000B,crc32=0x51756221)。
|
||
|
||
## 31. CLI 新增 reset/factory/uartrst/uartinfo(2026-09-04,V1.00.11)
|
||
|
||
四条维护命令(UART 与 BLE CLI 读写特征 `...e0003` 均可用):
|
||
|
||
- `reset` — 复位单板:打印应答后延时 200ms(与 OTA 复位同一约定,
|
||
保证应答帧先出去),`NVIC_SystemReset()` 重启,Boot 按 active bank 跳转。
|
||
- `factory` — 恢复出厂设置:新增 `app_params_restore_defaults()`(装载缺省值 +
|
||
落盘 flash),随后同样延时 200ms 复位。**只恢复 APP_DATA 参数区,不动
|
||
bootsetting**(bootsetting 决定启动 bank,不是用户配置,动它有变砖风险)。
|
||
- `uartrst` — 复位串口:补上 `bsp_usart.h` 里早已声明但未实现的
|
||
`bsp_usart_set_baud()`(等 TXC 排空 → 关 USART → 按默认 115200 8N1 重 init →
|
||
xQueueReset 清空 RX 队列 → 重开 RXDNE 中断与 USART)。
|
||
- `uartinfo` — 查询串口参数:打印 TX=PB6/RX=PB7(AF4)、波特率/数据位/校验/停止位、
|
||
TX DMA CH1 + RX 中断队列形态。
|
||
|
||
构建 0 Error/0 Warning,V1.00.11 `Code=38840 RO=4492 RW=2028 ZI=27580`,
|
||
整包/OTA 镜像已生成(_ota.bin 44876B,crc32=0x3DB21431)。
|
||
|
||
## 32. help 改两级输出(2026-09-04,V1.00.12)
|
||
|
||
实测 BLE 读写特征跑 `help` 只收到 512B 被截断:14 条命令的完整帮助表约 840B,
|
||
超过读写特征应答的 ATT 属性值硬上限 512B(`CLI_RW_RSP_MAX`),排在表尾的
|
||
reset/factory/uartrst/uartinfo 整条丢失。
|
||
|
||
- `help`(无参)改为只列命令名(约 230B,任何 MTU 下都完整);
|
||
- `help <cmd>` 输出单条命令的完整帮助/usage;
|
||
- UART 与 BLE 两侧行为一致,Tab 补全不受影响(走 `cli_cmd_name()`)。
|
||
|
||
构建 0 Error/0 Warning,V1.00.12 `Code=38972 RO=4524 RW=2028 ZI=27580`,
|
||
整包/OTA 镜像已生成(_ota.bin 45040B,crc32=0x458CCBD6)。
|
||
|
||
## 33. CLI 读写特征改分包上报(2026-09-04,V1.00.13)
|
||
|
||
V1.00.12 的 help 紧凑列表是绕过 512B 上限的权宜之计;根因是 ATT 属性值硬上限
|
||
512B,而命令表全表已约 840B。本节把读写特征应答改为**分包上报**,彻底解除限制:
|
||
|
||
- **为什么不能靠 Read Blob 扩长**:SDK rdtss profile 的 `RDTSS_VALUE_REQ_IND`
|
||
不下发 blob 偏移(`rdtss_task.h` 结构体只有 conidx/att_idx),ROM GATT 收到
|
||
blob 读会再次问应用层要全量值再自行切片——应用层若按"每次读推进游标"返回下一片,
|
||
blob 偏移会切到错误的窗口。因此分片必须避开 blob:**单片 ≤ att_mtu−2,恒为短读,
|
||
对端协议栈不会发起 blob**;读到 0 长度包 = 应答结束。
|
||
- 固件(app_ble_proto.c):应答缓冲 512B→1024B;新增 `s_cliRspOff` 游标,
|
||
每次 `app_ble_proto_cli_rsp()` 返回下一片(片长 = `app_env.max_mtu`−2,
|
||
连接后默认 23→21B/片,MTU 247 后 245B/片);写新命令或断连重置游标。
|
||
- `help` 恢复完整帮助表(UART 体验不变),`help <cmd>` 单条查询保留。
|
||
- PC 工具 ble_cli_test.py 与 App `McmCli.ts` 同步改循环读(读到空包止,
|
||
各带 64 片兜底)。**客户端必须配套升级**:旧固件重复读返回同一缓冲,
|
||
循环读会重复拼接。
|
||
|
||
构建 0 Error/0 Warning,V1.00.13 `Code=38988 RO=4524 RW=2028 ZI=28092`,
|
||
整包/OTA 镜像已生成(_ota.bin 45056B,crc32=0xB2469318)。
|
||
|
||
## 34. 引入 cJSON(infra 层)+ 参数接口 JSON 化(2026-09-04,V1.00.14)
|
||
|
||
评估结论:JSON 的价值在**接口层**(App 原生 JSON.parse,新增参数旧客户端天然兼容),
|
||
不在 Flash 存储层——APP_DATA 记录保持二进制 `caiic_params_t`(magic+layout_ver+CRC32),
|
||
半写坏记录靠 CRC 识别回落缺省,比 JSON 文本(空格/键序敏感、解析失败路径难收敛)更稳。
|
||
|
||
- **infra 层落地**:vendor cJSON v1.7.18(MIT)到 `mcm-ddc-ble/src/infra/`,
|
||
`infra_cjson.c` 用 `cJSON_InitHooks` 把分配挂到 FreeRTOS `pvPortMalloc/vPortFree`
|
||
(惰性一次性初始化,命令首次用到时才挂钩子)。uvprojx 三个 target 均加 infra 组
|
||
与 `..\src\infra` include path。改动只在 mcm-ddc-ble 内,nations-tec 只读区未动。
|
||
- **MicroLIB 注意**:cJSON 数字序列化对整数值走 `%d` 快路径(valueint),不触发
|
||
MicroLIB 不支持的浮点 `%g`;解析侧 `strtod` MicroLIB 支持。本工程参数全为整数,
|
||
若未来引入浮点参数需先验证打印路径。
|
||
- **接口**:`appget json` 输出 `{"led":500,"pwm":0,"valid":1}`;
|
||
`appset json {"led":500,"pwm":50}`(CLI 分词后的 JSON 片段自动重组;未知键忽略 =
|
||
前向兼容;所有键先校验范围,任一越界则整体不改动;成功后落盘并回显 JSON)。
|
||
原纯文本 `appget`/`appset <led|pwm> <val>` 保持不变。
|
||
- 命令行长度假定 ≤79B(JSON 重组缓冲 80B),BLE 读写特征 63B 上限内可用紧凑 JSON。
|
||
|
||
构建 0 Error/0 Warning,V1.00.14 `Code=46912 RO=4604 RW=2060 ZI=28604`,
|
||
整包/OTA 镜像已生成(_ota.bin 53072B,crc32=0x603CBC54)。
|
||
|
||
## 35. appsw 命令:切换运行 bank(2026-09-04,V1.00.15)
|
||
|
||
`appsw [1|2]`(app_bootset.c):无参切到对侧 bank,带参切到指定 bank。
|
||
安全校验层层兜底,防止跳进坏 bank:
|
||
|
||
- bootsetting 记录必须 valid(无效直接拒绝,不像 bsset 那样从零重建);
|
||
- 目标 bank 记录一致性:`start_address` 必须等于该 bank 固定基址
|
||
(APP1=0x01008000 / APP2=0x01040000),`size` 在 1B~224KB 内;
|
||
- **复算目标 bank 镜像 CRC32 与记录比对**(软件 CRC 逐位实现,224KB 约数秒,
|
||
期间不关中断、BLE 不断连),不匹配则拒绝并提示先跑 OTA;
|
||
- 通过后 `bootset_commit` 改 `active_bank`(自动重算 CRC + 擦除编程 + 读回校验),
|
||
延时 200ms 让应答出去,`NVIC_SystemReset()`。Boot 端不校验镜像 CRC,
|
||
切换安全性全部由本命令的前置校验承担。
|
||
|
||
构建 0 Error/0 Warning,V1.00.15 `Code=47680 RO=4752 RW=2060 ZI=28604`,
|
||
整包/OTA 镜像已生成(_ota.bin 53988B,crc32=0xC0500D4E)。
|
||
|
||
## 36. 双 APP 整包脚本(appsw 测试包,2026-09-04,V1.00.15/APP2=V1.00.16)
|
||
|
||
`tools\make_dual_package.bat` 一键出**完整整片包** `tools/out/caiic_ble_dual.{hex,bin}`,
|
||
包含全部 5 个区域:Boot + bootsetting(双 bank 记录,size/crc32/version 均填实)
|
||
+ APP_DATA(缺省 `caiic_params_t` 52B 记录,led=500/pwm=0)+ APP1(V1.00.15,
|
||
链接 0x01008000)+ APP2(V1.00.16,链接 0x01040000)。烧录后 `appsw` 可在两个
|
||
真实镜像间来回切换,`version`/`devinfo` 读到的版本号即当前 bank。
|
||
|
||
实现要点:
|
||
|
||
- **APP2 必须链接在 0x01040000**:Cortex-M0 代码位置相关,直接把 APP1 的 bin
|
||
烧进 APP2 会因绝对地址/字库指回 0x01008xxx 而"偷跑"APP1 内容。uvprojx 新增
|
||
target **APP2**(克隆 N32WB03x target):IROM/OCR_RVCT4 改 0x01040000,
|
||
独立 `Objects-app2/`、`Listings-app2/`、`bin/mcm-ddc-ble-app2.bin`,
|
||
Define 追加 `APP_BASE_ADDR=0x01040000u, APP_FW_VERSION=\"V1.00.16\",
|
||
APP_FW_VERSION_NUM=0x00010010u`(字符串宏在 Define 里用 `\"` 转义,
|
||
`"` 不会被还原,实测编译报 #20 后改)。**APP2 版本号同时写在 uvprojx
|
||
Define 与 make_dual_package.bat 的 APP2_VERSION,两处必须同步**。
|
||
- 固件配套改动(对 APP1 行为中性,故 APP1 版本不递增):`main.c` VTOR 基址由
|
||
宏 `APP_BASE_ADDR`(缺省 0x01008000)替代硬编码;`app_version.h` 两个宏加
|
||
`#ifndef` 允许 target 级覆盖。`app_ota.c` 本来就用 `Image$$ER_IROM1$$Base`
|
||
判当前 bank,APP2 target 天然正确(OTA 目标自动为 APP1)。
|
||
- `merge_image.py` 扩展:`--app2 <bin> --app2-version N --with-appdata`,
|
||
bootsetting 生成双 bank 记录,APP_DATA 生成缺省参数记录;位置参数兼容
|
||
原 `make_package.bat` 流程(单 bank 包行为不变)。
|
||
- **OTA 跨 bank 链接地址注意**:OTA 载荷必须链接在**目标 bank** 地址。当前
|
||
`_ota.bin` 是 APP1 链接的镜像——只有运行在 APP2 时 OTA(写 APP1)才是严格
|
||
正确的;运行在 APP1 时 OTA 写 APP2 的 APP1 链接镜像,boot 后名义 active=APP2
|
||
实际执行会滑回 APP1 flash(VTOR 也指向 APP1)。要完整支持双 bank OTA,需出
|
||
两份 bank 匹配的 OTA 包(本工程的 APP1/APP2 双 target 已具备这个能力)。
|
||
|
||
## 37. 实测:板载芯片 Flash 只有 256KB 可用(2026-09-04,重要)
|
||
|
||
双 APP 整包(§36)烧录后 `appsw 2` 被自身 CRC 校验拦下(记录 0xCCDBC8B0,
|
||
实算 0xD30FB2BD)。逐层定位:
|
||
|
||
1. 本地复算:`mcm-ddc-ble-app2.bin` 的 zlib CRC32 = 0xCCDBC8B0(与 bootsetting
|
||
记录一致),而 0xD30FB2BD 恰好等于 **dual 整包 [0x01000000, +54288) 区段**的
|
||
CRC——即固件(CPU)读 0x01040000 拿到的是 0x01000000 处的内容(256KB 回绕别名)。
|
||
2. NSpyocd(AHB-AP/SWD)读 0x01040000 直接 TransferFault;读 0x0103FF00 正常。
|
||
总线在 0x01040000 以上没有存储器。
|
||
3. NSpyocd 烧写 0x01040000 以上"成功"(FLM 未报错),但 CPU 读回证明数据实际
|
||
不可见;Boot/APP1 未被破坏说明写也未回绕到低区——上方写入被静默丢弃。
|
||
|
||
**结论:当前开发板上的芯片实际表现为 256KB Flash(0x01000000~0x0103FFFF),
|
||
与"N32WB031KEQ6-2 = 512KB"的预期不符。** 需核对板子实际丝印/物料(可能实装了
|
||
256KB 的 KCQ6-1)。受此影响:
|
||
|
||
- §36 的双 APP 整包/`appsw` 功能在这块板上不可用(APP2 地址无效);
|
||
脚本与 APP2 target 保留,待 512KB 芯片到位后可直接复用。
|
||
- **现有 512KB 双 bank 布局(dfu_layout.h)在此板上整体不成立**:BLE OTA 向
|
||
APP2(0x01040000)的直写会被静默丢弃,OTA"成功"后会切到无效 bank。
|
||
若确认板上就是 256KB 料,应回退到官方 256KB DFU 布局(APP1 0x01008000/112KB、
|
||
APP2 0x01020000/112KB,bootsetting/APP_DATA 相应下移),改动涉及
|
||
dfu_layout.h、Boot、app_ota.c、merge_image.py 与全部文档。
|
||
- flash_package.bat 已改用 DFP pack 的 n32wb031keq6_2 target(512KB 映射)
|
||
+ `-O smart_flash=false`(pack target 的预编程 diff 读 0x01000000 会 fault,
|
||
编程+校验正常);对 256KB 内的常规整包烧录同样适用(已实测)。
|
||
|
||
## 附:本次调试的正面结果
|
||
|
||
- `appsw` 的三层安全校验按设计拦下了无效 bank(记录 CRC ≠ 实算 CRC),
|
||
没有跳进坏镜像——校验逻辑本身验证通过。
|
||
- 分包读 CLI 应答(§33)实测正常:BLE 读 `version`/`appsw` 输出完整。
|
||
|
||
## 38. 回退 256KB 布局 + appsw 双 bank 实测通过(2026-09-04,V1.00.16/APP2=V1.00.17)
|
||
|
||
确认板载硅片为 256KB(§37)后的重排:Boot 16KB / bootsetting 8KB / APP_DATA 8KB
|
||
不动,余下 224KB 均分:**APP1 0x01008000/112KB(0x1C000),APP2 0x01024000/112KB**,
|
||
末尾 0x0103FFFF 对齐 256KB 终点;IMAGE_UPDATE 区取消(BASE 改为 0x01040000 作
|
||
flash 结束标记,SIZE=0,Boot 的 start_address 上界检查沿用该区间)。
|
||
|
||
改动点:
|
||
|
||
- `Boot/src/dfu_layout.h`:`CAIIC_APP_BANK_SIZE` 0x38000→0x1C000,
|
||
`CAIIC_APP2_BASE` 0x01040000→0x01024000,IMAGE_UPDATE 归零。Boot/APP 全量重建。
|
||
- uvprojx:target N32WB03x 的 IROM/OCR_RVCT4 size 0x38000→0x1c000;
|
||
target APP2 的 start 0x1040000→0x1024000、size 0x1c000,
|
||
Define `APP_BASE_ADDR=0x01024000u`、版本覆盖升至 **V1.00.17/0x00010011u**
|
||
(APP1 默认版本升 V1.00.16/0x00010010u;bat 的 APP2_VERSION 同步)。
|
||
- `merge_image.py`:`APP2_ADDR` 0x01024000。
|
||
- app_bootset.c 提示文案去掉硬编码地址(改指宏名)。
|
||
|
||
实测(NSpyocd 烧 `caiic_ble_dual.hex`,bleak 客户端操作):
|
||
|
||
- 烧录后跑 APP1:BLE `version` → **V1.00.16**;`appsw 2` → bank2 CRC 校验通过、
|
||
更新 active=2、复位;
|
||
- 重连后 `version` → **V1.00.17**(APP2,链接 0x01024000,BLE/CLI 全功能正常,
|
||
VTOR 宏化生效);`bsdump` 记录 valid,双 bank size/crc/ver 正确;
|
||
- 无参 `appsw` 切回 APP1,`version` 再次 → **V1.00.16**。双向切换全通。
|
||
- 已知小现象:设备在写应答 ACK 前后复位时,bleak 写特征偶报
|
||
WinError -2147023673(操作已取消),实际命令已送达执行——属 Windows BLE
|
||
栈对端复位的时序表现,非固件问题。
|
||
|
||
构建 0 Error/0 Warning:APP1 `Code=47704 RO=4752 RW=2060 ZI=28604`,
|
||
APP2 `Code=48004`(同源码、不同链接地址/版本号,体积差 300B 属正常链接差异)。
|
||
整包/双包/OTA 镜像均已重新生成。
|
||
|
||
## 39. OTA 双 bank 配套:CUR_BANK 信息项 + 双载荷出包 + 向量表防呆(2026-09-04,V1.00.17)
|
||
|
||
回答"不知道当前跑 APP1 还是 APP2、OTA bin 链接地址不匹配怎么办":
|
||
|
||
- **信息项 0x07 CUR_BANK**(u8,1=APP1/2=APP2,按链接基址 `Image$$ER_IROM1$$Base`
|
||
判定):`devinfo` 首行新增 `cur bank: APPn`,帧协议 INFO_QUERY 与只读特征
|
||
`...e0004` 的 TLV 同步包含。任何时刻客户端都能确定运行 bank,不依赖版本号。
|
||
- **双 OTA 载荷**:`make_package.bat`/`make_dual_package.bat` 现在都构建 APP2
|
||
target,`merge_image.py` 新增 `--ota-app2`:出 `<包名>_ota.bin`(target_bank=1)
|
||
与 `<包名>_ota_app2.bin`(target_bank=2),清单 json 增加 `target_bank` 字段。
|
||
客户端规则:读 CUR_BANK → OTA 目标 = 对侧 bank → 选对应载荷。
|
||
- **固件防呆**:OTA_END 整镜像 CRC 通过后,校验镜像向量表 Reset 地址落在目标
|
||
bank 范围内,否则回 OTA_RSP(status=6 bank_mismatch)、中止不切换。
|
||
(通知上行未修复,手机端 OTA 页仍停用;该校验 PC 帧协议客户端可达。)
|
||
- **APP2 target 取消版本号覆盖**:两个 bank 必须出同一 release(否则 OTA 清单
|
||
version 与镜像自报版本不一致)。bank 区分改由 CUR_BANK 承担——比"+1 版本号"
|
||
更通用(任意 OTA 之后仍有效)。`--app2-version` 缺省=主版本号。
|
||
- ble_cli_test.py 的 `param` 命令同步解码 cur_bank。
|
||
|
||
实测(双包烧录):APP1 devinfo `cur bank: APP1` → `appsw` → APP2 devinfo
|
||
`cur bank: APP2`(两 bank 同为 V1.00.17)→ e0004 TLV 含 `cur_bank` →
|
||
`appsw 1` 切回。构建 0 Error/0 Warning(双 target),整包/双包/双 OTA 载荷
|
||
均已重新生成。
|