本帖最后由 oxlm 于 2023-7-12 23:57 编辑


  • 前言
在某个电子工程师的群里面,发现了面包板的赠书活动,一看书名,刚好是自己感兴趣的RTT芯片驱动开发方向的指南,因此直接申请参加了这次赠书活动,也非常荣幸的拿到了《RT-Thread设备驱动开发指南》这本书籍。

  • 知识背景

  由于自己之前又配过一系列简单驱动,对基础篇中的驱动配置都十分熟悉,因此直接跳过基础篇的驱动配置内容,查看最近使用的sensor部分。
     在阅读sensor部分,首先得了解rtt上很通用的posix标准,sensor框架对接应用层驱动是基于该标准实现,即驱动层需要实现rt_device_ops
  1. #ifdef RT_USING_DEVICE_OPS
  2. const static struct rt_device_ops rt_sensor_ops =
  3. {
  4.     RT_NULL,
  5.     rt_sensor_open,
  6.     rt_sensor_close,
  7.     rt_sensor_read,
  8.     RT_NULL,
  9.     rt_sensor_control
  10. };
  11. #endif
同时,需通过 rt_device_register注册设备,
  1. rt_err_t rt_device_register(rt_device_t dev, const char *name, rt_uint16_t flags)
,驱动层完成以上步骤后,应用层就可以通过 rt_device_open , rt_device_close, rt_device_control, rt_device_read 和 rt_device_set_rx_indicate等接口实现逻辑控制。

  • sensor框架各接口的使用
  • 初始化接口
