地磁传感器移植指南

本章节将实现地磁传感器的在Solution Sensor框架下的移植,以QMC6310为参考。

1. 原生驱动移植

本节实现传感器芯片最基础的硬件通信功能,包括I2C总线操作、中断处理和电源管理。

1.1 配置与宏定义

在 sdk\customer\peripherals\sensor 目录下创建以qmc6310命名的目录,添加原生驱动qmc6310.c。 修改sdk\customer\peripherals\sensor对应qmc6310传感器类型的目录下kconfig文件,新建宏来实现驱动的控制

宏名称

类型

说明

MAG_USING_QMC6310

必需

启用QMC6310地磁传感器

QMC6310_I2C_BUS

必需

I2C总线设备名称(如"i2c2")

QMC6310_POW_PIN

可选

电源控制GPIO引脚号

1.2 I2C总线初始化

初始化需要通过宏定义找到对应的总线设备,打开设备并对总线进行参数设置。

bool qmc6310_i2c_init(void)
{
    qmc6310_i2cbus = (struct rt_i2c_bus_device *)rt_device_find(QMC6310_I2C_BUS);
    if (RT_Device_Class_I2CBUS != qmc6310_i2cbus->parent.type)
    {
        qmc6310_i2cbus = NULL;
    }
    if (qmc6310_i2cbus)
    {
        rt_device_open((rt_device_t)qmc6310_i2cbus, RT_DEVICE_FLAG_RDWR);
    }
    else
    {
        rt_kprintf("bus not find\r\n");
        return RT_FALSE;
    }
    {
        struct rt_i2c_configuration configuration =
        {
            .mode = 0,
            .addr = 0,
            .timeout = 200,
            .max_hz = 400000,
        };

        rt_i2c_configure(qmc6310_i2cbus, &configuration);
    }

    rt_kprintf("mag_i2c_init ok!\r\n");

    return RT_TRUE;
}

1.3 I2C读写接口

总线读写函数供原生驱动调用,实现寄存器的数据交互。

rt_err_t mag_i2c_read(uint8_t i2c_addr, uint8_t reg, uint8_t *buf, uint8_t len)
{
    struct rt_i2c_msg msgs[2];
    uint32_t res = -RT_ERROR;
    uint8_t retries = 0;

    if (qmc6310_i2cbus)
    {

        msgs[0].addr = i2c_addr;
        msgs[0].flags = RT_I2C_WR;
        msgs[0].buf = ®
        msgs[0].len = 1;

        msgs[1].addr = i2c_addr;
        msgs[1].flags = RT_I2C_RD;
        msgs[1].buf = buf;
        msgs[1].len = len;

        if (rt_i2c_transfer(qmc6310_i2cbus, msgs, 2) == 2)
        {
            res = RT_EOK;
        }
        else
        {
            res = -RT_ERROR;
        }
        return res;
    }

    return res;
}
rt_err_t mag_i2c_write(uint8_t i2c_addr, uint8_t reg, uint8_t data)
{
    struct rt_i2c_msg msgs[1];
    uint8_t value[2];
    uint32_t res = -RT_ERROR;;
    uint8_t retries = 0;

    if (qmc6310_i2cbus)
    {
        value[0] = reg;
        value[1] = data;

        msgs[0].addr = i2c_addr;
        msgs[0].flags = RT_I2C_WR;
        msgs[0].buf = value;
        msgs[0].len = 2;

        if (rt_i2c_transfer(qmc6310_i2cbus, msgs, 1) == 1)
        {
            res = RT_EOK;
        }
        else
        {
            res = -RT_ERROR;
        }
        return res;
    }

    return res;
}

1.4 电源管理

void qmc6310_power_onoff(bool onoff)
{
    if (onoff)
    {
#if(QMC6310_POW_PIN >= 0)
        rt_pin_mode(QMC6310_POW_PIN, PIN_MODE_OUTPUT);
        rt_pin_write(QMC6310_POW_PIN, PIN_HIGH);
#endif
        rt_kprintf("qmc6310 power on!\n");
    }
    else
    {
#if(QMC6310_POW_PIN >= 0)
        rt_pin_mode(QMC6310_POW_PIN, PIN_MODE_OUTPUT);
        rt_pin_write(QMC6310_POW_PIN, PIN_LOW);
#endif
        rt_kprintf("qmc6310 power off!\n");
    }

}

