当前页面为 开发中 版本,查看特定版本的文档,请在页面左下角的下拉菜单中进行选择。

Solution: Multimode Mouse

重要

此例程仅存在于特殊版本的SDK中,如有需要请联系Panchip。

1 功能概述

此sample为pan107(32pin芯片)在实体鼠标上演示三模鼠标基础功能的EVB demo,为低功耗办公键鼠提供参考方案。

1.1 核心特性

通用功能:

  • 三模切换:支持USB/2.4G PRF/BLE三种工作模式

    • 三模切换不复位(user_is_sleep_allow接口模式返回false较稳定,BLE模式连接功耗高0.2mA)

    • 三模切换复位(默认 CONFIG_CHANGE_MODE_RESET=1):拨动开关/ADC 检测到模式变化时 sys_reboot() 整片复位,上电后由硬件重新检测模式;不写入 Flash KV

  • 光电传感:通过sensor获取鼠标坐标,支持DPI按键切换传感器DPI

  • QDEC滚轮:支持去抖的正交解码器,反馈鼠标滚轮变化

  • 按键模块:基础按键(左/中/右/侧边),底部按键用于模式切换和功能测试

  • LED指示:顶部RGB灯及底部指示灯,显示不同模式和连接状态

  • 电量检测:ADC采集电量信息及模式检测

  • 供电管理:电池供电/USB供电/USB插入PC自动切换

USB模式:

  • 最大上报率1000Hz

  • 配合Panchip DFU Tool可进行USB DFU升级

  • USB插入时优先级最高,自动切换到USB模式

2.4G模式(PRF增强型):

  • 需配合PRF Dongle使用(支持PAN101/PAN107/PAN2628等多种Dongle)

  • 跳频机制:连接阶段 ACK 连续丢失达阈值后在 8 个私有频点间跳频(配对第一阶段当前代码不跳频,固定公共频点重传)

  • 对码协议:单向配对策略,公共地址对码后切换到私有地址通信

  • 重传机制:丢包时快速重传直到收到对端回复

  • 动态发射功率(可选):连接后根据ACK质量实时升降TX功率,近距离省电、远距离保链路

  • ACK解析:可解析的ACK,支持自定义回传消息

  • 性能指标:

    • USB/2.4G 默认上报率 1000Hz(CONFIG_DEFAULT_REPORT_RATE=3,可切换 125/250/500/1000 Hz,索引写入 KV prf-usb/rate_index)

    • BLE 模式 slptmr 固定 125Hz(main.capp_rate=125)

    • T->R 转换时间约 25us(最快时序);配对过程全速运行

    • 空闲时由 Idle 调度进入 deepsleep 休眠

  • Dongle支持:多pipe模式,多主设备可共用一个Dongle

BLE模式:

  • 默认133Hz(7.5ms interval)

  • 支持3台设备配对和分时连接

  • 空闲时由Idle调度进入deepsleep休眠

  • 连接建立约 2s 后请求 conn_latency=35(app_ble_conn_upd_timer);无活动约 428 个连接事件后启用 slave latency

  • 持续空闲 300s(CONFIG_BLE_IDLE_TIMEOUT_S)触发 standby M1;配对/断连超时同为 300s(CONFIG_BLE_PAIR_TIMEOUT_S / CONFIG_BLE_DISCONNECT_TIMEOUT_S)

  • 唤醒后系统会reset(目前已知问题)

