当前文档版本为 NDK-v1.1.0,您可以访问当前页面的 开发中 版本以获取最近可能的更新。

Common PRF Dongle

重要

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

1 功能概述

此sample为pan107/pan101上演示通用Dongle配合多个PRF设备(鼠标、键盘等)的接收控制功能。

核心特性:

  • 多设备支持: 支持最多3个PRF设备同时配对到同一个Dongle

  • 多Pipe架构: 利用PAN107的多Pipe地址收取功能,实现并发通信

  • 独立数据通道: 键盘、鼠标、复合设备分别使用独立的ring buffer和USB端点

  • 高上报率: 通过重传机制,多设备场景下仍可保持1000Hz上报率

2 环境要求

  • board: pan107QFN32核心板/ pan101MSOP10核心板 + evb底板

  • uart0: 设置P16,P17作为默认的LOG输出端口,波特率921600

  • USB: 需要使用MPC版本之后USB修复后的芯片(早期版本USB不稳定)

3 编译和烧录

例程位置:

  • PAN107: <home>\nimble\samples\solutions_hid\common_prf_dongle\keil_107x

  • PAN101: <home>\nimble\samples\solutions_hid\common_prf_dongle\keil_101x

使用keil进行打开项目进行编译烧录,需要先移植确认flm文件(modules\hal\panchip\panplat\pan1070\_hal_release\mcu_misc)拷贝至keil安装目录

4 演示说明

4.1 单设备配对流程

  1. Keil全擦芯片后,先编译烧录Boot程序(samples\solutions_hid\bootloader\keil_107x),再烧录common_prf_dongle程序;上电后Dongle进入对码状态(prf_state.pairing=true)

  2. Dongle在2412 MHz公共频点、地址{ 0x7b, 0x41, 0x29, 0x72 }(PIPE0)监听;对码阶段固定公共频点,不跳频

  3. PRF设备(如mult_ms配合pair_with_common_dongle.c)进入强制配对,在相同频点/地址发送7字节对码包:data[0]为设备类型,data[1..6]为本机MAC

  4. Dongle收到对码请求后,通过ACK回复7字节:0xFF(DEVICE_DONGLE_TYPE)+ Dongle MAC[6]

  5. 设备收到Dongle回复后,根据Dongle MAC计算8个私有跳频频点,并将私有地址首字节设为设备类型(0x00/0x01/0x02),后3字节取自Dongle MAC,切换到私有地址通信

  6. Dongle侧:app_slptmr_init(10)1 s后调用mouse_prf_pair_handle(),预配置PIPE0/1/2三路私有接收地址并结束对码;之后按pipe_num在对应PIPE上收发,并在8个私有频点间跳频

4.2 多设备配对示例

演示步骤:

  1. 准备3个PRF设备(例如:1个键盘+1个鼠标+1个复合设备)

  2. 编译下载common_prf_dongle程序到PAN107 Dongle

  3. 第一个设备配对:

    • 复位Dongle,设备1进入配对状态

    • 配对成功后,设备1可以正常通信

  4. 第二个设备配对:

    • 设备1保持连接(使用另一私有地址/Pipe)

    • 设备2进入配对状态

    • 配对成功后,设备2使用不同的设备类型字节(对应另一Pipe槽位)

  5. 第三个设备配对:

    • 重复上述步骤,设备3占用第三个Pipe槽位(PIPE2)

  6. 并发通信:

    • 三个设备可以同时工作,互不干扰

    • 每个设备的数据通过独立的ring buffer传输到USB

上报率表现:

  • 单设备: 可达1000Hz

  • 双设备: 每个设备可达500-1000Hz(取决于重传策略)

  • 三设备: 每个设备约300-500Hz

4.3 设备类型与Pipe映射

对码及通信时,PRF载荷首字节data[0]表示设备类型(app_prf.h):

#define DEVICE_MS_TYPE      0x00  // 鼠标,私有地址首字节0x00 → PIPE0
#define DEVICE_KB_TYPE      0x01  // 键盘,私有地址首字节0x01 → PIPE1
#define DEVICE_LKB_TYPE     0x02  // 左键盘/复合类,私有地址首字节0x02 → PIPE2
#define DEVICE_DONGLE_TYPE  0xFF  // Dongle ACK标识