2. RT-Thread 传感器设备移植

本节将原生驱动封装为RT-Thread标准传感器设备,实现与系统框架的无缝对接。

2.1 配置与宏定义

在目录solution\components\sensor\sensor_algo\mag添加对应的器件目录“qmc6310”,在“qmc6310"目录下创建qmc6310_mag_service.c文件,用于实现qmc6310注册为Sensor设备;

宏名称

类型

功能说明

取值/注意事项

QMC6310_BUFF_SIZE

宏定义

FIFO数据缓冲区大小,限制单次读取的最大帧数

默认1,单位:帧

QMC6310_PERIOD_TIMER

宏定义

数据读取周期,决定应用层数据刷新频率

默认200ms,单位:毫秒

MAG_USING_QMC6310

条件编译宏

控制整个驱动模块的编译开关

需在menuconfig选项中定义以启用驱动

2.2 关键数据结构

定义设备私有数据结构体和全局变量。

struct qmc6310_device
{
    rt_device_t bus;
    rt_uint8_t id;
    rt_uint8_t i2c_addr;
    void *gs_input;
};

static struct qmc6310_device *qmc6310_dev;

2.3 设备注册接口

将QMC6310注册为RT-Thread标准传感器设备。

static int rt_hw_qmc6310_register(const char *name)
{
    int result;
    {
        sensor_mag = rt_calloc(1, sizeof(struct rt_sensor_device));
        if (sensor_mag == RT_NULL)
            goto __exit;

        sensor_mag->info.type       = RT_SENSOR_CLASS_MAG;
        sensor_mag->info.vendor     = RT_SENSOR_VENDOR_UNKNOWN;
        sensor_mag->info.model      = NULL;
        sensor_mag->info.unit       = RT_SENSOR_UNIT_MGAUSS;
        sensor_mag->info.intf_type  = RT_SENSOR_INTF_I2C;
        sensor_mag->info.range_max  = 360;
        sensor_mag->info.range_min  = 0;
        sensor_mag->info.period_min = 1;
        sensor_mag->data_len = 0;
        sensor_mag->data_buf = NULL;
        sensor_mag->config.mode = RT_SENSOR_MODE_POLLING;
        sensor_mag->config.irq_pin.pin = RT_PIN_NONE;
        sensor_mag->ops = &sensor_ops;

        result = rt_hw_sensor_register(sensor_mag, name, RT_DEVICE_FLAG_RDWR, RT_NULL);
        if (result != RT_EOK)
        {
            rt_kprintf("MAG [%s] register err code: %d", name, result);;
            goto __exit;
        }
    }

    rt_kprintf("MAG [%s] init success!\n", name);
    return RT_EOK;

__exit:

    if (sensor_mag != RT_NULL)
    {
        rt_free(sensor_mag);
        sensor_mag = RT_NULL;
    }

    return -RT_ERROR;

}

static int qmc6310_register(void)
{
    /*if menuconfig config name, use menuconfig name*/
#ifdef QMC6310_MODEL_NAME
    static char  name[] = QMC6310_MODEL_NAME;
#else
    static char  name[] = "qmc6310";
#endif
    int ret = rt_hw_qmc6310_register(name);
    return ret;
}
INIT_COMPONENT_EXPORT(qmc6310_register);

INIT_COMPONENT_EXPORT(qmc6310_register);是RT-Thread系统组件初始化命令,用于在系统启动时调用qmc6310_register()完成设备的注册。

2.4 传感器接口实现

注册为Sensor设备必须完善接口,实现rt_sensor_ops结构体。

static struct rt_sensor_ops sensor_ops =
{
    qmc6310_fetch_data,
    qmc6310_control
};

2.4.1 数据获取接口

qmc6310_fetch_data()用于服务层向驱动层获取数据。