2 环境要求

  • 开发板: pan107(32pin芯片,MPC+版本,USB功能较稳定)开发板 × 2

  • 串口配置: Git 默认 CONFIG_UART_LOG_ENABLE=0(关闭);调试时可置 1,配合 CONFIG_LOG_UART_PIN=2(P16)、CONFIG_LOG_UART_BAUDRATE=115200

    • 若改 CONFIG_LOG_UART_PIN=0(P05),部分板级 RGB 红灯同引脚会冲突,需按板级头文件 board/*.h 确认

  • 蓝牙主机: PC或手机等支持BLE的设备

  • PRF Dongle: prf_dongle solution用于演示配对和跳频控制(支持PAN101/PAN107/PAN2628等)

  • 测试工具:

    • PPK功耗测试工具

    • Panchip DFU Tool(USB升级)

    • KEYTEST.exe(键盘测试工具,可选)

3 编译和烧录

3.1 例程位置

  • BOOT程序: <nimble>/samples/solutions_hid/bootloader

  • APP程序: <nimble>/samples/solutions_hid/mult_ms/keil_107x

3.2 编译步骤

  1. 使用Keil打开项目工程

  2. 根据目标芯片选择对应的board配置

  3. 编译BOOT和APP两个固件

  4. 先烧录BOOT固件,再烧录APP固件

3.3 注意事项

  • 需要烧录两个固件(BOOT + APP)

  • 蓝牙和2.4G模式默认空闲进入deepsleep,此时JLink烧录容易失败

  • 可以运行Keil工具JLink erase或切换到其他模式下进行烧录

4 功能说明

本程序为实体鼠标固件(非EVB演示程序),支持完整的按键组合功能和三模切换。

4.1 按键定义

基础按键:

  • 左键(Left): MS_LEFT_KEY

  • 中键(Middle/Wheel): MS_MIDDLE_KEY

  • 右键(Right): MS_RIGHT_KEY

  • 前进键(Forward): MS_FORWARD_KEY (侧边)

  • 后退键(Back): MS_BACK_KEY (侧边)

  • DPI键: MS_DPI_KEY (底部功能键)

模式切换:

  • 通过底部拨动开关或ADC检测进行USB/2.4G/BLE三模切换

  • USB插入时自动优先切换到USB模式

4.2 组合键功能

组合键由周期事件 combine_key_period_event 调度,周期 20ms(KEY_HANDLE_TIME_MS,定义于 board/*.h)。逻辑在 app_common.capp_combine_key_handle() 中实现,各功能可通过板级头文件中的 MS_*_EN / MS_*_KEY / MS_*_DELAY_MS 宏独立开关。

触发时间说明:

  • DPI: 单独按下 DPI 键,持续 ≥20ms 即触发(防抖短按,非长按2秒)

  • 其余组合键: 需同时按住对应按键达到宏定义延迟(默认 2000ms)

  • 下表时间为秒,代码中对应 MS_*_DELAY_MS(DPI 为 20ms,其余默认 2000ms):

    按键

    检测时间

    2.4G模式

    USB模式

    蓝牙模式

    DPI

    短按(≥20ms)

    切换传感器DPI

    切换传感器DPI

    切换传感器DPI

    L+M+R

    2s

    重新配对

    重新配对

    M+R

    2s

    自动画圈

    自动画圈

    自动画圈

    M

    2s

    切换上报率

    切换上报率

    L+M

    2s

    切换蓝牙多设备

    DPI+L

    2s

    恢复出厂设置

    恢复出厂设置

    恢复出厂设置

组合键处理流程:

combine_key_period_event (20ms)
        |
        v
app_combine_key_handle()
        |
        +-- 按键不匹配 --> 清零 long_press_cnt
        |
        +-- 按键匹配 --> 累加 long_press_cnt
                |
                +-- 未达 DELAY_MS --> 继续等待
                |
                +-- 已达 DELAY_MS --> 按功能分支:
                        |
                        +-- DPI --> sensor_cyclic_increment_dpi() + LED 闪烁
                        +-- 上报率 --> 投递 rate_change_event
                        +-- 画圈 --> 切换 test_mode_auto_circle
                        +-- 重新配对/多设备/出厂 --> app_combine_key_flag_set()
                                |
                                +-- 约 200ms 后投递 wireless_repair_event /
                                |   ble_id_change_event,或 app_factory_reset()
                                |
                                +-- long_key_flag=1 期间屏蔽键鼠上报

重新配对与出厂重置细节:

  • 左+中+右(BLE): 达标后 app_ble_send_start(),约 200ms 后投递 wireless_repair_eventapp_ble_repair()(不重启,重新广播配对)

  • 左+中+右(2.4G): 投递 wireless_repair_eventapp_prf_repair()(重置配对状态并进入重新配对流程,不擦除 Flash 中 prf/dg_type_addr)

  • DPI+左: 约 200ms 后调用 app_factory_reset(),擦除 KV 分区并重新初始化应用

  • 重新配对/出厂重置执行期间 app_combine_key_flag_get()==1 时,app_device_data_get() 会屏蔽鼠标键值上报

DPI 档位与 LED 颜色(app_sensor.c 定义 CPI 表,app_common.csensor_dpi_index_get() 显示颜色):

索引

LED 颜色

PAW3220 CPI(默认板)

PAW3311 CPI

0

绿

~800

800

1

~1200

1600

2

~2400

2400

3

黄(默认)

~3200

3200

4

~4000

6500

5

~4953

12000

PAW3220 的 CPI 由寄存器值 × 39 换算(见 P3220_DPI[] 注释)。文档中常见的「400/6400/26000」等档位不在当前代码中。

LED指示说明:

状态

LED表现

触发条件

DPI切换

对应颜色闪烁约2s(200ms间隔)

按下DPI键

上报率切换

白色闪烁约2s(200ms间隔)

长按中键

2.4G未配对

白色慢闪(400ms间隔)

无配对信息

2.4G配对中

白色快闪(100ms间隔)

正在对码

2.4G已连接

LED熄灭

配对成功并连接

BLE未配对

蓝色慢闪(400ms间隔)

无配对信息

BLE配对中

蓝色快闪(100ms间隔)

正在广播

BLE已连接

LED熄灭

配对成功并连接

USB模式

绿色常亮

USB枚举完成

低电量

红色闪烁(400ms间隔)

电压低于阈值

4.3 操作流程说明

4.3.1 初始上电

  1. 首次上电:编译后全部擦除下载,根据硬件配置默认进入2.4G或BLE模式

  2. 模式切换:默认 CONFIG_CHANGE_MODE_RESET=1,拨码变化时整片复位,上电后硬件重新检测模式(不写 Flash)

  3. 自动画圈:如果使能CONFIG_POWER_ON_AUTO_CIRCLES,上电后自动进入画圈测试模式

4.3.2 2.4G配对流程

  1. 上电配对:烧录了PRF Dongle的接收器,鼠标自动开始配对

  2. 配对过程:

    • 在公共地址2412MHz单频点进行

    • 白色LED快闪表示配对中

    • 配对成功后切换到私有地址和频点

    • LED熄灭表示连接成功

  3. 重新配对:长按左+中+右键2秒进入重新配对流程

  4. 稳定性:每秒打印收发情况,挂测稳定

4.3.3 BLE模式操作

  1. 广播配对:切换到BLE模式后自动广播,PC/手机可搜索到设备

  2. 多设备支持:支持3台设备配对(CONFIG_BT_MAX_PAIRED=3)

  3. 设备切换:长按左+中键2秒循环切换设备0/1/2

  4. 重新配对:长按左+中+右键2秒进入重新配对(不重启)

  5. Latency:连接约2s后设 conn_latency=35;无活动约428个连接事件后启用 slave latency

  6. Standby:持续空闲 300s(CONFIG_BLE_IDLE_TIMEOUT_S)进入 standby M1 断开

已知问题:BLE唤醒后系统会reset,目前reset后广播异常发不出,需chip reset恢复

4.3.4 USB模式

  1. 自动切换:USB插入PC时自动切换到USB模式,优先级最高

  2. DFU升级:配合Panchip DFU Tool可进行boot内USB DFU升级

  3. 上报率:支持125/250/500/1000 Hz四档切换

  4. 拔出恢复:拔出USB后恢复到之前的无线模式

4.4 Bootloader说明

4.4.1 Boot功能概述

当使能CONFIG_ENABLE_BOOTLOADER=y时,工程合并了支持2.4G和USB双模升级的Bootloader:

Boot位置: <nimble>/samples/solutions_hid/bootloader

支持的升级方式:

  1. USB DFU升级 (Boot 工程 BOOT_ENABLE_USB_DFU=1):

    • Boot 内 USB HID 厂商命令传输固件

    • 支持 GPIO 按键或 Flash DFU 标志进入

    • 固件直接写入 App 分区

    • VID: 0x046D, PID: 0xC055, 设备名: “boot dfu”

  2. 2.4G PRF OTA升级 (Boot 工程 BOOT_ENABLE_PRF_OTA=1,可选):

    • Boot 内通过 2.4G 接收固件并直接写入 App 分区

    • 完成后重启运行新 App

    • 详细说明: 请参考 PanChip 2.4G OTA升级指南

4.4.2 Boot工作流程

int main(void)
{
    APP_LOG("Bootloader in..\n\n");
    
    // 1. 检查Backup分区是否有有效镜像
    ss_connect(0, sig_back_up_is_completed_image, on_image_load_enter);
    
    // 2. 检查是否进入UART DFU模式(可选)
    #if BOOT_ENABLE_UART_DFU
    ss_connect(1, sig_key1_push_down, on_uart_dfu_enter);
    #endif
    
    // 3. 检查是否进入USB DFU模式
    #if BOOT_ENABLE_USB_DFU
    #if BOOT_USB_DFU_MODE == 0x00
    ss_connect(2, sig_key2_push_down, on_usb_dfu_enter);
    #endif
    ss_connect(3, sig_usb_dfu_enter_check, on_usb_dfu_enter);
    #endif
    
    #if BOOT_ENABLE_PRF_OTA
    ss_connect(4, sig_ota_start_received, on_prf_ota_enter);
    #endif
    
    // 4. 执行信号槽处理
    sig_process();
    
    // 5. 如果没有进入DFU,跳转到App
    jump_to_app();
}

升级流程:

[正常启动]
Boot 上电 --> 检查 Backup 是否有完整镜像 --> 有则搬运到 App --> jump_to_app
                              |
                              +-- 无有效镜像 --> jump_to_app 直接运行 App

[USB DFU]
App 调用 dfu_flag_set() 或按键触发 --> 重启进入 Boot USB DFU
    --> 固件直接写入 App 分区 --> 重启 jump_to_app

[2.4G OTA (Boot )]
2.4G OTA 握手 --> Boot 接收固件 --> 直接写入 App 分区 --> 重启 jump_to_app

提示: 本方案 USB DFU 与 Boot 内 2.4G OTA 均直接升级 App,不走 Backup 暂存。2.4G 协议细节见官方 OTA 指南。

4.4.3 Boot配置说明

App 工程关键宏 (mult_ms/keil_107x/configuration/sdk_config.h):

// 使能Bootloader(合并Boot+App镜像,Git默认=1)
#define CONFIG_ENABLE_BOOTLOADER                    1
#define CONFIG_MERGE_IMAGES                         1
#define CONFIG_APP_USE_IMAGE_HEADER                   1

Boot 工程关键宏 (bootloader/keil_107x/configuration/sdk_config.h,Git默认):

#define BOOT_ENABLE_USB_DFU                         1
#define BOOT_USB_DFU_MODE                           0x00  // GPIO按键触发进DFU
#define BOOT_ENABLE_UART_DFU                        0
#define BOOT_ENABLE_PRF_OTA                         1     // Boot内2.4G OTA
#define CFG_RF_MANUFACTOR_TEST                      0

Flash分区布局(当 CONFIG_ENABLE_BOOTLOADER=1 且使用默认分区大小时):

分区

起始地址

大小

用途

Bootloader

0x00000

40 KB

Bootloader 程序

App

0x0A000

220 KB

主应用程序

App Backup

0x41000

220 KB

见下文「Backup 可复用说明」

KV Store

0x78000

16 KB

配对信息、上报率等键值存储

User Custom

0x7C000

12 KB

用户数据;末 4KB 保留 DFU 标志

总计

-

508 KB

CONFIG_FLASH_SIZE=0x7F000

起始地址由 sdk_config.hCONFIG_FLASH_PARTITION_* 宏自动计算,修改任一分区大小时需保证各分区之和不超过 Flash 总容量。

分区使用要点(Boot + App 配合)

重要

User Custom 末 4KB 为 DFU 升级标志保留区,禁止使用

  • 存放位置: User Custom 最后一个 4KB 扇区,默认 0x7E000 ~ 0x7F000
    (= CONFIG_FLASH_PARTITION_USER_CUSTOM_ADDR + CONFIG_FLASH_PARTITION_USER_CUSTOM_SIZE - 0x1000)

  • 标志值: 扇区首字节 0x5A (USB_DFU_ENTER_FLAG) 时,下次上电 Boot 进入 USB DFU

  • App: dfu_flag_set() / dfu_flag_check_clear()(app_usb_protocol.c);设置时会擦除整个末扇区

  • Boot: is_dfu_flag_valid()(bootloader/src/usb_dfu.c)

  • 用户可用: 默认 User Custom 前 8KB(0x7C000 ~ 0x7DFFF);末 4KB 禁止读写

  • 配置: CONFIG_FLASH_PARTITION_USER_CUSTOM_SIZE_KB(默认 12)与 Boot/App 末扇区逻辑绑定,不建议修改

Backup 分区可复用说明

本方案 USB DFUBoot 内 2.4G OTA直接写入 App 分区,升级不依赖 Backup 暂存。因此 220KB App Backup(0x41000)可供用户存储数据

注意:

  1. Boot 上电仍检查 Backup 是否有完整有效 App 镜像;若有会 fm_image_move() 覆盖 App

  2. 复用 Backup 时勿写入有效 App 镜像头,避免误触发搬运

  3. 保持 CONFIG_FLASH_PARTITION_APP_BACKUP_* 默认即可;由应用层管理该地址范围内读写

区域

默认大小

建议用途

约束

User Custom 前段

8 KB

小容量用户参数

避开末 4KB

User Custom 末段

4 KB

DFU 标志(系统保留)

禁止用户访问

App Backup

220 KB

大容量用户数据

勿写有效 App 镜像头

4.4.4 使用Panchip DFU Tool升级

升级步骤:

  1. 准备工具:

    • 安装量产烧录工具\Panchip DFU Tool

    • 选择”Pan10xx NDK芯片平台”

  2. 进入DFU模式:

    • 方式1: App 内设置 DFU 标志后重启

      dfu_flag_set();   // 写入 User Custom 末扇区 0x5A
      sys_reboot(0);    // 下次上电 Boot 进入 USB DFU
      

      亦可通过 USB HID 厂商命令 USB_VENDOR_DFU_FORCE_UPGRADE 由工具/App 触发

    • 方式2: 按住 Boot 配置的 GPIO 按键上电(BOOT_USB_DFU_MODE=0x00)

  3. 加载固件:

    • 点击”加载固件”,选择编译生成的app.signed.bin

    • 工具会自动识别Boot DFU设备(VID:0x046D, PID:0xC055)

  4. 开始升级:

    • 点击”开始升级”,等待进度条完成

    • 升级成功后自动重启进入新App

  5. 验证升级:

    • 查看串口Log确认版本号

    • 测试基本功能正常

注意事项:

  • 升级过程中不要断电或拔插USB

  • 建议使用签名固件(app.signed.bin)确保安全

  • 升级失败可重新进入DFU模式再次升级

  • Boot区本身也可通过特殊工具升级(谨慎操作)

4.5 测试模式

模式指示:

  • 蓝牙:按键由底部往上看,下拨,配对时左一灯快闪,连接后熄灭,断连时慢闪

  • 2.4G:按键由底部往上看,上拨,配对时中间灯快闪,连接后熄灭,断连时慢闪

  • EMI:按住L+M上电,进入EMI测试,可以连接USB上位机工具进行EMI对测

  • Log:开启log时,调试log可由最下方灯IO输出

4.6 2.4G对码协议详解

4.6.1 对码流程概述

mult_ms采用单向配对策略,基于公共地址进行初始配对,配对成功后切换到私有地址和私有频点进行通信。

对码三阶段:

  1. PRF_PAIR_FIRST_STAGE:鼠标发送配对请求(包含鼠标MAC地址)

  2. PRF_PAIR_SECOND_STAGE:Dongle回复ACK(包含Dongle MAC地址)

  3. PRF_PAIR_THIRD_STAGE:鼠标确认并保存配对信息

  4. PRF_PAIR_END_STAGE:切换到私有地址和频点,进入正常通信

4.6.2 2.4G配对流程详解

配对阶段划分:

代码中将配对过程分为5个阶段(enum prf_stage):

enum prf_stage {
    PRF_IDLE_STAGE = 0,        // 空闲状态
    PRF_PAIR_INIT_STAGE,       // 配对初始化
    PRF_PAIR_FIRST_STAGE,      // 第一阶段:发送鼠标MAC
    PRF_PAIR_SECOND_STAGE,     // 第二阶段:等待Dongle回复
    PRF_PAIR_THIRD_STAGE,      // 第三阶段:确认配对
    PRF_PAIR_END_STAGE,        // 配对结束,切换私有地址
    PRF_CONNECT_STAGE          // 正常通信阶段
};

详细配对时序:

阶段1: 配对初始化 (PRF_PAIR_INIT_STAGE)
// 设置公共地址和公共频点
void app_prf_set_public_adr_chn(void)
{
    // 公共地址: {0x7b, 0x41, 0x29, 0x72}
    uint8_t public_addr[4] = PAIR_PUBLIC_ADDR;
    
    // 公共频点: 2412 MHz (channel_list_public[1])
    panchip_prf_set_chn(PAIR_PUBLIC_CHANNEL);  // 2412
    
    // 设置RF地址(4字节)
    panchip_prf_set_addr(public_addr, 4, PRF_PIPE0, PRI_RF_MODE_SEL_TRX);
    
    // 配对时使用低功率(-30dBm)减少干扰
    RF_SetPowerLevel(CONFIG_PRF_PAIR_RF_POWER);  // -30 dBm
    RF_RefreshPhySeqRAM(0);
}
阶段2: 发送配对请求 (PRF_PAIR_FIRST_STAGE)

鼠标发送包含自己MAC地址的配对包:

数据包格式 (7字节):
┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ Type     │ MAC[0]   │ MAC[1]   │ MAC[2]   │ MAC[3]   │ MAC[4]   │ MAC[5]   │
│ 0x00     │          │          │          │          │          │          │
└──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘

关键字段说明:

  • Type = 0x00: 表示普通鼠标类型(PAIR_COMMON_MOUSE_TYPE)

  • MAC[0-5]: 鼠标的6字节MAC地址

阶段3: Dongle回复 (PRF_PAIR_SECOND_STAGE)

Dongle收到配对请求后,回复包含自己信息的ACK:

Dongle回复ACK (7字节):
┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ 0xFF     │ DG_Type  │ MAC[0]   │ MAC[1]   │ MAC[2]   │ MAC[3]   │ MAC[4]   │
│          │          │          │          │          │          │          │
└──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘

关键字段说明:

  • 0xFF: 固定标识,表示这是Dongle回复

  • DG_Type: Dongle类型标识(用于区分不同Dongle)

  • MAC[0-4]: Dongle的5字节MAC地址(实际是6字节,但只传5字节)

阶段4: 鼠标处理响应 (PRF_PAIR_END_STAGE)

鼠标收到Dongle回复后,保存配对信息并生成私有地址/频点:

// 接收Dongle回复的数据
if (rx_payload.data[0] == 0xff && rx_payload.data_length == 7) {
    // 保存Dongle类型和MAC地址到 dg_type_addr[7]
    prf_state.dg_type_addr[0] = rx_payload.data[1];  // DG_Type
    prf_state.dg_type_addr[1] = rx_payload.data[2];  // Dongle MAC[0]
    prf_state.dg_type_addr[2] = rx_payload.data[3];  // Dongle MAC[1]
    prf_state.dg_type_addr[3] = rx_payload.data[4];  // Dongle MAC[2]
    prf_state.dg_type_addr[4] = rx_payload.data[5];  // Dongle MAC[3]
    prf_state.dg_type_addr[5] = rx_payload.data[6];  // Dongle MAC[4]
    
    // 保存到Flash
    common_kv_write("prf/dg_type_addr", prf_state.dg_type_addr, 7);
    
    // 进入配对结束阶段
    app_prf_stage_transform(PRF_PAIR_END_STAGE);
}
阶段5: 生成私有地址和频点

私有RF地址生成(4字节):

void app_prf_set_private_adr_chn(void)
{
    // 私有地址由Dongle的MAC地址生成
    prf_state.private_rf_addr[0] = PAIR_COMMON_MOUSE_TYPE;  // 0x00 (鼠标类型)
    prf_state.private_rf_addr[1] = prf_state.dg_type_addr[3];  // Dongle MAC[2]
    prf_state.private_rf_addr[2] = prf_state.dg_type_addr[4];  // Dongle MAC[3]
    prf_state.private_rf_addr[3] = prf_state.dg_type_addr[5];  // Dongle MAC[4]
    
    // 示例:
    // 如果 Dongle MAC = {AA, BB, CC, DD, EE, FF}
    // 则 dg_type_addr = {Type, AA, BB, CC, DD, EE}
    // 私有地址 = {0x00, CC, DD, EE}
}

关键点:

  • 私有地址不是由鼠标MAC生成,而是由Dongle MAC的后3字节生成

  • 这样可以确保同一个Dongle配对的多个设备使用相同的地址前缀

私有跳频频点生成(8个频点):

void calculate_combo_freq(uint8_t *addr)
{
    // addr 指向 dg_type_addr[2],即 Dongle MAC[1]
    // 使用 Dongle MAC[1] 和 Dongle MAC[3] 生成频点
    
    uint8_t x = addr[0] % 5;  // Dongle MAC[1] % 5
    uint8_t y = addr[2] % 8;  // Dongle MAC[3] % 8
    
    APP_LOG_INFO("calculate_combo_freq use Dongle MAC[1]=%d, MAC[3]=%d\n", 
                 addr[0], addr[2]);
    APP_LOG_INFO("x = %d, y = %d\n", x, y);
    
    // 生成8个频点
    for (uint8_t i = 0; i < 8; i++) {
        // 公式: frequency = 2402 + 2 * (8 * x + y)
        prf_state.private_rf_channel[i] = 2402 + 2 * (8 * x + y);
        
        // x和y递增,产生不同的频点
        x = (x + 1) % 5;
        y = (y + 1) % 8;
        
        // 避开WiFi干扰频点 2432MHz 和 2464MHz
        if ((prf_state.private_rf_channel[i] == 2432) || 
            (prf_state.private_rf_channel[i] == 2464)) {
            APP_LOG_INFO("Skip WiFi channel %d MHz\n", 
                        prf_state.private_rf_channel[i]);
            // 重新计算下一个频点
            prf_state.private_rf_channel[i] = 2402 + 2 * (8 * x + y);
            x = (x + 1) % 5;
        }
    }
    
    APP_LOG_INFO("Private channels: ");
    for (uint8_t i = 0; i < 8; i++) {
        APP_LOG_INFO("%d ", prf_state.private_rf_channel[i]);
    }
    APP_LOG_INFO("\n");
}

频点生成算法说明:

  1. 输入: Dongle MAC的两个字节 (MAC[1]MAC[3])

  2. 初始值:

    • x = MAC[1] % 5 (范围0-4)

    • y = MAC[3] % 8 (范围0-7)

  3. 频点公式: freq = 2402 + 2 * (8 * x + y)

    • 基础频率: 2402 MHz

    • 步长: 2 MHz

    • 范围: 2402 ~ 2480 MHz

  4. 迭代: 每次循环x和y递增,生成8个不同频点

  5. 避坑: 自动跳过2432和2464两个WiFi常用频点

示例计算:

假设 Dongle MAC = {0xAA, 0x12, 0x34, 0x56, 0x78, 0x9A}

addr[0] = MAC[1] = 0x12 = 18
addr[2] = MAC[3] = 0x56 = 86

x = 18 % 5 = 3
y = 86 % 8 = 6

频点计算:
i=0: freq = 2402 + 2*(8*3+6) = 2402 + 60 = 2462 MHz
     x=4, y=7
     
i=1: freq = 2402 + 2*(8*4+7) = 2402 + 78 = 2480 MHz
     x=0, y=0
     
i=2: freq = 2402 + 2*(8*0+0) = 2402 + 0 = 2402 MHz
     x=1, y=1
     
... (继续计算8个频点)

为什么这样设计?

  1. 唯一性: 不同Dongle的MAC不同,生成的频点序列也不同,避免互相干扰

  2. 均匀分布: 通过模运算确保频点在2.4G频段内均匀分布

  3. 抗干扰: 自动避开WiFi频点,提高稳定性

  4. 可预测: 双方使用相同算法,无需额外协商

阶段6: 切换到私有模式 (PRF_CONNECT_STAGE)
// 配对完成后
app_prf_set_private_adr_chn();  // 设置私有地址和频点

// 切换到连接功率(+1dBm或+7dBm)
RF_SetPowerLevel(CONFIG_PRF_CONNECT_RF_POWER);
RF_RefreshPhySeqRAM(0);

#if CONFIG_PRF_DYN_PWR_EN
app_prf_dyn_pwr_on_connect();  // 启用动态功率,从 CONNECT_RF_POWER 起始
#endif

// 更新状态
prf_state.stored_pair = true;   // 已存储配对
prf_state.pairing = false;      // 配对结束
prf_state.connect = true;       // 进入连接状态

APP_LOG_INFO("PRF pairing completed!\n");

配对完成后的通信:

  • 地址: 使用生成的4字节私有地址

  • 频点: 使用生成的8个私有频点,按顺序跳频

  • 功率: 使用连接功率(通常+1~+9dBm);若使能CONFIG_PRF_DYN_PWR_EN,则在连接阶段按链路质量自动调节(见 6.1.5.1)

  • 超时: 连接阶段连续 20 次未收到有效 ACK 后跳频到下一个私有频点(见 4.6.4)

4.6.3 配对流程图

上电
  |
  v
读取 Flash 配对信息 (prf/dg_type_addr)
  |
  +-- 有配对信息 --> 加载私有地址/频点 --> PRF_CONNECT_STAGE --> 正常 HID 通信
  |
  +-- 无配对信息 --> 设置公共地址/2412MHz/配对功率 -30dBm
          |
          v
      PRF_PAIR_FIRST_STAGE: 发送鼠标 MAC 
          |
          +-- 超时 --> 同频点重传 (当前代码配对阶段不跳公共频点)
          |
          +-- 收到 Dongle ACK --> 保存 dg_type_addr  Flash
                  |
                  v
              生成私有地址与 8 个私有频点 --> 切换连接功率 +1dBm
                  |
                  +-- CONFIG_PRF_DYN_PWR_EN=1 --> app_prf_dyn_pwr_on_connect()
                  |
                  v
              PRF_CONNECT_STAGE --> 正常 HID 通信

4.6.4 跳频机制

跳频触发条件:

不同阶段有不同的ACK丢失阈值:

// pair_with_common_dongle.c 中的定义
#define CONNECT_ACK_LOST_CNT_TRIGGER_HOP      20   // 连接阶段:20次
#define PAIR_FIRST_ACK_LOST_CNT_TRIGGER_HOP    5   // 配对第一阶段:5次
#define PAIR_SECOND_ACK_LOST_CNT_TRIGGER_HOP  15   // 配对第二阶段:15次
#define PAIR_THIRD_ACK_LOST_CNT_TRIGGER_HOP   15   // 配对第三阶段:15次

跳频逻辑实现

void app_prf_hop(void)
{
    switch (g_prf_ctrl.work_stage) {
    case PRF_PAIR_FIRST_STAGE:
        /* 当前代码:配对第一阶段不跳频,固定公共频点重传 */
        break;
    case PRF_PAIR_THIRD_STAGE:
        break;
    case PRF_CONNECT_STAGE:
        if (prf_state.ack_lost_cnt >= CONNECT_ACK_LOST_CNT_TRIGGER_HOP) {
            prf_state.channel_index++;
            prf_state.channel_index = prf_state.channel_index % 8;
            panchip_prf_set_chn(prf_state.private_rf_channel[prf_state.channel_index]);
            prf_state.hop_cnt++;
            prf_state.hop_recover_pending = true;
        } else {
            prf_state.ack_lost_cnt++;
        }
        break;
    default:
        break;
    }
}