设备侧对码发送示例(pair_with_common_dongle.c):

uint8_t pair_data[7] = {
    PAIR_COMMON_MOUSE_TYPE,   /* 或 DEVICE_KB_TYPE / DEVICE_LKB_TYPE */
    own_addr[0], own_addr[1], own_addr[2],
    own_addr[3], own_addr[4], own_addr[5],
};

Dongle对码ACK回复(app_prf.c event_rx_fun, prf_state.pairing分支):

ack_payload_ms.data[0] = DEVICE_DONGLE_TYPE;  /* 0xFF */
memcpy(&ack_payload_ms.data[1], prf_state.own_addr, 6);
ack_payload_ms.data_length = PAIR_DATA_LEN;   /* 7 */

连接后USB数据分流由载荷data[3]DATA_TYPE_USB_EPx决定,而非Pipe号直接决定端点。

5 开发说明

5.1 Flash配置及接口说明

PAN107(512K 32pin)芯片作为调试芯片,最终PAN101(仅4个IO:P00 P01作为烧录脚,可以复用;P13 P14作为USB通信线,无Reset脚,reset需要重新上电;16K RAM 256K flash)作为实际使用芯片

为确保PAN107编译的程序可以直接切换到PAN101芯片中

BOOT默认划分40k flash;APP分区PAN107为440k、PAN101为184k,分别在keil_107x/keil_101xsdk_config.h中配置

CONFIG_ENABLE_BOOTLOADER=1:程序从boot启动后跳转到APP编译地址0xA000,需要先进行boot烧录

CONFIG_ENABLE_BOOTLOADER=0:设置0可以将APP编译到0x0地址,rebuild烧录后,芯片不含boot区域

其他配置可以参考,不建议改动

// <h> Flash Partition Config

// <e> Enable Bootloader
// <i> Enable bootloader for current App Project.
// <i> That means, App Image would not be generated (linked) at Flash 0 address, instead, it would be generated (linked) at flash address right after Bootloader Flash Partition.
#define CONFIG_ENABLE_BOOTLOADER                            1

// <o> Bootloader Flash Partition Size (KB)
// <i> Note that partition size should be multiple of 4KB!
#define CONFIG_FLASH_PARTITION_BOOTLOADER_SIZE_KB           40

// <s> Bootloader Project Path (Directory)
// <i> Specify relative or absolute path of Bootloader project.
// <i> NOTE here we should use slash ('/') as path separator instead of backslash ('\')!
#define CONFIG_BOOTLOADER_PROJECT_PATH                      "../../bootloader/keil_107x"

// <e> Forcibly Build Bootloader Project
// <i> Build bootloader project:
// <i> - AFTER current App Image build done
// <i> - BEFORE Bootloader/App image merging (if enabled).
#define CONFIG_FORCE_BUILD_BOOTLOADER_PROJECT               0

// <o> Select Bootloader Build Command
// <i> Here prvides two build commands for selection, they are completely equal with corresponding buttons on Keil UI.
// <0=> Build
// <1=> Rebuild
#define CONFIG_BOOTLOADER_BUILD_COMMAND                     0

// <q> Show Bootloader Build Logs
// <i> Show bootloader build logs in Build Output window of current App project.
#define CONFIG_SHOW_BOOTLOADER_BUILD_LOG                    1
// </e> Forcibly Build Bootloader Project End

// <e> Merge Bootloader and App Into One Single Image
// <i> Copy bootloader image to App 'Images' folder and then merge bootloader and app into one single image.
// <i> It is recommended to flash the Merged Image when using PanLink or JFlash Tool.
#define CONFIG_MERGE_IMAGES                                 1

// <s> Merged Image Name
// <i> Specify the name of generated merged image.
#define CONFIG_MERGED_IMAGE_NAME                            "nImageMerged"
// </e> Enable App Image Header End

