杰理 SDK 文档中心
首页
首页
  • SDK 概述与入门

    • SDK 总览
    • 支持芯片与蓝牙认证
    • 工程结构导航
  • 开发环境与构建

    • 环境搭建与工具链安装
    • 编译指南与工程选择
    • 烧录与生产工具
  • BLE 透传/数传应用

    • 透传应用框架与处理模块
    • 透传与数传示例
    • 多连接与自定义服务示例
    • FindMy 与查找网络示例
  • HID 人机交互应用

    • 键盘与按键设备示例
    • 鼠标设备示例
    • 遥控器示例
    • HID 蓝牙应用模块
  • 公共 BSP 模块

    • 按键、编码器与红外输入
    • 传感器驱动
    • LED 与显示控制
    • 串口与 USB 通信
    • 存储、参数与时钟
    • 电源与温度管理
    • 消息、内存与系统配置
    • OTA 升级框架
  • 蓝牙协议栈与库

    • BLE 控制器与协议栈适配
    • 经典蓝牙 BR/EDR 支持
    • 第三方蓝牙协议
    • 设备管理框架
    • DUT 测试与射频认证
  • 构建系统与开发工具

    • Makefile 构建系统
    • 固件后处理与配置工具
    • 辅助脚本与库合并
  • 文档与硬件资料

    • AT 命令参考
    • 硬件参考资料
    • SDK 文档与在线资源

传感器驱动

本文档介绍 AW33N BLE SDK 中传感器驱动的整体框架与实现,涵盖重力传感器(G-Sensor / 加速度计)与光学鼠标传感器(Optical Mouse Sensor)两套驱动体系,包括注册机制、IIC 通信原语、数据读取流程与配置选项。

Purpose and Scope

本页面向 apps/app/bsp/common/gsensor 与 apps/app/bsp/common/mouse_sensor 两个传感器驱动子系统,说明:

  • G-Sensor 驱动框架:gsensor_api.c/h(应用层 API)、gSensor_manage.c/h(管理层)、具体芯片驱动(msa310.c、SC7A20_E.c、SC7A20_TR.c);
  • 光学鼠标传感器框架:OMSensor_manage.c/h 与 HAL3205 芯片驱动;
  • IIC 读写原语、寄存器命令枚举、自旋锁并发保护与传感器搜索机制;
  • 相关编译开关(TCFG_GSENSOR_ENABLE、TCFG_SC7A20_EN、TCFG_SC7A20_E_EN、TCFG_MSA310_EN 等)与平台配置宏。

不属于本页范围的相邻主题:按键驱动(key)、LED 驱动(led)、红外编解码(ir)等外设驱动各有独立页面;FindMy 场景中通过 UART 透传传感器的示例(ble_fmy_sensor_uart.c)属于示例应用,本页仅作为扩展点提及。

Overview

在嵌入式 BLE 产品(如智能手环、防丢器、无线鼠标)中,传感器驱动需要同时满足三个诉求:芯片可替换性(不同供应商的加速度计寄存器各不相同)、总线资源独占(IIC 为多外设共享总线,需要互斥保护)、低功耗与运动检测(被动/主动两种检测状态)。

SDK 采用经典的三段式驱动分层 + 链接段注册表设计:

  1. 设备层(Device):每个芯片驱动(MSA310、SC7A20、HAL3205 等)通过宏 REGISTER_GRAVITY_SENSOR / REGISTER_OMSENSOR 把自己注册进链接脚本的专用段(.gsensor_dev / .omsensor_dev),驱动代码无需修改框架;
  2. 管理层(Manager):gSensor_manage.c 遍历注册段查找可用传感器,提供统一 IIC 读写原语(带自旋锁保护)、命令分发与平台数据解析;
  3. 应用层(API):gsensor_api.c 对上层暴露 sensor_init、sensor_data_get、get_sensor_avg、sensor_motion_detection 等精简接口,并维护 DETECTION_PASSIVE / DETECTION_ACTIVE 检测状态。

