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_107xPAN101:
<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 单设备配对流程¶
Keil全擦芯片后,先编译烧录Boot程序(
samples\solutions_hid\bootloader\keil_107x),再烧录common_prf_dongle程序;上电后Dongle进入对码状态(prf_state.pairing=true)Dongle在2412 MHz公共频点、地址
{ 0x7b, 0x41, 0x29, 0x72 }(PIPE0)监听;对码阶段固定公共频点,不跳频PRF设备(如
mult_ms配合pair_with_common_dongle.c)进入强制配对,在相同频点/地址发送7字节对码包:data[0]为设备类型,data[1..6]为本机MACDongle收到对码请求后,通过ACK回复7字节:
0xFF(DEVICE_DONGLE_TYPE)+ Dongle MAC[6]设备收到Dongle回复后,根据Dongle MAC计算8个私有跳频频点,并将私有地址首字节设为设备类型(0x00/0x01/0x02),后3字节取自Dongle MAC,切换到私有地址通信
Dongle侧:
app_slptmr_init(10)约1 s后调用mouse_prf_pair_handle(),预配置PIPE0/1/2三路私有接收地址并结束对码;之后按pipe_num在对应PIPE上收发,并在8个私有频点间跳频
4.2 多设备配对示例¶
演示步骤:
准备3个PRF设备(例如:1个键盘+1个鼠标+1个复合设备)
编译下载
common_prf_dongle程序到PAN107 Dongle第一个设备配对:
复位Dongle,设备1进入配对状态
配对成功后,设备1可以正常通信
第二个设备配对:
设备1保持连接(使用另一私有地址/Pipe)
设备2进入配对状态
配对成功后,设备2使用不同的设备类型字节(对应另一Pipe槽位)
第三个设备配对:
重复上述步骤,设备3占用第三个Pipe槽位(PIPE2)
并发通信:
三个设备可以同时工作,互不干扰
每个设备的数据通过独立的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_101x的sdk_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_dongle的load_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();
}
关键步骤说明:
全局变量
rx_config,部分来源于config文件,部分来源于直接配置,定义好后,panchip_prf_init(&rx_config);会进行除了频点之外的初始化,一定要在之后进行频点设置panchip_prf_set_chn(rx_config.rf_channel);init后,设置地址全匹配,关闭pid err中断,开启len err中断,rf状态可控,增强型模式下,一定会进行完成
r->t/timeout/crc/len err状态,中断内控制好下一次trx start之前进行flash操作、状态控制,不会引起rf死机状态CONFIG_APP_PRF_DBG(sdk_config.h)控制RF debug引脚(P10-T/P04-R/P05-ACC/P07-RxData),可抓取RF时序;开启后可能影响CRC率,关闭后恢复正常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个私有频点 */
设置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 }
最后调用
panchip_prf_trx_start()启动RF收发(Dongle初始为RX监听模式)
5.2.2 时间说明¶
说明比较重要的时间量取参数:

Timeout中断延迟: timeout debug信号结束到进入timeout中断约9us
设置频点时间: 调用
panchip_prf_set_chn()约50usTX启动时间: trx start调用到debug信号拉取到发送出数据约24us
RX转TX时间: Dongle端rx自动转tx发送出ACK约26us
TRX Start执行时间:
panchip_prf_trx_start()函数本身执行时间很短(<1us),主要耗时在硬件状态切换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]==0x05→ringbuf_ms→ EP2鼠标(Report ID 5)DATA_TYPE_USB_EP2(0x12)且data[4]!=0x05→ringbuf_comp→ EP2复合报告DATA_TYPE_USB_EP3(0x13) →ringbuf_custom→ EP3厂商/DFU
多设备配对示例:
准备3个PRF设备(键盘+鼠标+复合/左键盘),设备侧分别使用
DEVICE_KB_TYPE/DEVICE_MS_TYPE/DEVICE_LKB_TYPE编译下载
common_prf_dongle到PAN107 Dongle(默认PAIR_MAX_NUM=3,无需改宏)设备1进入配对,复位Dongle,配对成功 → 占用PIPE0/1/2之一(由设备类型字节决定)
设备2、设备3依次进入配对,各自占用剩余Pipe槽位
三设备可同时工作;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 |
|---|---|---|
设备支持 |
单设备或双设备(改 |
原生支持3设备( |
Ring Buffer |
2个( |
4个(kb/ms/comp/custom),448字节 |
USB端点 |
简单映射 |
多端点分离(EP1/EP2/EP3) |
设备/Pipe |
PIPE0(配对)+PIPE1/2(通信) |
PIPE0(配对)+PIPE0/1/2(三设备私有地址) |
数据分流 |
统一buffer |
按 |
Flash存储 |
2个配对地址(0x32000, 0x33000) |
3个配对地址(0x32000–0x34000) |
配对结束 |
收到PIPE数据后结束 |
slptmr约1 s后 |
应用场景 |
一对一或一对二 |
一对多(键鼠套件等) |
上报率 |
单设备1000Hz,双设备500Hz+ |
三设备300-1000Hz(视负载) |
主要改进点:
多设备原生支持: 默认
PAIR_MAX_NUM=3,无需像prf_dongle那样改PAIR_ONLY_ONE数据类型分离: 通过
DATA_TYPE_USB_EPx和独立Ring Buffer/USB端点隔离键盘、鼠标、复合、厂商数据Pipe架构: 同时监听3路私有地址,配合8频点跳频实现一对多
扩展性: 预留
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% |
关键差异:
Flash代码大小: PAN107约40.3KB,PAN101约49.3KB(同功能下101编译体积更大)
RAM占用: PAN107约11.4KB(23.75%),PAN101约12.7KB(79.59%)
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平台(可选优化):
如果只需要支持单设备或双设备,可以考虑:
🔴 减少
PAIR_MAX_NUM: 从3改为2或1节省配对地址数组空间
减少状态管理开销
预计节省: ~512字节 RAM
🟡 移除未使用的Ring Buffer:
// 如不需要自定义设备,可注释掉 // struct ring_buf ringbuf_custom; // uint8_t ringbuf_data_custom[RINGBUFFER_SIZE];
预计节省: 448字节 RAM + 少量Flash
🟡 减小Ring Buffer大小:
#define RINGBUFFER_SIZE 256 // 从448改为256
4个Buffer共节省: 4 × 192 = 768字节 RAM
注意: 需测试是否会影响高上报率性能
🟡 关闭未使用的USB端点:
如不需要厂商自定义功能,可移除EP3
预计节省: ~1KB Flash + ~512字节 RAM
🔴 关闭日志:
#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)
更适合键鼠套件等多设备场景