First, preparation
Ultrasonic Module HC-SR04 Introduction: https://blog.csdn.net/super828/article/details/84112824 .
Sensor Driver Development Guide: https://www.rt-thread.org/document/site/development-guide/sensor/sensor_driver_development/# .
Sensor drive frame description: https://www.rt-thread.org/document/site/development-guide/sensor/sensor_driver/ .
Two, Sensor drive frame
Effect Sensor drive frame is: to provide for the upper unified user interface , to improve the upper layer code reusability; simplified difficulty bottom-driven development, as long as to achieve a simple ops (operations: an operation command) to the sensor can be registered on the system.
That sensor registered with the system, becoming the device file, and then the upper layer application can call a unified API to control the sensor, such as sensor data acquisition operation of the class.
Sensor FIG overall structure of the drive frame as follows:
It provided for the upper layer is a standard device interfaces open/close/read/write/control
.
Provided for the underlying driver is a simple interface to ops: fetch_data/control
.
Module1 and support frame (block), there is a coupling of the bottom sensor device providing services.
2.1, works
Sensor device is standard equipment in fact a rich, is the addition of Sensor own unique part of the standard equipment on the basis of the original and , as shown below: rt_device
属性
控制命令
Sensor entire apparatus comprises two parts:
1, inherits some of the characteristics from the standard apparatus, comprising: a standard control interface 回调函数
, device_id
and the like.
2, Sensor device unique portion , Sensor 的类型
comprising: 相关的信息
, 特有的控制命令
, , ops
, and some 数据的结构
.
.Sensor device structure is as follows:
struct rt_sensor_device
{
struct rt_device parent; /* The standard device */
struct rt_sensor_info info; /* The sensor info data */
struct rt_sensor_config config; /* The sensor config data */
void *data_buf; /* The buf of the data received */
rt_size_t data_len; /* The size of the data received */
const struct rt_sensor_ops *ops; /* The sensor ops 操作命令*/
struct rt_sensor_module *module; /* The sensor module */
};
typedef struct rt_sensor_device *rt_sensor_t;
Which, struct rt_sensor_info info stored in some information related to the Sensor itself, in providing devices registered when the Sensor should not modify its contents during use. Individual members as shown in FIG.
struct rt_sensor_info
{
rt_uint8_t type; /* The sensor type */
rt_uint8_t vendor; /* Vendor of sensors 供应商*/
const char *model; /* model name of sensor 比如MPU6050*/
rt_uint8_t unit; /* unit of measurement */
rt_uint8_t intf_type; /* Communication interface type ,such as IIc */
rt_int32_t range_max; /* maximum range of this sensor's value. unit is 'unit'*/
rt_int32_t range_min; /* minimum range of this sensor's value. unit is 'unit' */
rt_uint32_t period_min; /* Minimum measurement period,unit:ms. zero = not a constant rate */
rt_uint8_t fifo_max; /* Maximum depth of fifo */
};
Sensor-driven framework to abstract some common configuration options that can be configured is placed struct rt_sensor_config
, the members are as follows:
struct rt_sensor_config
{
struct rt_sensor_intf intf; /* sensor interface config */
struct rt_device_pin_mode irq_pin; /* Interrupt pin, The purpose of this pin is to notification read data */
rt_uint8_t mode; /* sensor work mode */
rt_uint8_t power; /* sensor power mode */
rt_uint16_t odr; /* sensor out data rate */
rt_int32_t range; /* sensor range of measurement */
};
struct rt_sensor_intf
{
char *dev_name; /* The name of the communication device */
rt_uint8_t type; /* Communication interface type */
void *user_data; /* Private data for the sensor. ex. i2c addr,spi cs,control I/O */
};
Some of the remaining Sensor configuration items is a unique control command, the combined control of the interface ops , to complete the configuration of the sensor. As follows:
#define RT_SENSOR_CTRL_GET_ID (0) /* 读设备ID */
#define RT_SENSOR_CTRL_GET_INFO (1) /* 获取设备信息 */
#define RT_SENSOR_CTRL_SET_RANGE (2) /* 设置传感器测量范围 */
#define RT_SENSOR_CTRL_SET_ODR (3) /* 设置传感器数据输出速率,unit is HZ */
#define RT_SENSOR_CTRL_SET_MODE (4) /* 设置工作模式 */
#define RT_SENSOR_CTRL_SET_POWER (5) /* 设置电源模式 */
#define RT_SENSOR_CTRL_SELF_TEST (6) /* 自检 */
Sensor for storing data, in order to facilitate the parsed data, a type of each predetermined Sensor has its own unique data structure used between these members 共用体
in order to reduce the code amount.
/* 3-axis Data Type */
struct sensor_3_axis
{
rt_int32_t x;
rt_int32_t y;
rt_int32_t z;
};
struct rt_sensor_data
{
rt_uint32_t timestamp; /* The timestamp when the data was received */
rt_uint8_t type; /* The sensor type of the data */
union
{
struct sensor_3_axis acce; /* Accelerometer. unit: mG */
struct sensor_3_axis gyro; /* Gyroscope. unit: mdps */
struct sensor_3_axis mag; /* Magnetometer. unit: mGauss */
rt_int32_t temp; /* Temperature. unit: dCelsius */
rt_int32_t humi; /* Relative humidity. unit: permillage */
rt_int32_t baro; /* Pressure. unit: pascal (Pa) */
rt_int32_t light; /* Light. unit: lux */
rt_int32_t proximity; /* Distance. unit: centimeters */
rt_int32_t hr; /* Heat rate. unit: HZ */
rt_int32_t tvoc; /* TVOC. unit: permillage */
rt_int32_t noise; /* Noise Loudness. unit: HZ */
rt_uint32_t step; /* Step sensor. unit: 1 */
} data;
};
Unique ops
OPS (operation function) comprises two function pointers, a role is to obtain sensor data (fetch_data), the other role is to control the sensor by a control command (control).
struct rt_sensor_ops
{
rt_size_t (*fetch_data)(struct rt_sensor_device *sensor, void *buf, rt_size_t len);
rt_err_t (*control)(struct rt_sensor_device *sensor, int cmd, void *arg);
};
way to register
Sensor driver framework provides a registration function Sensor, Sensor by passing control blocks, name, and private data flag, it is possible to complete the registration sensor device.
int rt_hw_sensor_register(rt_sensor_t sensor,
const char *name,
rt_uint32_t flag,
void *data);
It would appear Sensor-driven framework relying on the framework of standard equipment, as long as the sensor is connected to the drive of the Sensor ops, and by calling the rt_hw_sensor_register
register function Sensor devices can be controlled through the standard device interface of the sensor.
module support
Defined module is to solve the two sensors coupled to the bottom occurs, and some sensors have a function of both the accelerometer gyro function, and they are common to the FIFO in the FIFO mode, only the two types sensor data are simultaneously read out, which shows that they are coupled to the data. To solve this problem, we define the type of module
struct rt_sensor_module
{
rt_mutex_t lock; /* The module lock */
rt_sensor_t sen[RT_SENSOR_MODULE_MAX]; /* The module contains a list of sensors */
rt_uint8_t sen_num; /* Number of sensors contained in the module */
};
Which contains a pointer device control block coupled to the sensor, this function can be via the read data when the gyroscope, while updating the value of the accelerometer, to solve the problem underlying coupling.
Third, the development of guidelines --- ultrasonic module HC-SR04 A Case Study
The main task is to develop ops docking interfaces Sensor drive frame, and then register for the Sensor device, and then be able to control the behavior of the sensor by driving relevant framework.
framework were given two sensor interfaces ( fetch_data
/ control
) required to achieve these two interfaces in the drive.
3.1、fetchdata
Action: acquiring sensor data. Interface Prototype:
rt_size_t (*fetch_data)(struct rt_sensor_device *sensor, void *buf, rt_size_t len);
Sensor-driven framework to support the current default polling (POLLING), interrupt (INT), FIFO three operating modes. If the sensor is to develop the support 中断
and FIFO
operation mode, the operation mode where the sensor is determined, and then return to the sensor data according to different modes. As follows:
static rt_size_t xxx_acc_fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
{
if (sensor->config.mode == RT_SENSOR_MODE_POLLING)
{
return _xxx_acc_polling_get_data(sensor, buf, len);
}
else if (sensor->config.mode == RT_SENSOR_MODE_INT)
{
return _xxx_acc_int_get_data(sensor, buf, len);
}
else if (sensor->config.mode == RT_SENSOR_MODE_FIFO)
{
return _xxx_acc_fifo_get_data(sensor, buf, len);
}
else
return 0;
}
Developers should return data to identify the data type for storing data, and then filled with a time stamp data field, as follows:
sensor_data->type = RT_SENSOR_CLASS_ACCE;
sensor_data->data.acce.x = acceleration.x;
sensor_data->data.acce.y = acceleration.y;
sensor_data->data.acce.z = acceleration.z;
sensor_data->timestamp = rt_sensor_get_ts();
HC-SR04 as an example:
static rt_size_t _fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
{
struct rt_sensor_data *data = buf;
data->type = RT_SENSOR_CLASS_PROXIMITY;
data->data.proximity = distance;
data->timestamp = rt_sensor_get_ts();
return 1;
}
3.2、control
rt_err_t (*control)(struct rt_sensor_device *sensor, int cmd, void *arg);
Control sensors rely on this interface function is realized by performing different incoming command word determining the different operations.
HC-SR04 as an example:
static rt_err_t _control(struct rt_sensor_device *sensor, int cmd, void *args)
{
rt_err_t result = RT_EOK;
switch (cmd)
{
case RT_SENSOR_CTRL_SET_POWER:
result = _set_power(sensor, (rt_uint32_t)args & 0xff);
break;
default:
return RT_EOK;
}
return result;
}
3.3, the device interface structure ops
But also to achieve a storage device interface ops above structure interface functions:
static struct rt_sensor_ops xxx_ops =
{
xxx_acc_fetch_data,
xxx_acc_control
};
Fourth, the device registration
rt_int8_t result;
rt_sensor_t sensor_pr = RT_NULL;
sensor_pr = rt_calloc(1, sizeof(struct rt_sensor_device));
if (sensor_pr == RT_NULL)
return RT_NULL;
sensor_pr->info.type = RT_SENSOR_CLASS_PROXIMITY;
sensor_pr->info.model = "hr_sr04";
sensor_pr->info.unit = RT_SENSOR_UNIT_MM;
sensor_pr->info.intf_type = RT_SENSOR_INTF_ONEWIRE;
sensor_pr->info.range_max = RANG_MAX;
sensor_pr->info.range_min = RANG_MIN;
sensor_pr->info.period_min = 100;
rt_memcpy(&sensor_pr->config, cfg, sizeof(struct rt_sensor_config));
sensor_pr->ops = &sensor_ops;
sensor_pr->irq_handle = sr04_irq_handle;
result = rt_hw_sensor_register(sensor_pr, name, RT_DEVICE_FLAG_RDWR, RT_NULL);