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

Solution: Multimode Mouse

重要

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

1 功能概述

此sample为pan108xxb5(64pin芯片)或者pan108xxa3(48pin芯片)在实体鼠标板下的应用

具体支持的feature如下:

  • 通用功能:

    1. 光电传感:通过sensor进行鼠标基础坐标获取,可以通过按键进行切换Sensor DPI切换(PAW3325 800-1600(默认)-2400-3200-6400-12000)

    2. QDEC滚轮模块:支持去抖的正交解码器,反馈鼠标滚轮变化情况

    3. 按键模块:

      a. 基础按键左中右,中键长按1s切换2.4G上报率(1000-500-250-125),左中右长按进行强制对码

      b. 底部具有模式切换键

    4. LED模块:反馈对码情况(2.4G未对码/强制对码快闪黄灯,已存储配对信息慢闪黄灯,已连接RB紫色灯呼吸)

    5. 电量检测:ADC采集电量信息,通过串口反馈电量情况

    6. 供电及模式切换:

      ​ a. 电池供电:底部按键可以切换2.4G模式与蓝牙模式,开关拨到中间中间为断电状态,USB接入PC时为优先级最高的USB模式

      ​ b. USB仅供电:底部按键可以切换2.4G模式与蓝牙模式,中间为保电状态

      ​ c. USB插入PC:USB接入PC时为优先级最高的USB模式

    7. 休眠逻辑:休眠逻辑参考6.1章节说明

  • 2.4G模式(PRF增强型模式)

    1. 跳频:在信号质量不好(连续FREQ_HOP_NOACK_THREHOLD=15个ack未收到)/对码前在8个频点进行跳频

    2. 对码:上电跳频找到dongle端的频点后,通信互发对端的MAC地址后2字节,之后切换到私有地址进行通信

    3. 重传:丢包时会进行重传,以最快速度进行重传直到收到对端回复

    4. ACK:可解析的ACK,具有演示代码

    5. 性能:默认上报率1000的情况下,近距离稳定在990包以上,8-9米稳定在960包以上;近距离可以切换上报率进行测试(可选)

    6. 测试模式(可选):宏控制自动画圈;关闭PWM灯测试功耗;设置功率测试;ACK测试

  • BLE模式

    1. 蓝牙白名单(未用),切换不同设备

    2. 配对,保存

    3. 连接,重连功能

    4. OTA(未使能):与mcuboot配合通过NRF工具进行升级

    5. 性能:133HZ上报率

    6. 性能:兼容性

  • USB模式

    1. 性能:USB2.0最高速率1000hz

    2. 电脑的休眠唤醒

    3. 升级:与mcuboot配合通过USB工具进行升级

  • EMI测试

  • 产线工具设置USB信息及发送单载波

2 环境要求

  • board: pan108xxb5或者pan108xxa3(芯片型号)鼠标板

  • uart (option):overlay中默认P24显示串口log

  • USB升级工具:量产烧录工具\Panchip DFU Tool

  • EMI测试工具:键鼠专用工具\PAN108x工具\PAN108xMouseRFTool

  • USB配置工具及自定义开发消息工具:键鼠专用工具\PAN108x工具\MouseDeviceTool

  • 高速鼠标测试工具:05_TOOLS\键鼠专用工具\第三方工具\鼠标测试工具\Polling Rate Tester App_v1.02.00.exe

3 编译和烧录

例程位置:zephyr\samples_panchip\solutions\multimode_mouse

使用 ZAL 工具可以对其进行编译、烧录、打开 VS Code 调试等操作。关于 ZAL 工具的详细介绍请参考:Zephyr APP Launcher 工具介绍

4 演示说明

芯片全部擦除还原默认状态,准备好烧录multimode_mouse_dongle的接收器

4.1 电池供电模式

  1. 电池上电,鼠标端默认中键关闭状态

  2. 鼠标端开关拨到左边为2.4G模式,黄色灯快闪,插入接收器至PC,黄色灯变为紫色呼吸灯,可以测试鼠标基础功能,最大上报率近距离达到1000,远距离8-9m达到900+,通过按DPI键切换DPI,通过长按中键测试上报率

  3. 鼠标端开关拨到右边为蓝牙模式,浅蓝色灯效,可以在开启蓝牙的PC端搜索到名为Pan_Mouse的蓝牙设备,连接后进行控制,最大可以达到133hz左右

  4. 拔出dongle,鼠标端通过拨动模式切换键再次进入2.4G模式,黄色灯慢闪,插入dongle变为呼吸灯,鼠标功能恢复

  5. 鼠标端通过拨动模式切换键再次进入BLE模式,等待蓝牙重新连接至PC,鼠标功能恢复

  6. 不拔出dongle,鼠标端再次通过拨动模式切换键进入2.4G模式,黄色灯慢闪,随后变为呼吸灯,鼠标功能恢复

  7. 长按左中右3键,黄色灯快闪,进入强制对码模式,此时重新复位dongle,鼠标对码成功呼吸灯启动,鼠标功能恢复

4.2 USB仅供电模式

​ USB供电与鼠标供电区别在于模式切换键在中间档位不断电,灯的状态暂时未固定,验证非断电模式切换正常即可

​ 模式切换键在中间状态下,插入USB供电,参考电池步骤5.6,测试2.4G与蓝牙下鼠标功能恢复

4.3 USB模式(USB插入PC)