前一章提到设备是通过 rt_device_register接口注册成传感器设备的,因此只需要找到传感器框架中调用该接口的位置便可找到具体实现逻辑。
  1. /*
  2. * sensor register
  3. */
  4. int rt_hw_sensor_register(rt_sensor_t sensor,
  5.                                          const char              *name,
  6.                                          rt_uint32_t              flag,
  7.                                          void                    *data)
  8. {
  9.      rt_int8_t result;
  10.     rt_device_t device;
  11.     RT_ASSERT(sensor != RT_NULL);
  12.     char *sensor_name = RT_NULL, *device_name = RT_NULL;
  13.     if (sensor->ops == RT_NULL)
  14.     {
  15.         sensor->ops = &local_ops;
  16.     }
  17.     /* Add a type name for the sensor device */
  18.     sensor_name = sensor_name_str[sensor->info.type];
  19.     device_name = (char *)rt_calloc(1, rt_strlen(sensor_name) + 1 + rt_strlen(name));
  20.     if (device_name == RT_NULL)
  21.     {
  22.         LOG_E("device_name calloc failed!");
  23.         return -RT_ERROR;
  24.     }
  25.     rt_memcpy(device_name, sensor_name, rt_strlen(sensor_name) + 1);
  26.     strcat(device_name, name);
  27.     if (sensor->module != RT_NULL && sensor->module->lock == RT_NULL)
  28.     {
  29.         /* Create a mutex lock for the module */
  30.         sensor->module->lock = rt_mutex_create(name, RT_IPC_FLAG_PRIO);
  31.         if (sensor->module->lock == RT_NULL)
  32.         {
  33.             rt_free(device_name);
  34.             return -RT_ERROR;
  35.         }
  36.     }
  37.     device = &sensor->parent;
  38.     #ifdef RT_USING_DEVICE_OPS
  39.     device->ops         = &rt_sensor_ops;
  40.     #else
  41.     device->init        = RT_NULL;
  42.     device->open        = rt_sensor_open;
  43.     device->close       = rt_sensor_close;
  44.     device->read        = rt_sensor_read;
  45.     device->write       = RT_NULL;
  46.     device->control     = rt_sensor_control;
  47. #endif
  48.     device->type        = RT_Device_Class_Sensor;
  49.     device->rx_indicate = RT_NULL;
  50.     device->tx_complete = RT_NULL;
  51.     device->user_data   = data;
  52.    <font color="#ff00ff"> result = rt_device_register(device, device_name, flag | RT_DEVICE_FLAG_STANDALONE);</font>
  53.     if (result != RT_EOK)
  54.     {
  55.         LOG_E("rt_sensor[%s] register err code: %d", device_name, result);
  56.         rt_free(device_name);
  57.         return result;
  58.     }
  59.     LOG_I("rt_sensor[%s] init success", device_name);
  60.     rt_free(device_name);
  61.     return RT_EOK;
  62. }
   而该接口的调用位置,即在驱动初始化的位置,以BMX160驱动中的地磁传感器为例,注册实现为:
  1. #ifdef BMX160_USING_MAG
  2. static void * _mag_init(const char *name, <font color="#ff8c00">struct rt_sensor_config *cfg, </font>void *hdev)
  3. {
  4.     rt_int8_t result;
  5.     rt_sensor_t sensor_mag = RT_NULL;
  6.     sensor_mag = rt_calloc(1, sizeof(struct rt_sensor_device));
  7.     if (sensor_mag == RT_NULL)
  8.         return RT_NULL;
  9.     sensor_mag->info.type       = RT_SENSOR_CLASS_MAG;
  10.     sensor_mag->info.vendor     = RT_SENSOR_VENDOR_BOSCH;
  11.     sensor_mag->info.model      = "bmi160_mag";
  12.     sensor_mag->info.unit       = RT_SENSOR_UNIT_MGAUSS;
  13.     sensor_mag->info.intf_type  = RT_SENSOR_INTF_I2C;
  14.     sensor_mag->info.range_max  = 2000;
  15.     sensor_mag->info.range_min  = 125;
  16.     sensor_mag->info.period_min = 100;
  17.     sensor_mag->info.fifo_max   = FIFO_DATA_LEN;
  18. <font color="#ff8c00">    rt_memcpy(&sensor_mag->config, cfg, sizeof(struct rt_sensor_config));</font>
  19. <font color="#2e8b57">    sensor_mag->ops = &sensor_ops;</font>
  20. <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>
  21.     if (result != RT_EOK)
  22.     {
  23.         LOG_E("device register err code: %d", result);
  24.         rt_free(sensor_mag);
  25.         rt_device_unregister(&sensor_mag->parent);
  26.         return RT_NULL;
  27.     }
  28.     return sensor_mag;
  29. }
  30. #endif

  • 应用打开设备接口
    由上一章节已知,应用打开传感器设备,使用的接口为rt_device_open,具体对应的驱动层接口为对应设备驱动结构体 rt_device_ops  中的init和open接口,由于init接口为空,因此直接调用接口为 rt_sensor_open,此函数实现如下:
  1. /* RT-Thread Device Interface */
  2. static rt_err_t rt_sensor_open(rt_device_t dev, rt_uint16_t oflag)
  3. {
  4.     rt_sensor_t sensor = (rt_sensor_t)dev;
  5.     RT_ASSERT(dev != RT_NULL);
  6.     rt_err_t res = RT_EOK;
  7.     rt_err_t (*local_ctrl)(struct rt_sensor_device * sensor, int cmd, void *arg) =  local_control;
  8.     if (sensor->module)
  9.     {
  10.         /* take the module mutex */
  11.         rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER);
  12.     }
  13.     if (sensor->module != RT_NULL && sensor->info.fifo_max > 0 && sensor->data_buf == RT_NULL)
  14.     {
  15.         /* Allocate memory for the sensor buffer */
  16.         sensor->data_buf = rt_malloc(sizeof(struct rt_sensor_data) * sensor->info.fifo_max);
  17.         if (sensor->data_buf == RT_NULL)
  18.         {
  19.             res = -RT_ENOMEM;
  20.             goto __exit;
  21.         }
  22.     }
  23.     if (sensor->ops->control != RT_NULL)
  24.     {
  25.         local_ctrl = sensor->ops->control;
  26.     }
  27.     sensor->config.mode = RT_SENSOR_MODE_POLLING;
  28.     if (oflag & RT_DEVICE_FLAG_RDONLY && dev->flag & RT_DEVICE_FLAG_RDONLY)
  29.     {
  30.         /* If polling mode is supported, configure it to polling mode */
  31. <font color="#ff00ff">        local_ctrl(sensor, RT_SENSOR_CTRL_SET_MODE, (void *)RT_SENSOR_MODE_POLLING);</font>
  32.     }
  33.     else if (oflag & RT_DEVICE_FLAG_INT_RX && dev->flag & RT_DEVICE_FLAG_INT_RX)
  34.     {
  35.         /* If interrupt mode is supported, configure it to interrupt mode */
  36. <font color="#ff00ff">        if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_MODE, (void *)RT_SENSOR_MODE_INT) == RT_EOK)</font>
  37.         {
  38.             /* Initialization sensor interrupt */
  39. <font color="#ff8c00">            rt_sensor_irq_init(sensor);</font>
  40.             sensor->config.mode = RT_SENSOR_MODE_INT;
  41.         }
  42.     }
  43.     else if (oflag & RT_DEVICE_FLAG_FIFO_RX && dev->flag & RT_DEVICE_FLAG_FIFO_RX)
  44.     {
  45.         /* If fifo mode is supported, configure it to fifo mode */
  46. <font color="#ff00ff">        if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_MODE, (void *)RT_SENSOR_MODE_FIFO) == RT_EOK)</font>
  47.         {
  48.             /* Initialization sensor interrupt */
  49. <font color="#ff00ff">            rt_sensor_irq_init(sensor);</font>
  50.             sensor->config.mode = RT_SENSOR_MODE_FIFO;
  51.         }
  52.     }
  53.     else
  54.     {
  55.         res = -RT_EINVAL;
  56.         goto __exit;
  57.     }
  58.     /* Configure power mode to normal mode */
  59.     if (<font color="#ff00ff">local_ctrl(sensor, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SENSOR_POWER_NORMAL) == RT_EOK</font>)
  60.     {
  61.         sensor->config.power = RT_SENSOR_POWER_NORMAL;
  62.     }
  63. __exit:
  64.     if (sensor->module)
  65.     {
  66.         /* release the module mutex */
  67.         rt_mutex_release(sensor->module->lock);
  68.     }
  69.     return res;
  70. }
  从代码中可以看出,整个open的过程实际上时sensor对应的ops中control实现的过程,而此ops也是在驱动注册时指定的,具体指定位置见 _mag_init中标绿部分,而ops的定义为:
  1. static rt_err_t _control(struct rt_sensor_device *sensor, int cmd, void *args)
  2. {
  3.     struct bmi160_dev *hdev = sensor->parent.user_data;
  4.     rt_err_t result = RT_EOK;
  5.     switch (cmd)
  6.     {
  7.     case RT_SENSOR_CTRL_GET_ID:
  8.         *(rt_uint8_t *)args = hdev->chip_id;
  9.         break;
  10.     case RT_SENSOR_CTRL_SET_ODR:
  11.         result = _set_odr(sensor, (rt_uint32_t)args & 0xffff);
  12.         break;
  13.     case RT_SENSOR_CTRL_SET_RANGE:
  14.         result = _set_range(sensor, (rt_uint32_t)args);
  15.         break;
  16.     case RT_SENSOR_CTRL_SET_POWER:
  17.         result = _set_power(sensor, (rt_uint32_t)args & 0xff);
  18.         break;
  19.     case RT_SENSOR_CTRL_SET_MODE:
  20.         result = _select_mode(sensor, (rt_uint32_t)args);
  21.         break;
  22.     case RT_SENSOR_CTRL_SELF_TEST:
  23.         /* TODO */
  24.         result = -RT_EINVAL;
  25.         break;
  26.     default:
  27.         return -RT_EINVAL;
  28.     }
  29.     return result;
  30. }
  31. <font color="#9932cc">static struct rt_sensor_ops sensor_ops =
  32. {
  33.     _fetch_data,
  34.     _control
  35. };</font>