这套设计把"换一颗芯片"的成本压缩为"新增一个 .c 文件 + 打开对应编译开关",上层代码完全不变。

Architecture

flowchart TD
    subgraph sg_App["应用层 (App)"]
        App["业务代码"]
        API["gsensor_api.c<br/>sensor_init / sensor_data_get / sensor_motion_detection"]
    end

    subgraph sg_Mgr["管理层 (Manager)"]
        Mgr["gSensor_manage.c<br/>gravity_sensor_init / get_gSensor_data"]
        IIC["IIC 原语<br/>gravity_sensor_command / _gravity_sensor_get_ndata"]
        Lock["spinlock_t sensor_iic 互斥锁"]
    end

    subgraph sg_Dev["设备层 (Device)"]
        S1["msa310.c (MSA310)"]
        S2["SC7A20_E.c / SC7A20_TR.c (SC7A20)"]
        OM["mouse_sensor/OMSensor_manage.c<br/>+ hal3205.c (光学鼠标传感器)"]
    end

    subgraph sg_HW["硬件层"]
        HW_IIC["IIC 总线 (IO_PORTA_08 SCL / IO_PORTA_07 SDA)"]
        HW_INT["传感器 INT 中断 IO"]
    end

    App -->|"调用"| API
    API -->|"G_SENSOR_INTERFACE 命令分发"| Mgr
    Mgr --> IIC
    Mgr --> Lock
    IIC --> HW_IIC
    S1 -->|"REGISTER_GRAVITY_SENSOR<br/>链接段 .gsensor_dev"| Mgr
    S2 -->|"REGISTER_GRAVITY_SENSOR<br/>链接段 .gsensor_dev"| Mgr
    OM -->|"REGISTER_OMSENSOR<br/>链接段 .omsensor_dev"| Mgr
    S1 --> HW_INT
    S2 --> HW_INT
    OM --> HW_IIC

架构说明:

  • 应用层只依赖 gsensor_api.h 暴露的 5 个函数,不感知具体芯片;DETECTION_STATES(DETECTION_PASSIVE=0 / DETECTION_ACTIVE)决定传感器是否处于主动上报运动中断的状态(见 gsensor_api.h)。
  • 管理层是核心枢纽:持有全局句柄 G_SENSOR_INTERFACE *gSensor_hdl 与运行时信息 G_SENSOR_INFO __gSensor_info,所有 IIC 读写都先取 sensor_iic 自旋锁,保证与其它共享 IIC 的外设互斥(见 gSensor_manage.c)。
  • 设备层通过编译开关裁剪:整个管理文件被 #if (TCFG_GSENSOR_ENABLE && (TCFG_SC7A20_EN || TCFG_SC7A20_E_EN || TCFG_MSA310_EN)) 包裹,未使能时整段代码不参与编译(见 gSensor_manage.c)。

G-Sensor 驱动框架详解

链接段注册机制(内核级插件式驱动)

G-Sensor 框架不维护任何驱动列表,而是利用链接脚本的段(section)实现"零注册代码"的插件机制:

#define REGISTER_GRAVITY_SENSOR(gSensor) \
	static G_SENSOR_INTERFACE gSensor SEC_USED(.gsensor_dev)

#define list_for_each_gsensor(c) \
	for (c=gsensor_dev_begin; c<gsensor_dev_end; c++)

来源:gSensor_manage.h

设计意图:SEC_USED(.gsensor_dev) 把每个驱动实例放入链接器自定义段,链接器自动生成段边界符号 gsensor_dev_begin / gsensor_dev_end(在 gSensor_manage.h 中以 extern 声明)。list_for_each_gsensor(c) 则让管理层像遍历数组一样遍历所有已注册驱动。新增一颗传感器 = 新写一个 .c 文件 + 定义一个 G_SENSOR_INTERFACE 静态实例并用该宏注册,框架代码零改动。同样的模式被光学鼠标传感器复用(REGISTER_OMSENSOR 注册到 .omsensor_dev 段,见 OMSensor_manage.h)。