// <o> App Flash Partition Size (KB)
// <i> Note that partition size should be multiple of 4KB!
#define CONFIG_FLASH_PARTITION_APP_SIZE_KB                  440

// <o> App Backup Flash Partition Size (KB)
// <i> Note that partition size should be multiple of 4KB!
#define CONFIG_FLASH_PARTITION_APP_BACKUP_SIZE_KB           0

// <o> KVStore Flash Partition Size (KB)
// <i> Note that partition size should be multiple of 8KB!
#define CONFIG_FLASH_PARTITION_KVSTORE_SIZE_KB              16

// <o> User Custom Flash Partition Size (KB)
// <i> Note that partition size should be multiple of 4KB!
#define CONFIG_FLASH_PARTITION_USER_CUSTOM_SIZE_KB          12

samples\solutions_hid\bootloader\keil_107x\project.sct(PAN107)中Boot工程SRAM为48KB;APP工程在keil_101x\project.sct中限制为16KB(PAN101)

#! armcc -E
#include ".\configuration\sdk_config.h"
; PAN107 Bootloader (keil_107x/project.sct)
LOAD_FLASH CONFIG_FLASH_PARTITION_BOOTLOADER_ADDR CONFIG_FLASH_PARTITION_BOOTLOADER_SIZE
{
    FLASH_TEXT +0 { ... }

    SRAM_DATA_TEXT 0x20000000 0x0000C000  // 48KB Common SRAM for PAN107x SoC
    {
        .ANY (+RW +ZI)
        *.o (.ramfunc)
    }
}
; PAN101 App (keil_101x/project.sct)
    SRAM_DATA_TEXT 0x20000000 0x00004000  // 16KB Common SRAM for PAN101x SoC
    {
        .ANY (+RW +ZI)
        *.o (.ramfunc)
    }

以上,确保107芯片上编译验证后可以进行直接切换下载到101芯片中

BOOT跳转注意点:

可以使用 boot工程中BOOT_ENABLE_USB_DFU来控制实现boot升级流程,也可以不使用,最终跳转接口jump_to_app

配对信息存储:

参考common_prf_dongle/prf_dongle代码,配对设备私有地址写入Flash,上电加载;复位后已配对设备可自动重连,无需重新对码。最多支持3路,地址如下:

/* 配对地址Flash存储位置 */
#define PRF_PAIR_ADDR_FLASH_ADDR0   0x32000  // 设备槽位0
#define PRF_PAIR_ADDR_FLASH_ADDR1   0x33000  // 设备槽位1
#define PRF_PAIR_ADDR_FLASH_ADDR2   0x34000  // 设备槽位2

/* 上电读取配对地址 */
FMC_ReadStream(FLCTL, PRF_PAIR_ADDR_FLASH_ADDR0, CMD_DREAD, read_addr0, 6);
FMC_ReadStream(FLCTL, PRF_PAIR_ADDR_FLASH_ADDR1, CMD_DREAD, read_addr1, 6);
FMC_ReadStream(FLCTL, PRF_PAIR_ADDR_FLASH_ADDR2, CMD_DREAD, read_addr2, 6);

/* 配对成功后写入 */
FMC_WriteStream(FLCTL, PRF_PAIR_ADDR_FLASH_ADDR0, &prf_state.pair_private_addr[0][0], 6);
FMC_WriteStream(FLCTL, PRF_PAIR_ADDR_FLASH_ADDR1, &prf_state.pair_private_addr[1][0], 6);
FMC_WriteStream(FLCTL, PRF_PAIR_ADDR_FLASH_ADDR2, &prf_state.pair_private_addr[2][0], 6);

实现接口参考prf_dongleload_pair_addr()/write_pair_addr();common工程扩展为3路(PAIR_MAX_NUM=3)。配合端设备侧(如mult_ms)亦将Dongle信息写入KV,双端均可在复位后恢复连接。

5.2 PRF说明

5.2.1 初始化