也就是说,control至少需要实现 RT_SENSOR_CTRL_SET_MODE 和 RT_SENSOR_CTRL_SET_POWER两个接口,另外,如果是中断设备,需要在设备注册时指定中断引脚信息,即驱动注册和打开驱动部分中标黄的部分,具体实现可见:
  1. /* Sensor interrupt initialization function */
  2. static rt_err_t rt_sensor_irq_init(rt_sensor_t sensor)
  3. {
  4.     if (sensor->config.irq_pin.pin == RT_PIN_NONE)
  5.     {
  6.         return -RT_EINVAL;
  7.     }
  8.     rt_pin_mode(sensor->config.irq_pin.pin, sensor->config.irq_pin.mode);
  9.     if (sensor->config.irq_pin.mode == PIN_MODE_INPUT_PULLDOWN)
  10.     {
  11. <font color="#2e8b57">        rt_pin_attach_irq(sensor->config.irq_pin.pin, PIN_IRQ_MODE_RISING, irq_callback, (void *)sensor);</font>
  12.     }
  13.     else if (sensor->config.irq_pin.mode == PIN_MODE_INPUT_PULLUP)
  14.     {
  15. <font color="#008080">        rt_pin_attach_irq(sensor->config.irq_pin.pin, PIN_IRQ_MODE_FALLING, irq_callback, (void *)sensor);</font>
  16.     }
  17.     else if (sensor->config.irq_pin.mode == PIN_MODE_INPUT)
  18.     {
  19. <font color="#008080">        rt_pin_attach_irq(sensor->config.irq_pin.pin, PIN_IRQ_MODE_RISING_FALLING, irq_callback, (void *)sensor);</font>
  20.     }
  21.     rt_pin_irq_enable(sensor->config.irq_pin.pin, RT_TRUE);
  22.     LOG_I("interrupt init success");
  23.     return 0;
  24. }


  • 应用设置参数接口
    设置参数接口,应用层调用的是rt_device_control接口,对应sensor框架中的实现为rt_sensor_control,此实现为:
  1. static rt_err_t rt_sensor_control(rt_device_t dev, int cmd, void *args)
  2. {
  3.     rt_sensor_t sensor = (rt_sensor_t)dev;
  4.     rt_err_t result = RT_EOK;
  5.     RT_ASSERT(dev != RT_NULL);
  6.     rt_err_t (*local_ctrl)(struct rt_sensor_device * sensor, int cmd, void *arg) = local_control;
  7.     if (sensor->module)
  8.     {
  9.         rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER);
  10.     }
  11.     if (sensor->ops->control != RT_NULL)
  12.     {
  13.         local_ctrl = sensor->ops->control;
  14.     }
  15.     switch (cmd)
  16.     {
  17.     case RT_SENSOR_CTRL_GET_ID:
  18.         if (args)
  19.         {
  20. <font color="#ff00ff">            result = local_ctrl(sensor, RT_SENSOR_CTRL_GET_ID, args);</font>
  21.         }
  22.         break;
  23.     case RT_SENSOR_CTRL_GET_INFO:
  24.         if (args)
  25.         {
  26.             rt_memcpy(args, &sensor->info, sizeof(struct rt_sensor_info));
  27.         }
  28.         break;
  29.     case RT_SENSOR_CTRL_SET_RANGE:
  30.         /* Configuration measurement range */
  31. <font color="#ff00ff">        result = local_ctrl(sensor, RT_SENSOR_CTRL_SET_RANGE, args);</font>
  32.         if (result == RT_EOK)
  33.         {
  34.             sensor->config.range = (rt_int32_t)args;
  35.             LOG_D("set range %d", sensor->config.range);
  36.         }
  37.         break;
  38.     case RT_SENSOR_CTRL_SET_ODR:
  39.         /* Configuration data output rate */
  40. <font color="#ff00ff">        result = local_ctrl(sensor, RT_SENSOR_CTRL_SET_ODR, args);</font>
  41.         if (result == RT_EOK)
  42.         {
  43.             sensor->config.odr = (rt_uint32_t)args & 0xFFFF;
  44.             LOG_D("set odr %d", sensor->config.odr);
  45.         }
  46.         break;
  47.     case RT_SENSOR_CTRL_SET_POWER:
  48.         /* Configuration sensor power mode */
  49. <font color="#ff00ff">        result = local_ctrl(sensor, RT_SENSOR_CTRL_SET_POWER, args);</font>
  50.         if (result == RT_EOK)
  51.         {
  52.             sensor->config.power = (rt_uint32_t)args & 0xFF;
  53.             LOG_D("set power mode code:", sensor->config.power);
  54.         }
  55.         break;
  56.     case RT_SENSOR_CTRL_SELF_TEST:
  57.         /* Device self-test */
  58. <font color="#ff00ff">        result = local_ctrl(sensor, RT_SENSOR_CTRL_SELF_TEST, args);</font>
  59.         break;
  60.     default:
  61.         if (cmd > RT_SENSOR_CTRL_USER_CMD_START)
  62.         {
  63.             /* Custom commands */
  64. <font color="#ff00ff">            result = local_ctrl(sensor, cmd, args);</font>
  65.         }
  66.         else
  67.         {
  68.             result = -RT_ERROR;
  69.         }
  70.         break;
  71.     }
  72.     if (sensor->module)
  73.     {
  74.         rt_mutex_release(sensor->module->lock);
  75.     }
  76.     return result;
  77. }