static rt_size_t qmc6310_fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
{
    RT_ASSERT(buf);
    return qmc6310_polling_get_data(sensor, buf);
}

qmc6310_polling_get_data()实现具体的数据读取逻辑:

static rt_size_t qmc6310_polling_get_data(rt_sensor_t sensor, void *data)
{
    mag_fifo_t *mag_fifo = (mag_fifo_t *)data;
    qmc6310_read_mag_xyz(&(mag_fifo->buf[0].mag_data[0]), &(mag_fifo->buf[0].mag_data[1]), &(mag_fifo->buf[0].mag_data[2]));
    mag_fifo->num = 1;
    return 1;
}

2.4.2 设备控制接口

qmc6310_control()用于服务层对驱动层的控制。

static rt_err_t qmc6310_control(struct rt_sensor_device *sensor, int cmd, void *args)
{
    rt_err_t result = RT_EOK;

    switch (cmd)
    {
    case RT_SENSOR_CTRL_GET_ID:
    {
        sensor_reg_info_t *info = (sensor_reg_info_t *)args;
        if (!qmc6310_dev)
        {
            info->sensor_id = 0;
            return RT_ERROR;
        }
        info->sensor_id = qmc6310_dev->id;

        if (info->gs_input)
            qmc6310_dev->gs_input = info->gs_input;     /*get gsensor data address */

        info->dev_period = QMC6310_PERIOD_TIMER;
        info->fifo_len = QMC6310_BUFF_SIZE;
        *(uint8_t *)args = qmc6310_dev->id;
        info->mag_algo_ops = qmc_algo_ops;
        info->mag_para_ops = qmc_para_ops;
    }
    break;
    case RT_SENSOR_CTRL_SET_RANGE:
        result = qmc6310_set_range(sensor, (rt_int32_t)args);
        break;
    case RT_SENSOR_CTRL_SET_ODR:
        result = -RT_EINVAL;
        break;
    case RT_SENSOR_CTRL_SET_MODE:
        result = qmc6310_set_mode(sensor, (rt_uint32_t)args & 0xff);
        break;
    case RT_SENSOR_CTRL_SET_POWER:
        result = qmc6310_set_power(sensor, (rt_uint32_t)args & 0xff);
        break;
    case RT_SENSOR_CTRL_SELF_TEST:
        result = qmc6310_self_test(sensor, *((rt_uint8_t *)args));
        break;
    default:
        return -RT_ERROR;
    }

    return result;
}

2.4.3 电源控制实现

qmc6310_set_power()实现对传感器电源状态的控制。

static rt_err_t qmc6310_set_power(rt_sensor_t sensor, rt_uint8_t power)
{
    switch (power)
    {
    case RT_SENSOR_POWER_DOWN:
        qmc6310_close();
        qmc6310_power_onoff(RT_FALSE);
        break;
    case RT_SENSOR_POWER_NORMAL:
        qmc6310_power_onoff(RT_TRUE);
        qmc6310_open();
        break;
    case RT_SENSOR_POWER_LOW:
        qmc6310_lowpowermode();
        break;
    case RT_SENSOR_POWER_HIGH:
        break;
    default:
        break;
    }
    return RT_EOK;
}

2.5 设备初始化函数

qmc6310_open()作为qmc6310地磁传感器设备的初始化入口,完成硬件唤醒、资源分配和参数配置,使传感器进入可工作状态。

static rt_err_t qmc6310_open(void)
{
    rt_err_t ret = RT_EOK;
#ifdef QMC6310_DEBUG
    rt_kprintf("qmc6310 open start ! \n");
#endif
    if (!qmc6310_dev)
    {
        if (qmc6310_init() == 0)
        {
            qmc6310_dev = rt_calloc(1, sizeof(struct qmc6310_device));
            if (qmc6310_dev == RT_NULL)
            {
                ret = RT_ENOMEM;
                goto err;
            }
            qmc6310_dev->bus = (rt_device_t)qmc6310_get_i2c_handle();
            qmc6310_dev->i2c_addr = qmc6310_get_dev_addr();
            qmc6310_dev->id = qmc6310_get_dev_id();
            rt_kprintf("(%s) open ok!\n", sensor_mag->parent.parent.name);
            return RT_EOK;
        }
        ret = RT_ERROR;
err:
        rt_kprintf("qmc6310 init err! code: %d\n", ret);
    }
    return ret;
}