PAIR_FIRST/SECOND/THIRD_*_TRIGGER_HOP 宏已定义,但当前仅在连接阶段使用 CONNECT_ACK_LOST_CNT_TRIGGER_HOP(20)。

跳频流程:

发送数据包 --> 等待 ACK
                  |
      +-----------+-----------+
      |                       |
  收到有效 ACK            未收到 ACK
      |                       |
 ack_lost_cnt = 0         ack_lost_cnt++
 hop_recover_pending      |
  hop_tms++              +-- 未达阈值 --> 重传
      |                    |
 继续当前频点              +-- 达阈值 --> channel_index = (index+1)%8
                              切换频点, hop_trig++, hop_recover_pending=true
                              --> 继续发送

关键点:

  1. 配对阶段: 当前 app_prf_hop()PRF_PAIR_FIRST_STAGE 不执行跳频,固定在 PAIR_PUBLIC_CHANNEL(2412MHz)重传

  2. 连接阶段: 在8个私有频点(根据 Dongle MAC 生成)之间跳频,阈值 20

  3. 跳频统计: hop_trig(=hop_cnt) 记录跳频触发次数;hop_tms 记录跳频后首次收到有效 ACK 的次数(用于链路恢复观测)

  4. 循环跳频: 到达第8个频点后回到第1个

4.6.5 重传机制

增强型模式特性:

  • TX后自动转入RX等待ACK

  • 未收到ACK时自动重传

  • 重传次数无限制,直到收到ACK或触发跳频

重传控制:

// 使能/禁用重传
void app_prf_tx_retransmit_enable(bool state);

// PID管理(防止重复包)
void app_prf_tx_pid_enable(bool state);

4.6.6 数据包格式

鼠标发送数据帧:

前导码

接入地址

Signal

Payload

CRC

3B

4B

10bit

可变长度

2B

0x550f71

公共/私有地址

增强型字段

鼠标数据

16bit CRC

Payload结构(最小4字节):

Type

Seq

Oppo_Seq

Data_Type

Data

1B

1B

1B

1B

N Bytes

设备类型

序列号

对端序列号

数据类型

实际数据

数据类型定义:

#define DATA_TYPE_NULL          0x00  // 空数据
#define DATA_TYPE_USB_EP0       0x10  // USB EP0数据
#define DATA_TYPE_USB_EP1       0x11  // USB EP1数据(标准键)
#define DATA_TYPE_USB_EP2       0x12  // USB EP2数据(多媒体/全键/鼠标)
#define DATA_TYPE_USB_EP3       0x13  // USB EP3数据(厂商自定义)
#define DATA_TYPE_REGROUP       0x20  // 重组数据
#define DATA_TYPE_CUSTOM        0x30  // 自定义数据

鼠标数据包示例(12字节):

void app_prf_set_ms_data(uint8_t *origin, uint8_t *tx_data, uint8_t *length)
{
    g_prf_pkt_seq++;  // 序列号递增
    
    tx_data[0] = PAIR_COMMON_MOUSE_TYPE;  // 0x00
    tx_data[1] = g_prf_pkt_seq;           // 发送序列号
    tx_data[2] = g_oppo_seq;              // 对端序列号
    tx_data[3] = DATA_TYPE_USB_EP2;       // 鼠标数据类型
    tx_data[4] = 0x05;                    // Report ID
    
    // 复制鼠标数据 (7字节: Key + X + Y + Roll)
    for (uint8_t i = 0; i < 7; i++) {
        tx_data[5 + i] = origin[i];
    }
    
    *length = 12;
}

4.6.7 多Dongle支持

代码支持多种Dongle类型,通过宏配置选择:

#if (CONFIG_DONGLE_TYPE == PAIR_WITH_PAN2628_DONGLE)
    #include "pair_with_pan2628_dongle.c"
#elif (CONFIG_DONGLE_TYPE == PAIR_WITH_PAN1010_DONGLE)
    #include "pair_with_pan1010_dongle.c"
#elif (CONFIG_DONGLE_TYPE == PAIR_WITH_COMBO_DONGLE)
    #include "pair_with_combo_dongle.c"
#elif (CONFIG_DONGLE_TYPE == PAIR_WITH_COMMON_DONGLE)
    #include "pair_with_common_dongle.c"
#elif (CONFIG_DONGLE_TYPE == PAIR_WITH_BY_DONGLE)
    #include "pair_with_by_dongle.c"
#endif

支持的Dongle类型:

  • PAN2628: 多pipe Dongle,支持键鼠套件

  • PAN1010: 低成本Dongle

  • COMMON: 通用Dongle,支持多设备共用

  • COMBO: 组合Dongle

  • BY: 自定义Dongle

