地磁传感器移植指南¶
本章节将实现地磁传感器的在Solution Sensor框架下的移植,以QMC6310为参考。
1. 原生驱动移植¶
本节实现传感器芯片最基础的硬件通信功能,包括I2C总线操作、中断处理和电源管理。
1.1 配置与宏定义¶
在 sdk\customer\peripherals\sensor 目录下创建以qmc6310命名的目录,添加原生驱动qmc6310.c。
修改sdk\customer\peripherals\sensor对应qmc6310传感器类型的目录下kconfig文件,新建宏来实现驱动的控制
宏名称 |
类型 |
说明 |
|---|---|---|
|
必需 |
启用QMC6310地磁传感器 |
|
必需 |
I2C总线设备名称(如"i2c2") |
|
可选 |
电源控制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设备;
宏名称 |
类型 |
功能说明 |
取值/注意事项 |
|---|---|---|---|
|
宏定义 |
FIFO数据缓冲区大小,限制单次读取的最大帧数 |
默认1,单位:帧 |
|
宏定义 |
数据读取周期,决定应用层数据刷新频率 |
默认200ms,单位:毫秒 |
|
条件编译宏 |
控制整个驱动模块的编译开关 |
需在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 运动传感器数据融合¶
地磁传感器必须借助运动传感器(加速度计、陀螺仪)进行姿态补偿与融合,才能输出稳定、精准的方位信息。
开启
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
}
算法片段:在通过
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 应用示例¶
mag_algo.c 中的宏定义,修改MAG_NAME为指定的"qmc6310",修改MAG_ALGO_NAME为指定的"qmclib"
初始化绑定设备,通过
sensor_reg_open()查找并验证传感器设备(mag_qmc6310)与算法设备(mag_qmclib),通过算法设备向sensor_reg_info_t结构体注入其处理函数指针 (mag_algo_ops_t、mag_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;
}
传感器设备与算法设备成功绑定,此时可以通过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定时器定时触发,实现了数据的采集、处理、上报全流程