​ 在以上任何情况下(电池供电下任何模式或者关闭/电池未供电),插入USB,鼠标变为USB功能,深蓝色灯效,拔出USB退出到插入之前的状态

4.4 测试模式

4.4.1 组合按键测试

按键线程每50ms扫描一次键值

#define KEY_SCAN_INTERVAL_MS                    50

void key_analysis(void)
{
	uint8_t key_value = 0;

	key_get_value(&key_value);
	#if EVB64_TEST
	evb_test_key();
	#endif
	if (mouse_work_mode == mouse_prf_mode) {
		combo_key_detect(key_value);
		unpair_key_detect(key_value);
		report_rate_key_detect(key_value);
	} else if (mouse_work_mode == mouse_usb_mode) {
		combo_key_detect(key_value);
		report_rate_key_detect(key_value);
	} else if (mouse_work_mode == mouse_ble_mode) {
		combo_key_detect(key_value);
		unpair_key_detect(key_value);
		ble_multi_dev_detect(key_value);
	}
	dpi_key_detect(key_value);
	long_press_key_detect(key_value);
	active_key_detect(key_value);
}

void thread_key(void *dummy1, void *dummy2, void *dummy3)
{
	printk("T key %d\n", KEY_THREAD_PRIORITY);
	while (1) {
		k_msleep(KEY_SCAN_INTERVAL_MS);
		key_analysis();
	}
}

组合按键说明

按键

检测时间
0代表短按

2.4G模式

USB模式

蓝牙模式

DPI

0

切换传感器灵敏度

切换传感器灵敏度

切换传感器灵敏度

DPI + L

0

Reboot

Reboot

Reboot

DPI + M

0

显示电压

更新USB VID,PID

显示电压

DPI + R

0

擦除配对 + Reboot

擦除配对 + Reboot

M

1

切换上报率

切换上报率

L + M + R

3

擦除配对 + Reboot

不重启重新配对

M + R

3

自动画圈

自动画圈

自动画圈

R + 4

3

关闭灯效

关闭灯效

关闭灯效

R + 5

3

切换彩虹灯效

空闲进入Deepsleep
会影响灯效

4 + 5

3

键鼠套件模式下
切换键盘

L

0

键鼠套件模式下
模拟上报键盘数据1

5

0

正常模式下
正常键值
键鼠套件模式下
上报键值A

正常键值

正常键值

底部按键

0

切换蓝牙多设备

4.4.2 EMI测试(RF测试模式)

环境要求:

  • PAN1080 鼠标板

  • USB TYPE-C线

  • PAN1080 ToolBox下载

测试说明:

  • TX模式,如下图所示:

    image

    RF TEST TX模式

    发包数必须设为0,当前不支持发包数的设置

  • RX模式,如下图所示:

    image

    RF TEST RX模式

  • TX单载波模式,如下图所示:

    image

    RF TEST 单载波模式

4.5 USB升级(DFU)

USB DFU升级操作可以参考 05_TOOLS\量产烧录工具\Panchip DFU Tool 工具最新版本的帮助内容内的操作说明,以下说明升级需要注意的点及原理

关于boot的文档可以参考https://docs.panchip.com/pan1080dk-doc/latest/docs-zdk/04_dev_guides/zephyr_bootloader_guidance.html

4.5.1 升级原理

SDK 1.0.2 之前的版本,升级通过App程序区的USB EP3端点进行消息交互,联同上位机进行升级流程,可以升级鼠标和dongle程序,但是需要注意识别过程需要正确写入芯片VID PID扫描到已有设备,为保证升级兼容性,rebuild编译后的工程强烈建议app区和controller区同时升级,并且进行app升级进行controller升级

SDK 1.0.2 包括之后的版本,灵活开放了boot区的编译,并默认提供了一种方式,程序区先写入flash flag确保进入强制升级,未退出强制升级之前,芯片重新上电始终会停留在boot区域,确认好固件正确性后可以退出强制升级

SDK 1.1.0 包括之后的版本,编译了两种特殊mcuboot固件(存放于01_SDK\modules\hal\panchip\panplat\pan1080\bootloader),支持boot内DFU升级

  1. bootdfu_for_mouse:支持xxa1编译所有鼠标工程及键盘dongle工程,支持boot内usb升级,支持boot内4k dongle或者8k鼠标的spi透传升级

  2. bootdfu_for_keyboard:支持xxb1编译的keyboard工程,支持boot内usb升级

通过应用层宏CONFIG_MCUBOOT_IMAGE_TYPE可以直接控制编译链接的特殊mcuboot固件,值对应上述固件类型

4.5.2 boot自定义编译说明

如果需要自定义更新mcuboot固件,需要注意以下对应关系,建议操作步骤如下

编译mcuboot,注意控制好相关的宏(CONFIG_MCUBOOT_PAN_USB_DFU或者CONFIG_MCUBOOT_PAN_USB_SPI)开启及编译board的选择

以自定义编译鼠标固件为例

ZAL工具编译mcuboot工程,编译board选择xxa1,提前修改01_SDK\bootloader\mcuboot\boot\zephyr\prj,conf内的宏,之后进行编译,编译后的mcuboot固件会自动替换原有的默认mcuboot固件(不包含任何升级功能)01_SDK\modules\hal\panchip\panplat\pan1080\bootloader\images