从代码上看,rt_sensor_control接口仅仅是将驱动中control中所实现的所有接口再一次暴露给应用,用于某些参数的更新。

  • 通知应用新数据接收到接口
    应用需调用 rt_device_set_rx_indicate接口注册回调事件,而sensor框架层实现回调接口注册见上文中 rt_sensor_irq_init 函数中标绿部分,其中sensor层统一处理回调的函数实现如下
  1. /* Sensor interrupt correlation function */
  2. /*
  3. * Sensor interrupt handler function
  4. */
  5. void rt_sensor_cb(rt_sensor_t sen)
  6. {
  7.     if (sen->parent.rx_indicate == RT_NULL)
  8.     {
  9.         return;
  10.     }
  11.     if (sen->irq_handle != RT_NULL)
  12.     {
  13.         sen->irq_handle(sen);
  14.     }
  15.     /* The buffer is not empty. Read the data in the buffer first */
  16.     if (sen->data_len > 0)
  17.     {
  18. <font color="#4169e1">        sen->parent.rx_indicate(&sen->parent, sen->data_len / sizeof(struct rt_sensor_data));</font>
  19.     }
  20.     else if (sen->config.mode == RT_SENSOR_MODE_INT)
  21.     {
  22.         /* The interrupt mode only produces one data at a time */
  23. <font color="#4169e1">        sen->parent.rx_indicate(&sen->parent, 1);</font>
  24.     }
  25.     else if (sen->config.mode == RT_SENSOR_MODE_FIFO)
  26.     {
  27. <font color="#4169e1">        sen->parent.rx_indicate(&sen->parent, sen->info.fifo_max);</font>
  28.     }
  29. }
  30. /* ISR for sensor interrupt */
  31. static void irq_callback(void *args)
  32. {
  33.     rt_sensor_t sensor = (rt_sensor_t)args;
  34.     rt_uint8_t i;
  35.     if (sensor->module)
  36.     {
  37.         /* Invoke a callback for all sensors in the module */
  38.         for (i = 0; i < sensor->module->sen_num; i++)
  39.         {
  40.             rt_sensor_cb(sensor->module->sen[i]);
  41.         }
  42.     }
  43.     else
  44.     {
  45.         rt_sensor_cb(sensor);
  46.     }
  47. }