pan_prf_config_t rx_config =
{
    .work_mode = (prf_mode_t)PRF_MODE_ENHANCE,
    .chip_mode = (prf_chip_mode_sel_t)PRF_CHIP_MODE_SEL_XN297,
    .trx_mode = (prf_trx_mode_t)PRF_RX_MODE,
    .phy = (prf_phy_t)PRF_PHY_2M,
    .crc = (prf_crc_sel_t)PRF_CRC_SEL_CRC16,
    .src = (prf_scramble_sel_t)PRF_SRC_SEL_EN,
    .mode_conf = (prf_mode_conf_sel_t)PRF_BLE_CONF,
    .rx_timeout = 5000,
    .rf_channel = PAIR_PUBLIC_CHANNEL,  // 2412
    .tx_no_ack = DISABLE,
    .trf_type = (prf_trf_t)PRF_TRF_NORMAL,
    .rx_length = 68,
    .sync_length = 4,
    .crc_include_sync = ENABLE,
    .src_include_sync = ENABLE,
    .sync = PAIR_PUBLIC_ADDR,  // { 0x7b, 0x41, 0x29, 0x72 }
    .pid_manual_flag = ENABLE,
    .tx_power = 9,
    .pipe = PRF_PIPE0,
};


void mouse_prf_init(void)
{
    ana_prf_ldo_en();

    panchip_prf_init(&rx_config);

    /* init not init channel, must init channel after init */
    panchip_prf_set_chn(rx_config.rf_channel);

    /* adr match bit match whole absolutely */
    PRI_RF_SetAddrMatchBit(PRI_RF, 0);
    /* disable pid err isr */
    panchip_prf_pid_cfg(&rx_config, 0);
    /* enable len err isr */
    panchip_prf_rx_length_irq_cfg(ENABLE);

    #if CONFIG_APP_PRF_DBG
    PRI_RF_WRITE_REG_VALUE(PRI_RF, TEST_MUX02, TST_MUX_SELECT_11, 0x14); // tx on
    SYS->P1_MFP |= SYS_MFP_P10_LL_DBG_11;

    PRI_RF_WRITE_REG_VALUE(PRI_RF, TEST_MUX02, TST_MUX_SELECT_09, 0x15); // rx on
    SYS->P0_MFP |= SYS_MFP_P04_LL_DBG_9;

    PRI_RF_WRITE_REG_VALUE(PRI_RF, TEST_MUX02, TST_MUX_SELECT_10, 0x17); // data
    SYS->P0_MFP |= SYS_MFP_P07_LL_DBG_10;

    PRI_RF_WRITE_REG_VALUE(PRI_RF, TEST_MUX03, TST_MUX_SELECT_12, 0x13); // acc match
    SYS->P0_MFP |= SYS_MFP_P05_LL_DBG_12;
    #endif

    mouse_prf_pair_init();

    panchip_prf_trx_start();
}

关键步骤说明:

  1. 全局变量rx_config,部分来源于config文件,部分来源于直接配置,定义好后,panchip_prf_init(&rx_config);会进行除了频点之外的初始化,一定要在之后进行频点设置panchip_prf_set_chn(rx_config.rf_channel);

  2. init后,设置地址全匹配,关闭pid err中断,开启len err中断,rf状态可控,增强型模式下,一定会进行完成r->t/timeout/crc/len err状态,中断内控制好下一次trx start之前进行flash操作、状态控制,不会引起rf死机状态

  3. CONFIG_APP_PRF_DBG(sdk_config.h)控制RF debug引脚(P10-T/P04-R/P05-ACC/P07-RxData),可抓取RF时序;开启后可能影响CRC率,关闭后恢复正常

  4. mouse_prf_pair_init()读取Dongle MAC,加载Flash中已存配对地址(若有),并置pairing=true;mouse_prf_pair_handle()(约1 s后由slptmr触发)根据Dongle MAC预配置PIPE0/1/2私有接收地址:

    for (i = 0; i < PAIR_MAX_NUM; i++) {
        addr_format[0] = i;  /* 0→PIPE0, 1→PIPE1, 2→PIPE2 */
        addr_format[1] = prf_state.own_addr[3];
        addr_format[2] = prf_state.own_addr[4];
        addr_format[3] = prf_state.own_addr[5];
        panchip_prf_set_addr(addr_format, 4, app_pipe_get(i), PRI_RF_MODE_SEL_RX);
    }
    calculate_combo_freq(&prf_state.own_addr[2]);  /* 8个私有频点 */
    
  5. 设置PRI_RF_MODE_SEL_RX地址仅设置接收PIPE,不会设置发送地址,rx isr中需要设置payload并且设置回复时的tx地址,设置发送地址参考

    /* set addr will set the tx addr, if want to ack data from dynamic rx pipe ,rx isr must set tx addr */
    CONFIG_RAM_CODE void app_prf_set_tx_addr(uint8_t *addr)
    {
        #if SET_TX_ADDR_DIRECT
        /* 1.25us */
        uint32_t tx_addr;
    
        tx_addr = (addr[0]) | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
    
        PRI_RF_WRITE_REG_VALUE(PRI_RF, R05_TX_ADDR_L, L32B, tx_addr);
        #else
        /* 6us no used third param */
        panchip_prf_set_addr(addr, 4, PRF_PIPE0, PRI_RF_MODE_SEL_TX);
        #endif
    
    }
    
  6. 最后调用panchip_prf_trx_start()启动RF收发(Dongle初始为RX监听模式)