此时如果需要使用此编译固件,可以将APP工程内的CONFIG_MCUBOOT_IMAGE_TYPE宏屏蔽,使用默认的值即会使用被替换掉的mcuboot(也可以灵活处理保存到特殊文件夹通过扩展宏自己控制)

4.5.3 注意事项

使用具有保护功能的boot时,boot的VID为0x046D,PID为0xC055,usb name 为 boot dfu

通过上位机工具量产烧录工具\Panchip DFU Tool升级时,可以参考工具内文档说明的步骤进行升级,注意选择支持强制升级的版本

PS

​ 程序run在boot区时,点击重启芯片可以跳转到app区域,程序升级正常之前,重新上电即可继续升级正确固件

4.6 DeviceTool使用

配合上位机工具键鼠专用工具\PAN108x工具\MouseDeviceTool可以进行产线USB信息测试及单载波测试,具体操作可以参考工具内说明文档

默认界面支持自定义消息开发

显示界面可以切换到USB设置测试功能界面

5 开发说明

5.1 架构说明

multi_model_mouse基于zephyr架构,进行多线程编程,线程静态初始化后,根据优先级进行先后初始化,之后各个线程运行至while(1)等待相应的信号量,以此通过控制信号量控制各个线程的调度关系

架构中应用层主要包含

  • 8个线程

    • 电量检测(包含WDT喂狗)

    • 组包(USB/2.4G模式进行应用层ringbuf缓存,蓝牙模式通过host buffer进行缓存(应用层不用处理))

    • 2.4G跳频(重传达到一定次数时,缓存当前数据,切换到调频线程发送跳频包,回复成功后切回发包线程继续上一包发送)

    • 2.4G发包(根据信号量,取出缓存包发送)

    • USB发包(根据信号量,取出缓存包发送)

    • BLE监测线程(监测断连状态及切换latency)

    • EMI线程(根据emi flag处理定时发包等逻辑)

    • 按键检测(实际产品中可以移除)

  • 4个中断

    • TIMER0中断(触发组包)

    • TIMER1中断(1ms刷新灯效)

    • USB中断

    • PRF中断

  • 3个重要接口

    • BLE接口(Zephyr API):FRAME组包后通过调用蓝牙接口进入HOST层进行发包,非阻塞接口,会为ble host填充最多6包数据

      /** @brief Notify attribute value change no wait.
       *
       *  Send notification of attribute value change, if connection is NULL notify
       *  all peer that have notification enabled via CCC otherwise do a direct
       *  notification only the given connection.
       *
       *  The attribute object on the parameters can be the so called Characteristic
       *  Declaration, which is usually declared with BT_GATT_CHARACTERISTIC followed
       *  by BT_GATT_CCC, or the Characteristic Value Declaration which is
       *  automatically created after the Characteristic Declaration when using
       *  BT_GATT_CHARACTERISTIC.
       *
       *  @param conn Connection object.
       *  @param attr Characteristic or Characteristic Value attribute.
       *  @param data Pointer to Attribute data.
       *  @param len Attribute value length.
       *
       *  @return 0 in case of success or negative value in case of error.
       */
      static inline int bt_gatt_notify_no_wait(struct bt_conn *conn,
      				 const struct bt_gatt_attr *attr,
      				 const void *data, uint16_t len)
      
    • USB EP2接口(VENDOR DFU):通过USB中断进入进行DFU升级,EMI测试

      void usb_vendor_ep_out(void)
      
    • 低功耗接口

      • 应用进入低功耗宏(长时间静止后进入Deepsleep)

        CONFIG_PM_MOUSE=y
        
      • 系统空闲进入Deepsleep宏,注意程序默认开启了CONFIG_PM=y,如果不用系统Deepsleep,需要以下四个宏一起屏蔽,蓝牙模式下生效

        开启 系统空闲进入Deepsleep 模式
        ### open CONFIG_PM ###
        CONFIG_PM=y
        #Clock Source is RCL
        CONFIG_BT_CTLR_SLEEP_CLOCK_SOURCE=1
        #Accuracy is 2000ppm
        CONFIG_BT_CTLR_SLEEP_TIMER_ACCURACY=2000
        #Enable RCL Force CALIBRATION
        CONFIG_SOC_FORCE_CALIB_RCL_CLK=y
        ### open CONFIG_PM ###
        
        关闭 系统空闲进入Deepsleep 模式
        ### not open CONFIG_PM ###
        # CONFIG_PM=y
        # #Clock Source is RCL
        # CONFIG_BT_CTLR_SLEEP_CLOCK_SOURCE=1
        # #Accuracy is 2000ppm
        # CONFIG_BT_CTLR_SLEEP_TIMER_ACCURACY=2000
        # #Enable RCL Force CALIBRATION
        # CONFIG_SOC_FORCE_CALIB_RCL_CLK=y
        ### not open CONFIG_PM ###
        

5.2 线程说明

线程定义方式如下,选用静态线程的方式,由于包含多种reboot操作,实际单模式生效可对其他无用线程进行中止操作,线程之间通过信号量进行切换或者挂起