3.RT-Thread 算法设备移植

算法负责原始数据处理(如滤波、特征提取)。 本节实现将算法嫁到到RT-Thread设备驱动框架上,封装为"算法设备",负责原始数据处理(如滤波、特征提取)。以移植qmclib算法为例。

3.1 配置

在目录solution\components\sensor\sensor_algo\mag\qmc6310目录下创建添加算法的lib文件,添加算法设备驱动的qmc6310_mag_service.c

3.2 设备注册接口

static int rt_hw_qmc_algo_register(const char *name)
{
    /* magnetometer/compass sensor register */
    qmc_algo = rt_calloc(1, sizeof(struct rt_sensor_device));
    RT_ASSERT(qmc_algo)

    qmc_algo->info.type       = RT_SENSOR_CLASS_MAG;
    qmc_algo->info.vendor     = RT_SENSOR_VENDOR_UNKNOWN;
    qmc_algo->info.model      = RT_NULL;
    qmc_algo->info.unit       = RT_SENSOR_UNIT_NONE;
    qmc_algo->info.intf_type  = 0;
    qmc_algo->info.range_max  = 220;
    qmc_algo->info.range_min  = 1;
    qmc_algo->info.period_min = 1;
    qmc_algo->info.fifo_max     = 1;
    qmc_algo->data_buf        = RT_NULL;
    qmc_algo->data_len            = 0;        //must be 0, because don't use data buf
    qmc_algo->config.mode = RT_SENSOR_MODE_POLLING;
    qmc_algo->config.irq_pin.pin = RT_PIN_NONE;
    qmc_algo->ops = &sensor_algo_ops;
    rt_err_t result = rt_hw_sensor_register(qmc_algo, name, RT_DEVICE_FLAG_RDWR, RT_NULL);
    if (result != RT_EOK)
    {
        rt_kprintf("MAG algo [%s] register err code: %d", name, result);
        goto __exit;
    }
    rt_kprintf("MAG algo[%s] init success!\n", name);
    return RT_EOK;
__exit:
    if (qmc_algo)
    {
        rt_free(qmc_algo);
        qmc_algo = RT_NULL;
    }
    return -RT_ERROR;
}
/**
 * @brief qmc algo  register, register name need unique, and longth is less than RT_NAME_MAX
*/
static int qmc_algo_register(void)
{
    /*register mag algo*/
    /*if  config QMC6310_ALGO_NAME, use QMC6310_ALGO_NAME, ohterwise use default name*/
#ifdef QMC6310_ALGO_NAME
    static char  name[] = QMC6310_ALGO_NAME;
#else
    static char  name[] = "qmclib";
#endif
    int ret = rt_hw_qmc_algo_register(name);
    return ret;
}
INIT_COMPONENT_EXPORT(qmc_algo_register);

3.3.1 数据获取接口

static rt_size_t qmc_algo_fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
{
    return 0;
}

:算法设备不通过数据获取接口获取数据,而是通过回调函数直接处理。

3.3.2 设备控制接口

static rt_err_t qmc_algo_control(struct rt_sensor_device *sensor, int cmd, void *args)
{
    rt_err_t result = RT_EOK;

    switch (cmd)
    {
    case RT_SENSOR_CTRL_GET_ID:
    {
        sensor_reg_info_t *info = args;
        info->sensor_id = 0xff;
        info->mag_algo_ops = qmc_algo_ops;
        info->mag_para_ops = qmc_para_ops;
        rt_kprintf("qmc algo_id	: %d ! \n", info->sensor_id);
        flag_calibrate = 0;
        break;
    }
    case RT_SENSOR_CTRL_SET_RANGE:
        result = RT_ERROR;
        break;
    case RT_SENSOR_CTRL_SET_ODR:
        result = RT_ERROR;
        break;
    case RT_SENSOR_CTRL_SET_MODE:
        result = RT_ERROR;
        break;
    case RT_SENSOR_CTRL_SET_POWER:
        result = RT_ERROR;
        break;
    case RT_SENSOR_CTRL_SELF_TEST:
        result = RT_ERROR;
        break;
    default:
        return -RT_ERROR;
    }

    return result;
}