5.2.2 时间说明

说明比较重要的时间量取参数:

prf_dg_time

  1. Timeout中断延迟: timeout debug信号结束到进入timeout中断约9us

  2. 设置频点时间: 调用panchip_prf_set_chn()约50us

  3. TX启动时间: trx start调用到debug信号拉取到发送出数据约24us

  4. RX转TX时间: Dongle端rx自动转tx发送出ACK约26us

  5. TRX Start执行时间: panchip_prf_trx_start()函数本身执行时间很短(<1us),主要耗时在硬件状态切换

  6. RX ISR中设置TX地址:

    RX中断服务程序中需要设置payload并设置回复时的TX地址。有两种方式:

    • 快速方式: 直接写寄存器,约1.25us

    • 封装接口: 调用panchip_prf_set_addr(),约6us

    即使当前次不能及时设置好地址,依然会在下次配对地址收到数据后在对应地址回复。

/* set addr will set the tx addr, if want to ack data from dynamic rx pipe, rx isr must set tx addr */
CONFIG_RAM_CODE void app_prf_set_tx_addr(uint8_t *addr)
{
    #if SET_TX_ADDR_DIRECT
    /* 1.25us - 直接写寄存器 */
    uint32_t tx_addr;
    tx_addr = (addr[0]) | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
    PRI_RF_WRITE_REG_VALUE(PRI_RF, R05_TX_ADDR_L, L32B, tx_addr);
    #else
    /* 6us - 调用封装接口 */
    panchip_prf_set_addr(addr, 4, PRF_PIPE0, PRI_RF_MODE_SEL_TX);
    #endif
}

5.2.3 多Pipe使用说明

核心优势:

PAN107相对于PAN108,增加了多Pipe地址收取的功能,灵活使用可以实现:

  • 配对地址和多通道地址同时可以收取回复数据

  • 多个主机设备配对同一Dongle,实现一对多通信

  • 主机端最快速度在250us内可以完成发收,通过重传可以做到至少2-3个设备配对同一Dongle后,仍可达到较高上报率

Ring Buffer架构:

common_prf_dongle使用4个独立的ring buffer分别处理不同类型的数据:

// main.c 中定义
struct ring_buf ringbuf_kb;      // 键盘数据缓冲区
struct ring_buf ringbuf_ms;      // 鼠标数据缓冲区
struct ring_buf ringbuf_comp;    // 复合设备数据缓冲区
struct ring_buf ringbuf_custom;  // 自定义数据缓冲区

uint8_t ringbuf_data_kb[RINGBUFFER_SIZE];     // 448字节
uint8_t ringbuf_data_ms[RINGBUFFER_SIZE];     // 448字节
uint8_t ringbuf_data_comp[RINGBUFFER_SIZE];   // 448字节
uint8_t ringbuf_data_custom[RINGBUFFER_SIZE]; // 448字节

