mcm-ddc-ble V1.00.09:新增bootsetting与APP_DATA参数区结构化读写(仅命令访问,无裸读写防变砖);param命令管理caiic_params_t参数记录(led1_blink_ms即时生效于LED1闪烁/pwm_duty_pct仅存储),bsdump/bsset结构化读写bootsetting(自动重算CRC+擦除编程+读回校验);UART与BLE CLI读写特征双通道可用;AGENTS.md恢复为/init新版并同步;整包+OTA包已出到tools/out
This commit is contained in:
parent
1bc2ca6ec5
commit
9c84bdb6cb
222
AGENTS.md
222
AGENTS.md
@ -2,85 +2,154 @@
|
||||
|
||||
## 项目概述
|
||||
|
||||
本仓库是基于国民技术(Nations)**N32WB031 BLE SoC** 的嵌入式固件工程集合。实际芯片型号 **N32WB031KEQ6-2**(Cortex-M0,64MHz HSI,**Flash 512KB**,RAM 48KB+16KB)。
|
||||
本仓库是 **mothercup(母乳杯)** 产品的完整代码仓库,包含三大部分:
|
||||
|
||||
当前活跃工程:
|
||||
1. **设备固件** — 基于国民技术(Nations)**N32WB031 BLE SoC**(实际型号 **N32WB031KEQ6-2**:Cortex-M0,64MHz HSI,**Flash 512KB**,RAM 48KB+16KB):
|
||||
- **`mcm-ddc-ble/`** — 唯一活跃的应用固件工程(APP,链接在 APP1 bank `0x01008000`/224KB)。以 SDK rdtss 例程为蓝本,集成 FreeRTOS、UART CLI、BLE 自定义 GATT 服务(CLI 透传 / 设备信息查询 / BLE OTA 双 bank 直写升级)、bootsetting 与 APP_DATA 参数区结构化读写命令。当前版本 **V1.00.09**(`mcm-ddc-ble/inc/app_version.h`)。历史上曾有 `mcm-ddc-04/` 主工程,**已删除**,其功能已全部并入本工程。
|
||||
- **`Boot/`** — 自写精简 bootloader(链接在 `0x01000000`/16KB):校验 bootsetting 记录自身完整性(magic + 结构体 CRC32)后按 active bank 的 `start_address` 直接跳转;**不校验镜像 CRC(CRC 校验在 OTA 升级过程中完成)**;记录无效或地址越界回退 APP1。
|
||||
2. **手机 App `SmartAssiter/`** — uni-app **Vue3 + TypeScript** 工程(HBuilderX 项目管理,无 package.json),通过 BLE 连接设备:查看运行参数(温度/电压/转速等)、CLI 终端、OTA 升级页(当前停用,见下)。另有登录/注册/用户信息等云端业务页面。
|
||||
3. **PC 工具 `tools/`** — 整片烧录包制作/烧录脚本 + bleak 蓝牙测试客户端。
|
||||
|
||||
- **`mcm-ddc-04/`** — 主工程(APP,链接在 APP1 bank `0x01008000`/224KB):UART(printf 重定向 + DMA 发送 + RX 中断)、CLI 命令框架(UART + BLE 双通道)、FreeRTOS 多任务、GPIO 点灯、BLE 协议栈(自定义 GATT 透传服务 CLS)、BLE OTA 双 bank 直写升级(见开发日志第 15/16 节、`docs/ble_protocol.md`)。
|
||||
- **`Boot/`** — 自写精简 bootloader(链接在 `0x01000000`/16KB):校验 bootsetting 自身完整性(magic + 结构体 CRC32)后按 active bank 的 `start_address` 直接跳转;**不校验镜像 CRC(在 OTA 升级过程中校验)**;记录无效或地址越界回退 APP1(开发日志第 19/21 节)。
|
||||
- **`mcm-ddc-ble/`** — 独立 BLE 工程(基于 SDK rdtss 例程 + FreeRTOS,睡眠已锁保 SWD,已并入 mcm-ddc-04 的 CLI 框架 + UART 驱动:CLI 任务 `caiic->`、UART/BLE 双通道应答,命令 help/version/sysinfo/led):当前链接在 `0x01008000`/0x38000 作为 APP1,与 Boot 组成整包 `caiic_ble_full.*`;单跑时把 IROM1 改回 `0x01000000, 0x40000`。日志在 `mcm-ddc-ble/docs/开发日志.md`。
|
||||
关键文档:
|
||||
|
||||
仓库顶层目录:
|
||||
- `docs/开发日志.md` — 固件全程开发日志(29 节,含所有踩坑根因与设计决策,排查问题先查这里)
|
||||
- `docs/ble_protocol.md` — CAIIC BLE 通信协议 V1.1(帧格式/GATT UUID/三类业务流程/维护命令/手机端开发指南)
|
||||
- `SmartAssiter/docs/修改记录_*.md` — App 侧每次改造的详细记录
|
||||
|
||||
- `mcm-ddc-04/` — 主工程(应用代码、MDK 工程文件、开发日志)
|
||||
- `mcm-ddc-ble/` — 独立 BLE 工程(rdtss 蓝本 + FreeRTOS,APP1 链接形态)
|
||||
- `Boot/` — bootloader 工程(`src/main.c`、`dfu_layout.h`、`boot_crc32.c`;后两个被 APP 工程以相对路径 `..\..\Boot\src` 共用)
|
||||
- `tools/` — 烧录包工具:`merge_image.py`(合并 boot + bootsetting 缺省记录 + APP 为整片 hex/bin,支持 `merge_image.py [app_bin] [输出名]`,自动从 `app_version.h` 取 `APP_FW_VERSION_NUM` 写入 OTA 清单)、`make_package.bat`(一键全量重建 `-r` + 合并)、`flash_package.bat`(NSpyocd 整片烧录),产物在 `tools/out/`;BLE 测试工具:`ble_cli_test.py` + `ble_cli.bat`(PC 端 bleak 蓝牙 CLI 客户端,支持帧协议与 `...c72e0003` 读写特征两种方式,venv 在 `tools/.venv-ble`,首次运行 `ble_cli.bat` 自动创建)
|
||||
- `nations-tec/` — 厂商资源:SDK V2.0.0、DFP 器件包、STB 开发板资料、官方 PDF 文档。**这些内容为只读参考资料,不要修改。**
|
||||
- `app/`、`docs/` — 顶层空目录,预留占位
|
||||
|
||||
关键参考路径(相对仓库根):
|
||||
|
||||
- SDK:`nations-tec/N32WB03x_SDK_V2.0.0`(固件库 `firmware/`、中间件 `middlewares/Nationstech/ble_library` 与 `middlewares/Third_Party/FreeRTOS`、官方例程 `projects/n32wb03x_EVAL/`、DFU 工具 `utilities/dfu`)
|
||||
- 官方例程:USART printf `projects/n32wb03x_EVAL/peripheral/USART/Printf`、点灯 `peripheral/GPIO/LedBlink`、FreeRTOS `application/FreeRTOS/FreeRTOS_ThreadCreation`
|
||||
- 开发日志与详细设计决策:`mcm-ddc-04/docs/开发日志.md`
|
||||
|
||||
## 工程结构(mcm-ddc-04)
|
||||
## 仓库顶层结构
|
||||
|
||||
```
|
||||
mcm-ddc-04/
|
||||
├── app/
|
||||
│ ├── main.c # 入口:VTOR 重映射 → USART 初始化+banner → LED 初始化 → app_ble_init → 建队列/任务/CLI → vTaskStartScheduler
|
||||
│ ├── bsp_usart.c/.h # USART1 初始化(PB6/PB7,115200 8N1)+ fputc 重定向('\n' 前自动补 '\r')+ DMA TX(CH1,轮询完成)+ RXDNE 中断字节队列 + TX 互斥锁
|
||||
│ ├── bsp_led.c/.h # LED1(PB0)/LED2(PA6) 初始化、on/off/toggle
|
||||
│ ├── app_tasks.c/.h # 3 个 FreeRTOS 任务 + 日志队列(生产者-消费者模型)+ 主动打印开关(默认关)
|
||||
│ ├── app_cli.c/.h # CLI UART 前端:CliTask 行接收/编辑/历史/Tab/Ctrl+Z,分行后交 cli_core 执行
|
||||
│ ├── cli_core.c/.h # CLI 核心(命令表/handler/分词执行),输出经可切换 cli_out_fn(默认 UART DMA);命令:help/version/sysinfo/log/led/bankinfo
|
||||
│ ├── app_ota.c/.h # BLE OTA 接收器:4KB 扇区缓冲直写对侧 bank + CRC32 校验 + bootsetting 更新 + 复位切换
|
||||
│ ├── app_version.h # 固件版本号 APP_FW_VERSION
|
||||
│ ├── n32wb03x_it.c/.h # NMI / HardFault 异常处理 + USART1_IRQHandler(转发到 bsp_usart_rx_isr_handler)
|
||||
│ ├── FreeRTOSConfig.h # heap 22KB,SVC/PendSV/SysTick 映射给 FreeRTOS port
|
||||
│ └── ble/
|
||||
│ ├── app_ble.c/.h # BLE 栈初始化/广播/连接事件 + BLE 调度任务 + notify 发送与下行回调 + app_ble_max_payload/is_connected
|
||||
│ ├── app_ble_proto.c/.h # BLE 帧协议前端:字节流重组、CLI_REQ/CLI_RSP 传输、OTA 帧分发、pending 重试(BleTask 上下文)
|
||||
│ ├── app_user_config.h # 广播名 CAIIC-MCM、连接参数、profile/日志开关(被 SDK rwip_config.h 包含)
|
||||
│ └── app_profile/
|
||||
│ ├── rwapp_config.h # CFG_APP_* → BLE_APP_* 映射
|
||||
│ └── app_cls.c/.h # 自定义 128-bit UUID GATT 服务(写 + notify 两特征,基于 SDK rdtss profile 引擎)
|
||||
├── MDK-ARM/
|
||||
│ ├── embeddedSrc.uvprojx / .uvoptx # Keil µVision5 工程文件(含 DFU 组:..\..\Boot\src\boot_crc32.c)
|
||||
│ ├── Objects/ # 编译产物(embeddedSrc.axf / .hex)
|
||||
│ ├── bin/ # fromelf 生成的 embeddedSrc.bin
|
||||
│ └── build.log
|
||||
└── docs/开发日志.md
|
||||
mothercup/
|
||||
├── mcm-ddc-ble/ # 应用固件工程(src/ inc/ MDK-ARM/)
|
||||
├── Boot/ # bootloader 工程(src/ + MDK-ARM/caiic_boot.uvprojx)
|
||||
├── SmartAssiter/ # 手机 App(uni-app vue3,HBuilderX 工程)
|
||||
├── tools/ # merge_image.py / make_package.bat / flash_package.bat / ble_cli_test.py 等
|
||||
├── docs/ # 开发日志.md + ble_protocol.md(仓库级权威文档)
|
||||
├── nations-tec/ # 厂商资源:SDK V2.0.0、DFP 器件包、STB 开发板资料、官方 PDF。**只读,不要修改**
|
||||
└── tools/out/ # 出包产物(caiic_ble_full.{hex,bin} + _ota.bin/_ota.json)
|
||||
```
|
||||
|
||||
SDK 源码(固件库、CMSIS、FreeRTOS V9.0.0、BLE 协议栈/profile/ns_library、启动文件)通过相对路径 `..\..\nations-tec\N32WB03x_SDK_V2.0.0` 被 uvprojx 引用,**不复制进工程**。Bootloader 共享代码(`Boot/src/dfu_layout.h`、`boot_crc32.c`)经 `..\..\Boot\src` 引用。因此 `mcm-ddc-04` 目录不能脱离仓库根单独移动。
|
||||
SDK 源码(固件库、CMSIS、FreeRTOS V9.0.0、BLE 协议栈/profile/ns_library、启动文件)通过相对路径 `..\..\nations-tec\N32WB03x_SDK_V2.0.0` 被 uvprojx 引用,**不复制进工程**;Bootloader 共享代码(`Boot/src/dfu_layout.h`、`boot_crc32.c`)经 `..\..\Boot\src` 被 APP 工程引用。因此各工程目录不能脱离仓库根单独移动。
|
||||
|
||||
工程配置:器件 `N32WB031KEQ6-2`(512KB Flash),IROM 0x01008000 / 0x38000(APP1 区,前 32KB 留给 Bootloader),**IRAM 0x20004000 / 0xC000**(低 16KB 保留给芯片 ROM/BLE,见下),MicroLIB,全局宏 `N32WB03X, USE_STDPERIPH_DRIVER`;链接器 Misc 附加 BLE ROM 符号表 `symbol_g15.obj`。
|
||||
## Flash / RAM 布局(铁律)
|
||||
|
||||
Flash 布局(512KB,`Boot/src/dfu_layout.h` 为唯一权威定义,官方 256KB DFU 布局每区加倍):
|
||||
|
||||
| 区域 | 地址 | 大小 |
|
||||
|---|---|---|
|
||||
| Bootloader | 0x01000000 | 16KB |
|
||||
| bootsetting | 0x01004000 | 8KB(用 1 个 4KB 扇区,结构体见 dfu_layout.h) |
|
||||
| APP_DATA | 0x01006000 | 8KB(区头为 `caiic_params_t` 参数记录,见 app_params.h) |
|
||||
| APP1 | 0x01008000 | 224KB(0x38000) |
|
||||
| APP2 | 0x01040000 | 224KB(0x38000) |
|
||||
|
||||
- **RAM 铁律**:SRAM 为 48KB+16KB,**低 16KB(0x20000000~0x20003FFF)由芯片 ROM/BLE 子系统占用**(rwip 堆描述符、patch 数组、中断中继表,由 ROM 启动代码预备)。**任何工程的 IRAM 执行区必须从 0x20004000 起**(含 Boot 和任何小工具),否则 .data/.bss 初始化冲掉 ROM 数据,BLE init 必然 HardFault(实测根因,开发日志 §21)。注意:mcm-ddc-ble.uvprojx 里 `<IRAM>` 镜像元素显示 0x20000000 是过期显示值,实际生效的是 OCR_RVCT9=0x20004000/0xC000——以 `Listings/mcm-ddc-ble.map` 的 `RW_IRAM1 (Exec base: 0x20004000)` 为准。
|
||||
- **VTOR**:Cortex-M0 无 SCB->VTOR,用 `PWR->VTOR_REG`(bit31=EN|[30:0]=基址)。规则:**BLE 初始化之前** VTOR 指向 APP 自身向量表(main 开头设 `0x80000000|0x01008000`,USART1 RX 中断需要);**`ns_ble_stack_init()` 之后 VTOR 必须为 0**,此后所有中断经芯片 ROM 跳板 + RAM 中继。**绝对不要在 BLE init 后重设 VTOR**(实测崩溃根因,开发日志 §18)。
|
||||
|
||||
## 固件工程(mcm-ddc-ble)
|
||||
|
||||
```
|
||||
mcm-ddc-ble/
|
||||
├── src/
|
||||
│ ├── main.c # 入口:VTOR 预置 → USART+banner → LED → app_ble_init → app_params_init
|
||||
│ │ # → ns_sleep_lock_acquire(锁睡眠保 SWD) → 建 BLE 调度/LED/CLI 任务 → vTaskStartScheduler
|
||||
│ ├── bsp_usart.c # USART1(PB6/PB7, 115200 8N1):fputc 重定向 + DMA TX(CH1) + RXDNE 中断字节队列 + TX 互斥锁
|
||||
│ ├── app_gpio.c # LED1(PB0)/LED2(PA6)
|
||||
│ ├── app_cli.c # CLI UART 前端:CliTask 行接收/编辑/历史/Tab/Ctrl+Z,提示符 caiic->
|
||||
│ ├── cli_core.c # CLI 核心(命令表 s_cmds[]/handler/分词执行),输出经可切换 cli_out_fn
|
||||
│ │ # 命令:help / version / sysinfo / devinfo / blelog / led / param / bsdump / bsset
|
||||
│ ├── app_ble.c # BLE 栈初始化/广播(名 CAIIC-MCM-20260902)/连接事件 + BLE 调度任务
|
||||
│ ├── app_ble_proto.c # 0xCA 帧协议:字节流重组、CLI_REQ/RSP、INFO_QUERY/RSP、OTA 帧分发、
|
||||
│ │ # CLI 读写特征(...e0003) 与只读参数特征(...e0004) 的执行/应答
|
||||
│ ├── app_info.c # 设备信息:ADC 芯片温度(CH7)/电压(CH6)、运行时长、堆剩余;风扇 weak 数据源
|
||||
│ ├── app_ota.c # BLE OTA:双 bank 直写(惰性擦扇区,仅 4B 对齐暂存)+ CRC32 校验 + bootsetting 更新 + 复位
|
||||
│ ├── app_params.c # APP_DATA 参数记录(caiic_params_t,magic+CRC)+ param 命令(led1_blink_ms/pwm_duty_pct)
|
||||
│ ├── app_bootset.c # bootsetting 结构化读写 bsdump/bsset(自动重算 CRC,防裸写变砖)
|
||||
│ ├── ble_up.c # CLI 应答的 BLE notify 上行(ke_msg 上下文约束:环形缓冲 + BLE 任务内发送)
|
||||
│ ├── n32wb03x_it.c # 异常处理(HardFault 栈帧打印)+ USART1_IRQHandler 转发
|
||||
│ ├── app_usart.c # 遗留文件,已不在工程中编译(rdtss 原透传 FIFO,勿使用)
|
||||
│ └── app_profile/ # app_rdtss.c(GATT 服务实现,读请求按 att_idx 分发 CLI_VAL/INFO_VAL)等
|
||||
├── inc/ # 对应头文件 + FreeRTOSConfig.h(heap 20KB)+ app_user_config.h(广播名/连接参数)
|
||||
└── MDK-ARM/ # mcm-ddc-ble.uvprojx(target "N32WB03x" 为活跃 target;
|
||||
# OTA_IMG_1/2 是 rdtss 遗产,保留不用)、Objects/、bin/、Listings/
|
||||
```
|
||||
|
||||
工程配置:器件 `N32WB031KEQ6-2`,IROM 0x01008000/0x38000(APP1),IRAM **0x20004000/0xC000**,MicroLIB,全局宏 `N32WB03X, USE_STDPERIPH_DRIVER`;链接器 Misc 附加 BLE ROM 符号表 `symbol_g15.obj`(SDK `middlewares/Nationstech/ble_library/ns_ble_stack/symdef/`)。
|
||||
|
||||
## 构建与烧录
|
||||
|
||||
工具链:Keil µVision5(ARMCC V5.06 update 6),安装于 `D:\Keil_v5`。
|
||||
|
||||
命令行构建(工作目录必须为 `mcm-ddc-04/MDK-ARM`):
|
||||
命令行构建(工作目录在对应工程的 `MDK-ARM/`):
|
||||
|
||||
```bash
|
||||
"D:\Keil_v5\UV4\UV4.exe" -b embeddedSrc.uvprojx -j0 -o build.log
|
||||
"D:\Keil_v5\UV4\UV4.exe" -b mcm-ddc-ble.uvprojx -j0 -o build.log # APP 增量构建
|
||||
"D:\Keil_v5\UV4\UV4.exe" -b caiic_boot.uvprojx -j0 -o build.log # Boot 增量构建
|
||||
```
|
||||
|
||||
构建成功后自动执行 `fromelf --bin --output=.\bin\embeddedSrc.bin .\Objects\embeddedSrc.axf`。
|
||||
当前基线结果:**0 Error(s), 0 Warning(s)**,体积 `Code=38348 RO-data=6932 RW-data=10600 ZI-data=36128`(RW+ZI≈45.7KB < 48KB 可用窗口,heap 22KB)。
|
||||
要求保持 **0 Error(s), 0 Warning(s)**。当前基线(V1.00.09):`Code=38352 RO-data=4192 RW-data=2028 ZI-data=27580`。
|
||||
|
||||
烧录与运行:
|
||||
**固件版本号约定(重要)**:每次修改固件代码必须递增 `mcm-ddc-ble/inc/app_version.h` 中的 `APP_FW_VERSION` 与 `APP_FW_VERSION_NUM`(格式 `0x00MMmmpp`,通常补丁位 +1),用于识别板上实际运行的固件;工程名与出包文件名保持不变。
|
||||
|
||||
**固件版本号约定(重要)**:每次修改固件代码必须递增 `mcm-ddc-ble/inc/app_version.h` 中的 `APP_FW_VERSION` 与 `APP_FW_VERSION_NUM`(格式 `0x00MMmmpp`,通常补丁位 +1),用于识别板上实际运行的固件;固件工程名与出包文件名称保持不变。`tools/merge_image.py` 出包时自动把 `APP_FW_VERSION_NUM` 写入 OTA 清单(`_ota.json`,显式传第三个参数可覆盖)。
|
||||
**出包约定(重要)**:每次固件修改构建通过后,必须直接运行 `tools\make_package.bat` 重新生成整片包与 OTA 升级包到 `tools/out/`(与代码改动一起交付,不要只交付源码)。
|
||||
|
||||
1. Keil 打开 `MDK-ARM/embeddedSrc.uvprojx`,F7 编译
|
||||
2. NS-LINK 接 SWD(PA4/PA5),F8 下载——Boot 跳转不校验镜像 CRC,Keil 直接下载 APP 即可正常启动调试;**但 Keil 下载选项必须是"Erase Sectors",整片擦除会杀掉 Boot**(杀掉后独立运行不启动,需重烧整片包恢复)
|
||||
3. 独立运行(脱调试器)需烧整片包:`tools\flash_package.bat tools\out\caiic_full.hex`(改代码后先 `make_package.bat` 重新出包)。**板子上烧过其他 0x01000000 起步的程序会覆盖 Boot/bootsetting,恢复靠重烧整片包**
|
||||
4. 串口助手接 PB6(TX)/PB7(RX),115200 8N1,复位后应看到启动 banner 与 `caiic->` CLI 提示符(输入 `help` 查看命令;LED 滚动日志默认关闭,用 `log on` 打开)
|
||||
5. BLE:手机 nRF Connect 应能搜到并连接 `CAIIC-MCM`,可见自定义服务(写特征 + notify 特征)
|
||||
出包与烧录:
|
||||
|
||||
1. `tools\make_package.bat` — 一键:`UV4 -r` **全量重建** Boot + APP(出包必须 `-r`,增量构建曾产生栈顶/ZI 不一致的砖包,见开发日志 §24)→ `merge_image.py` 合并。产物在 `tools/out/`:
|
||||
- `caiic_ble_full.hex/.bin` — 整片包(Boot + 缺省 bootsetting + APP1)
|
||||
- `caiic_ble_full_ota.bin` + `_ota.json` — OTA 载荷与清单(size/crc32/version;version 自动取 `APP_FW_VERSION_NUM`,手机端 OTA_BEGIN 直接取用)
|
||||
- 注意:`merge_image.py` 不带参数运行时默认 app 路径仍指向已删除的 `mcm-ddc-04/`,**手动调用必须显式传参**:`python tools/merge_image.py mcm-ddc-ble/MDK-ARM/bin/mcm-ddc-ble.bin caiic_ble_full`
|
||||
2. 首次/变砖恢复:`tools\flash_package.bat tools\out\caiic_ble_full.hex`(调 SDK 自带 NSpyocd,整片擦除 + 烧录;需 NS-LINK 接 SWD PA4/PA5 + 复位脚,先关闭 Keil)
|
||||
3. 日常开发调试:Keil F7 编译、F8 下载即可(Boot 不校验镜像 CRC,可直接下载 APP 调试);**Keil 下载选项必须是 "Erase Sectors",整片擦除会杀掉 Boot/bootsetting**(杀掉后需重烧整片包恢复)。板子上烧过其他 0x01000000 起步的程序同样会覆盖 Boot,恢复也是重烧整片包。
|
||||
4. 日常固件升级设计路径是 BLE OTA(手机 App 或 PC bleak 客户端)。
|
||||
|
||||
验证运行:串口助手接 PB6(TX)/PB7(RX),115200 8N1,复位后应看到 banner 与 `caiic->` 提示符(`help` 查看命令);手机应能搜到广播名 `CAIIC-MCM-20260902`。
|
||||
|
||||
## BLE 接口与协议(重要:当前双轨状态)
|
||||
|
||||
协议权威文档:`docs/ble_protocol.md`(V1.1)。广播名 `CAIIC-MCM-20260902`,自定义 128-bit UUID 服务 `00002760-08c2-11e1-9073-0e8ac72e1001`(SDK rdtss 服务),特征:
|
||||
|
||||
| 特征 UUID 尾段 | 属性 | 用途 |
|
||||
|---|---|---|
|
||||
| `...c72ee001` | Write Without Response | 0xCA 帧协议下行(CLI_REQ / INFO_QUERY / OTA_*) |
|
||||
| `...c72ee002` | Notify | 帧协议上行应答(CLI_RSP / INFO_RSP / OTA_RSP) |
|
||||
| `...c72ee003` | Read + Write(带响应) | **CLI 读写特征**:写原始命令行(≤63B)→ 读同一特征取回输出文本(≤512B),V1.00.02 新增 |
|
||||
| `...c72ee004` | Read | **只读参数特征**:读出全部信息项 TLV(同 INFO_RSP(all)),V1.00.04 新增 |
|
||||
|
||||
- **已知未决问题**:固件 notify 上行链路不通(帧协议应答收不到,下行写入正常),见开发日志 §28 末尾。因此 **App(SmartAssiter)已整体切换为只使用 `...e0003`/`...e0004` 两个读写特征**,删除了 notify/帧协议代码;**App 的 OTA 页当前停用**(OTA 应答依赖 notify)。固件侧帧协议与 OTA 代码仍完整保留,PC 端 `tools/ble_cli_test.py` 两种方式都支持。修复 notify 是本仓库最重要的待办。
|
||||
- 帧格式:`0xCA | TYPE | SEQ | LEN(LE16) | PAYLOAD | CRC16-CCITT(0x1021/0xFFFF, LE)`;OTA 为双 bank 直写、扇区级 ack 流控、END 整镜像 zlib CRC32 校验后更新 bootsetting 并复位。详见 ble_protocol.md。
|
||||
- 连接后设备主动发起 MTU=247 交换;失败退化为默认 20B/包,协议按字节流重组,两种情形都正确。
|
||||
- 信息项 id:0x01 固件版本 u32 / 0x02 芯片温度 i16(0.1°C,ADC CH7) / 0x03 风扇转速 u16(0xFFFF=无硬件,`app_fan_get_rpm()` 弱符号,产品板重写即可) / 0x04 电压 u16(mV,ADC CH6) / 0x05 运行时长 u32(s) / 0x06 剩余堆 u32(B)。
|
||||
- 调试手段:CLI 命令 `blelog on` 后,串口打印每个收/发协议帧 hex dump、连接/断开、CCCD 订阅事件(走 printf,不经 BLE 通道,避免自激)。
|
||||
- **维护命令(V1.00.09 起)**:bootsetting 与 APP_DATA 参数区为**结构化**读写(`param`/`bsdump`/`bsset`,不暴露裸读写),UART 与 BLE CLI 读写特征 `...e0003` 均可调用。详见 `docs/ble_protocol.md` §6.5。
|
||||
|
||||
## 手机 App(SmartAssiter)
|
||||
|
||||
- uni-app **Vue3 + TypeScript**(`manifest.json` vueVersion 3,appid `__UNI__884AC41`),**HBuilderX 工程**(有 `.hbuilderx/`,无 package.json/vite 配置)——开发/运行/打包均在 HBuilderX IDE 内进行(运行→运行到手机或模拟器;发行→原生 App 云打包)。目标平台为 Android/iOS App(BLE 功能仅 App 端有效;manifest 里保留 mp-weixin 配置但蓝牙不依赖它)。
|
||||
- 由 uni-app x(uvue/uts)+ 第三方蓝牙插件迁移而来,现蓝牙全部用 **uni 内置 BLE API**(vue3 App 端内置),标准基座即可运行(见 `SmartAssiter/docs/修改记录_2026-09-03_迁移uni-app-vue3与蓝牙去插件.md`)。
|
||||
- 结构:
|
||||
- `src/BluetoothManager.ts` — 蓝牙管理核心(扫描/连接/服务发现/读写/MTU/RSSI;读请求经 `onBLECharacteristicValueChange` 全局回调 + 内部串行队列 + 3s 超时;连接状态经 `uni.$emit("bleState", state)` 广播,0=已连接可用)
|
||||
- `src/mcm/` — 设备业务层:`McmCli.ts`(CLI 特征写命令/读应答,Promise 链串行)、`McmInfo.ts`(参数特征 TLV 解析)、`McmCommands.ts`(业务命令封装)
|
||||
- `pages/tabbar/` — home(设备连接+参数展示)、ota(升级页,**当前停用**并显示原因说明)、my;`pages/bleTest/bluetoothOperation/`(CLI 终端页);login/register/displayUserInfo 为云端账号业务
|
||||
- `api/` — 云端 HTTP 封装(`httpInstance.ts` 含服务器列表 SERVER_LIST,正式/测试/DEBUG 三地址,token 鉴权);`common/auth.ts`(token 本地存储)、`common/bleInfo.ts`(已连设备名/MAC 记忆)
|
||||
- `uni_modules/` 仅 uni-icons、uni-scss(官方组件,无第三方插件)
|
||||
- App 侧错误码约定(BluetoothManager):0=成功,10000=连接失败,10001=已断开,10002=蓝牙未开,10003=无权限,10004/10005=服务/特征缺失,10008=读写/MTU 失败或超时。
|
||||
|
||||
## PC 工具(tools/)
|
||||
|
||||
- `merge_image.py` — 纯 Python 无三方依赖;合并 boot+bootsetting(缺省记录,脚本生成)+APP 为整片 hex/bin,同时产出 `_ota.bin`/`_ota.json`;自动从 `app_version.h` 取 `APP_FW_VERSION_NUM` 写入清单
|
||||
- `make_package.bat` / `flash_package.bat` — 一键出包 / NSpyocd 整片烧录(脚本会自动找 Python312 全路径,本机 `python` 可能是商店占位 stub)
|
||||
- `ble_cli_test.py` + `ble_cli.bat` — PC 端 bleak 蓝牙 CLI 测试客户端(帧协议模式 + `-rw` 读写特征模式,交互模式 `-i`,venv 在 `tools/.venv-ble`,首次运行 bat 自动创建)
|
||||
- `ble_temp_watch.py` — 温度监测小工具
|
||||
|
||||
## 实时架构约定(固件)
|
||||
|
||||
- 使用 FreeRTOS V9.0.0 原生 API,**不使用 cmsis_os 封装**。
|
||||
- 任务:BLE 调度任务(栈 512 字,优先级 2,循环 `rwip_schedule(); vTaskDelay(1ms);`——**ke_msg/ke_timer 只允许在该任务上下文运行**);LED 任务(LED1 闪烁半周期读 APP_DATA 参数 `led1_blink_ms`);CliTask(优先级 3);CLI 输出经环形缓冲由 BLE 任务上下文发 notify(`ble_up.c`)。`configTOTAL_HEAP_SIZE = 20KB`(heap_4)。
|
||||
- SysTick 由 FreeRTOS port 接管:`main` 中不要手动 `SysTick_Config`,`n32wb03x_it.c` 中不要重复定义 SVC/PendSV/SysTick_Handler。
|
||||
- USART1_IRQn 优先级为 3(最低),因 ISR 内调用 FreeRTOS FromISR API,必须 ≥ `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`(=3)。BLE_SW/FIFO IRQ 优先级 0,其 ISR 内禁止调用 FromISR API。
|
||||
- 串口输出并发:多任务/CLI 输出分别持有 `bsp_usart_tx_lock()` 互斥锁;调度器启动前为空操作。不要在中断或多个任务里直接 printf。
|
||||
- **不接 ns_sleep 低功耗**(与 FreeRTOS tick 冲突):`main.c` 里 `ns_sleep_lock_acquire()` 永久锁睡眠,SWD 全程可调试;ns_sleep.c 仍需编译(ns_ble.c 引用其符号)。
|
||||
|
||||
## 硬件引脚约束(重要)
|
||||
|
||||
@ -88,40 +157,25 @@ SDK 源码(固件库、CMSIS、FreeRTOS V9.0.0、BLE 协议栈/profile/ns_libr
|
||||
- 板载 LED:LED1=PB0(跳线 J21)、LED2=PA6(跳线 J22),蓝色,4.7K 限流。
|
||||
- USART1:TX=PB6 / RX=PB7,复用 AF4,经排针 J3 引出。
|
||||
- PB8/PB9 默认接 32.768K 晶振;PB3 有下拉注意事项(用户手册 5.2.4)。
|
||||
|
||||
## 实时架构约定
|
||||
|
||||
- 使用 FreeRTOS V9.0.0 原生 API(`xTaskCreate` / `vTaskDelay` / `xQueue`),**不使用 cmsis_os 封装**。
|
||||
- 任务模型:LedTask(LED1,500ms)、LedTask2(LED2,1000ms)为生产者,只向日志队列投递 `LogMsg_t`;PrintTask(优先级 3,栈 1024 字)消费队列并 printf。**主动日志打印由 `AppTasks_SetLogEnabled()` 控制,默认关闭**(CLI 命令 `log on|off` 切换)。新增需要打印的任务时沿用此生产者-消费者模式,不要在中断或多个任务里直接 `printf`。
|
||||
- CLI 任务(优先级 3,栈 1024 字,见 `app_cli.c`):从 USART1 RXDNE 中断的字节队列取输入,行结束符 `\r\n` / `\n\r` / `\r` / `\n` 均识别;解析-执行-应答一体化,应答走 `bsp_usart_write_dma`(DMA_CH1)。新命令在 `s_cmds[]` 命令表中注册。支持 Tab 命令补全、上下方向键历史回翻(8 条环形缓冲)、Ctrl+Z 关闭主动打印。
|
||||
- 串口输出并发:PrintTask 的整条 printf 与 CLI 的整段应答分别持有 `bsp_usart_tx_lock()` 互斥锁,避免字节级交错;调度器启动前该锁为空操作。
|
||||
- SysTick 由 FreeRTOS port 接管(`FreeRTOSConfig.h` 中 `xPortSysTickHandler → SysTick_Handler` 映射):`main` 中不要手动 `SysTick_Config`,`n32wb03x_it.c` 中不要重复定义 SVC/PendSV/SysTick_Handler。
|
||||
- USART1_IRQn 中断优先级为 3(最低),因 ISR 内调用 FreeRTOS FromISR API,必须 ≥ `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`(=3)。
|
||||
- `configTOTAL_HEAP_SIZE = 22*1024`(4 个任务栈各 1024 字 + BLE 任务 512 字,另加队列/TCB/空闲任务开销),使用 heap_4。
|
||||
|
||||
## BLE 架构约定(重要)
|
||||
|
||||
- **RAM 布局(铁律)**:本芯片 SRAM 为 48KB+16KB。**低 16KB(0x20000000~0x20003FFF)由芯片 ROM/BLE 子系统占用**(rwip 堆描述符 0x20000118 起、patch 数组、中断中继表,由 ROM 启动代码预备,全 SDK 无源码重写)。任何工程的 IRAM 执行区必须从 **0x20004000** 起(含 Boot 和任何小工具),否则启动时代的 .data/.bss 初始化会冲掉 ROM 数据,BLE init 必然 HardFault(实测根因,开发日志第 21 节)。
|
||||
- **VTOR**:Cortex-M0 无 SCB->VTOR,向量重映射用 `PWR->VTOR_REG`(bit31=EN|[30:0]=基址)。规则:**BLE 初始化之前** VTOR 指向 APP 自身向量表(`0x80000000|0x01008000`,main 开头设置,USART1 RX 中断需要);**`ns_ble_stack_init()` 之后 VTOR 必须为 0**——此后所有中断经芯片 ROM 跳板 + RAM 中继(`ns_ble_stack_vtor_init` 把 APP 的 `__Vectors` 拷到 0x200000e8/0x200009c0 并把 BLE_FIFO/BLE_SLP/EXTI4_12 指向 ROM/RAM handler)。绝对不要在 app_ble_init() 后重设 VTOR,否则 BLE FIFO 中断落入 weak Default_Handler 死循环(实测崩溃根因,见开发日志第 18 节)。
|
||||
- **BLE 调度任务**(`app/ble/app_ble.c`,栈 512 字,优先级 2):循环 `rwip_schedule(); vTaskDelay(1ms);`。**ke_msg/ke_timer 只允许在该任务上下文运行**(SDK 约束),不要在其他任务或中断里直接调用。
|
||||
- BLE 中断向量不在 `n32wb03x_it.c` 定义:启动文件中 BLE_*IRQHandler 为 weak,真正 handler 由 `symbol_g15.obj`(ROM)+ SDK RAM 重映射(0x200000e8/0x200009c0)提供。BLE_SW/FIFO IRQ 优先级 0,其 ISR 内禁止调用 FreeRTOS FromISR API。
|
||||
- GATT 服务:自定义 CLS 服务(`app/ble/app_profile/app_cls.c`),复用 SDK rdtss profile 引擎;notify 发送为单包接口(忙返回 -1,上层重试)。**ns_sleep 低功耗不接**(与 FreeRTOS tick 冲突),NS_LOG/LPUART 不接。
|
||||
- 新增 GPIO 前必须核对开发日志第 4 节引脚分配表。
|
||||
- **寄存器级勘误修复必须先在 SDK 源码交叉验证地址用途**——曾按勘误表写 `0x40011004 |= 0x40`(AFEC 寄存器,与 BLE 协议栈共享)导致 BLE 射频挂死,已撤回(开发日志 §28 教训)。
|
||||
|
||||
## 代码风格
|
||||
|
||||
- 语言为 C(ARMCC,C 库 MicroLIB),文件头与函数头使用 Doxygen 风格注释(`@file` / `@brief`),注释用英文。
|
||||
- 命名:BSP 层函数 `bsp_<module>_<action>`;应用层聚合函数 `AppTasks_*` / `AppCli_*`;引脚/时钟等硬件参数集中在头文件顶部宏定义。
|
||||
- 使用 SDK 标准外设库 API(如 `RCC_EnableAPB2PeriphClk`、`GPIO_InitPeripheral`、`USART_Init`),不要直接操作寄存器。
|
||||
- 新增 GPIO 前必须核对开发日志第 4 节引脚分配表,避开 PA4/PA5。
|
||||
- 固件为 C(ARMCC,MicroLIB):文件头/函数头用 Doxygen 注释(`@file`/`@brief`),**注释用英文**;BSP 层函数 `bsp_<module>_<action>`;引脚/时钟等硬件参数集中在头文件顶部宏定义;使用 SDK 标准外设库 API,不要直接操作寄存器(确有例外需交叉验证,见上)。
|
||||
- App 为 TypeScript/Vue3:注释用中文;BLE 通信统一走 `src/BluetoothManager.ts` 的 `MyApiResult` 回调约定,设备业务封装在 `src/mcm/`;不改 uni_modules 官方组件。
|
||||
|
||||
## 测试策略
|
||||
|
||||
无自动化测试框架;验证方式为:
|
||||
|
||||
1. Keil 命令行构建必须保持 0 Error / 0 Warning;
|
||||
2. 烧录后通过串口输出与 LED 行为人工确认。
|
||||
1. Keil 命令行构建必须保持 0 Error / 0 Warning;出包必须 `UV4 -r` 全量重建,并核对 map 的 `__initial_sp` 与 bin 向量表初始 SP 一致;
|
||||
2. 烧录后通过串口输出(banner/`caiic->`/`devinfo`)、LED 行为人工确认;
|
||||
3. BLE 链路用 `tools/ble_cli_test.py`(PC bleak)或手机 App 实测,配合固件 `blelog on` 串口抓帧对照 `docs/ble_protocol.md` §8.3 示例帧;
|
||||
4. App 侧改动记录写入 `SmartAssiter/docs/修改记录_日期_主题.md`(沿用现有命名格式)。
|
||||
|
||||
## 其他注意事项
|
||||
|
||||
- `nations-tec/` 下的 SDK、器件包与 PDF 为第三方只读资料,改动应只发生在 `mcm-ddc-04/`(或新增工程目录)内。
|
||||
- BLE 协议栈(`middlewares/Nationstech/ble_library`)已接入(开发日志第 15 节);CLI-over-BLE 协议与 BLE OTA 为后续任务。
|
||||
- `nations-tec/` 下的 SDK、器件包与 PDF 为第三方只读资料,改动应只发生在 `mcm-ddc-ble/`、`Boot/`、`SmartAssiter/`、`tools/`、`docs/` 内。
|
||||
- 固件重大改动应同步追加 `docs/开发日志.md` 新章节(现有格式:`## N. 标题(日期)`),协议改动同步 `docs/ble_protocol.md`。
|
||||
- 每改固件必递增版本号(`mcm-ddc-ble/inc/app_version.h`),否则无法识别板上实际固件。
|
||||
|
||||
@ -127,6 +127,25 @@ flash 擦除单位 = 4KB 扇区。设备侧**直写 flash,不做扇区级 RAM
|
||||
注意:flash 擦写期间设备关中断数十 ms/扇区(Qflash 算法在 RAM 执行),BLE 链路靠
|
||||
5s supervision timeout 维持,属正常现象;但请避免在 OTA 期间主动断开。
|
||||
|
||||
## 6.5 维护命令:bootsetting 与 APP_DATA 参数区(V1.00.09 起,结构化访问)
|
||||
|
||||
bootsetting 与 APP_DATA 保留区(0x01006000/8KB)的读写以 CLI 命令形式提供,
|
||||
**只暴露结构化字段访问,无裸读写命令**。UART CLI 与 BLE CLI 读写特征
|
||||
`...c72e0003`(写原始命令行 → 读回文本应答,≤512B)命令集完全相同:
|
||||
|
||||
| 命令 | 说明 |
|
||||
|---|---|
|
||||
| `param` | 打印 APP_DATA 参数记录(led1_blink_ms / pwm_duty_pct)与 valid/default 状态 |
|
||||
| `param set <name> <val>` | 修改参数并落盘(led1_blink_ms 50~10000 即时生效于 LED1 闪烁;pwm_duty_pct 0~100 仅存储备用) |
|
||||
| `param save` | 当前 RAM 参数强制写盘 |
|
||||
| `bsdump` | 打印 bootsetting 记录全字段 + magic/CRC 校验结果 |
|
||||
| `bsset <field> <val>` | 写 bootsetting 单字段(`active 1\|2`、`b1addr/b2addr/b1size/b2size/b1crc/b2crc/b1ver/b2ver`),自动重算 CRC、擦除+编程+校验。**写错 active/addr 会导致 Boot 跳错,恢复靠 SWD 重烧整片包** |
|
||||
|
||||
参数记录(APP_DATA 区头,52B):magic `0xCA12DA7A` + layout_ver + 参数字段 +
|
||||
reserved[8] + CRC32;记录无效时固件以缺省值运行,`param set`/`param save` 时落盘。
|
||||
注意:flash 擦写关中断数十 ms/扇区,BLE 应答可能延迟;MTU 协商失败(20B/包)时
|
||||
长应答会被截断到 19B,建议先协商 MTU 247。
|
||||
|
||||
## 7. 首次烧录与恢复
|
||||
|
||||
- 出厂/首次:SWD 烧录整包(bootloader + bootsetting 缺省配置 + APP1),
|
||||
|
||||
25
docs/开发日志.md
25
docs/开发日志.md
@ -748,3 +748,28 @@ mcm-ddc-04 目录已由用户删除,mcm-ddc-ble 成为唯一应用工程。本
|
||||
(_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)。
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1078,6 +1078,16 @@
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\src\app_gpio.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>app_params.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\src\app_params.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>app_bootset.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\src\app_bootset.c</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
<Group>
|
||||
@ -1918,6 +1928,16 @@
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\src\app_gpio.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>app_params.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\src\app_params.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>app_bootset.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\src\app_bootset.c</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
<Group>
|
||||
@ -2758,6 +2778,16 @@
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\src\app_gpio.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>app_params.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\src\app_params.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>app_bootset.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\src\app_bootset.c</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
<Group>
|
||||
|
||||
25
mcm-ddc-ble/inc/app_bootset.h
Normal file
25
mcm-ddc-ble/inc/app_bootset.h
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @file app_bootset.h
|
||||
* @brief Structured read/write of the bootsetting record (0x01004000).
|
||||
* Raw writes are not exposed: every modification goes through a
|
||||
* field setter that recomputes the record CRC32, erases the sector,
|
||||
* programs and verifies. CLI handlers are registered in cli_core.c.
|
||||
*/
|
||||
#ifndef __APP_BOOTSET_H__
|
||||
#define __APP_BOOTSET_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** "bsdump": dump the bootsetting record fields + magic/CRC check result. */
|
||||
void AppBootset_CmdBsdump(int argc, char* argv[]);
|
||||
|
||||
/** "bsset <field> <val>": modify one bootsetting field (see app_bootset.c). */
|
||||
void AppBootset_CmdBsset(int argc, char* argv[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __APP_BOOTSET_H__ */
|
||||
57
mcm-ddc-ble/inc/app_params.h
Normal file
57
mcm-ddc-ble/inc/app_params.h
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file app_params.h
|
||||
* @brief Application parameter record stored in the APP_DATA flash region
|
||||
* (0x01006000, 8KB reserved). Structured access only: parameters are
|
||||
* read/modified by name through the "param" CLI command (UART and the
|
||||
* BLE CLI read/write characteristic); no raw region access is exposed.
|
||||
*/
|
||||
#ifndef __APP_PARAMS_H__
|
||||
#define __APP_PARAMS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Parameter record layout (stored at CAIIC_APP_DATA_ADDR) */
|
||||
#define CAIIC_PARAMS_MAGIC 0xCA12DA7Au
|
||||
#define CAIIC_PARAMS_LAYOUT_VER 1u
|
||||
|
||||
#define PARAM_LED1_BLINK_MS_MIN 50u
|
||||
#define PARAM_LED1_BLINK_MS_MAX 10000u
|
||||
#define PARAM_LED1_BLINK_MS_DEF 500u
|
||||
#define PARAM_PWM_DUTY_PCT_MAX 100u
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magic; /* CAIIC_PARAMS_MAGIC */
|
||||
uint32_t layout_ver; /* parameter layout version */
|
||||
uint16_t led1_blink_ms; /* LED1 blink half period in ms */
|
||||
uint16_t flags; /* reserved */
|
||||
uint32_t pwm_duty_pct; /* PWM duty 0..100, stored only (no PWM output yet) */
|
||||
uint32_t reserved[8]; /* future parameters */
|
||||
uint32_t crc32; /* IEEE CRC32 over all fields above this one */
|
||||
} caiic_params_t;
|
||||
|
||||
/**
|
||||
* @brief Load the parameter record from flash; fall back to defaults in RAM
|
||||
* when the record is missing/invalid (flash is left untouched until
|
||||
* the first "param set"/"param save").
|
||||
*/
|
||||
void app_params_init(void);
|
||||
|
||||
/** Current RAM copy of the parameters (always valid after init). */
|
||||
const caiic_params_t* app_params_get(void);
|
||||
|
||||
/** 1 when the on-flash record passed magic+CRC validation at init. */
|
||||
uint8_t app_params_is_valid(void);
|
||||
|
||||
/** "param [set <name> <val> | save]" CLI handler (registered in cli_core.c). */
|
||||
void AppParams_CmdParam(int argc, char* argv[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __APP_PARAMS_H__ */
|
||||
@ -5,8 +5,8 @@
|
||||
#ifndef __APP_VERSION_H__
|
||||
#define __APP_VERSION_H__
|
||||
|
||||
#define APP_FW_VERSION "V1.00.08"
|
||||
#define APP_FW_VERSION "V1.00.09"
|
||||
/* Numeric form used by the BLE info query / OTA records: 0x00MMmmpp */
|
||||
#define APP_FW_VERSION_NUM 0x00010008u
|
||||
#define APP_FW_VERSION_NUM 0x00010009u
|
||||
|
||||
#endif /* __APP_VERSION_H__ */
|
||||
|
||||
208
mcm-ddc-ble/src/app_bootset.c
Normal file
208
mcm-ddc-ble/src/app_bootset.c
Normal file
@ -0,0 +1,208 @@
|
||||
/**
|
||||
* @file app_bootset.c
|
||||
* @brief Structured read/write of the bootsetting record (0x01004000).
|
||||
*
|
||||
* bsdump prints every field of caiic_bootsetting_t plus the magic/CRC32
|
||||
* validation result. bsset modifies a single named field, then rewrites the
|
||||
* whole record: read current record (rebuilt zeroed when invalid) -> set
|
||||
* field -> recompute CRC32 -> erase sector -> program -> read-back verify.
|
||||
* Same write pattern as app_ota.c::ota_update_bootsetting().
|
||||
*
|
||||
* WARNING: a bad active_bank/start_address makes the bootloader jump to an
|
||||
* invalid image (falls back to APP1 or hangs; recovery is SWD reflash of
|
||||
* the full package). This is a maintenance tool command.
|
||||
*/
|
||||
#include "app_bootset.h"
|
||||
#include "cli_core.h"
|
||||
#include "dfu_layout.h"
|
||||
#include "boot_crc32.h"
|
||||
#include "n32wb03x.h"
|
||||
#include "n32wb03x_qflash.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static uint8_t s_qflash_ready;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Helpers */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void bootset_ensure_qflash(void)
|
||||
{
|
||||
if (!s_qflash_ready)
|
||||
{
|
||||
Qflash_Init(); /* copy the flash algorithm to RAM (once) */
|
||||
s_qflash_ready = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t bootset_crc(const caiic_bootsetting_t* bs)
|
||||
{
|
||||
return caiic_crc32((const uint8_t*)bs,
|
||||
(uint32_t)offsetof(caiic_bootsetting_t, crc32));
|
||||
}
|
||||
|
||||
static uint8_t bootset_valid(const caiic_bootsetting_t* bs)
|
||||
{
|
||||
return (bs->magic == CAIIC_BOOT_MAGIC && bs->crc32 == bootset_crc(bs)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void bootset_print(const caiic_bootsetting_t* bs)
|
||||
{
|
||||
cli_printf("bootsetting @ 0x%08lX: %s\r\n",
|
||||
(unsigned long)CAIIC_BOOTSETTING_ADDR,
|
||||
bootset_valid(bs) ? "valid" : "INVALID (bad magic/crc)");
|
||||
cli_printf(" magic = 0x%08lX\r\n", (unsigned long)bs->magic);
|
||||
cli_printf(" active_bank = %lu\r\n", (unsigned long)bs->active_bank);
|
||||
cli_printf(" bank1: addr=0x%08lX size=%lu crc=0x%08lX\r\n",
|
||||
(unsigned long)bs->bank1.start_address,
|
||||
(unsigned long)bs->bank1.size,
|
||||
(unsigned long)bs->bank1.crc32);
|
||||
cli_printf(" ver=0x%08lX\r\n", (unsigned long)bs->bank1.version);
|
||||
cli_printf(" bank2: addr=0x%08lX size=%lu crc=0x%08lX\r\n",
|
||||
(unsigned long)bs->bank2.start_address,
|
||||
(unsigned long)bs->bank2.size,
|
||||
(unsigned long)bs->bank2.crc32);
|
||||
cli_printf(" ver=0x%08lX\r\n", (unsigned long)bs->bank2.version);
|
||||
cli_printf(" crc32 = 0x%08lX\r\n", (unsigned long)bs->crc32);
|
||||
}
|
||||
|
||||
static uint8_t parse_u32(const char* s, uint32_t* out)
|
||||
{
|
||||
char* end = NULL;
|
||||
uint32_t v = strtoul(s, &end, 0);
|
||||
if (end == s || *end != '\0')
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
*out = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* CLI handlers */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
void AppBootset_CmdBsdump(int argc, char* argv[])
|
||||
{
|
||||
caiic_bootsetting_t bs;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
memcpy(&bs, (const void*)CAIIC_BOOTSETTING_ADDR, sizeof(bs));
|
||||
bootset_print(&bs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Program the modified record and verify by read-back.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
static uint8_t bootset_commit(caiic_bootsetting_t* bs)
|
||||
{
|
||||
bootset_ensure_qflash();
|
||||
bs->magic = CAIIC_BOOT_MAGIC;
|
||||
bs->crc32 = bootset_crc(bs);
|
||||
|
||||
if (Qflash_Erase_Sector(CAIIC_BOOTSETTING_ADDR) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
/* sizeof(caiic_bootsetting_t) = 44, already 4-byte aligned */
|
||||
if (Qflash_Write(CAIIC_BOOTSETTING_ADDR, (uint8_t*)bs, sizeof(*bs)) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(bs, (const void*)CAIIC_BOOTSETTING_ADDR, sizeof(*bs)) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AppBootset_CmdBsset(int argc, char* argv[])
|
||||
{
|
||||
caiic_bootsetting_t bs;
|
||||
caiic_bank_t* bank;
|
||||
uint32_t v;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
cli_write("usage: bsset <field> <val>\r\n");
|
||||
cli_write(" field: active <1|2>\r\n");
|
||||
cli_write(" b1addr|b2addr|b1size|b2size|b1crc|b2crc|b1ver|b2ver <hex|dec>\r\n");
|
||||
return;
|
||||
}
|
||||
if (parse_u32(argv[2], &v) != 0)
|
||||
{
|
||||
cli_write("bsset: bad value\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&bs, (const void*)CAIIC_BOOTSETTING_ADDR, sizeof(bs));
|
||||
if (!bootset_valid(&bs))
|
||||
{
|
||||
memset(&bs, 0, sizeof(bs));
|
||||
cli_write("bsset: existing record invalid, rebuild from scratch\r\n");
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "active") == 0)
|
||||
{
|
||||
if (v != CAIIC_ACTIVE_BANK1 && v != CAIIC_ACTIVE_BANK2)
|
||||
{
|
||||
cli_write("bsset: active must be 1 or 2\r\n");
|
||||
return;
|
||||
}
|
||||
bs.active_bank = v;
|
||||
}
|
||||
else if (argv[1][0] == 'b' && (argv[1][1] == '1' || argv[1][1] == '2'))
|
||||
{
|
||||
bank = (argv[1][1] == '1') ? &bs.bank1 : &bs.bank2;
|
||||
if (strcmp(argv[1] + 2, "addr") == 0)
|
||||
{
|
||||
if (v != CAIIC_APP1_BASE && v != CAIIC_APP2_BASE)
|
||||
{
|
||||
cli_write("bsset: addr must be 0x01008000 or 0x01040000\r\n");
|
||||
return;
|
||||
}
|
||||
bank->start_address = v;
|
||||
}
|
||||
else if (strcmp(argv[1] + 2, "size") == 0)
|
||||
{
|
||||
if (v > CAIIC_APP_BANK_SIZE)
|
||||
{
|
||||
cli_write("bsset: size exceeds 224KB bank\r\n");
|
||||
return;
|
||||
}
|
||||
bank->size = v;
|
||||
}
|
||||
else if (strcmp(argv[1] + 2, "crc") == 0)
|
||||
{
|
||||
bank->crc32 = v;
|
||||
}
|
||||
else if (strcmp(argv[1] + 2, "ver") == 0)
|
||||
{
|
||||
bank->version = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
cli_write("bsset: unknown field\r\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cli_write("bsset: unknown field\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cli_printf("bsset: %s = 0x%08lX, writing...\r\n", argv[1], (unsigned long)v);
|
||||
if (bootset_commit(&bs) != 0)
|
||||
{
|
||||
cli_write("bsset: flash fail\r\n");
|
||||
return;
|
||||
}
|
||||
cli_write("bsset: ok (verified)\r\n");
|
||||
bootset_print(&bs);
|
||||
}
|
||||
210
mcm-ddc-ble/src/app_params.c
Normal file
210
mcm-ddc-ble/src/app_params.c
Normal file
@ -0,0 +1,210 @@
|
||||
/**
|
||||
* @file app_params.c
|
||||
* @brief Application parameter record in the APP_DATA flash region.
|
||||
*
|
||||
* caiic_params_t lives at CAIIC_APP_DATA_ADDR with magic + CRC32 (same
|
||||
* pattern as the bootsetting record). "param set" modifies the RAM copy,
|
||||
* then erases the first APP_DATA sector and programs the record back with
|
||||
* read-back verification. No raw flash access is exposed: the only way to
|
||||
* touch the region is by named parameter.
|
||||
*
|
||||
* Qflash erase/write disables interrupts for tens of ms per sector (SDK
|
||||
* driver runs the flash algorithm from RAM); the BLE link survives via the
|
||||
* connection supervision timeout - same behaviour as the OTA path.
|
||||
*/
|
||||
#include "app_params.h"
|
||||
#include "cli_core.h"
|
||||
#include "dfu_layout.h"
|
||||
#include "boot_crc32.h"
|
||||
#include "n32wb03x.h"
|
||||
#include "n32wb03x_qflash.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static caiic_params_t s_params;
|
||||
static uint8_t s_valid; /* flash record valid at init */
|
||||
static uint8_t s_qflash_ready;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Helpers */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void params_ensure_qflash(void)
|
||||
{
|
||||
if (!s_qflash_ready)
|
||||
{
|
||||
Qflash_Init(); /* copy the flash algorithm to RAM (once) */
|
||||
s_qflash_ready = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void params_load_defaults(void)
|
||||
{
|
||||
memset(&s_params, 0, sizeof(s_params));
|
||||
s_params.magic = CAIIC_PARAMS_MAGIC;
|
||||
s_params.layout_ver = CAIIC_PARAMS_LAYOUT_VER;
|
||||
s_params.led1_blink_ms = PARAM_LED1_BLINK_MS_DEF;
|
||||
s_params.pwm_duty_pct = 0;
|
||||
}
|
||||
|
||||
static uint32_t params_crc(const caiic_params_t* p)
|
||||
{
|
||||
return caiic_crc32((const uint8_t*)p, (uint32_t)offsetof(caiic_params_t, crc32));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Program the RAM parameter copy to flash and verify by read-back.
|
||||
* @return 0 on success, 1 on flash failure.
|
||||
*/
|
||||
static uint8_t params_save(void)
|
||||
{
|
||||
params_ensure_qflash();
|
||||
s_params.crc32 = params_crc(&s_params);
|
||||
|
||||
if (Qflash_Erase_Sector(CAIIC_APP_DATA_ADDR) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
/* sizeof(caiic_params_t) = 52, already 4-byte aligned */
|
||||
if (Qflash_Write(CAIIC_APP_DATA_ADDR, (uint8_t*)&s_params, sizeof(s_params)) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(&s_params, (const void*)CAIIC_APP_DATA_ADDR, sizeof(s_params)) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
s_valid = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse a u32 argument, decimal or 0x-prefixed hex.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
static uint8_t parse_u32(const char* s, uint32_t* out)
|
||||
{
|
||||
char* end = NULL;
|
||||
uint32_t v = strtoul(s, &end, 0);
|
||||
if (end == s || *end != '\0')
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
*out = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Public interface */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
void app_params_init(void)
|
||||
{
|
||||
memcpy(&s_params, (const void*)CAIIC_APP_DATA_ADDR, sizeof(s_params));
|
||||
if (s_params.magic == CAIIC_PARAMS_MAGIC &&
|
||||
s_params.layout_ver == CAIIC_PARAMS_LAYOUT_VER &&
|
||||
s_params.crc32 == params_crc(&s_params))
|
||||
{
|
||||
s_valid = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
params_load_defaults();
|
||||
s_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const caiic_params_t* app_params_get(void)
|
||||
{
|
||||
return &s_params;
|
||||
}
|
||||
|
||||
uint8_t app_params_is_valid(void)
|
||||
{
|
||||
return s_valid;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* CLI: param */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void param_print_all(void)
|
||||
{
|
||||
cli_printf("params: %s\r\n", s_valid ? "valid" : "default (not saved)");
|
||||
cli_printf(" led1_blink_ms = %u\r\n", (unsigned int)s_params.led1_blink_ms);
|
||||
cli_printf(" pwm_duty_pct = %lu\r\n", (unsigned long)s_params.pwm_duty_pct);
|
||||
cli_printf(" flags = 0x%04X\r\n", (unsigned int)s_params.flags);
|
||||
}
|
||||
|
||||
void AppParams_CmdParam(int argc, char* argv[])
|
||||
{
|
||||
uint32_t v;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
param_print_all();
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "save") == 0)
|
||||
{
|
||||
if (params_save() == 0)
|
||||
{
|
||||
cli_write("param saved\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
cli_write("param save: flash fail\r\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "set") != 0 || argc < 4)
|
||||
{
|
||||
cli_write("usage: param [set <led1_blink_ms|pwm_duty_pct> <val> | save]\r\n");
|
||||
return;
|
||||
}
|
||||
if (parse_u32(argv[3], &v) != 0)
|
||||
{
|
||||
cli_write("param set: bad value\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(argv[2], "led1_blink_ms") == 0)
|
||||
{
|
||||
if (v < PARAM_LED1_BLINK_MS_MIN || v > PARAM_LED1_BLINK_MS_MAX)
|
||||
{
|
||||
cli_printf("led1_blink_ms range %u..%u\r\n",
|
||||
(unsigned int)PARAM_LED1_BLINK_MS_MIN,
|
||||
(unsigned int)PARAM_LED1_BLINK_MS_MAX);
|
||||
return;
|
||||
}
|
||||
s_params.led1_blink_ms = (uint16_t)v;
|
||||
}
|
||||
else if (strcmp(argv[2], "pwm_duty_pct") == 0)
|
||||
{
|
||||
if (v > PARAM_PWM_DUTY_PCT_MAX)
|
||||
{
|
||||
cli_printf("pwm_duty_pct range 0..%u\r\n",
|
||||
(unsigned int)PARAM_PWM_DUTY_PCT_MAX);
|
||||
return;
|
||||
}
|
||||
s_params.pwm_duty_pct = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
cli_write("unknown param (led1_blink_ms, pwm_duty_pct)\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (params_save() == 0)
|
||||
{
|
||||
cli_printf("%s set ok\r\n", argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
cli_write("param set: flash fail\r\n");
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,8 @@
|
||||
#include "app_gpio.h"
|
||||
#include "app_info.h"
|
||||
#include "app_ble_proto.h"
|
||||
#include "app_params.h"
|
||||
#include "app_bootset.h"
|
||||
#include "n32wb03x.h" /* SystemTrimValueGet (temp debug) */
|
||||
|
||||
#include <stdio.h>
|
||||
@ -245,6 +247,9 @@ static const CliCmd_t s_cmds[] = {
|
||||
{"devinfo", "show device info (temp/vdd/fan, same as BLE INFO_QUERY all)", CmdDevInfo},
|
||||
{"blelog", "blelog [on|off]: BLE traffic log (events + frame hex dump)", CmdBleLog},
|
||||
{"led", "led <1|2> <on|off|toggle>: control board LED", CmdLed},
|
||||
{"param", "param [set <led1_blink_ms|pwm_duty_pct> <val>|save]: app params", AppParams_CmdParam},
|
||||
{"bsdump", "bsdump: show bootsetting record + crc check", AppBootset_CmdBsdump},
|
||||
{"bsset", "bsset <field> <val>: write bootsetting field (careful!)", AppBootset_CmdBsset},
|
||||
};
|
||||
|
||||
#define CLI_CMD_COUNT (sizeof(s_cmds) / sizeof(s_cmds[0]))
|
||||
|
||||
@ -80,6 +80,7 @@
|
||||
#include "ble_up.h"
|
||||
#include "app_cli.h"
|
||||
#include "app_ble_proto.h"
|
||||
#include "app_params.h"
|
||||
#include "app_version.h"
|
||||
#include "app_user_config.h"
|
||||
|
||||
@ -121,16 +122,23 @@ static void ble_schedule_task(void *pvParameters)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LED blink task: toggle LED1 (PB0) every 500 ms as a run indicator.
|
||||
* LED2 (PA6) stays owned by app_ble.c as the connection state LED.
|
||||
* @brief LED blink task: toggle LED1 (PB0) as a run indicator; the half
|
||||
* period comes from the APP_DATA parameter record (led1_blink_ms,
|
||||
* "param set led1_blink_ms <50..10000>"). LED2 (PA6) stays owned by
|
||||
* app_ble.c as the connection state LED.
|
||||
*/
|
||||
static void led_task(void *pvParameters)
|
||||
{
|
||||
(void)pvParameters;
|
||||
for (;;)
|
||||
{
|
||||
uint16_t period = app_params_get()->led1_blink_ms;
|
||||
if (period < PARAM_LED1_BLINK_MS_MIN)
|
||||
{
|
||||
period = PARAM_LED1_BLINK_MS_DEF;
|
||||
}
|
||||
LedBlink(LED1_PORT, LED1_PIN);
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
vTaskDelay(pdMS_TO_TICKS(period));
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,6 +183,9 @@ int main(void)
|
||||
LedInit(LED1_PORT,LED1_PIN); // power led
|
||||
LedInit(LED2_PORT,LED2_PIN); //connection state
|
||||
|
||||
/* Load APP_DATA parameter record (defaults in RAM when invalid) */
|
||||
app_params_init();
|
||||
|
||||
/* Keep SWD debug accessible: never enter sleep (also required because
|
||||
* deep sleep conflicts with the FreeRTOS tick). */
|
||||
ns_sleep_lock_acquire();
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
{
|
||||
"file": "caiic_ble_full_ota.bin",
|
||||
"size": 41168,
|
||||
"crc32": "0x26056D5B",
|
||||
"version": 65544
|
||||
"size": 44088,
|
||||
"crc32": "0xE246E2B2",
|
||||
"version": 65545
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user