:在这个函数中将qmc_algo_ops()qmc_para_ops()传递给上层的sensor_reg_info_t中的函数指针上,由上层的mag_algo进行统一调用。

3.3 算法处理函数

3.3.1 配置入口

用于处理上层下发的配置信息(如采样周期等参数)

static void qmc_para_ops(uint16_t msg_id, void *data)
{
    switch (msg_id)
    {
    case APP_SENSOR_SETTING_MAG_TIME:
    {
        qmc_result_peroid = *((uint32_t *)data);
        rt_kprintf("set qmc_result_peroid is %d ! \n", qmc_result_peroid);
        break;
    }
    default:
        ;
    }
}

3.3.2 数据入口

将地磁传感器原始数据传入函数,主动获取运动传感器数据,经过坐标对齐、磁场校正、姿态融合等算法操作后,产出方位角、俯仰角、横滚角和校准精度等数据,

static void  qmc_algo_ops(uint32_t peroid, mag_fifo_t *data, void *g_in)
{
    float mag_data[3];
    float result_data[3];
    float offset_data[3];
    float rr_data;
    float ori_data[3];
    int8_t accuracy;
    uint8_t mag_coordinate;
    float raw_mag[3];
    if (g_in)
        mag_get_gsensor_accxyz(g_in);
    else
        rt_kprintf("mag can't get acc data, try open macro USING_GSENSOR_DATA_STORE_LIST ,and open gs!\n");
    mag_data[0] = data->buf[0].mag_data[0];
    mag_data[1] = data->buf[0].mag_data[1];
    mag_data[2] = data->buf[0].mag_data[2];

    /* Convert the coordinate system */
    mag_coordinate = 2; //default
#ifdef COORDINATE_GS_TO_MAG
    mag_coordinate = 6;
#endif
    mag_coordinate_raw_to_real(mag_coordinate, mag_data, mag_real_data);

    raw_mag[0] = mag_real_data[0] * evers[0][0] + mag_real_data[1] * evers[0][1] + mag_real_data[2] * evers[0][2];
    raw_mag[1] = mag_real_data[0] * evers[1][0] + mag_real_data[1] * evers[1][1] + mag_real_data[2] * evers[1][2];
    raw_mag[2] = mag_real_data[0] * evers[2][0] + mag_real_data[1] * evers[2][1] + mag_real_data[2] * evers[2][2];


    convert_magnetic(raw_mag, result_data, offset_data, &rr_data, &accuracy);
    if ((!flag_calibrate) && accuracy == 3)
    {
        flag_calibrate = 1;
        rt_kprintf("flag_calibrate set 1\n");
    }
#ifdef QMC6310_DEBUG

    rt_kprintf("x = %f, y = %f, z = %f, x_bias= %f, y_bias= %f, z_bias = %f, accuracy = %d;\n",
               result_data[0], result_data[1], result_data[2], raw_mag[0] - result_data[0], raw_mag[1] - result_data[1],
               raw_mag[2] - result_data[2], accuracy);

    rt_kprintf("offset_data_x = %f, offset_data_y = %f, offset_data_z = %f, rr_data= %f;\n",
               offset_data[0], offset_data[1], offset_data[2], rr_data);
#endif
    QST_ORI_progress(acc, result_data, ori_data, &accuracy);

#ifdef QMC6310_DEBUG
    rt_kprintf("qmc data: mag_real_X=%f, mag_real_Y=%f, mag_real_Z=%f, accX=%f, accY=%f, accZ=%f !\n", \
               mag_real_data[0], mag_real_data[1], mag_real_data[2], acc[0], acc[1], acc[2]);
    rt_kprintf("mag data:ori_data=%f,%f,%f,uracy=%d\n", ori_data[0], ori_data[1], ori_data[2], accuracy);
#endif

    if ((!flag_calibrate))
        qmc_msg.uracy = accuracy;
    else
        qmc_msg.uracy = 3;



    qmc_msg.azimuth = ori_data[0];
    qmc_msg.pitch = ori_data[1];
    qmc_msg.roll = ori_data[2];
    if (qmc_msg.uracy == 0)
    {
        rt_kprintf("mag data invalid, Please calibrate first.\n");
    }
    mag_meas_result_postprocess(peroid, &qmc_msg);
}