核心接口与数据结构

每个重力传感器驱动必须实现一个 G_SENSOR_INTERFACE:

typedef struct {
    u8   logo[20];                                    // 驱动标识/名称
    u8(*gravity_sensor_init)(void);                   // 芯片初始化
    char (*gravity_sensor_check)(void);               // 芯片存在性检查(读 ID)
    int (*gravity_sensor_ctl)(u8 cmd, void *arg);     // 命令分发入口
} G_SENSOR_INTERFACE;

来源:gSensor_manage.h

gravity_sensor_ctl 是设备层唯一的总线入口,上层通过命令枚举驱动芯片行为:

enum {
    GSENSOR_DISABLE = 0,      // 关闭传感器(进入低功耗)
    GSENSOR_RESET_INT,        // 复位中断
    GSENSOR_RESUME_INT,       // 恢复中断使能
    GSENSOR_INT_DET,          // 中断检测(运动唤醒)
    READ_GSENSOR_DATA,        // 读取三轴原始数据
    GET_ACCEL_DATA,           // 获取加速度(含换算)
    SEARCH_SENSOR,            // 搜索/枚举传感器
};

来源:gSensor_manage.h

设计意图:把"寄存器差异"封装进命令实现内部。例如 READ_GSENSOR_DATA 对 MSA310 与 SC7A20 的寄存器地址、数据格式完全不同,但管理层的 get_gSensor_data() 只需调用 gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data) 即可拿到统一的 axis_info_t 数组,实现芯片无关的数据消费。

配套数据结构:

  • axis_info_t { short x, y, z; } —— 单次采样三轴原始值(gSensor_manage.h#L29-L33);
  • gsensor_platform_data { u8 iic; char gSensor_name[20]; u32 gSensor_int_io; } —— 平台配置:IIC 句柄、传感器名、中断 IO(gSensor_manage.h#L43-L47);
  • G_SENSOR_INFO { iic_hdl, iic_delay, ctl_flag, init_flag, check_cnt, check_timer_hdl } —— 运行时状态,其中 iic_delay 是两字节数据之间的延时(不改变 IIC 时钟频率),check_cnt / check_timer_hdl 用于定时轮询芯片存在性(gSensor_manage.h#L49-L56)。

IIC 读写原语(自旋锁保护的原子操作)

管理层提供两条对设备驱动透明的 IIC 原语。写寄存器:

u8 gravity_sensor_command(u8 w_chip_id, u8 register_address, u8 function_command)
{
    spin_lock(&sensor_iic);
    u8 ret = 1;
    iic_start(gSensor_info->iic_hdl);
    if (0 == iic_tx_byte(gSensor_info->iic_hdl, w_chip_id)) {
        ret = 0;
        log_info("\n gsen iic wr err 0");
        goto __gcend;
    }
    delay(gSensor_info->iic_delay);
    if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) {
        ret = 0;
        log_info("\n gsen iic wr err 1");
        goto __gcend;
    }
    delay(gSensor_info->iic_delay);
    if (0 == iic_tx_byte(gSensor_info->iic_hdl, function_command)) {
        ret = 0;
        log_info("\n gsen iic wr err 2\n");
        goto __gcend;
    }
__gcend:
    iic_stop(gSensor_info->iic_hdl);
    spin_unlock(&sensor_iic);
    return ret;
}

来源:gSensor_manage.c

写操作流程:iic_start → 发送器件写地址(w_chip_id)→ 发送寄存器地址 → 发送数据字节 → iic_stop。任一步 iic_tx_byte 返回 0 即判定失败并 goto 统一收尾(先 iic_stop 再释放锁,避免异常路径挂死总线),同时打印错误级日志 [GSENSOR_MAN] gsen iic wr err N。

读多字节(带 IIC 重复起始位,用于读取三轴连续寄存器):

u8 _gravity_sensor_get_ndata(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
{
    spin_lock(&sensor_iic);
    u8 read_len = 0;
    iic_start(gSensor_info->iic_hdl);
    if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id - 1)) { ... }
    delay(gSensor_info->iic_delay);
    if (0 == iic_tx_byte(gSensor_info->iic_hdl, register_address)) { ... }
    iic_start(gSensor_info->iic_hdl);                       // 重复起始
    if (0 == iic_tx_byte(gSensor_info->iic_hdl, r_chip_id)) { ... }
    delay(gSensor_info->iic_delay);
    for (; data_len > 1; data_len--) {
        *buf++ = iic_rx_byte(gSensor_info->iic_hdl, 1, NULL);   // 前 N-1 字节带 ACK
        read_len ++;
    }
    *buf = iic_rx_byte(gSensor_info->iic_hdl, 0, NULL);         // 最后一字节 NACK
    read_len ++;
__gdend:
    iic_stop(gSensor_info->iic_hdl);
    delay(gSensor_info->iic_delay);
    spin_unlock(&sensor_iic);
    return read_len;
}

来源:gSensor_manage.c

设计意图:IIC 读需要"写寄存器地址 → 重复起始 → 读数据"三段式时序;读地址为 r_chip_id - 1(7 位地址左移后最低位为 0 表示写),读阶段地址为 r_chip_id(最低位为 1 表示读)。最后一个字节必须以 NACK(iic_rx_byte(..., 0, NULL))结束,否则从机不会释放总线。整个序列用 sensor_iic 自旋锁包裹,因为同一 IIC 总线可能被多个外设(如鼠标传感器)共享,非原子操作会导致总线时序错乱。

三轴数据导出

管理层把设备驱动的 axis_info_t 数组"扁平化"为上层易用的 short 缓冲:

int get_gSensor_data(short *buf)
{
    axis_info_t accel_data[32];
    int axis_info_len = gSensor_hdl->gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data);
    for (int i = 0; i < axis_info_len; i++) {
        buf[i * 3] = accel_data[i].x;
        buf[i * 3 + 1] = accel_data[i].y;
        buf[i * 3 + 2] = accel_data[i].z;
    }
    return axis_info_len;
}