4.7 PRF动态发射功率(概述)

使能 CONFIG_PRF_DYN_PWR_EN=1 后,鼠标在 PRF 已连接阶段根据每包 ACK 质量实时调节 TX 功率:近距离自动降功率省电,远距离升功率保链路。实现位于 src/app_prf_dyn_pwr.c / app_prf_dyn_pwr.h

功率调节流程:

每包 TX/RX 完成 --> 根据该 seq  timeout 次数判定 ACK 质量
        |
        +-- timeout=0 (干净 ACK) --> consec_ok++, consec_miss=0
        +-- timeout>=2 ( ACK)   --> consec_miss++, consec_ok=0
        +-- timeout=1 (一般 ACK)  --> 不累计升降计数
        |
        v
app_prf_idle_is()  app_prf_dyn_pwr_process():
        |
        +-- consec_miss>=3 或当前 seq timeout>=2 --> 升功率 +STEP_DB
        +-- consec_ok>=80 且冷却结束              --> 降功率 -STEP_DB
        +-- 否则                                    --> 保持当前功率
        |
        v
RF_SetPowerLevel() + 冷却 COOLDOWN_ROUNDS 

默认配置: CONFIG_PRF_DYN_PWR_EN=0(关闭),量产无额外风险;配对/断连时自动复位动态功率状态。

完整配置项、调试日志字段与调参建议见 6.1.5.1 动态发射功率

5 性能说明

5.1 功耗说明

关闭log,降低频率降低功率可以在使用场景下进行优化功耗。

2.4G模式功耗

2.4G配对后,test_mode_auto_circle开启情况下,关闭log,可以PPK测试当前上报率下满载数据通信条件下的功耗。

功耗特点:

  • 空闲时间进入deepsleep模式6~7ms,对功耗降低有一定帮助

  • 不同发射功率下功耗差异明显

测试结果:

发射功率

工作电流

备注

+9 dBm

700uA+

高功率模式

0 dBm

500uA+

标准功率模式

mult_ms_prf9dm

BLE模式功耗

BLE配对后,test_mode_auto_circle开启情况下,关闭log,可以PPK测试当前上报率下满载数据通信条件下的功耗。

功耗特点:

  • 空闲时间进入deepsleep模式2ms+,对功耗降低有一定帮助

  • 蓝牙写入数据的函数为flash function,执行速度与代码当前cache有一定关系

  • 以下代码执行1.3ms~2.5ms级别对应芯片的普通运行状态电流

  • 剩余时间由controller判断是否执行休眠,因此蓝牙功耗测试可能不同次复位的情况下,功耗略不同

om = ble_hs_mbuf_from_flat(&app_data, sizeof(app_data));
ble_gatts_notify_custom(peri_conn_handle, hid_app_input_handle, om);

测试结果:

发射功率

工作电流

备注

+9 dBm

3mA+

高功率模式

0 dBm

2mA+

标准功率模式

mult_ms_ble9dm

BLE不同状态功耗:

除了全速运行状态,还有仅连接不上报数据状态、slave latency 连接状态(当前代码 conn_latency=35):

状态

电流

说明

仅连接(0dBm)

1mA+

保持连接但不上报数据

Slave latency(35)

约100uA+

跳过连接事件降功耗(实测曲线可能因固件版本略有差异)

Standby M1

uA级别

空闲300s后断连待机

mult_ms_ble0dmconnect

mult_ms_ble0dmlatency

6 开发说明

6.1 SDK配置宏详解

以下列出mult_ms工程的关键配置宏,按功能模块分类说明。

重要提示:

  • 所有配置默认值均基于库上的原始sdk_config.h文件(git HEAD版本)

  • 实际项目中可根据需求修改这些配置,但需充分测试

  • 配置文件位置: keil_107x/configuration/sdk_config.h

  • 可通过Keil IDE的 “Configuration Wizard” 图形化界面进行配置

6.1.1 硬件与板级配置

宏定义

默认值

说明

取值范围

CONFIG_BOARD_TYPE

1

鼠标硬件类型选择:
• 0: BOARD_4200MV_PAW3311_20241212
1: BOARD_1500MV_PAW3220_20250430(当前使用)
• 2: BOARD_SYAZU_PAW3220_20260305

0-2

CONFIG_APP_RAM_CODE_ENABLE

1

使能RAM代码执行
将关键代码加载到RAM提升性能

0/1

CONFIG_SOC_DCDC_PAN1070

1

电源模式选择:
• 0: LDO模式(简单,功耗略高)
1: DCDC模式(高效,推荐)

0/1

注意: CONFIG_BOARD_TYPE 决定按键映射、传感器驱动、LED引脚等硬件相关配置,必须与实际PCB设计匹配。

6.1.2 工作模式配置

宏定义

默认值

说明

取值范围

CONFIG_CHANGE_MODE_RESET

1

模式切换时是否复位芯片
• =1: 切换模式时执行chip reset(推荐,更稳定)
• =0: 不复位直接切换(需处理好状态清理)

0/1

CONFIG_POWER_ON_FIXED_PRF_MODE

0

上电固定进入2.4G模式

0/1

CONFIG_POWER_ON_FIXED_BLE_MODE

0

上电固定进入BLE模式

0/1

CONFIG_POWER_ON_FIXED_USB_MODE

0

上电固定进入USB模式

0/1

CONFIG_POWER_ON_AUTO_CIRCLES

0

上电自动开启画圈测试

0/1

注意: 以上四个POWER_ON_FIXED_*宏互斥,最多只能使能一个。如果都不使能,则通过硬件(拨动开关/ADC)检测模式。

6.1.3 应用层功能配置

宏定义

默认值

说明

取值范围

CONFIG_FAST_CONN_TEST

1

快速连接测试模式
优化连接速度,适合量产测试

0/1

CONFIG_REPORT_RATE_UNCHANGE

0

锁定上报率不可切换
• =1: 固定为默认值
• =0: 允许按键切换

0/1

CONFIG_DEFAULT_REPORT_RATE

3

默认上报率索引:
• 0: 125Hz
• 1: 250Hz
• 2: 500Hz
3: 1000Hz(高性能)

0-3

CONFIG_APP_CID

0x07D10006

客户ID(Customer ID)
用于DFU防误升级识别,不同客户应设置不同CID

32bit值

上报率配置建议:

  • 办公场景: DEFAULT_REPORT_RATE=0 (125Hz), 省电

  • 游戏场景: DEFAULT_REPORT_RATE=3 (1000Hz), 低延迟

  • 通用场景: DEFAULT_REPORT_RATE=2 (500Hz), 平衡

6.1.4 时间参数配置

宏定义

默认值

单位

说明

CONFIG_BLE_DISCONNECT_TIMEOUT_S

300

BLE断连后超时时间(5分钟)

CONFIG_BLE_PAIR_TIMEOUT_S

300

BLE配对超时时间

CONFIG_BLE_IDLE_TIMEOUT_S

300

BLE空闲超时时间

CONFIG_PRF_PAIR_TIMEOUT_S

60

2.4G配对超时时间

CONFIG_PRF_IDLE_TIMEOUT_S

3

2.4G空闲进入deepsleep时间

CONFIG_PRF_CONNECTION_INTERVALS_MS

200

毫秒

2.4G连接状态下发包间隔

CONFIG_PRF_CONNECT_TIMEOUT_S

1

2.4G连接建立超时

CONFIG_PRF_DISCONNECT_TIMEOUT_S

60

2.4G断连后重新扫描时间

时间参数调优建议:

  • 低功耗优先: 减小PRF_IDLE_TIMEOUT_S(更快休眠)

  • 响应速度优先: 减小PRF_CONNECTION_INTERVALS_MS(更快上报)

  • 稳定性优先: 增大PRF_DISCONNECT_TIMEOUT_S(更长重连等待)

6.1.5 2.4G PRF射频配置

宏定义

默认值

说明

取值范围

CONFIG_DONGLE_TYPE

3

Dongle类型选择:
• 0: PAIR_WITH_PAN1010_DONGLE
• 1: PAIR_WITH_PAN2628_DONGLE
• 2: PAIR_WITH_COMBO_DONGLE
3: PAIR_WITH_COMMON_DONGLE(推荐,通用型)
• 4: PAIR_WITH_BY_DONGLE

0-4

CONFIG_PRF_PAIR_RF_POWER

-30

配对时发射功率(dBm)
配对时使用极低功率减少干扰,避免误配对

-30 ~ +9

CONFIG_PRF_CONNECT_RF_POWER

+1

连接时起始发射功率(dBm)
配对完成后的初始TX功率;未开动态功率时全程使用此值

-30 ~ +9

CONFIG_PRF_DYN_PWR_EN

0

使能动态发射功率
• =1: 连接后按ACK质量实时升降功率
• =0: 固定使用CONNECT_RF_POWER

0/1

CONFIG_PRF_THREAD_EN

1

使能独立PRF线程
• =1: 创建独立FreeRTOS线程处理PRF(推荐,实时性更好)
• =0: 在主循环中处理

0/1

CONFIG_PRF_MODE_ALWAYS_PAIR

0

每次上电强制重新配对
(调试用,正常产品应=0)

0/1

CONFIG_PRF_RF_TRANSFE_DEBUG

0

PRF收发调试信息打印
(调试时=1,量产时=0)

0/1

6.1.5.1 动态发射功率

使能CONFIG_PRF_DYN_PWR_EN后,鼠标在PRF已连接阶段根据每包ACK质量逐包实时调节TX功率,实现近距离降功率省电、远距离升功率保链路。实现位于src/app_prf_dyn_pwr.c / app_prf_dyn_pwr.h(由app_prf.c include)。

生效条件(须同时满足):

  1. CONFIG_PRF_DYN_PWR_EN = 1

  2. 处于PRF_CONNECT_STAGEprf_state.connect == true(非配对阶段)

  3. 连接后已完成CONFIG_PRF_DYN_WARMUP_ACKS次ACK预热(预热期间不调功率)

配对/断连时调用app_prf_dyn_pwr_on_pair()复位;连接成功时app_prf_dyn_pwr_on_connect()将当前功率设为CONFIG_PRF_CONNECT_RF_POWER

调制逻辑

每个逻辑seq(一包HID数据对应一轮TX/RX)统计该轮内RX timeout次数timeouts_in_round。收到ACK时:

该seq收到ACK前的timeout次数

判定

计数器影响

0

干净ACK

consec_ok++,consec_miss=0

CONFIG_PRF_DYN_N_TIMEOUTS_PER_ROUND(默认2)

弱ACK

consec_miss++,consec_ok=0

1(低于弱ACK阈值)

一般ACK

升降功率均不累计,仅consec_ok=0

PRF任务空闲时(app_prf_idle_is())执行app_prf_dyn_pwr_process()决策:

条件

动作

consec_miss CONFIG_PRF_DYN_N_UP(默认3)

升功率 +CONFIG_PRF_DYN_STEP_DB

当前seq的timeouts_in_round已达弱ACK阈值,且冷却结束

升功率(重传过程中即可响应,不等ACK)

consec_miss==0consec_ok CONFIG_PRF_DYN_N_DOWN(默认80)

降功率 -CONFIG_PRF_DYN_STEP_DB

功率变化后调用RF_SetPowerLevel() + RF_RefreshPhySeqRAM(0),同步tx_config.tx_power,并进入CONFIG_PRF_DYN_COOLDOWN_ROUNDS轮冷却。实际功率限制在[CONFIG_PRF_DYN_PWR_MIN, CONFIG_PRF_DYN_PWR_MAX]

动态功率相关配置

宏定义

默认值

说明

取值范围

CONFIG_PRF_DYN_PWR_MIN

-20

动态调制功率下限(dBm)

-30 ~ +9

CONFIG_PRF_DYN_PWR_MAX

+8

动态调制功率上限(dBm)

-30 ~ +9

CONFIG_PRF_DYN_STEP_DB

1

每次升降步进(dBm)

1 ~ 9

CONFIG_PRF_DYN_N_UP

3

连续弱ACK次数触发升功率

1 ~ 20

CONFIG_PRF_DYN_N_DOWN

80

连续干净ACK次数触发降功率

10 ~ 500

CONFIG_PRF_DYN_N_TIMEOUTS_PER_ROUND

2

单seq timeout达到此次数,该ACK计为弱ACK