其中标蓝部分即为通知应用数据准备好实现


  • 应用读取数据接口
    应用读取数据接口为rt_device_read,此接口对应sensor框架接口为rt_sensor_read,此函数具体实现为
  1. static rt_ssize_t rt_sensor_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t len)
  2. {
  3.     rt_sensor_t sensor = (rt_sensor_t)dev;
  4.     rt_size_t result = 0;
  5.     RT_ASSERT(dev != RT_NULL);
  6.     if (buf == NULL || len == 0)
  7.     {
  8.         return 0;
  9.     }
  10.     if (sensor->module)
  11.     {
  12.         rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER);
  13.     }
  14.     /* The buffer is not empty. Read the data in the buffer first */
  15.     if (sensor->data_len > 0)
  16.     {
  17.         if (len > sensor->data_len / sizeof(struct rt_sensor_data))
  18.         {
  19.             len = sensor->data_len / sizeof(struct rt_sensor_data);
  20.         }
  21.         rt_memcpy(buf, sensor->data_buf, len * sizeof(struct rt_sensor_data));
  22.         /* Clear the buffer */
  23.         sensor->data_len = 0;
  24.         result = len;
  25.     }
  26.     else
  27.     {
  28.         /* If the buffer is empty read the data */
  29.         if (sensor->ops->fetch_data !=  RT_NULL)
  30.         {
  31. <font color="#ff00ff">            result = sensor->ops->fetch_data(sensor, buf, len);</font>
  32.         }
  33.     }
  34.     if (sensor->module)
  35.     {
  36.         rt_mutex_release(sensor->module->lock);
  37.     }
  38.     return result;
  39. }