3.4 运动传感器数据融合

地磁传感器必须借助运动传感器(加速度计、陀螺仪)进行姿态补偿与融合,才能输出稳定、精准的方位信息。

  1. 开启USING_GSENSOR_DATA_STORE_LIST后,通过接收上层传入的数据链表获取可用的运动传感器数据。

static void qmc6310_get_gsensor_data(uint8_t index, float *x, float *y, float *z, void *g_in)
{
#if defined (USING_GSENSOR_DATA_STORE_LIST) && (defined (BF0_LCPU) || defined (SENSOR_IN_HCPU))
    /*mag and gs all in hcpu or  all in lcpu*/
    rt_list_t *pos, *next;
    gsensors_fifo_t *node;
    if (qmc6310_dev->gs_input)
    {
        rt_list_t *gsensor_data_header = (rt_list_t *)g_in;
        if (!rt_list_len(gsensor_data_header))  //if no gsensor data , return
            return;
        rt_list_for_each_safe(pos, next, gsensor_data_header)
        {
            node = rt_list_entry(pos, gsensors_fifo_t, list);
            if (index > node ->num)
                index = node ->num - 1;

            *x = node -> buf[index].acce_data[0];
            *y = node -> buf[index].acce_data[1];
            *z = node -> buf[index].acce_data[2];
#ifdef QMC6310_DEBUG
            rt_kprintf("qmc6310_get_gs_data: x=%f, y=%f, z=%f;\n", node -> buf[index].acce_data[0], node -> buf[index].acce_data[1], node -> buf[index].acce_data[2]);
#endif
            break;
        }

    }
#else
    /*mag inhcpu and gs in lcpu*/
    //to be add: get gs data in ui;
#endif
}
  1. 算法片段:在通过convert_magnetic获得已校准的地磁矢量后,将其与加速度计数据一同送入QST_ORI_progress,完成融合解算,得到最终的姿态输出。

    convert_magnetic(raw_mag, result_data, offset_data, &rr_data, &accuracy);
    if ((!flag_calibrate) && accuracy == 3)
    {
        flag_calibrate = 1;
        rt_kprintf("flag_calibrate set 1\n");
    }
    QST_ORI_progress(acc, result_data, ori_data, &accuracy);

4.地磁传感器调度模块

调度模块是 Solution 传感器系统的核心,负责将器件采集的原始数据(如 PPG 信号、加速度值)转换为业务可用数据(如心率、计步数)。

4.1 器件与算法关联

4.1.1 核心接口说明

sensor_reg_open 是 Solution 基于 RT-Thread 扩展的核心接口,负责在系统初始化阶段“连接”已注册的传感器设备与算法设备,构建“硬件采集→算法处理”的数据链路,是传感器从“注册态”进入“可用态”的关键步骤。 主注册接口

rt_err_t sensor_reg_open(
    const char *sensor_name,     // 传感器设备名(如"mag_qmc6310")
    const char *algo_name,       // 算法设备名(如"mag_qmclib")
    sensor_reg_info_t *sensor_info, // 输出:传感器+算法信息
    rt_device_t *sensor_device   // 输出:传感器设备句柄
);

功能:完成传感器设备与算法模块的查找、验证与绑定。

数据结构定义