1 ~ 15

CONFIG_PRF_DYN_COOLDOWN_ROUNDS

80

每次改功率后的冷却轮数

10 ~ 500

CONFIG_PRF_DYN_WARMUP_ACKS

100

连接后预热ACK数,期间不调节

0 ~ 500

调试日志

开启 CONFIG_PRF_RF_TRANSFE_DEBUG=1 时,每秒通过 prf_stats_print_event 异步打印(不阻塞 PRF 热路径):

1s sensor N tx N new_seq N retx N ack_rx N ... hop_trig N hop_tms N
  ch[0] 2462MHz ack N
  ...
  pwr cur -1 ok 12 miss 0 tmo 0 cd 0 wu 0 up 2 down 0   //  CONFIG_PRF_DYN_PWR_EN=1

字段

含义

hop_trig

跳频触发次数(=hop_cnt)

hop_tms

跳频后首次收到有效 ACK 的次数

pwr cur

当前 TX 功率(dBm),需 DYN_PWR_EN=1

ok / miss

连续干净/弱 ACK 计数

tmo

当前 seq 已累计的 timeout 次数

cd / wu

冷却/预热剩余

up / down

过去 1 秒内升/降功率次数

调参建议

现象

建议

拉远后功率升得慢

减小CONFIG_PRF_DYN_N_UP(如2),或减小CONFIG_PRF_DYN_N_TIMEOUTS_PER_ROUND(如1)

功率来回抖动

增大CONFIG_PRF_DYN_COOLDOWN_ROUNDSCONFIG_PRF_DYN_N_DOWN

近距离功耗仍偏高

确认干净ACK能稳定累计;适当降低CONFIG_PRF_DYN_PWR_MIN

拉远上报率仍差

提高CONFIG_PRF_DYN_PWR_MAXCONFIG_PRF_CONNECT_RF_POWER

量产不需要统计

CONFIG_PRF_RF_TRANSFE_DEBUG=0(不影响动态功率本身,仅无log)

功率配置建议:

  • 办公场景(近距离<2米,固定功率): PAIR=-30, CONNECT=0, DYN_PWR_EN=0 → 功耗~500uA

  • 办公场景(近距离,动态功率): PAIR=-30, CONNECT=+1, DYN_PWR_EN=1, PWR_MIN=-20 → 近距离自动降功率

  • 通用场景(3-5米): PAIR=-30, CONNECT=+7, DYN_PWR_EN=1 → 远近自适应

  • 远距离(>5米,固定功率): PAIR=-30, CONNECT=+9, DYN_PWR_EN=0 → 功耗~900uA

Dongle类型选择指南:

  • COMMON_DONGLE(推荐): 通用型,支持多设备共用,兼容性好

  • PAN2628_DONGLE: 多pipe Dongle,支持键鼠套件同时连接

  • PAN1010_DONGLE: 低成本方案,适用于价格敏感产品

  • COMBO_DONGLE: 组合型Dongle,特殊应用场景

  • BY_DONGLE: 自定义协议,需自行实现配对逻辑

6.1.6 BLE蓝牙配置

BLE基础配置:

宏定义

默认值

说明

取值范围

CONFIG_LATENCY_ENHANCE

1

BLE延迟优化
使能后降低BLE通信延迟

0/1

CONFIG_BLE_REPAIR_REFRESH_INFO

0

重新配对时刷新绑定信息
• =1: 清除旧绑定
• =0: 保留旧绑定

0/1

CONFIG_BLE_ADV_RSP_NAME

1

广播响应包中包含设备名称

0/1

CONFIG_BLE_ADV_COMPLETE_NAME

“PanMS-LP”

BLE完整设备名称(最大31字节)

字符串

CONFIG_BLE_ADV_SHORT_NAME

“PanMS-LP”

BLE短设备名称

字符串

CONFIG_BLE_ID_MAX

3

最大可切换BLE设备数
支持在多个已配对设备间切换

1-8

BLE DIS(Device Information Service)配置:

宏定义

默认值

说明

CONFIG_BLE_DIS_PNP_VID_SRC

2

PnP Vendor ID Source:
• 1: Bluetooth SIG
• 2: USB Implementers Forum

CONFIG_BLE_DIS_PNP_VID

0x07D1

Vendor ID (厂商ID)

CONFIG_BLE_DIS_PNP_PID

0x0006

Product ID (产品ID)

CONFIG_BLE_DIS_PNP_VER

1

Version (版本号)

BLE连接参数:

宏定义

默认值

说明

计算方式

CONFIG_BT_PERIPHERAL_PREF_MIN_INT

6

最小连接间隔

6 × 1.25ms = 7.5ms

CONFIG_BT_PERIPHERAL_PREF_MAX_INT

6

最大连接间隔

6 × 1.25ms = 7.5ms

CONFIG_BT_PERIPHERAL_PREF_LATENCY

30

偏好 Latency(协商前)

连接后约2s改为 35

CONFIG_BT_PERIPHERAL_PREF_TIMEOUT

200

Supervision Timeout

200 × 10ms = 2000ms

BLE低功耗管理(app_ble.c 运行时逻辑):

宏/行为

默认值

说明

CONFIG_BLE_IDLE_TIMEOUT_S

300 s

连接空闲超时后进 standby M1

CONFIG_BLE_PAIR_TIMEOUT_S

300 s

配对广播超时

CONFIG_BLE_DISCONNECT_TIMEOUT_S

300 s

已连接但无 notify 超时

app_ble_conn_upd_timer

2000 ms

连接后定时请求 conn_latency=35

latency_delay_cnt

428 事件

无活动约 428 个连接事件后启用 slave latency

BLE功耗优化策略:

  1. Latency: 连接约 2s 后设 conn_latency=35;无活动约 428 个连接事件(约 3.2s @7.5ms)后启用

  2. Standby: 持续空闲 300sstandby_m1_event 断开连接(uA 级)

  3. 连接间隔: MIN_INT=MAX_INT=6(7.5ms,约 133Hz 事件率)

6.1.7 USB HID配置

USB VID/PID配置:

宏定义

默认值

说明

CONFIG_USB_VID_H

0x07

USB Vendor ID 高字节

CONFIG_USB_VID_L

0xD1

USB Vendor ID 低字节
完整VID = 0x07D1

CONFIG_USB_PID_H

0x00

USB Product ID 高字节

CONFIG_USB_PID_L

0x06

USB Product ID 低字节
完整PID = 0x0006

USB描述符配置:

宏定义

默认值

说明

CONFIG_MANUFACTURER_DESCRIPTOR_1

“panchip”

制造商字符串(第1段)

CONFIG_MANUFACTURER_DESCRIPTOR_2

“fs_ms_107x”

制造商字符串(第2段)

CONFIG_MANUFACTURER_DESCRIPTOR_3

“1234”

制造商字符串(第3段)

USB低功耗:

宏定义

默认值

说明

CONFIG_USB_DEEPSLEEP_EN

0

USB模式下使能deepsleep
• =1: 支持休眠(需注意USB唤醒)
• =0: USB模式下不休眠(稳定)

注意: VID/PID需要向USB-IF申请,或使用PanChip提供的默认值。

6.1.8 EMI测试配置

宏定义

默认值

说明

CONFIG_EMI_TEST_TYPE

1

EMI测试类型:
• 0: EMI USB Test
1: EMI Carrier Test(载波测试)

CONFIG_EMI_CARRIER_RF_POWER

0

EMI载波发射功率(dBm)

CONFIG_EMI_CARRIER_RF_CHANNEL

2402

EMI载波频点(MHz)
2402~2480范围内任意值

EMI测试说明:

  • Carrier Test: 持续发射单频载波,用于频谱分析仪测试辐射

  • USB Test: 通过USB发送特定数据包,测试USB通信时的EMI

  • 量产前必测: 确保产品通过FCC/CE等电磁兼容认证

6.1.9 ARGB灯效配置(可选)

ARGB功能使能:

宏定义

默认值

说明

APP_ARGB_FUNC_EN

0

使能ARGB灯效功能
• =1: 使能ARGB
• =0: 禁用ARGB(省电)

SPI接口配置:

宏定义

默认值

说明

CONFIG_ARGB_SPI_ID

0

SPI模块选择:
• 0: SPI0
• 1: SPI1

CONFIG_ARGB_SPI_DIV

1

SPI分频系数
实际时钟 = 系统时钟 / (2 × DIV)
DIV=1 → 24MHz(推荐)

引脚配置:

宏定义

默认值

说明

APP_ARGB_DOUT_EN

1

使能ARGB数据输出

CONFIG_ARGB_DOUT_PIN

3

SPI MOSI(DOUT)引脚:
• 0: P22 (SPI0)
• 1: P21 (SPI1)
• 2: P07 (SPI0)
3: P11 (SPI0)

APP_ARGB_CLK_EN

0

使能ARGB时钟输出测试

CONFIG_ARGB_CLK_PIN

2

SPI CLK引脚:
• 0: P14 (SPI0)
• 1: P00 (SPI0)
2: P04 (SPI0)

LED数量:

宏定义

默认值

说明

CONFIG_ARGB_LED_MAX

8

ARGB LED总数
根据实际硬件设计配置

注意: ARGB功能会增加功耗(~5-10mA),电池供电产品建议禁用或仅在充电时使能。

6.1.10 调试与测试配置

宏定义

默认值

说明

CONFIG_POWER_ON_AUTO_CIRCLES

0

上电自动开启画圈测试
(自动化测试用)

CONFIG_POWER_ON_FIXED_PRF_MODE

0

上电固定进入2.4G模式
(调试用,跳过模式检测)

CONFIG_POWER_ON_FIXED_BLE_MODE

0

上电固定进入BLE模式

CONFIG_POWER_ON_FIXED_USB_MODE

0

上电固定进入USB模式

CONFIG_POWER_ON_FIXED_EMI_MODE

0

上电固定进入EMI测试模式

CONFIG_PRF_MODE_ALWAYS_PAIR

0

每次上电强制重新配对
(调试配对流程用)

CONFIG_BLE_MODE_ALWAYS_PAIR

0

BLE每次上电强制重新配对

CONFIG_PRF_RF_TRANSFE_DEBUG

0

PRF收发数据调试打印

CONFIG_APP_IO_DBG

0

GPIO调试信息打印

CONFIG_APP_PRF_DBG

0

PRF调试IO输出(P10-T/P04-R/P05-ACC/P07-RxData)

CONFIG_APP_ADC_LOG_EN

0

ADC电量采样日志打印
量产建议=0

调试建议:

  • 开发阶段: 使能相关DEBUG宏,方便定位问题

  • 量产前: 关闭所有DEBUG宏,节省Flash/RAM资源

  • 自动化测试: 使用POWER_ON_*固定模式宏,简化测试流程

6.1.11 Bootloader配置

App工程Boot配置:

宏定义

默认值

说明

CONFIG_ENABLE_BOOTLOADER

1

使能Bootloader功能
• =1: 合并boot支持USB/2.4G升级(库上默认)
• =0: 不使用boot(直接运行app)

CONFIG_FLASH_PARTITION_BOOTLOADER_SIZE_KB

40

Bootloader分区大小(KB)
必须为4KB的倍数

CONFIG_BOOTLOADER_PROJECT_PATH

“../../bootloader/keil_107x”

Bootloader工程相对路径

CONFIG_FORCE_BUILD_BOOTLOADER_PROJECT

0

强制重新编译Bootloader

CONFIG_MERGE_IMAGES

1

合并Boot+App为一个镜像文件
(推荐,方便烧录)

CONFIG_APP_USE_IMAGE_HEADER

1

使能App镜像头
(OTA升级必需)

App版本信息:

宏定义

默认值

说明

CONFIG_APP_IMG_VER_MAJOR

0

主版本号

CONFIG_APP_IMG_VER_MINOR

0

次版本号

CONFIG_APP_IMG_VER_REVISION

1

修订版本号

CONFIG_APP_IMG_VER_BUILD

0

构建号

Flash分区布局(当CONFIG_ENABLE_BOOTLOADER=1时):

分区名称

起始地址

大小

说明

Bootloader

0x00000

40KB

Boot程序,支持USB DFU + 2.4G OTA

App

0x0A000

220KB

应用程序主分区

App Backup

0x41000

220KB