由此可见,驱动层需实现fetch_data接口即可,在前面有提到(打开传感器中,control接口描述中标紫部分),对应的_fetch_data实现为:
  1. static void _copy_data(struct rt_sensor_data *dst, struct bmi160_sensor_data *src)
  2. {
  3.     dst->data.acce.x = src->x;
  4.     dst->data.acce.y = src->y;
  5.     dst->data.acce.z = src->z;
  6.     dst->timestamp = rt_sensor_get_ts();
  7. }
  8. static int _get_data(struct rt_sensor_device *sensor, void *buf)
  9. {
  10.     struct bmi160_dev *hdev = sensor->parent.user_data;
  11.     struct rt_sensor_data *data = buf;
  12.     struct bmi160_sensor_data acce_data, gyro_data;
  13.     if (sensor->info.type == RT_SENSOR_CLASS_MAG)
  14.     {
  15.         if (hdev->chip_id == BMX160_CHIP_ID) /* BMX160 */
  16.         {
  17.             _get_mag_data(hdev, data);
  18.             return 1;
  19.         }
  20.         return 0;
  21.     }
  22.     bmi160_get_sensor_data(BMI160_ACCEL_SEL | BMI160_GYRO_SEL, &acce_data, &gyro_data, hdev);
  23.     if (sensor->info.type == RT_SENSOR_CLASS_ACCE)
  24.     {
  25.         data->type = RT_SENSOR_CLASS_ACCE;
  26.         _copy_data(data, &acce_data);
  27.     }
  28.     else if (sensor->info.type == RT_SENSOR_CLASS_GYRO)
  29.     {
  30.         data->type = RT_SENSOR_CLASS_GYRO;
  31.         _copy_data(data, &gyro_data);
  32.     }
  33.     return 1;
  34. }
  35. static int _get_fifo_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
  36. {
  37.         int i;
  38.     uint8_t frame_len = FIFO_DATA_LEN;
  39.     struct rt_sensor_data *data = buf;
  40.     struct bmi160_sensor_data buffer[FIFO_DATA_LEN]; // 32 data frames
  41.     struct bmi160_dev *hdev = sensor->parent.user_data;
  42.     rt_uint8_t data_type;
  43.     if (bmi160_get_fifo_data(hdev) != BMI160_OK)
  44.         return 0;
  45.     if (sensor->info.type == RT_SENSOR_CLASS_ACCE)
  46.     {
  47.         data_type = RT_SENSOR_CLASS_ACCE;
  48.         bmi160_extract_accel(buffer, &frame_len, hdev);
  49.     }
  50.     else if(sensor->info.type == RT_SENSOR_CLASS_GYRO)
  51.     {
  52.         data_type = RT_SENSOR_CLASS_GYRO;
  53.         bmi160_extract_gyro(buffer, &frame_len, hdev);
  54.     }
  55.     else if (sensor->info.type == RT_SENSOR_CLASS_MAG)
  56.     {
  57.         struct bmi160_aux_data aux_data[FIFO_DATA_LEN];
  58.         data_type = RT_SENSOR_CLASS_MAG;
  59.         bmi160_extract_aux(aux_data, &frame_len, hdev);
  60.         _extract_mag(hdev, aux_data, buffer, frame_len);
  61.     }
  62.     len = len < frame_len ? len : frame_len;
  63.     for (i = 0; i < len; i++)
  64.     {
  65.         data[i].type = data_type;
  66.         _copy_data(data + i, buffer + i);
  67.     }
  68.     return len;
  69. }
  70. static rt_size_t _fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
  71. {
  72.     if (sensor->config.mode == RT_SENSOR_MODE_FIFO)
  73.         return _get_fifo_data(sensor, buf, len);
  74.     return _get_data(sensor, buf);
  75. }