USB端点映射:

#define STAND_KB_ENDPOINT       1   // 标准键盘端点
#define COMPOSITE_ENDPOINT      2   // 复合设备端点(包含鼠标Report ID 5)
#define VENDOR_ENDPOINT         3   // 厂商自定义端点(DFU & EMI)

数据流转:

PRF载荷data[3]DATA_TYPE_USB_EPx决定Ring Buffer(prf_data_process()):

  • DATA_TYPE_USB_EP1(0x11) → ringbuf_kb → EP1标准键盘

  • DATA_TYPE_USB_EP2(0x12)且data[4]==0x05ringbuf_ms → EP2鼠标(Report ID 5)

  • DATA_TYPE_USB_EP2(0x12)且data[4]!=0x05ringbuf_comp → EP2复合报告

  • DATA_TYPE_USB_EP3(0x13) → ringbuf_custom → EP3厂商/DFU

多设备配对示例:

  1. 准备3个PRF设备(键盘+鼠标+复合/左键盘),设备侧分别使用DEVICE_KB_TYPE/DEVICE_MS_TYPE/DEVICE_LKB_TYPE

  2. 编译下载common_prf_dongle到PAN107 Dongle(默认PAIR_MAX_NUM=3,无需改宏)

  3. 设备1进入配对,复位Dongle,配对成功 → 占用PIPE0/1/2之一(由设备类型字节决定)

  4. 设备2、设备3依次进入配对,各自占用剩余Pipe槽位

  5. 三设备可同时工作;EP2上报时ringbuf_comp优先于ringbuf_ms

设备类型与Pipe对应关系见 4.3;Ring Buffer分流由运行时data[3]/data[4]决定,见上文。

5.3 USB说明

USB init软件过程基本与PAN108一致,其他部分使用也一致

硬件需要注意,PAN101/PAN107系列早期存在USB有问题版本,接入hub并且在hub上的第一个口通常能识别成功但也不稳定,直插线的方式在大部分电脑上都不能成功识别,一定要选用MPC版本之后USB修复后的芯片

void usb_init(void)
{
    usbd_desc_register(0, hid_descriptor);
    
    // 标准键盘接口
    usbd_add_interface(0, usbd_hid_init_intf(0, &intf0, standard_keyboard_report, DEF_Intface0_ReportDes_SIZE));
    usbd_add_endpoint(0, &hid_intf0_in_ep);
    
    // 复合设备接口(包含鼠标)
    usbd_add_interface(0, usbd_hid_init_intf(0, &intf1, keyboard_report, DEF_Intface1_ReportDes_SIZE));
    usbd_add_endpoint(0, &hid_intf1_in_ep);
    usbd_add_endpoint(0, &hid_intf1_out_ep);
    
    // DFU接口
    usbd_add_interface(0, usbd_hid_init_intf(0, &intf2, dfu_report, DEF_Intface2_ReportDes_SIZE));
    usbd_add_endpoint(0, &hid_intf2_in_ep);
    usbd_add_endpoint(0, &hid_intf2_out_ep);

    usbd_initialize(0, USB_BASE, usbd_event_handler);
}

USB数据上报:

void usb_report(void)
{
    // 检查是否有数据需要上报
    if ((!ring_buf_is_empty(&ringbuf_kb)) || 
        (!ring_buf_is_empty(&ringbuf_ms)) || 
        (!ring_buf_is_empty(&ringbuf_custom)) || 
        (!ring_buf_is_empty(&ringbuf_comp))) {
        
        // 键盘数据上报 (EP1)
        if (((USB->CSR0_INCSR1 & 0X2) == 0) && (!(ring_buf_is_empty(&ringbuf_kb)))) {
            ring_buf_get(&ringbuf_kb, (uint8_t *)&report_len, 1);
            ring_buf_get(&ringbuf_kb, (uint8_t *)&cur_report_data, report_len);
            // 发送到EP1...
        }
        
        // 鼠标/复合设备数据上报 (EP2, comp优先于ms)
        if (((USB->CSR0_INCSR1 & 0X2) == 0) && 
            ((!(ring_buf_is_empty(&ringbuf_ms))) || (!(ring_buf_is_empty(&ringbuf_comp))))) {
            if (!(ring_buf_is_empty(&ringbuf_comp))) {
                ring_buf_get(&ringbuf_comp, ...);
            } else {
                ring_buf_get(&ringbuf_ms, ...);
            }
            // 发送到EP2...
        }
    }
}

