- 前言
- 知识背景
在阅读sensor部分,首先得了解rtt上很通用的posix标准,sensor框架对接应用层驱动是基于该标准实现,即驱动层需要实现rt_device_ops :
- #ifdef RT_USING_DEVICE_OPS
- const 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框架各接口的使用
- 初始化接口
- /*
- * sensor register
- */
- int rt_hw_sensor_register(rt_sensor_t sensor,
- const char *name,
- rt_uint32_t flag,
- void *data)
- {
- rt_int8_t result;
- rt_device_t device;
- RT_ASSERT(sensor != RT_NULL);
- char *sensor_name = RT_NULL, *device_name = RT_NULL;
- if (sensor->ops == RT_NULL)
- {
- sensor->ops = &local_ops;
- }
- /* Add a type name for the sensor device */
- sensor_name = sensor_name_str[sensor->info.type];
- device_name = (char *)rt_calloc(1, rt_strlen(sensor_name) + 1 + rt_strlen(name));
- if (device_name == RT_NULL)
- {
- LOG_E("device_name calloc failed!");
- return -RT_ERROR;
- }
- rt_memcpy(device_name, sensor_name, rt_strlen(sensor_name) + 1);
- strcat(device_name, name);
- if (sensor->module != RT_NULL && sensor->module->lock == RT_NULL)
- {
- /* Create a mutex lock for the module */
- sensor->module->lock = rt_mutex_create(name, RT_IPC_FLAG_PRIO);
- if (sensor->module->lock == RT_NULL)
- {
- rt_free(device_name);
- return -RT_ERROR;
- }
- }
- device = &sensor->parent;
- #ifdef RT_USING_DEVICE_OPS
- device->ops = &rt_sensor_ops;
- #else
- device->init = RT_NULL;
- device->open = rt_sensor_open;
- device->close = rt_sensor_close;
- device->read = rt_sensor_read;
- device->write = RT_NULL;
- device->control = rt_sensor_control;
- #endif
- device->type = RT_Device_Class_Sensor;
- device->rx_indicate = RT_NULL;
- device->tx_complete = RT_NULL;
- device->user_data = data;
- <font color="#ff00ff"> result = rt_device_register(device, device_name, flag | RT_DEVICE_FLAG_STANDALONE);</font>
- if (result != RT_EOK)
- {
- LOG_E("rt_sensor[%s] register err code: %d", device_name, result);
- rt_free(device_name);
- return result;
- }
- LOG_I("rt_sensor[%s] init success", device_name);
- rt_free(device_name);
- return RT_EOK;
- }
- #ifdef BMX160_USING_MAG
- static 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
- 应用打开设备接口
- /* RT-Thread Device Interface */
- static rt_err_t rt_sensor_open(rt_device_t dev, rt_uint16_t oflag)
- {
- rt_sensor_t sensor = (rt_sensor_t)dev;
- RT_ASSERT(dev != RT_NULL);
- rt_err_t res = RT_EOK;
- rt_err_t (*local_ctrl)(struct rt_sensor_device * sensor, int cmd, void *arg) = local_control;
- if (sensor->module)
- {
- /* take the module mutex */
- rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER);
- }
- if (sensor->module != RT_NULL && sensor->info.fifo_max > 0 && sensor->data_buf == RT_NULL)
- {
- /* Allocate memory for the sensor buffer */
- sensor->data_buf = rt_malloc(sizeof(struct rt_sensor_data) * sensor->info.fifo_max);
- if (sensor->data_buf == RT_NULL)
- {
- res = -RT_ENOMEM;
- goto __exit;
- }
- }
- if (sensor->ops->control != RT_NULL)
- {
- local_ctrl = sensor->ops->control;
- }
- sensor->config.mode = RT_SENSOR_MODE_POLLING;
- if (oflag & RT_DEVICE_FLAG_RDONLY && dev->flag & RT_DEVICE_FLAG_RDONLY)
- {
- /* If polling mode is supported, configure it to polling mode */
- <font color="#ff00ff"> local_ctrl(sensor, RT_SENSOR_CTRL_SET_MODE, (void *)RT_SENSOR_MODE_POLLING);</font>
- }
- else if (oflag & RT_DEVICE_FLAG_INT_RX && dev->flag & RT_DEVICE_FLAG_INT_RX)
- {
- /* If interrupt mode is supported, configure it to interrupt mode */
- <font color="#ff00ff"> if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_MODE, (void *)RT_SENSOR_MODE_INT) == RT_EOK)</font>
- {
- /* Initialization sensor interrupt */
- <font color="#ff8c00"> rt_sensor_irq_init(sensor);</font>
- sensor->config.mode = RT_SENSOR_MODE_INT;
- }
- }
- else if (oflag & RT_DEVICE_FLAG_FIFO_RX && dev->flag & RT_DEVICE_FLAG_FIFO_RX)
- {
- /* If fifo mode is supported, configure it to fifo mode */
- <font color="#ff00ff"> if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_MODE, (void *)RT_SENSOR_MODE_FIFO) == RT_EOK)</font>
- {
- /* Initialization sensor interrupt */
- <font color="#ff00ff"> rt_sensor_irq_init(sensor);</font>
- sensor->config.mode = RT_SENSOR_MODE_FIFO;
- }
- }
- else
- {
- res = -RT_EINVAL;
- goto __exit;
- }
- /* Configure power mode to normal mode */
- if (<font color="#ff00ff">local_ctrl(sensor, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SENSOR_POWER_NORMAL) == RT_EOK</font>)
- {
- sensor->config.power = RT_SENSOR_POWER_NORMAL;
- }
- __exit:
- if (sensor->module)
- {
- /* release the module mutex */
- rt_mutex_release(sensor->module->lock);
- }
- return res;
- }
- static rt_err_t _control(struct rt_sensor_device *sensor, int cmd, void *args)
- {
- struct bmi160_dev *hdev = sensor->parent.user_data;
- rt_err_t result = RT_EOK;
- switch (cmd)
- {
- case RT_SENSOR_CTRL_GET_ID:
- *(rt_uint8_t *)args = hdev->chip_id;
- break;
- case RT_SENSOR_CTRL_SET_ODR:
- result = _set_odr(sensor, (rt_uint32_t)args & 0xffff);
- break;
- case RT_SENSOR_CTRL_SET_RANGE:
- result = _set_range(sensor, (rt_uint32_t)args);
- break;
- case RT_SENSOR_CTRL_SET_POWER:
- result = _set_power(sensor, (rt_uint32_t)args & 0xff);
- break;
- case RT_SENSOR_CTRL_SET_MODE:
- result = _select_mode(sensor, (rt_uint32_t)args);
- break;
- case RT_SENSOR_CTRL_SELF_TEST:
- /* TODO */
- result = -RT_EINVAL;
- break;
- default:
- return -RT_EINVAL;
- }
- return result;
- }
- <font color="#9932cc">static struct rt_sensor_ops sensor_ops =
- {
- _fetch_data,
- _control
- };</font>
也就是说,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 格式数据上报,唯一的区别仅仅是不同工作模式需上报数据的数据量多少差异。
- 应用关闭设备接口
- static rt_err_t rt_sensor_close(rt_device_t dev)
- {
- rt_sensor_t sensor = (rt_sensor_t)dev;
- int i;
- rt_err_t (*local_ctrl)(struct rt_sensor_device * sensor, int cmd, void *arg) = local_control;
- RT_ASSERT(dev != RT_NULL);
- if (sensor->module)
- {
- rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER);
- }
- if (sensor->ops->control != RT_NULL)
- {
- local_ctrl = sensor->ops->control;
- }
- /* Configure power mode to power down mode */
- if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SENSOR_POWER_DOWN) == RT_EOK)
- {
- sensor->config.power = RT_SENSOR_POWER_DOWN;
- }
- if (sensor->module != RT_NULL && sensor->info.fifo_max > 0 && sensor->data_buf != RT_NULL)
- {
- for (i = 0; i < sensor->module->sen_num; i ++)
- {
- if (sensor->module->sen[i]->parent.ref_count > 0)
- goto __exit;
- }
- /* Free memory for the sensor buffer */
- for (i = 0; i < sensor->module->sen_num; i ++)
- {
- if (sensor->module->sen[i]->data_buf != RT_NULL)
- {
- rt_free(sensor->module->sen[i]->data_buf);
- sensor->module->sen[i]->data_buf = RT_NULL;
- }
- }
- }
- if (sensor->config.mode != RT_SENSOR_MODE_POLLING)
- {
- /* Sensor disable interrupt */
- if (sensor->config.irq_pin.pin != RT_PIN_NONE)
- {
- rt_pin_irq_enable(sensor->config.irq_pin.pin, RT_FALSE);
- }
- }
- __exit:
- if (sensor->module)
- {
- rt_mutex_release(sensor->module->lock);
- }
- return RT_EOK;
- }
- 参考资料
- rtt源码中:/components/driver/sensor/v1/sensor.c
- rtt软件包中的 BMI160/BMX60驱动
- 《RT-Thread设备驱动开发指南》 传感器设备驱动开发章节
- 注意事项