来源:gSensor_manage.c

该函数返回采样点数,输出缓冲按 x,y,z 交错排列,一次最多导出 32 组采样(axis_info_t accel_data[32])。上层拿到的是统一格式,无论底层是 MSA310 还是 SC7A20。ACCEL_OF_GRAVITY(10) 与 ACCEL_DATA_GAIN(10) 两个宏(gSensor_manage.h#L13-L14)定义了 g 值与原始数据的换算基准,供 GET_ACCEL_DATA 命令做量纲换算。

初始化流程与传感器搜索

gravity_sensor_init(void *_data) 是管理层的初始化入口,_data 指向平台数据 struct gsensor_platform_data:

int gravity_sensor_init(void *_data)
{
    if (sensor_iic_init_status == 0) {
        spin_lock_init(&sensor_iic);
        sensor_iic_init_status = 1;
    }
    gSensor_info->init_flag  = 0;
    int retval = 0;
    platform_data = (const struct gsensor_platform_data *)_data;
    gSensor_info->iic_hdl = platform_data->iic;
    struct iic_master_config iic_config = { ... };   // 按平台数据配置 IIC 主机
    ...
}

来源:gSensor_manage.c

初始化要点(结合源码可见部分与头文件声明):

  1. 自旋锁一次性初始化:sensor_iic_init_status 是模块级标志,保证 sensor_iic 锁只初始化一次(多实例/重复 init 安全);
  2. 绑定平台数据:从 gsensor_platform_data 取出 iic 句柄写入 gSensor_info->iic_hdl,之后所有 IIC 原语都使用该句柄;
  3. 设备搜索:初始化过程中通过 list_for_each_gsensor(c) 遍历 .gsensor_dev 段,调用各驱动的 gravity_sensor_check() 探测芯片 ID,命中者被赋给全局句柄 gSensor_hdl;
  4. 失败重试:G_SENSOR_INFO.check_cnt / check_timer_hdl 表明框架支持定时器驱动的周期性存在性检查(对应命令 SEARCH_SENSOR),芯片掉线后可自动重新搜索。

运动检测状态机

gsensor_api.h 定义了应用可见的检测状态:

typedef enum {
    DETECTION_PASSIVE = 0,   // 被动检测:不产生中断,上层按需读取
    DETECTION_ACTIVE         // 主动检测:芯片使能运动中断,唤醒后上报
} DETECTION_STATES;

static DETECTION_STATES detection_status = DETECTION_PASSIVE;

来源:gsensor_api.h

bool sensor_motion_detection(void) 切换/查询检测模式,配合命令枚举中的 GSENSOR_RESET_INT、GSENSOR_RESUME_INT、GSENSOR_INT_DET 使用。设计意图:在低功耗场景(如 FindMy 防丢器)中,默认 DETECTION_PASSIVE 让传感器处于低功耗待机,仅当需要监控移动时才切换为 DETECTION_ACTIVE,由芯片 INT 引脚唤醒 MCU,避免高频轮询消耗电流。

Core Flow

sequenceDiagram
    participant App as 应用代码
    participant API as gsensor_api.c
    participant Mgr as gSensor_manage.c
    participant Dev as 芯片驱动 (msa310/SC7A20)
    participant IIC as IIC 总线 (iic_api)
    participant HW as 传感器芯片

    App->>API: sensor_init()
    API->>Mgr: gravity_sensor_init(platform_data)
    Mgr->>Mgr: 初始化 spinlock / iic_hdl
    loop 遍历 .gsensor_dev 段
        Mgr->>Dev: gravity_sensor_check()
        Dev->>IIC: _gravity_sensor_get_ndata(读 ChipID 寄存器)
        IIC->>HW: IIC 读序列 (start/addr/reg/restart/read)
        HW-->>IIC: ChipID 数据
        IIC-->>Dev: buf
        Dev-->>Mgr: 命中则 gSensor_hdl = dev
    end
    Mgr-->>API: 初始化完成
    API-->>App: 0

    App->>API: sensor_data_get()
    API->>Mgr: get_gSensor_data(buf)
    Mgr->>Dev: gravity_sensor_ctl(READ_GSENSOR_DATA, accel_data)
    Dev->>IIC: 读三轴连续寄存器 (spin_lock 保护)
    IIC->>HW: 6+ 字节连续读
    HW-->>IIC: x/y/z 原始数据
    IIC-->>Dev: axis_info_t[]
    Dev-->>Mgr: 采样点数
    Mgr-->>API: 扁平化 short 缓冲
    API-->>App: 三轴数据

    App->>API: sensor_motion_detection()
    API->>Mgr: gravity_sensor_ctl(GSENSOR_RESUME_INT/GSENSOR_INT_DET)
    Mgr->>Dev: 配置 INT 寄存器
    HW-->>Mgr: 运动触发 INT
    Mgr-->>API: 检测结果 (DETECTION_ACTIVE)

流程要点: 初始化阶段的关键是"段遍历 + ChipID 探测"——框架不知道板子上焊了哪颗芯片,靠遍历注册表逐个读 ID 自动发现;数据读取阶段每笔 IIC 事务都被 sensor_iic 自旋锁原子化;运动检测阶段把中断控制交给芯片驱动,应用层只关心状态切换。

Usage Examples

应用层调用(G-Sensor)

int sensor_init();
int sensor_data_get();
void get_sensor_avg(axis_info_t *axis_avg);
int sensor_deinit();
bool sensor_motion_detection(void);

来源:gsensor_api.h

典型用法:开机调用 sensor_init();周期任务调用 sensor_data_get() 获取三轴原始数据,或用 get_sensor_avg(axis_avg) 获取多次采样平均(用于消抖/校准);低功耗场景先 sensor_motion_detection() 使能运动中断,收到唤醒事件后读取数据;关机时 sensor_deinit() 释放 IIC 与中断资源。

驱动注册示例(设备层)

#define REGISTER_GRAVITY_SENSOR(gSensor) \
	static G_SENSOR_INTERFACE gSensor SEC_USED(.gsensor_dev)

#define GSENSOR_PLATFORM_DATA_BEGIN(data) \
		static const struct gsensor_platform_data data = {

#define GSENSOR_PLATFORM_DATA_END() \
};

来源:gSensor_manage.h

新增芯片驱动(如 msa310.c)时,定义 static G_SENSOR_INTERFACE 实例并用 REGISTER_GRAVITY_SENSOR 注册,实现 gravity_sensor_init(芯片寄存器配置)、gravity_sensor_check(读 ChipID)、gravity_sensor_ctl(命令 switch 分发,内部调用 gravity_sensor_command / _gravity_sensor_get_ndata 完成 IIC 访问)。

光学鼠标传感器(HID 报告格式)

// HID鼠标的报告格式
typedef struct {
    uint8_t buttonMask;        // 按钮状态,5位用于按钮,3位用于填充
    uint8_t wheel;             // 滚轮移动,8位
    uint8_t xymovement[4];     // 数组来存放X和Y轴的移动量
} mouse_packet_data_t;

typedef struct {
    uint8_t button_send_flag;
    uint8_t wheel_send_flag;
    uint8_t sensor_send_flag;
} mouse_send_flags_t;

来源:OMSensor_manage.h

鼠标传感器驱动把传感器位移数据打包为 HID 标准鼠标报告:buttonMask(5 位按钮 + 3 位填充)、wheel(滚轮增量)、xymovement[4](X/Y 位移,各 2 字节)。optical_mouse_read_sensor_handler_high() 负责把传感器数据填充进该结构,再交给上层 HID 上报;VECTOR_REVERS(vec) 宏用于处理传感器位移方向的取反。OMSENSOR_INTERFACE(OMSensor_manage.h#L29-L38)除运动读取外还暴露了 OMSensor_wakeup(唤醒传感器)、OMSensor_led_switch(LED 亮度控制)、OMSensor_set_cpi(灵敏度调节)等光学传感器特有能力,optical_mouse_sensor_timer_init/deinit 管理周期性采样定时器。

Configuration Options

配置项类型默认/取值说明
TCFG_GSENSOR_ENABLE编译开关0/1总开关,关闭后整个 gSensor_manage.c 不参与编译(gSensor_manage.c#L19)
TCFG_SC7A20_EN编译开关0/1使能 SC7A20 基础驱动(SC7A20_TR.c)
TCFG_SC7A20_E_EN编译开关0/1使能 SC7A20 增强驱动(SC7A20_E.c)
TCFG_MSA310_EN编译开关0/1使能 MSA310 驱动(msa310.c / msa310_function.c)
GSENSOR_PRINTF_ENABLE编译开关0/1使能 [GSENSOR_MAN] 前缀的调试日志与 hexdump(gSensor_manage.c#L31-L38)
IIC_SCL_IOIO 宏IO_PORTA_08G-Sensor IIC 时钟引脚(gSensor_manage.h#L16)
IIC_SDA_IOIO 宏IO_PORTA_07G-Sensor IIC 数据引脚(gSensor_manage.h#L17)
ACCEL_OF_GRAVITY常量10重力加速度换算基准(mg/LSB 相关),用于 GET_ACCEL_DATA
ACCEL_DATA_GAIN常量10原始数据到加速度的增益系数
G_SENSOR_INFO.iic_delay运行时10两字节数据间的 IIC 延时(不影响时钟频率,只影响字节间隔),默认在 __gSensor_info 初始化中设置(gSensor_manage.c#L44)
gsensor_platform_data.iic平台数据由板级配置指定 G-Sensor 挂载的 IIC 控制器句柄(gSensor_manage.h#L43-L47)

平台数据通过 GSENSOR_PLATFORM_DATA_BEGIN/END 宏以静态常量方式定义;OMSENSOR_PLATFORM_DATA(OMSensor_manage.h#L22-L27)则声明了光学鼠标传感器的 sclk_io / data_io / int_io 引脚配置。

API Reference

G-Sensor 应用层(gsensor_api.h)

函数参数返回说明
sensor_init()无int初始化 G-Sensor:初始化自旋锁、配置 IIC、搜索并绑定芯片驱动;0 表示成功
sensor_data_get()无int触发一次三轴数据读取并缓存,供 get_sensor_avg 使用
get_sensor_avg(axis_info_t *axis_avg)axis_avg:三轴平均结果输出void对多次采样做平均,用于去抖/静态校准
sensor_deinit()无int反初始化:关闭传感器、释放 IIC/中断资源
sensor_motion_detection()无bool运动检测:切换/查询 DETECTION_PASSIVE / DETECTION_ACTIVE 状态

G-Sensor 管理层(gSensor_manage.h/c)

函数参数返回说明
gravity_sensor_init(void *_data)_data:gsensor_platform_data*int绑定平台数据、配置 IIC 主机、执行传感器搜索
gsensor_disable()无int关闭 G-Sensor(对应 GSENSOR_DISABLE 命令)
gravity_sensor_command(u8 w_chip_id, u8 reg, u8 cmd)写地址、寄存器地址、数据u8带自旋锁的单字节 IIC 写;1 成功,0 失败
_gravity_sensor_get_ndata(u8 r_chip_id, u8 reg, u8 *buf, u8 len)读地址、寄存器、缓冲、长度u8带自旋锁的 IIC 连续读(重复起始);返回实际读取字节数
get_gSensor_data(short *buf)buf:输出缓冲int读取三轴数据,按 x/y/z 交错写入,返回采样点数
gsensor_io_ctl(u8 cmd, void *arg)命令、参数void透传调用 gSensor_hdl->gravity_sensor_ctl

光学鼠标传感器(OMSensor_manage.h)

函数说明
optical_mouse_sensor_init(OMSENSOR_PLATFORM_DATA *priv)初始化光学传感器(枚举 .omsensor_dev 段、绑定芯片驱动)
optical_mouse_sensor_read_motion_handler(void *priv)定时器回调:读取位移增量
optical_mouse_read_sensor_handler_high(mouse_packet_data_t*, mouse_send_flags_t*)把传感器数据打包为 HID 鼠标报告
optical_mouse_sensor_set_cpi(u16) / clear_cpi(u16)设置/清除 CPI(灵敏度)
optical_mouse_sensor_data_ready()查询数据就绪状态
optical_mouse_sensor_force_wakeup()强制唤醒传感器(退出休眠)
optical_mouse_sensor_led_switch(u8)控制传感器 LED 开关
optical_mouse_sensor_timer_init/deinit()启动/停止采样定时器
get_optical_mouse_sensor_status()获取传感器在线状态

Failure Modes, Edge Cases & Concurrency

  • IIC 写失败:gravity_sensor_command 中任一 iic_tx_byte 返回 0 即中断流程,打印 gsen iic wr err N(N 表示失败阶段),并以 goto 统一执行 iic_stop + spin_unlock。这种"先停总线再放锁"的顺序保证异常时不会把 IIC 总线锁死在中间状态。
  • IIC 读失败:_gravity_sensor_get_ndata 在读地址/寄存器地址阶段失败时 read_len = 0 并跳转收尾,上层可通过返回值判断读操作是否完整。
  • 并发访问:所有 IIC 事务都被模块级自旋锁 sensor_iic 串行化;锁通过 sensor_iic_init_status 保证只初始化一次。若其它外设(如鼠标传感器)也使用同一 IIC 控制器,必须共用同一把锁,否则总线时序会被打断。
  • 芯片不在线/掉线:SEARCH_SENSOR 命令与 check_cnt/check_timer_hdl 定时器支撑周期性探测;驱动未命中时 gSensor_hdl 为空,上层调用 get_gSensor_data 前应判空。
  • 字节间时序:iic_delay 不改变 IIC 时钟频率,而是控制两字节数据间的延时——部分传感器(尤其较慢的 SC7A20 系)在连续读时要求字节间隔,过小会导致数据错位。出现"数据偶发跳变"时应优先排查该延时。
  • 方向/符号边界:鼠标传感器位移可为负值,VECTOR_REVERS(vec)(vec = ~vec; vec++,即取反加一)处理位移方向反转;xymovement[4] 中 X/Y 各占 2 字节,需按有符号数解释,避免溢出截断。

Performance & Operational Notes

  • 锁粒度:IIC 原语以"一次完整事务"为锁边界(start→读写→stop),而非逐字节加锁,兼顾了原子性与吞吐。
  • 轮询与中断权衡:DETECTION_PASSIVE 模式下读取为显式轮询,适合低频采样;DETECTION_ACTIVE 模式依赖芯片 INT 引脚唤醒,MCU 可深度睡眠,是低功耗产品(防丢器/手环)的首选路径。get_sensor_avg 通过均值滤波降低噪声,但会引入采样延迟,需按应用场景调节采样次数。
  • 调试开关:GSENSOR_PRINTF_ENABLE 使能后日志带 [GSENSOR_MAN] 前缀,且 log_info_hexdump(put_buf)可直接打印 IIC 读到的原始寄存器内容,便于现场排查芯片 ID 与数据格式问题。
  • 编译裁剪:管理文件整体受 TCFG_GSENSOR_ENABLE 及芯片开关约束,未使能时不产生代码与数据,Flash/RAM 零开销;量产固件应关闭 GSENSOR_PRINTF_ENABLE 以减小镜像。

Extension Points

  1. 新增 G-Sensor 芯片:新建 .c 文件实现 G_SENSOR_INTERFACE(logo / gravity_sensor_init / gravity_sensor_check / gravity_sensor_ctl),用 REGISTER_GRAVITY_SENSOR 注册进 .gsensor_dev 段,打开对应 TCFG_xxx_EN 开关即可,框架与上层应用无需改动。
  2. 新增光学鼠标传感器:实现 OMSENSOR_INTERFACE(OMSensor_init / OMSensor_read_motion / OMSensor_data_ready / OMSensor_set_cpi 等),用 REGISTER_OMSENSOR 注册进 .omsensor_dev 段;参考现有 HAL3205 驱动(apps/app/bsp/common/mouse_sensor/hal3205/hal3205.c)。
  3. 自定义平台数据:通过 GSENSOR_PLATFORM_DATA_BEGIN/END 与 OMSENSOR_PLATFORM_DATA 在板级配置中声明 IIC 句柄、中断 IO 与传感器名称,驱动代码不感知具体管脚。
  4. 示例参考:FindMy 演示工程通过 UART 透传传感器数据的示例见 apps/demo/transfer/examples/findmy/ble_fmy_sensor_uart.c/h,可作为传感器数据对外上报(非 IIC 路径)的集成范本。

Related Links

  • G-Sensor 应用层 API(gsensor_api.h)
  • G-Sensor 管理层头文件(gSensor_manage.h)
  • G-Sensor 管理层实现(gSensor_manage.c)
  • 光学鼠标传感器管理(OMSensor_manage.h)
  • HAL3205 光学传感器驱动
  • FindMy 传感器 UART 透传示例
  • 相关外设驱动页面(按键 / LED / IR)见各自目录:apps/app/bsp/common/key、apps/app/bsp/common/led、apps/app/bsp/common/ir
Prev
按键、编码器与红外输入
Next
LED 与显示控制