// 算法信息载体(在sensor_reg.h中定义)
typedef struct {
    sensor_type_t type;          // 传感器类型
    uint32_t sensor_id;          // 传感器芯片ID
    uint32_t dev_period;         // 采样周期(ms)
    uint8_t fifo_len;            // FIFO深度
    rt_uint32_t algo_period;    //算法周期(ms)
    // 算法函数指针(由算法设备注入)
    
    void (* mag_algo_ops_t)(uint32_t peroid, mag_fifo_t *data, void *g_in);
    void (* mag_para_ops_t)(uint16_t msg_id, void *data);
} sensor_reg_info_t;

4.1.2 应用示例

  1. mag_algo.c 中的宏定义,修改MAG_NAME为指定的"qmc6310",修改MAG_ALGO_NAME为指定的"qmclib"

fishy
  1. 初始化绑定设备,通过sensor_reg_open()查找并验证传感器设备(mag_qmc6310)与算法设备(mag_qmclib),通过算法设备向sensor_reg_info_t结构体注入其处理函数指针 (mag_algo_ops_tmag_para_ops_t);此后数据流处理时,调度器直接通过该函数指针调用算法。

static int mag_init(void)
{
    char *mag_name = "mag_"MAG_NAME;
#ifdef MAG_ALGO_NAME
    char *mag_algo_name = "mag_"MAG_ALGO_NAME;
#else
    char *mag_algo_name =  NULL;
#endif
    sensor_info.type = SENSOR_MAG;

    /*mag need gs data,so tell mag drv gs data list header*/
#if defined (SENSOR_USING_6D) && !defined (BSP_USING_PC_SIMULATOR) && defined (USING_GSENSOR_DATA_STORE_LIST)
    if (gsensor_is_opened())
        sensor_info.gs_input = gsensor_get_stored_data();
#endif
    if (RT_EOK != sensor_reg_open(mag_name, mag_algo_name, &sensor_info, &mag_device))
    {
        return RT_ERROR;
    }
    mag_id          = sensor_info.sensor_id;
    mag_period      = sensor_info.dev_period;;
    mag_fifo_len    = sensor_info.fifo_len;

#ifdef MAG_ALGO_DEBUG
    LOG_I("%s: type = %d, period = %d, fifo_len = %d, mag_algo_ops = 0x%p, mag_para_ops = 0x%p!", __func__, SENSOR_MAG,
          mag_period, mag_fifo_len, sensor_info.mag_algo_ops, sensor_info.mag_para_ops);
#endif
    return RT_EOK;
}
  1. 传感器设备与算法设备成功绑定,此时可以通过rt_device_read()直接读取处理经过算法处理后的传感器数据。

static int32_t mag_data_fetch(uint32_t data_size, void *data)
{
    if (!mag_device || !data) return RT_ERROR;

    rt_size_t size = rt_device_read(mag_device, 0, data, 1);

    if (0 == size) LOG_W("mag_data_fetch: err!!!\n");
    return size;
}

4.2 模块调度

4.2.1 基础概念

Solution 基于 RT-Thread 软件定时器 实现传感器的自动化调度,替代原生轮询机制,可灵活配置采样周期,同时适配低功耗场景(支持动态调整周期)。该调度器是 “器件采集→算法处理→数据上报” 全流程的触发核心。

4.2.2 示例代码

void mag_algo_scheduler(uint32_t period)
{
    static uint16_t mag_peroid_time = 0;
    int32_t ret = 0;
    if (!mag_is_opened())
        return;
    mag_peroid_time += period;
    if (mag_peroid_time < mag_period)
        return;
    mag_peroid_time = 0;

    /*LCPU  need fetch data in mag_algo_scheduler*/
#ifndef SENSOR_IN_HCPU
    ret = mag_data_fetch(0, &mag_data);
#endif
#ifdef MAG_ALGO_DEBUG
    rt_kprintf("mag_data x= %f, num = %d;\n", mag_data.buf[0].mag_data[0], mag_data.num);
#endif
    if (mag_data.num > 0 && sensor_info.mag_algo_ops)
    {
        sensor_info.mag_algo_ops(period, &mag_data, sensor_info.gs_input);
    }
}

:该函数由sensor_timer定时器定时触发,实现了数据的采集、处理、上报全流程