见§4.4.3 Backup 可复用说明

KV Store

0x78000

16KB

键值存储(配对信息/配置)

User Custom

0x7C000

12KB

用户数据;末4KB保留DFU标志

总计

-

508KB

PAN1070 Flash总容量

注意:

  • Boot 相关 BOOT_* 宏在 bootloader 工程 sdk_config.h 配置;App 工程用 CONFIG_ENABLE_BOOTLOADER

  • User Custom 末 4KB 为 DFU 标志保留区;Backup 在本方案升级中可复作用户存储(见§4.4.3)

  • CONFIG_APP_CID用于DFU防误升级,不同客户应设置不同CID

  • 2.4G OTA详细说明: 请参考官方文档 PanChip 2.4G OTA升级指南

6.1.12 上报率配置

宏定义

默认值

说明

CONFIG_DEFAULT_REPORT_RATE

3

默认上报率索引:
• 0: 125Hz
• 1: 250Hz
• 2: 500Hz
3: 1000Hz(高性能)

CONFIG_REPORT_RATE_UNCHANGE

0

锁定上报率不可切换
• =1: 固定为默认值
• =0: 允许按键切换

上报率配置建议:

  • 办公场景: DEFAULT_REPORT_RATE=0 (125Hz), 省电

  • 游戏场景: DEFAULT_REPORT_RATE=3 (1000Hz), 低延迟

  • 通用场景: DEFAULT_REPORT_RATE=2 (500Hz), 平衡

6.1.13 平台与时钟配置

宏定义

默认值

说明

CONFIG_SYSTEM_CLOCK

48

系统主时钟(MHz):
• 48: DPLL 48MHz(推荐)
• 32: DPLL 32MHz(低功耗)

CONFIG_APB1_CLOCK_DIVISOR

2

APB1总线分频系数
APB1时钟 = SYS_CLK / DIV

CONFIG_APB2_CLOCK_DIVISOR

12

APB2总线分频系数
APB2时钟 = SYS_CLK / DIV

CONFIG_LOW_SPEED_CLOCK_SRC

0

32K低速时钟源:
0: RCL(32000Hz, RC振荡器)
• 1: XTL(32768Hz, 晶振)
• 2: ACT32K(32000Hz)

CONFIG_FORCE_CALIB_RCL_CLK

1

强制校准RCL时钟
(上电时执行,耗时~35ms)

CONFIG_RAM_FUNCTION

1

使能RAM函数
将关键代码加载到SRAM提升性能

CONFIG_FLASH_LDO_EN

1

使能Flash LDO(1.8V)
替代VBAT供电,降低功耗

CONFIG_VECTOR_REMAP_TO_RAM

1

中断向量表重映射到RAM
提升中断响应速度

CONFIG_INTERRUPT_STACK_SIZE

1536

中断栈大小(字节)
MSP栈,用于中断处理

CONFIG_LIBC_HEAP_SIZE

0

C库堆大小(字节)
设为0禁用malloc/free

时钟配置建议:

  • 高性能: SYS_CLOCK=48, APB1_DIV=2, APB2_DIV=2

  • 低功耗: SYS_CLOCK=32, APB1_DIV=2, APB2_DIV=12

  • 时钟源: 无外部晶振时用RCL,有晶振时用XTL(精度更高)

6.1.14 低功耗管理配置

宏定义

默认值

说明

CONFIG_PM

1

使能电源管理(deepsleep/standby)

CONFIG_SYSTEM_WATCH_DOG_ENABLE

0

使能系统看门狗
(调试时建议关闭)

CONFIG_KEEP_FLASH_POWER_IN_LP_MODE

1

低功耗模式下保持Flash供电
• =1: 保持供电(功耗+1uA,无峰值电流)
• =0: 关闭供电(有>15mA峰值电流)

CONFIG_DEEPSLEEP_MODE_2

1

DeepSleep模式选择:
• 0: Mode 1(~4uA,唤醒源:GPIO/SleepTimer)
1: Mode 2(~8uA,额外支持HW Timer/PWM)

CONFIG_PM_BOOT_DEEPSLEEP_DELAY_MS

500

上电后延迟进入deepsleep时间(ms)
方便SWD连接调试

CONFIG_SOC_INCREASE_LPLDOH_CALIB_CODE

0

增加LPLDOH电压校准值
用于特殊低功耗场景

CONFIG_PM_STANDBY_M1_WAKEUP_WITHOUT_RESET

0

Standby M1唤醒后是否复位:
• =0: 唤醒后复位(稳定)
• =1: 唤醒后继续运行(快速)

DeepSleep模式对比:

特性

Mode 1

Mode 2

功耗

~4uA

~8uA

唤醒源

GPIO, SleepTimer CH0/1/2

GPIO, SleepTimer, HW Timer0/1/2

PWM输出

不支持

支持

适用场景

纯低功耗

需要PWM/定时器

6.1.15 LL RAM使用配置

说明: LL RAM是BLE Link Layer专用的RAM区域,可被App借用存储数据以节省SRAM。

宏定义

默认值

说明

CONFIG_USE_LL_RAM

1

使能App访问LL RAM

CONFIG_LL_RAM_BLE_TASK

1

BLE Host任务使用LL RAM

CONFIG_LL_RAM_OS_MSYS

1

OS msys缓冲区使用LL RAM

CONFIG_LL_RAM_BLE_TRANSPORT

1

BLE传输缓冲区使用LL RAM

CONFIG_LL_RAM_BLE_STORE

0

BLE存储使用LL RAM

CONFIG_LL_RAM_BLE_SM

1

BLE安全管理器使用LL RAM

CONFIG_LL_RAM_BLE_HCI

0

BLE HCI使用LL RAM

CONFIG_LL_RAM_BLE_GATTC

0

BLE GATT Client使用LL RAM

CONFIG_LL_RAM_BLE_ATT_SVR

0

BLE ATT Server使用LL RAM

LL_DATA_FREE_SIZE

4096

LL Data RAM剩余大小(字节)
保留给BLE使用的空间

LL RAM优化建议:

  • 内存紧张时: 使能更多LL RAM选项,释放SRAM

  • 稳定性优先: 保留足够LL_DATA_FREE_SIZE,避免BLE异常

  • 推荐配置: 保持默认值,已经过充分测试

6.1.16 RTOS(FreeRTOS)配置

宏定义

默认值

说明

CONFIG_OS_EN

1

使能FreeRTOS操作系统

configMAX_PRIORITIES

8

最大任务优先级数

configTOTAL_HEAP_SIZE

9000

OS总堆大小(字节)
所有任务栈+动态分配从此分配

CONFIG_MAIN_TASK_STACK_SIZE

500

Main任务栈大小(word)
实际字节 = 500 × 4 = 2000字节

CONFIG_MAIN_TASK_PRIO

3

Main任务优先级
数值越大优先级越高

CONFIG_BLE_HOST_THREAD_STACK_SIZE

400

BLE Host任务栈大小(word)
实际字节 = 400 × 4 = 1600字节

CONFIG_BLE_HOST_THREAD_PRIO

6

BLE Host任务优先级
高优先级确保BLE实时性

configUSE_TIMERS

1

使能软件定时器

configTIMER_TASK_STACK_DEPTH

192

Timer任务栈深度(word)

configTIMER_TASK_PRIORITY

2

Timer任务优先级

configTIMER_QUEUE_LENGTH

12

Timer命令队列长度

configUSE_IDLE_HOOK

0

使能Idle Hook回调

configUSE_TICK_HOOK

0

使能Tick Hook回调

configUSE_MALLOC_FAILED_HOOK

1

使能malloc失败Hook
(调试内存泄漏用)

configCHECK_FOR_STACK_OVERFLOW

2

栈溢出检测模式:
• 0: 禁用
• 1: Mode 1(简单检查)
2: Mode 2(深度检查,推荐)

configSUPPORT_STATIC_ALLOCATION

1

支持静态内存分配

configMINIMAL_STACK_SIZE

84

Idle任务最小栈大小(word)

任务优先级规划:

优先级

任务名称

说明

7 (最高)

-

保留给紧急中断处理

6

BLE Host

BLE协议栈,高优先级保证实时性

5

-

预留

4

-

预留

3

Main Task

主任务,处理事件队列

2

Timer

软件定时器任务

1

-

预留

0 (最低)

Idle

空闲任务

内存优化建议:

  • RAM紧张: 减小configTOTAL_HEAP_SIZE,关闭未使用的Hook

  • 稳定性优先: 增大任务栈大小,使能栈溢出检测Mode 2

  • 调试阶段: 使能configUSE_MALLOC_FAILED_HOOK,检测内存泄漏

6.1.17 日志与调试输出配置

日志系统总开关:

宏定义

默认值

说明

PAN_LOG_ENABLE

1

使能日志系统总开关
关闭后所有日志API失效

PAN_ASSERT_ENABLE

0

使能断言(Assert)
• =1: 使能APP_ASSERT/SYS_ASSERT
• =0: 禁用断言(量产推荐)

APP日志配置:

宏定义

默认值

说明

APP_LOG_EN

1

使能APP层日志

APP_LOG_LVL

4

日志级别:
• 4: DEBUG(最详细)
• 3: INFO
• 2: WARNING
• 1: ERROR
• 0: NONE(无日志)

APP_LOG_LVL_OUTPUT_EN

1

打印日志级别前缀([DEBUG]/[INFO]等)

APP_LOG_TRACE_OUTPUT_EN

0

打印详细信息(文件/行号/函数名)
(调试时用,占用Flash较多)

APP_LOG_PRINT_MODE

1

日志后端:
• 0: printf()(功能全,栈消耗大)
1: printk()(轻量级,推荐)

SYS日志配置:

宏定义

默认值

说明

PAN_SYS_LOG_ENABLE

0

使能SYS层日志
(SDK内部日志,一般关闭)

PAN_SYS_LOG_LVL

3

SYS日志级别

PAN_SYS_LOG_PRINT_LEVEL_STRING

1

打印SYS日志级别前缀

PAN_SYS_LOG_PRINT_VERBOSE_STRING

0

打印SYS详细信息

PAN_SYS_LOG_PRINT_MODE

1

SYS日志后端(printf/printk)

BLE Controller日志:

宏定义

默认值

说明

BLE_LL_LOG_PRINT_MODE

2

BLE底层日志后端:
• 0: 禁用
• 1: vprintf()
2: vprintk()(轻量级)

日志输出通道:

宏定义

默认值

说明

CONFIG_UART_LOG_ENABLE

0

使能UART日志输出(Git默认关闭)

CONFIG_LOG_UART_PIN

2

日志UART TX引脚(Git默认):
• 0: P05 (UART0)
• 1: P11 (UART0)
2: P16 (UART0)
• 3: P01 (UART1)

CONFIG_LOG_UART_BAUDRATE

115200

日志UART波特率

CONFIG_RTT_LOG_ENABLE

0

使能RTT日志输出
(需J-Link连接,低功耗模式下不可用)

CONFIG_LOG_RTT_UP_BUFFER_SIZE

512

RTT上行缓冲区大小(字节)

IO时序追踪配置(高级调试):

宏定义

默认值

说明

CONFIG_IO_TIMING_TRACK

0

使能IO时序追踪
(通过GPIO翻转记录关键事件时序)

CONFIG_BT_CTLR_LINK_LAYER_DEBUG

0

BLE Link Layer内部时序追踪
(固定引脚:P04/P07/P10)

CONFIG_TRACK_PIN_DEEPSLEEP_MODE

0x22

DeepSleep模式追踪引脚(P22)

CONFIG_TRACK_PIN_SLEEP_MODE

0x23

Sleep模式追踪引脚(P23)

CONFIG_TRACK_PIN_LL_IRQ

0x99

BLE/PRF IRQ追踪引脚(禁用)

其他IRQ追踪引脚配置(共30+个)

日志配置建议:

阶段

推荐配置

说明

开发调试

APP_LOG_LVL=4, TRACE_OUTPUT=1, UART_LOG=1

最详细日志,方便定位问题

集成测试

APP_LOG_LVL=3, TRACE_OUTPUT=0, UART_LOG=1

正常日志,减少输出量

量产固件

PAN_LOG_ENABLE=0APP_LOG_EN=0

关闭日志,节省~11KB Flash + 2KB RAM

资源占用对比:

配置

Flash占用

RAM占用