/**
 * @brief Statically define and initialize a thread.
 *
 * The thread may be scheduled for immediate execution or a delayed start.
 *
 * Thread options are architecture-specific, and can include K_ESSENTIAL,
 * K_FP_REGS, and K_SSE_REGS. Multiple options may be specified by separating
 * them using "|" (the logical OR operator).
 *
 * The ID of the thread can be accessed using:
 *
 * @code extern const k_tid_t <name>; @endcode
 *
 * @param name Name of the thread.
 * @param stack_size Stack size in bytes.
 * @param entry Thread entry function.
 * @param p1 1st entry point parameter.
 * @param p2 2nd entry point parameter.
 * @param p3 3rd entry point parameter.
 * @param prio Thread priority.
 * @param options Thread options.
 * @param delay Scheduling delay (in milliseconds), zero for no delay.
 *
 *
 * @internal It has been observed that the x86 compiler by default aligns
 * these _static_thread_data structures to 32-byte boundaries, thereby
 * wasting space. To work around this, force a 4-byte alignment.
 *
 */
#define K_THREAD_DEFINE(name, stack_size,                                \
			entry, p1, p2, p3,                               \
			prio, options, delay)                            \
	K_THREAD_STACK_DEFINE(_k_thread_stack_##name, stack_size);	 \
	struct k_thread _k_thread_obj_##name;				 \
	STRUCT_SECTION_ITERABLE(_static_thread_data, _k_thread_data_##name) = \
		Z_THREAD_INITIALIZER(&_k_thread_obj_##name,		 \
				    _k_thread_stack_##name, stack_size,  \
				entry, p1, p2, p3, prio, options, delay, \
				NULL, name);				 	 \
	const k_tid_t name = (k_tid_t)&_k_thread_obj_##name

根据线程定义,定义了如下几个线程,并在common.h统一管理线程优先级及栈大小

#define BATTERY_THREAD_PRIORITY                     7
#define BATTERY_THREAD_STACKSIZE                    392

#define FRAME_PACK_THREAD_PRIORITY                  2
#define FRAME_PACK_THREAD_STACKSIZE                 656

#define FREQ_HOP_THREAD_PRIORITY                    2
#define FREQ_HOP_THREAD_STACKSIZE                   480

#define PRF_THREAD_PRIORITY                         1
#define PRF_THREAD_STACKSIZE                        512

#define USB_THREAD_PRIORITY                         2
#define USB_THREAD_STACKSIZE                        376

#define BLE_MONITOR_THREAD_PRIORITY                 3
#define BLE_MONITOR_THREAD_STACKSIZE                432

#define EMI_THREAD_PRIORITY                         2
#define EMI_THREAD_STACKSIZE                        368

#define KEY_THREAD_PRIORITY                         8
#define KEY_THREAD_STACKSIZE                        800

5.2.1 BATTERY线程

电量监测线程,ADC_SCAN_INTERVAL_MS = 100 ms的间隔进行电量采集,并同时进行WDT喂狗,监测到低电量会切换灯效,蓝牙模式会准备电量数据,在不移动鼠标时进行上报

5.2.2 FRAME线程

组包线程,以timer为调度周期(给出信号量)(以上报率1000为例,调度周期1ms)

主要处理组包有关逻辑(ringbuffer的填入),组合按键检测(基础按键组包,DPI模式切换,上报率切换,低电量ADC检测)

5.2.3 FREQ_HOP线程

跳频线程,初始化对码线程会触发进入,在收到ACK少的时候会触发,通过信号量与PRF线程存在互斥关系

5.2.4 PRF线程

2.4G主线程,会进行重传处理,在重传条件下收到ACK数量低于阈值进入跳频线程

5.2.5 USB线程

USB线程,USB插入PC时进入,获取组包并且上报

5.2.6 BLE监测线程

监测蓝牙连接状态并处理进入关灯切换空闲deepsleep并更新latency相关逻辑

5.2.7 EMI线程

通过TIMER0触发EMI测试中发包相关逻辑

5.2.8 KEY线程

按键检测线程,相对独立,实际应用中可以移除,按键组合可以参考 4.4.1 组合按键测试

5.3 RF中断说明

5.3.1 RF中断

鼠标端为PRF TX端,增强型模式会在TX后自动转入RX, 中断中主要处理信号量sem_prf_isr的给出及ack_lost_cnt的计数

5.3.2 TIMER中断

TIMER中断产生多线程的控制信号量,并且根据不同上报率切换timer中断间隔

5.4 主要数据结构说明

5.4.1 枚举状态

5.4.1.1 配对状态
enum prf_pair_stat_t {
	prf_pair_start,
	prf_pair_comm,
	prf_pair_addr,
	prf_pair_end,
	prf_paired_private,
	prf_paired_public,
};
5.4.1.2.连接状态
enum ble_connect_stat_t {
	ble_disconnect_stat,
	ble_connect_stat,
};
5.4.1.3 工作模式
enum mouse_work_mode_t {
	mouse_null_mode,
	mouse_usb_mode,
	mouse_prf_mode,
	mouse_ble_mode,
};
5.4.1.4 2.4G RF状态
enum prf_trx_stat_t {
	prf_idle_stat,
	prf_tx_done_stat,
	prf_rx_done_stat,
	prf_rx_timeout_stat,
	prf_rx_crc_err_stat,
	prf_rx_pid_err_stat,
};
5.4.1.5 跳频状态
enum prf_freq_hop_stat_t {
	freq_hop_disconnect_stat,
	freq_hop_connecting_stat,
	freq_hop_done_stat,
};
5.4.1.6 USB状态
enum usb_plug_mode_t {
	usb_plug_in,
	usb_plug_out,
};
5.4.1.7 灯状态
enum mouse_led_stat_t {
	led_unpair_stat,
	led_paired_stat,
	led_low_batt_stat,
	led_prf_connected,
	led_key_stat,
};
5.4.1.8 休眠唤醒低功耗状态
enum mouse_low_power_stat_t {
	active_stat,
	prf_off_stat,
	deep_sleep_v1_stat,
	deep_sleep_v2_stat,
	standby_stat,
};

5.4.2 全局结构

5.4.2.1 组包ring_buf(zephyr)
/**
 * @brief A structure to represent a ring buffer
 */
struct ring_buf {
	uint32_t head;	 /**< Index in buf for the head element */
	uint32_t tail;	 /**< Index in buf for the tail element */
	union ring_buf_misc {
		struct ring_buf_misc_item_mode {
			uint32_t dropped_put_count; /**< Running tally of the
						     * number of failed put
						     * attempts.
						     */
		} item_mode;
		struct ring_buf_misc_byte_mode {
			uint32_t tmp_tail;
			uint32_t tmp_head;
		} byte_mode;
	} misc;
	uint32_t size;   /**< Size of buf in 32-bit chunks */

	union ring_buf_buffer {
		uint32_t *buf32; /**< Memory region for stored entries */
		uint8_t *buf8;
	} buf;
	uint32_t mask;   /**< Modulo mask if size is a power of 2 */

	struct k_spinlock lock;
};
5.4.2.2 传感器结构体
struct sensor_data_t {
	uint8_t motion;
	uint8_t observation;
	uint8_t x_delta_l;
	uint8_t x_delta_h;
	uint8_t y_delta_l;
	uint8_t y_delta_h;
};
5.4.2.3 packet格式结构体

鼠标发送的2.4G帧格式如下

前导码

接入地址

signal

payload

crc

3B

5B

10bit

3/14B

2B

0x550f71

固定的

增强型的字段

跳频对码包/鼠标数据包

16bit crc

其中鼠标Payload为用户可以修改的数据段,Payload中又包含了3个字节的固定数据,其中3个字节的固定数据格式如下

Type

Addr

1B

2B

包的类型:对码跳频包/鼠标包

己端MAC地址后两个字节

Type定义如下

#define PRF_PKT_TYPE_PAIR                          (1 << 0)
#define PRF_PKT_TYPE_FREQ_HOP                      (1 << 1)
#define PRF_PKT_TYPE_MOUSE_DATA                    (1 << 2)

跳频对码包:

header: PRF_PKT_TYPE_FREQ_HOP | PRF_PKT_TYPE_PAIR

跳频包:

header: PRF_PKT_TYPE_FREQ_HOP

数据包:

header: PRF_PKT_TYPE_MOUSE_DATA

另外包含11个字节应用层数据(ringbuf管理的数据结构)

header

key_value

x_value

y_value

roll_value

sequence

rate_pkt_index

reserved

1B

1B

2B

2B

1B

1B

1B

1B

包头

按键

delta X

delta Y

滚轮数据

序列号

上报率

保留扩展位

struct pkt_detect_t {
	int8_t header;
	uint8_t key_value;
	int16_t x_value;
	int16_t y_value;
	int16_t roll_value;
	uint8_t sequence;
	uint8_t rate_pkt_index;
	int8_t reserved;
} __packed;

header数据为0x55为特殊idle数据,非0x55为鼠标数据

用户可以自定义header并自定义后10B数据格式,在dongle端根据header数据进行数据解析

鼠标接受的2.4G ACK数据帧格式如下

前导码

接入地址

signal

payload

crc

3B

5B

10bit

xB

2B

0x550f71

固定的

增强

ACK数据(长度自定义,默认数据长度为0)

16bit crc

用户可以根据需求扩展使用ACK数据

5.4.2.4 收包计数结构体
struct prf_pkt_cnt_t {
	uint32_t tx_cnt;
	uint32_t rx_cnt;
	uint8_t prf_repeat_cnt;
};
5.4.2.5 配对信息结构体
struct pair_ctrl_t {
	enum prf_pair_stat_t prf_pair_stat;
	uint32_t prf_pair_timeout;
	uint8_t pair_own_addr[2];
	uint8_t pair_peer_addr[2];
	bool paired_flag;
};

5.5 主要逻辑图示

5.5.1 鼠标端多线程流程图

5.5.1.1 模式检测及中断、低功耗接口流程图
image

鼠标主框架流程图

5.5.1.2 2.4G主要流程图
image

鼠标2.4G流程图

5.5.1.3 USB主要流程图
image

USB主要流程图

5.5.1.4 其他线程流程图
image

其他线程流程图

5.5.2 2.4G对码重传跳频

5.5.2.1 对码逻辑
image

对码逻辑

5.5.2.2 重传逻辑
image

重传逻辑

5.5.2.3 跳频逻辑
image

跳频逻辑

5.6 键鼠套件(附)

键鼠套件由PAN1080做主设备,可能是鼠标(1000hz),大键盘(125hz),小键盘(125hz)

需要配合配套键盘及配套2628dongle(支持多pipe)使用,PAN2628参考固件及烧录工具可以从05_TOOLS\键鼠专用工具\第三方工具\PAN2628固件工具\combo_usb_dongle获取,源码可联系我司获取

鼠标作为键鼠套件时,需要在commom.c中使能

#define KB_MOUSE_ONEDONLE                          1

5.6.1 配对过程

5.6.1.1 配对参数
  • 鼠标采用公共地址:0x7B, 0x41, 0x29, 0x79

  • 大键盘采用公共地址:0x7C, 0x41, 0x29, 0x79

  • 小键盘采用公共地址:0x7D, 0x41, 0x29, 0x79

  • 公共频点为:

u8 idata channel_list_public[8] =
{
    4, 12, 18, 30, 38, 44, 56, 74
};

dongle采用多pipe模式进行接收:

pipe0接收地址(鼠标):0x7B, 0x41, 0x29, 0x79

pipe1接收地址(大键盘):0x7C, 0x41, 0x29, 0x79

pipe2接收地址(小键盘):0x7D, 0x41, 0x29, 0x79

经以上配置后:

dongle从pipe0接收的数据认为是鼠标数据

dongle从pipe1接收的数据认为是大键盘数据

dongle从pipe2接收的数据认为是小键盘数据

5.6.1.2 配对时序

dongle上电后,配置完RF参数,再依次开启pipe0~pipe2开始接收公共地址的配对信息,dongle根据pipe号来区分是哪个设备发来的配对命令。 以mouse配对为例,mouse上电后,配置完RF参数后,设置RF地址为0x7B, 0x41, 0x29, 0x79,即鼠标的专用配对地址,并以channel_list_public为跳频地址表。之后mouse会发送配对请求包,请求包的格式为:

magic[4B]

命令[1B]

地址[6B]

0x31415926

0x01

mouse mac

dongle收到mouse的配对请求包后:

  1. 如果收到的配对请求命令不正确,则不回复任务消息。

  2. 如果配对请求命令校验正确无误,则回复以下响应:

magic[4B]

命令[1B]

地址[6B]

0x31415926

0x01

dongle mac

dongle收到正确的配对请求后,会将mouse的mac地址写入flash保存下来。

mouse收到dongle配对响应后,核对正确后,会将dongle的地址写入flash保存下来。

mouse写完dongle的mac地址后,会再次发送配对的检查命令,用于检查dongle端是否正确保存mouse的配对信息,命令格式如下:

magic[4B]

命令[1B]

0x31415926

0x02

dongle端收到mouse的检查命令后,如果命令核对不正确,则不回复任何消息。

如果命令核对正确,则回复以下消息:

magic[4B]

命令[1B]

地址[6B]

0x31415926

0x02

mouse mac

mouse端收到dongle的回复后,核对dongle地址无误后,则认为mouse配对过程结束,否则重新开始发送配对请求包,重新以上配对过程,直到配对成功。

以上配对流程总结如下图:

image-20230808135237514

套件配对逻辑

5.6.1.3 配对时间说明
  • dongle上电后,最长配对时间不超过20秒(当前配对时间窗口为3秒)

  • 如果mouse,keyboard都快速配对完成,则dongle不需要等待超时时间到达,提前进入通信流程

5.6.2 数据通信过程

5.6.2.1 私有地址
  • dongle Vs mouse:使用pipe0管道,采用mouse mac[5]和dongle mac[3]~mac[5]组成一个4字节的地址作为通信地址

  • dongle Vs 大键盘:使用pipe1管道,采用大键盘mac[5]和dongle mac[3]~mac[5]组成一个4字节的地址作为通信地址

  • dongle Vs 小键盘:使用pipe2管道,采用小键盘mac[5]和dongle mac[3]~mac[5]组成一个4字节的地址作为通信地址

5.6.2.2 跳频通道

根据dongle地址各自计算私有跳频列表,之后按私有跳频列表来进行跳频通信,跳频方式和之前相同。

5.6.2.3 跳频规则
  • dongle 若10ms内没有收到数据,则产生跳频,规则是切换至下一频道上监听10ms,10ms内没有收到数据,再切换至下一频道继续监听,直到在某个频道到收到数据包,则停止跳频,开始进行数据通信。

  • 设备(mouse,keyboard etc)若连续10包发送不成功,则产生跳频,规则是切换至下一频道并发送数据包,若没有收到ack,再切换至下一频道继续发送数据,直到收到ack,停止跳频。

5.6.2.4 超时时间

以鼠标为例,当鼠标配对完成后,进入数据通信模式,此时dongle可能因为大小键盘还没有完成配对,因此鼠标要设置一个最大数据发送超时时间T0,超出这个时间鼠标还不能进行正常数据通信,鼠标则要进入休眠模式,直到用户唤醒鼠标。

假如dongle设定的最长配对时间T1为5秒,则保证T1大于T0,量化下来T0 = T1 +1秒。

5.6.3 数据格式

5.6.3.1 通信包

鼠标发送的2.4G帧格式如下

前导码

接入地址

signal

payload

crc

3B

4B

10bit

3/11B

2B

0x550f71

固定的

增强型的字段

跳频对码包/鼠标数据包

16bit crc

其中鼠标Payload为用户可以修改的数据段,Payload中又包含了3个字节的固定数据,其中3个字节的固定数据格式如下

Type

Addr

1B

2B

包的类型:对码跳频包/鼠标包

己端MAC地址后两个字节

Type定义如下

#define PRF_PKT_TYPE_PAIR                          (1 << 0)
#define PRF_PKT_TYPE_FREQ_HOP                      (1 << 1)
#define PRF_PKT_TYPE_MOUSE_DATA                    (1 << 2)

跳频对码包:

header: PRF_PKT_TYPE_FREQ_HOP | PRF_PKT_TYPE_PAIR

跳频包:

header: PRF_PKT_TYPE_FREQ_HOP

数据包:

header: PRF_PKT_TYPE_MOUSE_DATA

另外包含11个字节应用层数据(ringbuf管理的数据结构)

5.6.3.2 数据包

应用数据包11字节,通信层包header固定使用PRF_PKT_TYPE_MOUSE_DATA,数据包内容header根据不同场景定义为不同数据

5.6.3.2.1 鼠标数据格式

sequence

header

key_value

x_value

y_value

roll_value

rate_pkt_index

reserved

1B

1B

1B

2B

2B

1B

1B

1B

序列号

0x00

按键

delta X

delta Y

滚轮数据

上报率

保留扩展位

struct pkt_detect_t {
    uint8_t sequence;
	int8_t header;
	uint8_t key_value;
	int16_t x_value;
	int16_t y_value;
	int16_t roll_value;
	uint8_t rate_pkt_index;
	int8_t reserved;
} __packed;
5.6.3.2.2 键盘数据格式

sequence

header

key_data

reserved

1B

1B

8B

1B

序列号

0x01

标准键盘8B数据

保留扩展位

struct pkt_detect_keyboard_t {
	uint8_t sequence;
	int8_t header;
	uint8_t key_data[8];
	int8_t reserved;
} __packed;
5.6.3.2.3 其他数据格式

header数据为0x55为特殊idle数据,非0x55为鼠标数据

用户可以自定义header并自定义后10B数据格式,在dongle端根据header数据进行数据解析

鼠标接受的2.4G ACK数据帧格式如下

前导码

接入地址

signal

payload

crc

3B

5B

10bit

xB

2B

0x550f71

固定的

增强

ACK数据(长度自定义,默认数据长度为0)

16bit crc

用户可以根据需求扩展使用ACK数据

5.6.4 操作说明

PAN2628dongle配套的固件及烧录工具说明可以从05_TOOLS\键鼠专用工具\第三方工具\PAN2628固件工具\multimode_usb_dongle获取烧录

PAN2628源码部分可以联系我司获取

5.6.4.1 1080鼠标代码宏定义键鼠套件 鼠标/键盘 说明
#define KB_MOUSE_ONEDONLE                          0
#if KB_MOUSE_ONEDONLE

	#define KEYBOARD_125HZ                          0
	#if KEYBOARD_125HZ
	#define PRF_PUBLIC_ADDR                         { 0x7c, 0x41, 0x29, 0x79 }
	#else /* 1000hz mouse addr */
	#define PRF_PUBLIC_ADDR                         { 0x7b, 0x41, 0x29, 0x79 }
	#endif

#else
#define PRF_PUBLIC_ADDR                         { 0x7b, 0x41, 0x29, 0x71 }
#endif

KB_MOUSE_ONEDONLE:

  • 默认值为0代表原始单鼠标套件,配对逻辑未修改,使用默认配对地址{ 0x7b, 0x41, 0x29, 0x71 }

  • 设值为1代表键鼠套件,配对逻辑已更新(可以通过此宏定义查看配对逻辑差异)

    KEYBOARD_125HZ:

    • 默认为0代表 键鼠套件1000hz鼠标,使用默认配对地址{ 0x7b, 0x41, 0x29, 0x79 }

    • 设置为1代表 键鼠套件125hz鼠标,使用默认配对地址{ 0x7c, 0x41, 0x29, 0x79 }

5.6.4.2 操作步骤
  1. 准备好2628dongle固件,烧录工程combo_usb_dongle固件,具有mac地址的使用MAC地址完成配对,否则使用默认值进行配对。

  2. 准备2块鼠标板,一块烧录 键鼠套件鼠标A,一块烧录 键鼠套件键盘B

  3. A和B同时进入配对快闪状态,复位dongle,观察AB灯效

  4. A快闪结束,进入断连状态,之后切换为呼吸灯效,B快闪结束,变为慢闪(由于配对完成后键盘不会主动上报数据,不会进入连接状态),B板按键K5,上报键盘数据1之后进入呼吸灯状态

  5. A可以设置为自动画圈状态,同时发送B按键数据,观察B发送包不丢失并且A的1000hz上报率受到轻微影响(测试目前不会掉900以下,基本上维持在980以上)

5.6.5 新增需求(不需要关注,套件键盘文档内说明)

  1. 由于需要支持无冲键盘,数据包长度需要扩充,组包逻辑中,单笔组包数据由11字节扩充为21字节,ringbuf size由11×40扩充为21×40,rf实际通信tx_payload改为24字节。6.3.1章节中rf数据格式payload字段改为21B,6.3.2章节内容统一描述见6.5.1

  2. 键盘需要从无长度ack变化为有长度ack(3B),其中可以自定义扩充回复ack信息(如大小写按键信息的上报),ack始终反馈如实际键盘的实际numlock

5.6.5.1 格式更新

应用数据包21字节,通信层包header固定使用PRF_PKT_TYPE_MOUSE_DATA,数据包内容header根据不同场景定义为不同数据

5.6.5.1.1 鼠标数据格式

sequence

header

key_value

x_value

y_value

roll_value

rate_pkt_index

reserved

1B

1B

1B

2B

2B

1B

1B

11B

序列号

0x00

按键

delta X

delta Y

滚轮数据

上报率

保留扩展位

struct pkt_detect_t {
    uint8_t sequence;
	int8_t header;
	uint8_t key_value;
	int16_t x_value;
	int16_t y_value;
	int16_t roll_value;
	uint8_t rate_pkt_index;
	uint8_t reserved[11];
} __packed;
5.6.5.1.2 键盘数据格式

sequence

header

key_data

reserved

1B

1B

8B

11B

序列号

0x01

标准键盘8B数据

保留扩展位

struct pkt_detect_keyboard_t {
	uint8_t sequence;
	int8_t header;
	uint8_t key_data[8];
	int8_t reserved[11];
} __packed;
5.6.5.1.3 其他数据格式

header数据为0x55为特殊idle数据,非0x55为鼠标数据

用户可以自定义header并自定义后20B数据格式,在dongle端根据header数据进行数据解析

鼠标接受的2.4G ACK数据帧格式如下

前导码

接入地址

signal

payload

crc

3B

5B

10bit

3B

2B

0x550f71

固定的

增强

ACK数据(长度自定义,默认数据长度为3)

16bit crc

用户可以根据需求填写ACK数据

5.6.5.2 参考demo

测试说明:

下载1080键鼠套件键盘程序到鼠标固件,对码后另一键盘按键Caps lock可以看到rgb灯关闭熄灭。

以1080键鼠套件中键盘设备对2628通信格式修改为例,鼠标端端发送长度更新为24,并且在rx中断中解析ack,当ack信息为0x00,0x00,0x01时,打开灯,当ack信息为0x00,0x00,0x001时,关闭灯

键盘模式下 KB_CAPS_LOCK_TEST 打开时默认键盘125hz上报空包,后续也可以改为定时发送空包逻辑来获取ack中键盘LED信息解析

参考代码更新:

1080软件见应用层更新demo,可以通过 KB_CAPS_LOCK_TEST 追溯相关灯控代码

6 补充说明

补充说明当前功耗测试情况,支持中遇到的问题(供参考)及已知仍可能存在的问题

6.1 功耗说明

功耗测试时,左键加中键长按3s关闭灯效进入关灯测试

功耗相关配置

ADC采样配置:No Buffer 模式,100ms,空闲关闭

apb1/2 div分频系数:4/1

2.4G功耗

划线停止10s后(10s内功耗3~5mA(不同上报率不同)),进入一级休眠(<200uA)(目前100uA+),10s后进入二级休眠(<60uA);一、二级休眠状态均可随时移动/按键唤醒(2级休眠逻辑上多了LP TIMER唤醒);

设备

上报率

状态1(mA)

状态2 (mA)

状态3 (uA)

状态4 (uA)

自动画圈(mA)

鼠标B

1000

12.44

3.24

0.09

35

7.1

鼠标B

500

10.11

3.06

0.09

35

4.96

鼠标B

250

8.73

2.88

0.09

35

3.81

鼠标B

125

8.13

2.79

0.09

35

3.25

状态1:关灯,手滑

状态2:移动停止3s后,关闭RF

状态3:30s后deepsleep ,传感器唤醒,rcl唤醒

状态4:60s后deepsleep,按键唤醒

蓝牙功耗

BLE:划线停止后(此状态维持30s,关闭灯效情况下,空闲进入deepsleep,interval保持7.5mS,功耗3mA),进入保持蓝牙连接的一级休眠(<200uA)(方便测试目前设置维持30s,目前500uA+,latency 120mS),10min后进入断开蓝牙连接的二级休眠(进入standby,移动可以唤醒,功耗100uA左右); 一、二级休眠状态均可随时移动/按键唤醒;(一级相当于idle deepsleep,二级为standby),二级休眠唤醒后蓝牙自动重连时间低于500ms;

设备

上报率

状态1(mA)

状态2 (mA)

状态3 (uA)

状态4(uA)

自动画圈(mA)

鼠标B

133

4.43

2.48

384.52

102

3.85

状态1:关灯,手滑

状态2:不移动 持续BLE_LED_OFF_S(30)s

状态3:关灯,修改latency(120ms),idle deepsleep状态,持续到BLE_IDLE_SLEEP(60)s,保持连接,移动按键唤醒

状态4:BLE_IDLE_SLEEP(60)s后断链 进入standby移动按键唤醒

6.2 蓝牙启动时间说明

2.4G和蓝牙启动需要对controller进行初始化,controller初始化时间可以由log观测,目前测试启动时间为66ms

6.3 已知问题

No

已知问题

目前状态

1

休眠模式下切换模式过快需要复位

由于鼠标处于休眠状态,切换模式本应该经过断电状态,但如果切换过快,休眠状态放电不充分,芯片不能完全断电复位,仍处于休眠状态,此时唤醒可以恢复对应模式的正常运行状态

7 RAM/Flash资源使用情况

FLASH部分包含蓝牙controller固定资源120K,不包含初始位置开始的60K MCUBOOT程序,FLASH资源由于mcuboot内已支持升级功能,实际可用大小可以扩展152K

Memory region

Used Size

Region Size

%age Used

FLASH

125700 B

152 KB

80.76%

SRAM

38602 B

50 KB

75.39%