6 与prf_dongle的差异对比

特性

prf_dongle

common_prf_dongle

设备支持

单设备或双设备(改PAIR_ONLY_ONE=0)

原生支持3设备(PAIR_MAX_NUM=3)

Ring Buffer

2个(ringbuf_raw, ringbuf_raw2),640字节

4个(kb/ms/comp/custom),448字节

USB端点

简单映射

多端点分离(EP1/EP2/EP3)

设备/Pipe

PIPE0(配对)+PIPE1/2(通信)

PIPE0(配对)+PIPE0/1/2(三设备私有地址)

数据分流

统一buffer

DATA_TYPE_USB_EPx分buffer

Flash存储

2个配对地址(0x32000, 0x33000)

3个配对地址(0x32000–0x34000)

配对结束

收到PIPE数据后结束

slptmr约1 s后mouse_prf_pair_handle()

应用场景

一对一或一对二

一对多(键鼠套件等)

上报率

单设备1000Hz,双设备500Hz+

三设备300-1000Hz(视负载)

主要改进点:

  1. 多设备原生支持: 默认PAIR_MAX_NUM=3,无需像prf_dongle那样改PAIR_ONLY_ONE

  2. 数据类型分离: 通过DATA_TYPE_USB_EPx和独立Ring Buffer/USB端点隔离键盘、鼠标、复合、厂商数据

  3. Pipe架构: 同时监听3路私有地址,配合8频点跳频实现一对多

  4. 扩展性: 预留ringbuf_custom和VENDOR EP3,支持DFU/EMI等厂商协议

7 RAM/Flash资源使用情况

7.1 PAN107x资源配置

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

Common PRF Dongle实际使用情况(PAN107, keil_107x 默认配置):

Memory Region

Start Address

Used Size

Region Size

%age Used

FLASH_TEXT

0x0000A200

41,264 B

440.00 KB

9.16%

SRAM_DATA_TEXT

0x20000000

11,672 B

48.00 KB

23.75%

说明:

  • Flash占用: 41,264字节 ≈ 40.3 KB

  • RAM占用: 11,672字节 ≈ 11.4 KB(含4个Ring Buffer + PRF状态 + USB缓冲)

7.2 PAN101x资源配置

Flash Total: 252 KB (0x3F000)
SRAM Total:  16 KB (0x4000)

Common PRF Dongle实际使用情况(PAN101, keil_101x 默认配置):

Memory Region

Start Address

Used Size

Region Size

%age Used

FLASH_TEXT

0x0000A200

50,500 B

184.00 KB

26.80%

SRAM_DATA_TEXT

0x20000000

13,040 B

16.00 KB

79.59%

说明:

  • Flash占用: 50,500字节 ≈ 49.3 KB

  • RAM占用: 13,040字节 ≈ 12.7 KB

7.3 平台对比分析

PAN107 vs PAN101 资源对比:

平台

Flash总大小

APP分区

SRAM总大小

Common PRF Flash

Common PRF RAM

Flash使用率

RAM使用率

PAN107

508 KB

440 KB

48 KB

40.3 KB

11.4 KB

9.16%

23.75%

PAN101

252 KB

184 KB

16 KB

49.3 KB

12.7 KB

26.80%

79.59%

关键差异:

  1. Flash代码大小: PAN107约40.3KB,PAN101约49.3KB(同功能下101编译体积更大)

  2. RAM占用: PAN107约11.4KB(23.75%),PAN101约12.7KB(79.59%)

  3. SRAM总量: PAN107为48KB,PAN101为16KB

7.4 资源占用分析