性能影响

日志全开(DEBUG+Trace)

~15KB

~3KB

-10%

日志正常(INFO)

~8KB

~2KB

-5%

日志关闭

0

0

0%

6.1.18 时钟输出与启动延迟配置

时钟 mux 到IO引脚(调试用):

宏定义

默认值

说明

CONFIG_MUX_CLOCKS_TO_IO_PADS

0

使能时钟输出到IO引脚
(用于示波器测量时钟频率)

CONFIG_MUX_OUTPUT_32K_CLOCK

1

32K低速时钟输出到P11

CONFIG_MUX_OUTPUT_AHB_CLOCK

0

AHB(系统)时钟输出到P06

CONFIG_MUX_OUTPUT_RCH_CLOCK

0

32M RCH时钟输出到P17

CONFIG_MUX_OUTPUT_XTH_CLOCK

0

32M XTH时钟输出到P27

CONFIG_MUX_OUTPUT_DPLL_CLOCK_DIV8

0

DPLL时钟(/8)输出到P23

启动延迟:

宏定义

默认值

说明

CONFIG_STARTUP_LONG_DELAY

1

使能上电长延迟
(方便J-Link在低功耗模式下连接)

使用场景:

  • 时钟测量: 使能对应时钟mux,用示波器测量实际频率

  • J-Link连接困难: 使能STARTUP_LONG_DELAY,给调试器更多连接时间

  • 量产固件: 关闭所有clock mux和startup delay


6.2 软件架构

6.2.1 目录结构

mult_ms/
├── keil_107x/              # Keil工程文件
├── src/                    # 源代码目录
│   ├── main.c              # 主程序入口,模式检测与初始化
│   ├── app_common.c/h      # 通用功能(KV存储/事件队列/组合键)
│   ├── app_prf.c/h         # 2.4G PRF通信模块
│   ├── app_prf_dyn_pwr.c/h # PRF动态发射功率(可选,CONFIG_PRF_DYN_PWR_EN)
│   ├── app_ble.c/h         # BLE蓝牙通信模块
│   ├── app_ble_gatt_svr.c/h# BLE GATT服务实现
│   ├── app_usb.c/h         # USB HID通信模块
│   ├── app_sensor.c/h      # 光电传感器驱动
│   ├── app_mouse_key.c/h   # 按键扫描与处理
│   ├── app_mouse_wheel.c/h # QDEC滚轮模块
│   ├── app_adc.c/h         # ADC电量检测
│   ├── app_led.c/h         # LED指示灯控制
│   ├── app_argb_led.c/h    # ARGB灯效控制
│   ├── app_pm.c/h          # 电源管理(deepsleep/standby)
│   ├── app_emi.c/h         # EMI测试模式
│   ├── fragment_regroup_packet.c/h # 数据分片与重组
│   ├── dongle/             # 不同Dongle配对协议实现
│   │   ├── pair_with_common_dongle.c
│   │   ├── pair_with_pan2628_dongle.c
│   │   ├── pair_with_pan1010_dongle.c
│   │   └── ...
│   └── usb/                # USB协议栈
└── board/                  # 板级配置文件

6.2.2 主程序流程

main函数启动流程:

int main(void)
{
    // 1. 打印版本信息(如果使能BOOT)
    #if CONFIG_BOOT_ENABLE
    print_version_info();
    #endif

    // 2. 上电初始化(复位原因检测/GPIO清除)
    power_on_init();

    // 3. 应用层初始化
    app_wdt_init();              // 看门狗初始化
    app_deepsleep_init();        // 深睡初始化
    app_run_time_init();         // 运行时间计数
    app_event_queue_init();      // 事件队列初始化

    // 4. 存储初始化
    kv_init();                   // KV存储系统

    // 5. 外设初始化
    #if !CONFIG_POWER_ON_AUTO_CIRCLES
    app_mouse_key_init();        // 按键初始化
    app_emi_mode_detect();       // EMI模式检测
    app_usb_detect_init();       // USB检测初始化
    app_mouse_wheel_init();      // 滚轮初始化
    sensor_spi_init();           // 传感器SPI初始化
    sensor_init();               // 传感器初始化
    app_led_init();              // LED初始化
    app_led_flicker_init();      // LED闪烁初始化
    app_argb_init();             // ARGB初始化
    app_battery_get();           // 电量检测
    #endif

    // 6. 模式检测与初始化
    app_mode_detect();           // 检测当前工作模式
    app_work_mode_init();        // 初始化对应模式

    // 7. PRF IO调试(可选)
    app_prf_io_debug();

    // 8. 主循环:处理事件队列
    while (1) {
        app_event_queue_handle();
    }
}

主循环与周期事件架构:

[sleep timer IRQ]
        |
        v
周期事件 (combine_key 20ms / led / battery / usb / switch / ble_period*)
        |
        +-- 可投递一次性事件 --> app_event_queue_put()
                                        |
                                        v
主循环 while(1): app_event_queue_handle()
        |
        +-- 队列有事件 -->  g_app_event_queue[] 执行 callback
        +-- 队列空     --> 阻塞等待

* ble_period  PRF 模式下由 app_prf_mode_init() 停止, deinit 时恢复

PRF模式注意: app_prf_mode_init()app_period_event_stop(ble_period_event),避免 PRF 模式下 BLE 周期任务占用事件队列;退出 PRF 时在 app_prf_mode_deinit() 中恢复。

模式切换逻辑:

void app_work_mode_deinit(void)
{
    switch (orgin_app_work_mode) {
    case app_usb_mode:
        app_usb_mode_deinit();
        app_slptmr_stop();
        break;
    case app_prf_mode:
        app_slptmr_stop();
        app_prf_mode_deinit();
        break;
    case app_ble_mode:
        app_ble_mode_deinit();
        app_slptmr_stop();
        break;
    // ...
    }
    orgin_app_work_mode = app_work_mode;
}

void app_work_mode_init(void)
{
    switch (app_work_mode) {
    case app_usb_mode:
        app_usb_mode_init();
        app_rate_init();
        app_slptmr_init(app_rate);
        break;
    case app_prf_mode:
        app_prf_mode_init();
        app_prf_pair_init();     // 初始化配对状态
        app_rate_init();
        app_slptmr_init(app_rate);
        break;
    case app_ble_mode:
        app_ble_mode_init();
        app_ble_mode_start();    // 启动BLE广播
        app_rate = 125;
        app_slptmr_init(app_rate);
        break;
    // ...
    }
}

6.2.3 事件驱动架构

mult_ms 采用事件队列 + 周期事件双层调度:一次性事件入 g_app_event_queue,周期任务由 sleep timer 驱动并在回调中可投递事件。

一次性事件类型(app_event_queue.h / app_event_table.c):

enum event_e {
    mode_change_event = 0,       // 模式切换
    ble_id_change_event,         // BLE 多设备 ID 切换
    wireless_repair_event,       // 重新配对(2.4G/BLE)
    standby_m1_event,            // Standby M1
    deepsleep_event,             // Deepsleep
    rate_change_event,           // 上报率切换
    usb_detect_event,            // USB 插拔检测
    ble_hid_transfer_send_event, // BLE HID 发送
    ble_pair_info_event,         // BLE 配对信息处理
    ble_reload_adv_event,        // BLE 重新加载广播
#if CONFIG_PRF_RF_TRANSFE_DEBUG
    prf_stats_print_event,       // PRF 1s 统计打印(异步)
#endif
#if (CONFIG_DONGLE_TYPE == PAIR_WITH_COMMON_DONGLE)
    prf_regroup_event,           // 分片重组完成
    prf_usb_ep3_handle_event,    // Dongle 回传 EP3 数据
#endif
    event_max                    // 队列深度 APP_EVENT_QUEUE_LEN_MAX=10
};

周期事件类型(enum period_event_e, ID 130+):

事件

周期

回调

说明

combine_key_period_event

20ms

app_combine_key_handle

组合键扫描

battery_check_period_event

可配

app_battery_check

电量更新

led_period_event

可配

app_led_handle

LED 闪烁

ble_period_event

可配

app_ble_handle

BLE 状态机;PRF 模式下停止

usb_period_event

可配

app_usb_handle

USB HID

switch_detect_period_event

可配

app_mode_switch_detect

三模拨动检测

事件处理主循环:

void app_event_queue_handle(void)
{
    uint8_t event;

    if (app_event_queue_get(&event)) {
        /* 在 g_app_event_queue[] 中查找 event 并调用 callback */
        for (i = 0; i < event_max; i++) {
            if (g_app_event_queue[i].event == event) {
                g_app_event_queue[i].callback();
                break;
            }
        }
    }
}

典型事件链路示例:

  • 组合键 左+中+右(重新配对)wireless_repair_eventapp_wireless_repair()app_prf_repair() / app_ble_repair()

  • 组合键 中键 2srate_change_eventapp_rate_change()

  • PRF 调试开启时,sleep timer 每秒投递 prf_stats_print_event,打印含 hop_trig/hop_tms/动态功率统计

优势:

  • 单线程模型,避免资源竞争

  • 事件优先级清晰,易于调试

  • 低功耗友好,无事件时可进入休眠

6.2.4 低功耗管理

休眠控制接口:

用户可以使用idle线程控制vApplicationIdleHook,也可以使用API user_is_sleep_allow接口控制休眠状态为deepsleep或者wfi sleep。

默认使用API接口控制并且关闭了idle线程。

Deepsleep钩子函数:

deepsleep前后拉了IO可以debug睡眠时间状态:

CONFIG_RAM_CODE void vSocDeepSleepEnterHook(void)
{
    // This hook function executes right before SoC entering DeepSleep Mode.
    APP_TRACK_CHN0_LOW  // 拉低IO,标记进入深睡
}

CONFIG_RAM_CODE void vSocDeepSleepExitHook(void)
{
    // This hook function executes right after SoC waking up from DeepSleep Mode.
    APP_TRACK_CHN0_HIGH  // 拉高IO,标记退出深睡
    
    #if !APP_CONN_EVEN_CB_EN
    if (app_work_mode == app_ble_mode) {
        app_ble_trigger_send_data();  // BLE模式下触发数据发送
    }
    #endif
}

低功耗状态机:

状态

描述

唤醒源

Active

活跃工作状态

-

Idle

空闲状态(WFI)

中断

DeepSleep

深度睡眠(RAM保持)

GPIO/WDT/LPTIMER

Standby M1

待机模式(RAM不保持)

GPIO

6.2.5 2.4G PRF模块

初始化流程(app_prf_mode_init):

void app_prf_mode_init(void)
{
    memset(&prf_state, 0, sizeof(prf_state));

    app_period_event_stop(ble_period_event);  // PRF 模式停止 BLE 周期任务

    sem_prf_data = xSemaphoreCreateBinary();
    app_prf_dongle_init();

    /* 发送环形缓冲: 7字节 × 30 包 (PRF_PERIPHERAL_DATA_NUMBER=30) */
    ring_buf_init(&g_prf_tx_ring_buf,
        PRF_PERIPHERAL_DATA_SIZE * PRF_PERIPHERAL_DATA_NUMBER, &g_tx_buf[0][0]);

    app_ble_phy_host_init_once();
    mode_change_protect_reset();
    PRI_RF_ChipModeSel(PRI_RF, PRI_RF_CHIP_MODE_297);
    panchip_prf_init(&tx_config);
    panchip_prf_set_chn(tx_config.rf_channel);
    panchip_prf_pid_cfg(&tx_config, 0);
    panchip_prf_rx_length_irq_cfg(ENABLE);

    app_prf_thread_init();  // CONFIG_PRF_THREAD_EN=1 时创建独立 PRF 任务
}

反初始化(app_prf_mode_deinit): 等待 PRF idle → 删除 PRF 任务 → app_period_event_start(ble_period_event) 恢复 BLE 周期任务。

发送缓冲: g_prf_tx_ring_buf 容量 30 包(每包 7 字节 HID 采样);满时新采样丢弃,不覆盖旧数据。

RF 调试统计(CONFIG_PRF_RF_TRANSFE_DEBUG=1): 每秒异步打印一行,含 hop_trig(跳频触发次数)、hop_tms(跳频后首次 ACK 次数)及动态功率字段;详见 6.1.5.1

PRF线程(可选):

