Solution: Multi Model Mouse¶
重要
此例程仅存在于特殊版本的SDK中,如有需要请联系Panchip。
1 功能概述¶
此sample为pan108xxb5
(64pin芯片)或者pan108xxa3
(48pin芯片)在实体鼠标板下的应用
具体支持的feature如下:
通用功能:
光电传感:通过sensor进行鼠标基础坐标获取,可以通过按键进行切换Sensor DPI切换(PAW3325 800-1600(默认)-2400-3200-6400-12000)
QDEC滚轮模块:支持去抖的正交解码器,反馈鼠标滚轮变化情况
按键模块:
a. 基础按键左中右,中键长按1s切换2.4G上报率(1000-500-250-125),左中右长按进行强制对码
b. 底部具有模式切换键
LED模块:反馈对码情况(2.4G未对码/强制对码快闪黄灯,已存储配对信息慢闪黄灯,已连接RB紫色灯呼吸)
电量检测:ADC采集电量信息,通过串口反馈电量情况
供电及模式切换:
a. 电池供电:底部按键可以切换2.4G模式与蓝牙模式,开关拨到中间中间为断电状态,USB接入PC时为优先级最高的USB模式
b. USB仅供电:底部按键可以切换2.4G模式与蓝牙模式,中间为保电状态
c. USB插入PC:USB接入PC时为优先级最高的USB模式
2.4G模式(PRF增强型模式)
跳频:在信号质量不好(连续
FREQ_HOP_NOACK_THREHOLD
=15个ack未收到)/对码前在8个频点进行跳频对码:上电跳频找到dongle端的频点后,通信互发对端的MAC地址后2字节,之后切换到私有地址进行通信
重传:丢包时会进行重传,以最快速度进行重传直到收到对端回复
ACK:可解析的ACK,具有演示代码
性能:默认上报率1000的情况下,近距离稳定在990包以上,8-9米稳定在960包以上;近距离可以切换上报率进行测试(可选)
测试模式(可选):宏控制自动画圈;关闭PWM灯测试功耗;设置功率测试;ACK测试
BLE模式
蓝牙白名单,分时连接
配对,保存
连接,重连功能:
OTA(未使能):与mcuboot配合通过NRF工具进行升级
性能:133HZ上报率
性能:兼容性
USB模式
性能:USB2.0最高速率1000hz
电脑的休眠唤醒(未做)
升级:与mcuboot配合通过USB工具进行升级
EMI测试
2 环境要求¶
board:
pan108xxb5
或者pan108xxa3
(芯片型号)鼠标板uart (option): overlay中默认P24显示串口log
USB升级工具(USB升级工具获取:https://docs.panchip.com/pan1080dk-doc/latest/docs-zdk/06_dev_tools/pan108x_toolbox_intro.html)
鼠标测试工具:
MouseTest.exe
3 编译和烧录¶
例程位置:zephyr\samples_panchip\solutions\multimode_mouse
使用 ZAL 工具可以对其进行编译、烧录、打开 VS Code 调试等操作。关于 ZAL 工具的详细介绍请参考:Zephyr APP Launcher 工具介绍。
4 演示说明¶
芯片全部擦除还原默认状态,准备好烧录multimode_mouse_dongle
的接收器
4.1 电池供电模式¶
电池上电,鼠标端默认中键关闭状态
鼠标端开关拨到左边为2.4G模式,黄色灯快闪,插入接收器至PC,黄色灯变为紫色呼吸灯,可以测试鼠标基础功能,最大上报率近距离达到1000,远距离8-9m达到900+,通过按DPI键切换DPI,通过长按中键测试上报率
鼠标端开关拨到右边为蓝牙模式,浅蓝色灯效,可以在开启蓝牙的PC端搜索到名为
Pan_Mouse
的蓝牙设备,连接后进行控制,最大可以达到133hz左右拔出dongle,鼠标端通过拨动模式切换键再次进入2.4G模式,黄色灯慢闪,插入dongle变为呼吸灯,鼠标功能恢复
鼠标端通过拨动模式切换键再次进入BLE模式,等待蓝牙重新连接至PC,鼠标功能恢复
不拔出dongle,鼠标端再次通过拨动模式切换键进入2.4G模式,黄色灯慢闪,随后变为呼吸灯,鼠标功能恢复
长按左中右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);
}
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();
}
}
组合按键说明
按键 |
检测时间 |
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 |
键鼠套件模式下 |
无 |
无 |
5 |
0 |
正常模式下 |
正常键值 |
正常键值 |
底部按键 |
0 |
无 |
无 |
切换蓝牙多设备 |
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 EP3接口(VENDOR DFU):通过USB中断进入进行DFU升级,EMI测试
void usb_vendor_ep3_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;
};
6 键鼠套件(附)¶
键鼠套件由PAN1080做主设备,可能是鼠标(1000hz),大键盘(125hz),小键盘(125hz)
需要配合配套键盘及配套2628dongle(支持多pipe)使用,PAN2628参考固件及烧录工具可以从05_TOOLS\dev-tools\MouseSupportTool\PAN2628Dongle
获取,源码可联系我司获取
鼠标作为键鼠套件时,需要在commom.c
中使能
#define KB_MOUSE_ONEDONLE 1
6.1 配对过程¶
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接收的数据认为是小键盘数据
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的配对请求包后:
如果收到的配对请求命令不正确,则不回复任务消息。
如果配对请求命令校验正确无误,则回复以下响应:
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配对过程结束,否则重新开始发送配对请求包,重新以上配对过程,直到配对成功。
以上配对流程总结如下图:
6.1.3 配对时间说明¶
dongle上电后,最长配对时间不超过20秒(当前配对时间窗口为3秒)
如果mouse,keyboard都快速配对完成,则dongle不需要等待超时时间到达,提前进入通信流程
6.2 数据通信过程¶
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字节的地址作为通信地址
6.2.2 跳频通道¶
根据dongle地址各自计算私有跳频列表,之后按私有跳频列表来进行跳频通信,跳频方式和之前相同。
6.2.3 跳频规则¶
dongle 若10ms内没有收到数据,则产生跳频,规则是切换至下一频道上监听10ms,10ms内没有收到数据,再切换至下一频道继续监听,直到在某个频道到收到数据包,则停止跳频,开始进行数据通信。
设备(mouse,keyboard etc)若连续10包发送不成功,则产生跳频,规则是切换至下一频道并发送数据包,若没有收到ack,再切换至下一频道继续发送数据,直到收到ack,停止跳频。
6.2.4 超时时间¶
以鼠标为例,当鼠标配对完成后,进入数据通信模式,此时dongle可能因为大小键盘还没有完成配对,因此鼠标要设置一个最大数据发送超时时间T0,超出这个时间鼠标还不能进行正常数据通信,鼠标则要进入休眠模式,直到用户唤醒鼠标。
假如dongle设定的最长配对时间T1为5秒,则保证T1大于T0,量化下来T0 = T1 +1秒。
6.3 数据格式¶
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管理的数据结构)
6.3.2 数据包¶
应用数据包11字节,通信层包header固定使用PRF_PKT_TYPE_MOUSE_DATA
,数据包内容header根据不同场景定义为不同数据
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;
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;
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数据
6.4 操作说明¶
PAN2628dongle配套的固件及烧录工具说明可以从05_TOOLS\MouseSupportTool\PAN2628Dongle
获取烧录
PAN2628源码部分可以联系我司获取
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 }
6.4.2 操作步骤¶
准备好2628dongle固件,烧录工程
combo_usb_dongle
固件,具有mac地址的使用MAC地址完成配对,否则使用默认值进行配对。准备2块鼠标板,一块烧录 键鼠套件鼠标A,一块烧录 键鼠套件键盘B
A和B同时进入配对快闪状态,复位dongle,观察AB灯效
A快闪结束,进入断连状态,之后切换为呼吸灯效,B快闪结束,变为慢闪(由于配对完成后键盘不会主动上报数据,不会进入连接状态),B板按键K5,上报键盘数据
1
之后进入呼吸灯状态A可以设置为自动画圈状态,同时发送B按键数据,观察B发送包不丢失并且A的1000hz上报率受到轻微影响(测试目前不会掉900以下,基本上维持在980以上)
6.5 新增需求(不需要关注,套件键盘文档内说明)¶
由于需要支持无冲键盘,数据包长度需要扩充,组包逻辑中,单笔组包数据由11字节扩充为21字节,ringbuf size由11×40扩充为21×40,rf实际通信tx_payload改为24字节。6.3.1章节中rf数据格式payload字段改为21B,6.3.2章节内容统一描述见6.5.1
键盘需要从无长度ack变化为有长度ack(3B),其中可以自定义扩充回复ack信息(如大小写按键信息的上报),ack始终反馈如实际键盘的实际
numlock
值
6.5.1 格式更新¶
应用数据包21字节,通信层包header固定使用PRF_PKT_TYPE_MOUSE_DATA
,数据包内容header根据不同场景定义为不同数据
8.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;
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;
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数据
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 追溯相关灯控代码
7 补充说明¶
补充说明当前功耗测试情况,支持中遇到的问题(供参考)及已知仍可能存在的问题
7.1 功耗说明¶
功耗测试首先进行不开启休眠唤醒的测试,但需要关闭PWM灯的宏进行测试或者长按右键+4键关闭灯效之后进行休眠唤醒电流测试。
CONFIG_LED_THREAD_ENABLE=n
之后进行休眠唤醒电流测试。
2.4G模式功耗如下(为节约RAM,降速了组包逻辑速度(减少使用ramfunc),对功耗(2.4G全速1000hz)会有300uA左右上升):
设备 |
LED灯(clk off) |
ADC配置 |
apb div |
上报率 |
状态1-电流(移动)(mA) |
状态2-关闭rF (mA) |
状态3-deepsleep,关灯 (mA) |
状态4-deepsleep+传感器关闭 uA |
自动画圈mA |
---|---|---|---|---|---|---|---|---|---|
鼠标D |
OFF |
50ms,空闲关闭 |
4 |
1000 |
12.44 |
3.24 |
0.09 |
35 |
7.1 |
鼠标D |
OFF |
50ms,空闲关闭 |
4 |
500 |
10.11 |
3.06 |
0.09 |
35 |
4.96 |
鼠标D |
OFF |
50ms,空闲关闭 |
4 |
250 |
8.73 |
2.88 |
0.09 |
35 |
3.81 |
鼠标D |
OFF |
50ms,空闲关闭 |
4 |
125 |
8.13 |
2.79 |
0.09 |
35 |
3.25 |
蓝牙模式功耗如下:
设备 |
LED灯(clk off) |
ADC配置 |
apb div |
上报率 |
状态1-电流(移动)(mA) |
状态2-关灯,idle deepsleep (uA) |
状态3-deepsleep(uA) |
状态4-deepsleep+传感器关闭 uA |
自动画圈mA |
---|---|---|---|---|---|---|---|---|---|
鼠标D |
OFF |
50ms,空闲关闭 |
4 |
133 |
9.79 |
600 |
59 |
35 |
5.10 |
7.2 已知问题¶
No |
已知问题 |
目前状态 |
---|---|---|
1 |
休眠模式下切换模式过快需要复位 |
由于鼠标处于休眠状态,切换模式本应该经过断电状态,但如果切换过快,休眠状态放电不充分,芯片不能完全断电复位,仍处于休眠状态,此时唤醒可以恢复对应模式的正常运行状态 |
8 RAM/Flash资源使用情况¶
FLASH部分包含蓝牙controller固定资源120K,不包含初始位置开始的60K MCUBOOT程序
Memory region Used Size Region Size %age Used
FLASH: 111400 B 152 KB 71.57%
SRAM: 36162 B 50 KB 70.63%