Flash主要占用(PAN107/PAN101通用):

  • PRF协议栈: ~15KB

    • 射频驱动和跳频逻辑

    • 多Pipe地址管理

    • 配对协议实现

  • USB HID驱动: ~10KB

    • 3个HID接口描述符(intf0/intf1/intf2)

    • 端点管理和数据转发

  • 多设备管理: ~5KB

    • 设备类型识别逻辑

    • Ring Buffer管理

    • 配对状态机

  • 应用层代码: ~8–17KB

    • PAN107: ~8KB

    • PAN101: ~17KB

RAM主要占用:

  • 4个Ring Buffer: 4 × 448 = 1792字节

    • ringbuf_kb: 键盘数据

    • ringbuf_ms: 鼠标数据

    • ringbuf_comp: 复合设备数据

    • ringbuf_custom: 自定义数据

  • PRF状态管理: ~2KB

    • 多设备连接状态

    • 配对地址数组 (PAIR_MAX_NUM × 6字节)

    • 跳频频点表

  • USB缓冲区: ~3KB

    • USB端点发送缓冲

    • HID报告缓冲

  • 系统栈和堆: ~5–6KB

    • 主循环栈

    • 系统堆内存

    • 全局变量

7.5 优化建议

PAN107平台(推荐配置):可使用完整配置(支持3设备)

  • Flash和RAM余量充足

  • 无需特别优化

  • 可添加更多功能(如日志、调试等)

PAN101平台(可选优化):

如果只需要支持单设备或双设备,可以考虑:

  1. 🔴 减少PAIR_MAX_NUM: 从3改为2或1

    • 节省配对地址数组空间

    • 减少状态管理开销

    • 预计节省: ~512字节 RAM

  2. 🟡 移除未使用的Ring Buffer:

    // 如不需要自定义设备,可注释掉
    // struct ring_buf ringbuf_custom;
    // uint8_t ringbuf_data_custom[RINGBUFFER_SIZE];
    
    • 预计节省: 448字节 RAM + 少量Flash

  3. 🟡 减小Ring Buffer大小:

    #define RINGBUFFER_SIZE    256  // 从448改为256
    
    • 4个Buffer共节省: 4 × 192 = 768字节 RAM

    • 注意: 需测试是否会影响高上报率性能

  4. 🟡 关闭未使用的USB端点:

    • 如不需要厂商自定义功能,可移除EP3

    • 预计节省: ~1KB Flash + ~512字节 RAM

  5. 🔴 关闭日志:

    #define APP_LOG_EN              0   /* sdk_config.h */
    #define CONFIG_UART_LOG_ENABLE  0
    
    • 预计节省: ~2KB Flash + ~1KB RAM

PAN101优化后预期(参考):

优化前: Flash 49.3KB, RAM 12.7KB (79.59%)
优化后: Flash ~45KB, RAM ~10.5KB (~65%)  ← 可按需评估

优化效果对比:

优化项

Flash节省

RAM节省

影响

减少PAIR_MAX_NUM(3→2)

~0.5KB

~0.5KB

最多支持2设备

移除custom buffer

~0.2KB

~0.4KB

无自定义设备支持

减小Ring Buffer(448→256)

~0KB

~0.8KB

可能影响高上报率

关闭日志

~2KB

~1KB

无调试输出

总计

~2.7KB

~2.7KB

RAM约降至65%

7.6 与prf_dongle对比

单设备模式对比(prf_dongle PAIR_ONLY_ONE=1):

工程

平台

Flash占用

RAM占用

特点

prf_dongle

PAN107

~38.8KB

~10.5KB

单设备,简单稳定

common_prf_dongle

PAN107

40.3KB

11.4KB

多设备架构,略多RAM

多设备模式对比(prf_dongle PAIR_ONLY_ONE=0):

工程

平台

Flash占用

RAM占用

特点

prf_dongle

PAN107

~40KB

~11KB

最多2设备

common_prf_dongle

PAN107

40.3KB

11.4KB

最多3设备,独立buffer

结论:

  • common_prf_dongle Flash/RAM略高于单设备prf_dongle,换取3设备与独立Buffer

  • 支持更多设备(3 vs 2)

  • 更适合键鼠套件等多设备场景