void app_prf_thread_init(void)
{
    static bool prf_thread_inited = false;
    
    if (prf_thread_inited) {
        return;
    }
    prf_thread_inited = true;
    
    /* Create an PRF Task */
    int r = xTaskCreate(task_prf_entry,     // Task Function
                        "task_prf",         // Task Name
                        300,                // Task Stack Size
                        NULL,               // Task Parameter
                        7,                  // Task Priority
                        &task_prf_hd        // Task Handle
                        );
    
    /* Check if task has been successfully created */
    if (r != pdPASS) {
        APP_LOG_INFO("Error, PRF Task created failed!\n");
        while (1);
    }
}

关键特性:

  • 根据使用场景主要用到了sleep timer irq trigger组包

  • RF中断处理重传或者动态配置可以进入deepsleep

  • 发包状态下始终控制不休眠状态稳定

6.2.6 BLE模块

初始化流程:

void app_ble_mode_init(void)
{
    // 确保芯片模式为BLE
    app_ble_ensure_chip_mode();
    
    // 初始化BLE Host线程(内部创建)
    pan_ble_stack_init(app_ble_pre_init_cb, app_ble_enabled_cb);
    
    // 初始化BLE线程
    app_ble_thread_init_once();
}

void app_ble_ensure_chip_mode(void)
{
    APP_LOG_INFO("bleprph_on_sync chip mode1 %d\n", 
                 PRI_RF_GetChipMode(PRI_RF));
    
    // 切换到BLE芯片模式
    PRI_RF_ChipModeSel(PRI_RF, PRI_RF_CHIP_MODE_BLE);
    
    APP_LOG_INFO("bleprph_on_sync chip mode1 %d\n", 
                 PRI_RF_GetChipMode(PRI_RF));
}

连接参数调整:

动态修改latency以降低功耗:

void app_ble_change_latency(uint16_t itvl_min, uint16_t itvl_max, 
                            uint16_t latency, uint16_t supervision_timeout)
{
    APP_LOG_INFO("latency %d change\n", latency);
    
    struct ble_gap_upd_params upd_params = {
        .itvl_min = itvl_min,
        .itvl_max = itvl_max,
        .latency = latency,
        .supervision_timeout = supervision_timeout,
    };
    
    ble_gap_update_params(peri_conn_handle, &upd_params);
}

BLE线程:

static void app_ble_thread_init_once(void)
{
    static bool app_ble_thread_inited = false;
    
    if (app_ble_thread_inited) {
        return;
    }
    app_ble_thread_inited = true;
    
    // 注册连接事件关闭回调(trigger组包使用)
    #if APP_CONN_EVEN_CB_EN
    pan_misc_register_conn_evt_close_cb(
        (pan_conn_evt_close_cb_t)app_conn_evt_close_cb);
    #endif
}

关键接口:

  • 广播接口:重新配对等处理参考代码调度

  • 不复位切换需要注意处理好蓝牙状态,线程调度状态

  • 动态改latency接口用于功耗优化

6.3 主要数据结构

6.3.1 工作状态枚举

enum app_work_mode_t {
    app_null_mode,      // 0: 无效模式
    app_charge_mode,    // 1: 充电模式
    app_usb_mode,       // 2: USB有线模式
    app_prf_mode,       // 3: 2.4G PRF模式(默认)
    app_ble_mode,       // 4: BLE蓝牙模式
    app_emi_mode,       // 5: EMI测试模式
};

6.3.2 PRF状态结构

struct prf_state_t {
    volatile bool init;              // 初始化标志
    volatile bool stored_pair;       // 已存储配对信息
    volatile bool pairing;           // 正在配对
    volatile bool connect;           // 已连接
    volatile bool ack_done;          // ACK完成
    volatile bool trx_flag;          // 收发标志
    volatile uint16_t trx_wait_irq_cnt;  // 收发等待中断计数
    
    uint8_t own_addr[6];             // 本机MAC地址
    uint8_t private_rf_addr[4];      // 私有RF地址
    uint8_t dg_type_addr[7];         // Dongle类型+地址
    uint16_t private_rf_channel[8];  // 私有跳频频点
    volatile uint8_t channel_index;  // 当前频点索引
    
    uint16_t ack_lost_cnt;           // ACK丢失计数
    uint16_t hop_cnt;                // 跳频触发计数(日志 hop_trig)
    uint16_t hop_tms;                // 跳频后首次有效ACK计数
    volatile bool hop_recover_pending; // 跳频后等待首次ACK标志
    uint16_t ch_ack_cnt[8];          // 各频点ACK统计
    uint16_t tx_new_seq_cnt;         // 新seq发送计数
    uint16_t tx_retx_cnt;            // 重传计数
    uint16_t ack_rx_cnt;             // ACK接收计数
    uint16_t rx_test_cnt;            // RX测试计数
    uint16_t valid_rx_test_cnt;      // 有效RX测试计数
    uint16_t tx_test_cnt;            // TX测试计数
    uint16_t tx_irq_test_cnt;        // TX中断测试计数
    uint16_t timout_test_cnt;        // 超时测试计数
    uint16_t crc_test_cnt;           // CRC错误计数
    uint16_t pid_test_cnt;           // PID错误计数
    uint16_t rx_len_err_test_cnt;    // RX长度错误计数
    uint16_t sensor_test_cnt;        // 传感器测试计数
    uint16_t keep_work_time;         // 保持工作时间
    volatile uint32_t trx_idle_cnt;  // 收发空闲计数
    volatile uint32_t ack_err_cnt;   // ACK错误计数
    volatile uint32_t prf_trx_time;  // PRF收发时间
};

6.3.3 配对控制结构

typedef struct {
    volatile enum prf_stage work_stage;  // 工作阶段
    volatile bool prf_retransmit;        // 重传使能
    volatile bool prf_pid;               // PID使能
    volatile bool pad_data_flag;         // 填充数据标志
    volatile bool no_data_flag;          // 无数据标志
    volatile bool empty_flag;            // 空数据标志
    volatile bool dongle_read_flag;      // Dongle读取标志
} prf_ctrl_t;

7 RAM/Flash资源使用情况

PAN107x资源配置:

Flash Total: 508 KB (0x7F000)
SRAM Total:  48 KB (0xC000)

实际使用情况(当前配置):

Memory Region

Start Address

Used Size

Region Size

%age Used

FLASH_TEXT

0x0000A200

182,254 B

220.00 KB

80.90%

SRAM_DATA_TEXT

0x20000000

47,280 B

48.00 KB

96.19%

说明:

  • Flash占用: 182,254字节 ≈ 178.0 KB (包含Bootloader + App代码和数据)

  • RAM占用: 47,280字节 ≈ 46.2 KB (包含系统栈、堆、BLE协议栈和应用数据)

  • Flash分区: Bootloader(40KB) + App(220KB) + Backup(220KB) + KV Store(16KB) + User(12KB) = 508KB

  • RAM紧张: SRAM使用率已达96.19%,接近上限,需注意内存优化

资源优化建议:

  1. Flash优化:

    • 关闭日志(PAN_LOG_ENABLE=0): 节省约11KB

    • 关闭调试信息(APP_LOG_TRACE_OUTPUT_EN=0): 节省约3KB

    • 移除未使用的功能模块(如ARGB): 节省约5-10KB

  2. RAM优化:

    • 减小任务栈大小(谨慎操作,需测试稳定性)

    • 关闭未使用的LL RAM选项

    • 减小OS堆大小(configTOTAL_HEAP_SIZE): 当前9000字节

    • 关闭malloc失败Hook(configUSE_MALLOC_FAILED_HOOK=0): 节省少量RAM

  3. 当前配置特点:

    • 使能Bootloader(CONFIG_ENABLE_BOOTLOADER=1)

    • 使能独立PRF线程(CONFIG_PRF_THREAD_EN=1)

    • 使能BLE Host(CONFIG_BT_MAX_NUM_OF_PERIPHERAL=1)

    • 默认上报率1000Hz(CONFIG_DEFAULT_REPORT_RATE=3)

    • 这些配置都会增加RAM占用

8 已知问题

实体鼠标中,已知问题(待进一步优化软件硬件):

No

问题描述

影响

解决方案/状态

1

某些硬件测试到过蓝牙切USB导致跳线

模式切换异常

硬件改版后改善

2

某些2628硬件配对交互35B性能不一致

配对稳定性

软件优化中

3

2.4G强干扰下小概率CRC误判

数据传输错误

需软硬件协同优化(详见下文)

4

传感器精确度需要进一步确认

定位精度

待测试验证

5

功耗仍有优化空间

电池续航

通过延长deepsleep方式为主要优化点

6

BLE唤醒后reset,广播异常发不出

重连失败

需chip reset恢复,临时方案

8.1 2.4G强干扰下CRC误判问题

8.1.1 问题现象

在以下极端条件下,有极小概率出现CRC16校验通过但数据内容错误的情况:

  1. 硬件收发质量略差:

    • RF前端匹配不佳(天线/电感/电容参数偏差)

    • PCB布局不合理(RF走线过长/阻抗不连续)

    • 电源噪声较大(LDO纹波/DCDC开关噪声)

  2. 空中强干扰环境:

    • WiFi密集区域(多个AP同时工作,信道重叠)

    • 蓝牙设备密集(办公区大量BLE设备)

    • 微波炉/无线电话等2.4G干扰源附近

    • 长时间挂测(数小时~数天持续运行)

  3. 典型表现:

    [正常情况]
    TX: {0x05, 0x01, 0x02, 0x03}  → CRC16 = 0xABCD
    RX: {0x05, 0x01, 0x02, 0x03}  → CRC16 = 0xABCD ✓ 数据正确
    
    [异常情况 - 极小概率]
    TX: {0x05, 0x01, 0x02, 0x03}  → CRC16 = 0xABCD
    RX: {0x05, 0xFF, 0x02, 0x03}  → CRC16 = 0xABCD ✗ 数据错误但CRC匹配!
    

8.1.2 根本原因分析

CRC16碰撞原理:

CRC16是16位循环冗余校验,理论上存在碰撞可能:

CRC16碰撞概率 ≈ 1 / 2^16 = 1 / 65536 ≈ 0.0015%

但在实际场景中,碰撞概率会显著增加:

  1. 干扰导致比特翻转:

    原始数据: 0x05 0x01 0x02 0x03
               ↓    ↓    ↓    ↓
    干扰翻转: 0x05 0xFF 0x02 0x03  (第2字节从0x01翻转为0xFF)
    
  2. 特定翻转模式可能导致CRC巧合匹配:

    • 多比特同时翻转

    • 翻转位置恰好使CRC多项式计算结果相同

    • RF解调错误导致的系统性偏差

  3. 长时间运行累积效应:

    假设每秒1000个数据包,运行10小时:
    总包数 = 1000 × 3600 × 10 = 36,000,000 包
    
    理论碰撞次数 ≈ 36,000,000 / 65536 ≈ 549 次
    
    但实际上,由于干扰不是随机的,碰撞概率会更高
    

8.1.3 当前状态

问题影响范围:

  • 发生概率: 极低(< 0.001%)

  • 触发条件: 需要硬件收发质量较差 + 强干扰环境 + 长时间运行

  • 影响程度: 偶发鼠标指针跳跃或按键误触发

已采取的措施:

  • 协议层已有CRC16校验,可拦截大部分传输错误

  • 重传机制可在丢包时自动恢复

  • 跳频机制可避开干扰严重的频点

后续优化方向:

  • 应用层增加额外校验机制(如累加和/XOR校验)

  • 优化硬件RF前端设计和PCB布局

  • 增强抗干扰能力(ACK确认/FEC等)

  • 启用crc24校验(已测试挂测3天正常,而实际增大需要考虑和其他设备兼容性及包载荷变长引起上报率略微下降)


优化建议:

  1. 功耗优化:

    • 延长deepsleep时间为主要优化点

    • 使能动态发射功率(CONFIG_PRF_DYN_PWR_EN=1)按距离自动降功率,或手动降低CONFIG_PRF_CONNECT_RF_POWER

    • 关闭不必要的log输出

    • 优化BLE latency参数

  2. 稳定性优化:

    • 统一硬件版本后进行充分测试

    • 优化BLE重连逻辑

    • 改进传感器滤波算法

  3. 性能优化:

    • 调整PRF重传策略

    • 优化跳频阈值

    • 改进数据包调度