- 前言
- 知识背景
在阅读sensor部分,首先得了解rtt上很通用的posix标准,sensor框架对接应用层驱动是基于该标准实现,即驱动层需要实现rt_device_ops :
#ifdef RT_USING_DEVICE_OPSconst static struct rt_device_ops rt_sensor_ops = { RT_NULL, rt_sensor_open, rt_sensor_close, rt_sensor_read, RT_NULL, rt_sensor_control }; #endif
复制代码rt_err_t rt_device_register(rt_device_t dev, const char *name, rt_uint16_t flags)
复制代码- sensor框架各接口的使用
- 初始化接口
#ifdef BMX160_USING_MAGstatic void * _mag_init(const char *name, <font color="#ff8c00">struct rt_sensor_config *cfg, </font>void *hdev) { rt_int8_t result; rt_sensor_t sensor_mag = RT_NULL; sensor_mag = rt_calloc(1, sizeof(struct rt_sensor_device)); if (sensor_mag == RT_NULL) return RT_NULL; sensor_mag->info.type = RT_SENSOR_CLASS_MAG; sensor_mag->info.vendor = RT_SENSOR_VENDOR_BOSCH; sensor_mag->info.model = "bmi160_mag"; sensor_mag->info.unit = RT_SENSOR_UNIT_MGAUSS; sensor_mag->info.intf_type = RT_SENSOR_INTF_I2C; sensor_mag->info.range_max = 2000; sensor_mag->info.range_min = 125; sensor_mag->info.period_min = 100; sensor_mag->info.fifo_max = FIFO_DATA_LEN; <font color="#ff8c00"> rt_memcpy(&sensor_mag->config, cfg, sizeof(struct rt_sensor_config));</font> <font color="#2e8b57"> sensor_mag->ops = &sensor_ops;</font> <font color="#ff00ff"> result = rt_hw_sensor_register(sensor_mag, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_FIFO_RX, hdev);</font> if (result != RT_EOK) { LOG_E("device register err code: %d", result); rt_free(sensor_mag); rt_device_unregister(&sensor_mag->parent); return RT_NULL; } return sensor_mag; } #endif
复制代码- 应用打开设备接口
也就是说,control至少需要实现 RT_SENSOR_CTRL_SET_MODE 和 RT_SENSOR_CTRL_SET_POWER两个接口,另外,如果是中断设备,需要在设备注册时指定中断引脚信息,即驱动注册和打开驱动部分中标黄的部分,具体实现可见:
/* Sensor interrupt initialization function */static rt_err_t rt_sensor_irq_init(rt_sensor_t sensor) { if (sensor->config.irq_pin.pin == RT_PIN_NONE) { return -RT_EINVAL; } rt_pin_mode(sensor->config.irq_pin.pin, sensor->config.irq_pin.mode); if (sensor->config.irq_pin.mode == PIN_MODE_INPUT_PULLDOWN) { <font color="#2e8b57"> rt_pin_attach_irq(sensor->config.irq_pin.pin, PIN_IRQ_MODE_RISING, irq_callback, (void *)sensor);</font> } else if (sensor->config.irq_pin.mode == PIN_MODE_INPUT_PULLUP) { <font color="#008080"> rt_pin_attach_irq(sensor->config.irq_pin.pin, PIN_IRQ_MODE_FALLING, irq_callback, (void *)sensor);</font> } else if (sensor->config.irq_pin.mode == PIN_MODE_INPUT) { <font color="#008080"> rt_pin_attach_irq(sensor->config.irq_pin.pin, PIN_IRQ_MODE_RISING_FALLING, irq_callback, (void *)sensor);</font> } rt_pin_irq_enable(sensor->config.irq_pin.pin, RT_TRUE); LOG_I("interrupt init success"); return 0; }
复制代码- 应用设置参数接口
static rt_err_t rt_sensor_control(rt_device_t dev, int cmd, void *args){ rt_sensor_t sensor = (rt_sensor_t)dev; rt_err_t result = RT_EOK; RT_ASSERT(dev != RT_NULL); rt_err_t (*local_ctrl)(struct rt_sensor_device * sensor, int cmd, void *arg) = local_control; if (sensor->module) { rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER); } if (sensor->ops->control != RT_NULL) { local_ctrl = sensor->ops->control; } switch (cmd) { case RT_SENSOR_CTRL_GET_ID: if (args) { <font color="#ff00ff"> result = local_ctrl(sensor, RT_SENSOR_CTRL_GET_ID, args);</font> } break; case RT_SENSOR_CTRL_GET_INFO: if (args) { rt_memcpy(args, &sensor->info, sizeof(struct rt_sensor_info)); } break; case RT_SENSOR_CTRL_SET_RANGE: /* Configuration measurement range */ <font color="#ff00ff"> result = local_ctrl(sensor, RT_SENSOR_CTRL_SET_RANGE, args);</font> if (result == RT_EOK) { sensor->config.range = (rt_int32_t)args; LOG_D("set range %d", sensor->config.range); } break; case RT_SENSOR_CTRL_SET_ODR: /* Configuration data output rate */ <font color="#ff00ff"> result = local_ctrl(sensor, RT_SENSOR_CTRL_SET_ODR, args);</font> if (result == RT_EOK) { sensor->config.odr = (rt_uint32_t)args & 0xFFFF; LOG_D("set odr %d", sensor->config.odr); } break; case RT_SENSOR_CTRL_SET_POWER: /* Configuration sensor power mode */ <font color="#ff00ff"> result = local_ctrl(sensor, RT_SENSOR_CTRL_SET_POWER, args);</font> if (result == RT_EOK) { sensor->config.power = (rt_uint32_t)args & 0xFF; LOG_D("set power mode code:", sensor->config.power); } break; case RT_SENSOR_CTRL_SELF_TEST: /* Device self-test */ <font color="#ff00ff"> result = local_ctrl(sensor, RT_SENSOR_CTRL_SELF_TEST, args);</font> break; default: if (cmd > RT_SENSOR_CTRL_USER_CMD_START) { /* Custom commands */ <font color="#ff00ff"> result = local_ctrl(sensor, cmd, args);</font> } else { result = -RT_ERROR; } break; } if (sensor->module) { rt_mutex_release(sensor->module->lock); } return result; }
复制代码- 通知应用新数据接收到接口
/* Sensor interrupt correlation function *//* * Sensor interrupt handler function */ void rt_sensor_cb(rt_sensor_t sen) { if (sen->parent.rx_indicate == RT_NULL) { return; } if (sen->irq_handle != RT_NULL) { sen->irq_handle(sen); } /* The buffer is not empty. Read the data in the buffer first */ if (sen->data_len > 0) { <font color="#4169e1"> sen->parent.rx_indicate(&sen->parent, sen->data_len / sizeof(struct rt_sensor_data));</font> } else if (sen->config.mode == RT_SENSOR_MODE_INT) { /* The interrupt mode only produces one data at a time */ <font color="#4169e1"> sen->parent.rx_indicate(&sen->parent, 1);</font> } else if (sen->config.mode == RT_SENSOR_MODE_FIFO) { <font color="#4169e1"> sen->parent.rx_indicate(&sen->parent, sen->info.fifo_max);</font> } } /* ISR for sensor interrupt */ static void irq_callback(void *args) { rt_sensor_t sensor = (rt_sensor_t)args; rt_uint8_t i; if (sensor->module) { /* Invoke a callback for all sensors in the module */ for (i = 0; i < sensor->module->sen_num; i++) { rt_sensor_cb(sensor->module->sen[i]); } } else { rt_sensor_cb(sensor); } }
复制代码- 应用读取数据接口
static rt_ssize_t rt_sensor_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t len){ rt_sensor_t sensor = (rt_sensor_t)dev; rt_size_t result = 0; RT_ASSERT(dev != RT_NULL); if (buf == NULL || len == 0) { return 0; } if (sensor->module) { rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER); } /* The buffer is not empty. Read the data in the buffer first */ if (sensor->data_len > 0) { if (len > sensor->data_len / sizeof(struct rt_sensor_data)) { len = sensor->data_len / sizeof(struct rt_sensor_data); } rt_memcpy(buf, sensor->data_buf, len * sizeof(struct rt_sensor_data)); /* Clear the buffer */ sensor->data_len = 0; result = len; } else { /* If the buffer is empty read the data */ if (sensor->ops->fetch_data != RT_NULL) { <font color="#ff00ff"> result = sensor->ops->fetch_data(sensor, buf, len);</font> } } if (sensor->module) { rt_mutex_release(sensor->module->lock); } return result; }
复制代码static void _copy_data(struct rt_sensor_data *dst, struct bmi160_sensor_data *src){ dst->data.acce.x = src->x; dst->data.acce.y = src->y; dst->data.acce.z = src->z; dst->timestamp = rt_sensor_get_ts(); } static int _get_data(struct rt_sensor_device *sensor, void *buf) { struct bmi160_dev *hdev = sensor->parent.user_data; struct rt_sensor_data *data = buf; struct bmi160_sensor_data acce_data, gyro_data; if (sensor->info.type == RT_SENSOR_CLASS_MAG) { if (hdev->chip_id == BMX160_CHIP_ID) /* BMX160 */ { _get_mag_data(hdev, data); return 1; } return 0; } bmi160_get_sensor_data(BMI160_ACCEL_SEL | BMI160_GYRO_SEL, &acce_data, &gyro_data, hdev); if (sensor->info.type == RT_SENSOR_CLASS_ACCE) { data->type = RT_SENSOR_CLASS_ACCE; _copy_data(data, &acce_data); } else if (sensor->info.type == RT_SENSOR_CLASS_GYRO) { data->type = RT_SENSOR_CLASS_GYRO; _copy_data(data, &gyro_data); } return 1; } static int _get_fifo_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len) { int i; uint8_t frame_len = FIFO_DATA_LEN; struct rt_sensor_data *data = buf; struct bmi160_sensor_data buffer[FIFO_DATA_LEN]; // 32 data frames struct bmi160_dev *hdev = sensor->parent.user_data; rt_uint8_t data_type; if (bmi160_get_fifo_data(hdev) != BMI160_OK) return 0; if (sensor->info.type == RT_SENSOR_CLASS_ACCE) { data_type = RT_SENSOR_CLASS_ACCE; bmi160_extract_accel(buffer, &frame_len, hdev); } else if(sensor->info.type == RT_SENSOR_CLASS_GYRO) { data_type = RT_SENSOR_CLASS_GYRO; bmi160_extract_gyro(buffer, &frame_len, hdev); } else if (sensor->info.type == RT_SENSOR_CLASS_MAG) { struct bmi160_aux_data aux_data[FIFO_DATA_LEN]; data_type = RT_SENSOR_CLASS_MAG; bmi160_extract_aux(aux_data, &frame_len, hdev); _extract_mag(hdev, aux_data, buffer, frame_len); } len = len < frame_len ? len : frame_len; for (i = 0; i < len; i++) { data[i].type = data_type; _copy_data(data + i, buffer + i); } return len; } static rt_size_t _fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len) { if (sensor->config.mode == RT_SENSOR_MODE_FIFO) return _get_fifo_data(sensor, buf, len); return _get_data(sensor, buf); }
复制代码由实现可以知道,该接口需要实现读取数据,并将数据转换成 rt_sensor_data 格式数据上报,唯一的区别仅仅是不同工作模式需上报数据的数据量多少差异。
- 应用关闭设备接口
- 参考资料
- rtt源码中:/components/driver/sensor/v1/sensor.c
- rtt软件包中的 BMI160/BMX60驱动
- 《RT-Thread设备驱动开发指南》 传感器设备驱动开发章节
- 注意事项