概述
目的与概述
本文档为RT-ThreadSensor驱动框架下传感器驱动的开发指南文档,给开发团队提供开发标准和规范。
阅读对象
进行传感器驱动开发的工程人员注意事项:在阅读本篇文档之前,请先翻阅历史文章查看传感器驱动框架介绍。
开发指南
开发一个传感器驱动一般需要下面的几个步骤:调研与准备、开发、测试、提交。
开发过程可以参考已经支持的传感器,如果需要获取传感器列表请直接留言即可。
调研与准备
根据datasheet或其他途径,了解传感器的特性,并记录下来,如下面几种:
传感器类型通讯接口(i2c/spi/…)测量范围最短测量周期支持几种工作模式、电源模式开发
开发的主要任务就是对接Sensor驱动框架的ops接口,然后注册为Sensor设备,进而能够通过驱动框架控制传感器的相关行为。
ops接口对接
sensor框架共给出了两个接口(
fetch_data
/
control
),需要在驱动中实现这两个接口。
fetchdata
作用:获取传感器的数据。接口原型:
1rt_size_t(*fetch_data)(structrt_sensor_device*sensor,void*buf,rt_size_tlen);
Sensor驱动框架当前默认支持轮询(POLLING)、中断(INT)、FIFO这三种工作模式。如果要开发的传感器支持
中断
和
FIFO
的工作模式,需要在这里判断传感器的工作模式,然后再根据不同的模式返回传感器数据。
如下所示:
1staticrt_size_txxx_acc_fetch_data(structrt_sensor_device*sensor,void*buf,rt_size_tlen)2{3if(sensor-config.mode==RT_SENSOR_MODE_POLLING)4{5return_xxx_acc_polling_get_data(sensor,buf,len);6}7elseif(sensor-config.mode==RT_SENSOR_MODE_INT)8{9return_xxx_acc_int_get_data(sensor,buf,len);10}11elseif(sensor-config.mode==RT_SENSOR_MODE_FIFO)12{13return_xxx_acc_fifo_get_data(sensor,buf,len);14}15else16return0;17}
开发人员在返回数据时应先标识存储数据的数据类型,然后再填充数据域与时间戳,如下所示:
1sensor_data-type=RT_SENSOR_CLASS_ACCE2sensor_data-data.acce.x=acceleration.x;3sensor_data-data.acce.y=acceleration.y;4sensor_data-data.acce.z=acceleration.z;5sensor_data-timestamp=rt_sensor_get_ts();
注意事项
-时间戳的获取函数请使用Sensor驱动框架提供的时间戳获取函数
rt_sensor_get_ts
-在FIFO模式下底层数据可能会有耦合,需要使用module,同时更新两个传感器的数据。-要将数据的单位转换为Sensor驱动框架里规定的数据单位。
数据单位参考如下:
注:后期会迭代增加新的传感器数据单位。
control
1rt_err_t(*control)(structrt_sensor_device*sensor,intcmd,void*arg);
传感器的控制就是依靠这个接口函数实现的,通过判断传入的命令字的不同执行不同的操作,目前支持以下命令字:
1#defineRT_SENSOR_CTRL_GET_ID(0)/*读设备ID*/2#defineRT_SENSOR_CTRL_GET_INFO(1)/*获取设备信息(由框架实现,在驱动中不需要实现)*/3#defineRT_SENSOR_CTRL_SET_RANGE(2)/*设置传感器测量范围*/4#defineRT_SENSOR_CTRL_SET_ODR(3)/*设置传感器数据输出速率,unitisHZ*/5#defineRT_SENSOR_CTRL_SET_MODE(4)/*设置工作模式*/6#defineRT_SENSOR_CTRL_SET_POWER(5)/*设置电源模式*/7#defineRT_SENSOR_CTRL_SELF_TEST(6)/*自检*/
需要在驱动里实现这个函数,如下所示:
1staticrt_err_txxx_acc_control(structrt_sensor_device*sensor,intcmd,void*args)2{3rt_err_tresult=RT_EOK;45switch(cmd)6{7caseRT_SENSOR_CTRL_GET_IDresult=_xxx_acc_get_id(sensor,args);9break;10caseRT_SENSOR_CTRL_SET_RANGE:11result=_xxx_acc_set_range(sensor,(rt_int32_t)args);12break;13caseRT_SENSOR_CTRL_SET_ODR:14result=_xxx_acc_set_odr(sensor,(rt_uint32_t)args0xffff);15break;16caseRT_SENSOR_CTRL_SET_MODE:17result=_xxx_acc_set_mode(sensor,(rt_uint32_t)args0xff);18break;19caseRT_SENSOR_CTRL_SET_POWER:20result=_xxx_acc_set_power(sensor,(rt_uint32_t)args0xff);21break;22caseRT_SENSOR_CTRL_SELF_TEST:23break;24default:25return-RT_ERROR;26}27returnresult;28}
注意事项:
这里需要注意传来参数的数据类型是由structrt_sensor_config这个结构体规定的,因此
RT_SENSOR_CTRL_SET_RANGE
这个命令传来的参数是
rt_int32_t
类型的,需要经过强转一次,才可以得到正确的参数。
然后实现一个设备接口的结构体ops存储上面的接口函数,
1staticstructrt_sensor_opsxxx_ops=2{3xxx_acc_fetch_data,4xxx_acc_control5};
设备注册
完成Sensor的ops的对接之后还要注册一个sensor设备,这样上层才能找到这个传感器设备,进而进行控制。
设备的注册一般需要这样的步骤:创建一个rt_sensor_t的结构体指针,然后为结构体分配内存,并完成相关初始化,最后调用rt_hw_sensor_register完成传感器设备的注册。
1intrt_hw_xxx_init(constchar*name,structrt_sensor_config*cfg)2{3rt_int8_tresult;4rt_sensor_tsensor=RT_NULL;56sensor=rt_calloc(1,sizeof(structrt_sensor_device));7if(sensor==RT_NULL)8return-1;sensor-info.type=RT_SENSOR_CLASS_ACCE;11sensor-info.vendor=RT_SENSOR_VENDOR_STM;12sensor-info.model=xxx_acce;13sensor-info.unit=RT_SENSOR_UNIT_MG;14sensor-info.intf_type=RT_SENSOR_INTF_I2C;15sensor-info.range_max=SENSOR_ACC_RANGE_16G;16sensor-info.range_min=SENSOR_ACC_RANGE_2G;17sensor-info.period_min=;rt_memcpy(sensor-config,cfg,sizeof(structrt_sensor_config));20sensor-ops=sensor_ops;result=rt_hw_sensor_register(sensor,name,RT_DEVICE_FLAG_RDWR
RT_DEVICE_FLAG_FIFO_RX,RT_NULL);23if(result!=RT_EOK)24{25LOG_E(deviceregistererrcode:%d,result);26rt_free(sensor);27return-RT_ERROR;28}LOG_I(accsensorinitsuccess);31return0;32}
注意事项:
-
rt_hw_sensor_register
会为传入的name自动添加前缀,如
加速度计
类型的传感器会自动添加
acce_
的前缀。由于系统默认的设备名最长为7个字符,因此如果传入的名称超过3个字符的话会被裁掉。-注册时如传感器支持FIFO的话,需要添加RT_DEVICE_FLAG_FIFO_RX的标志位。-如果两个设备有耦合的话,需要利用module解耦。初始化一个module,将两个传感器的设备控制块赋值到里面,并将module的地址赋值给两个传感器设备。框架会自动完成module锁的创建。
其中传入参数
structrt_sensor_config*cfg
是用来解耦硬件的通讯接口的,通过在底层驱动初始化的时候传入这个参数,实现硬件接口的配置。里面包含
structrt_sensor_intf
这个结构体,
1structrt_sensor_intf2{3char*dev_name;/*Thenameofthe