由实现可以知道,该接口需要实现读取数据,并将数据转换成 rt_sensor_data 格式数据上报,唯一的区别仅仅是不同工作模式需上报数据的数据量多少差异。

  • 应用关闭设备接口
    应用层关闭sensor接口为 rt_device_close,对应sensor框架中接口为 rt_sensor_close,此函数实现为:
  1. static rt_err_t rt_sensor_close(rt_device_t dev)
  2. {
  3.     rt_sensor_t sensor = (rt_sensor_t)dev;
  4.     int i;
  5.     rt_err_t (*local_ctrl)(struct rt_sensor_device * sensor, int cmd, void *arg) = local_control;
  6.     RT_ASSERT(dev != RT_NULL);
  7.     if (sensor->module)
  8.     {
  9.         rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER);
  10.     }
  11.     if (sensor->ops->control != RT_NULL)
  12.     {
  13.         local_ctrl = sensor->ops->control;
  14.     }
  15.     /* Configure power mode to power down mode */
  16.     if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SENSOR_POWER_DOWN) == RT_EOK)
  17.     {
  18.         sensor->config.power = RT_SENSOR_POWER_DOWN;
  19.     }
  20.     if (sensor->module != RT_NULL && sensor->info.fifo_max > 0 && sensor->data_buf != RT_NULL)
  21.     {
  22.         for (i = 0; i < sensor->module->sen_num; i ++)
  23.         {
  24.             if (sensor->module->sen[i]->parent.ref_count > 0)
  25.                 goto __exit;
  26.         }
  27.         /* Free memory for the sensor buffer */
  28.         for (i = 0; i < sensor->module->sen_num; i ++)
  29.         {
  30.             if (sensor->module->sen[i]->data_buf != RT_NULL)
  31.             {
  32.                 rt_free(sensor->module->sen[i]->data_buf);
  33.                 sensor->module->sen[i]->data_buf = RT_NULL;
  34.             }
  35.         }
  36.     }
  37.     if (sensor->config.mode != RT_SENSOR_MODE_POLLING)
  38.     {
  39.         /* Sensor disable interrupt */
  40.         if (sensor->config.irq_pin.pin != RT_PIN_NONE)
  41.         {
  42.             rt_pin_irq_enable(sensor->config.irq_pin.pin, RT_FALSE);
  43.         }
  44.     }
  45. __exit:
  46.     if (sensor->module)
  47.     {
  48.         rt_mutex_release(sensor->module->lock);
  49.     }
  50.     return RT_EOK;
  51. }
通过该接口可知,关闭sensor实现较为简单,即关闭sensor,释放资源,同时关闭io口中断。

  • 参考资料

  • rtt源码中:/components/driver/sensor/v1/sensor.c
  • rtt软件包中的 BMI160/BMX60驱动
  • 《RT-Thread设备驱动开发指南》 传感器设备驱动开发章节


  • 注意事项
    目前sensor框架在做V2版本的重构,后续版本的sensor框架实现可能部分与该文描述不符。