4.8.5. 设计说明

4.8.5.1. 源码说明

源代码位于 bsp/artinchip/

  • bsp/artinchip/drv/tsen/drv_tsen.c,TSenor Driver 层实现

  • bsp/artinchip/hal/tsen/hal_tsen.c,TSenor HAL 层实现

  • bsp/artinchip/include/hal/hal_tsen.h,TSenor HAL 层接口头文件

4.8.5.2. 模块架构

TSensor 驱动 Driver 层采用 RT-Thread 的Sensor设备驱动框架,如果只使用HAL层也可以支持 baremetal 方式的应用场景。

../../../_images/sw_system16.png

图 4.31 TSensor 驱动的软件架构图

4.8.5.3. 关键流程设计

4.8.5.3.1. 初始化流程

TSensor 驱动的初始化接口通过 INIT_DEVICE_EXPORT(drv_tsen_init) 完成,会通过调用 Sensor子系统的接口 rt_hw_sensor_register() 注册一个 Sensor设备。

TSensor 控制器的初始化过程,主要步骤有:

  1. 初始化模块的clk

  2. 注册中断

  3. 初始化默认参数

  4. 向设备框架中注册Sensor设备

4.8.5.3.2. 中断处理流程

TSensor 支持使用中断方式来读取数据,这样避免应用层的忙等待。

../../../_images/tsen_irq_flow.png

图 4.32 TSensor 非周期模式的数据采集流程

  • 对于非周期模式:当用户层触发 ops->fetch_data() 接口,就会启动一次硬件去读数据

  • 当硬件准备好数据,会产生一个中断

  • 在中断处理函数中,用INT Flag来区分是哪个通道有数据,逐个通道扫描将数据读出,会缓存到一个全局变量中

  • 对于周期模式: TSensor 控制器会自动按给定周期产生一次数据中断

4.8.5.4. 数据结构设计

4.8.5.4.1. struct aic_tsen_dev

属于 Driver 层内部使用的数据结构,管理TSensor控制器的设备资源:

struct aic_tsen_dev {
    struct rt_sensor_device dev;
    u32 pclk_rate;
    struct aic_tsen_ch *ch;
};

4.8.5.4.2. struct aic_tsen_ch

属于 HAL 层接口,管理一个 TSensor 通道的配置信息:

struct aic_tsen_ch {
    int id;
    bool available;
    char name[16];
    enum aic_tsen_mode mode;
    bool diff_mode;
    bool inverted;
    u16  latest_data; // 10 * actual temperature value
    u16  smp_period; // in seconds

    bool hta_enable; // high temperature alarm
    u16  hta_thd;    // 10 * temperature value
    u16  hta_rm_thd; // 10 * temperature value
    bool lta_enable; // low temperature alarm
    u16  lta_thd;    // 10 * temperature value
    u16  lta_rm_thd; // 10 * temperature value
    bool otp_enable; // over temperature protection
    u16  otp_thd;    // 10 * temperature value

    int slope;       // 10000 * actual slope
    int offset;      // 10000 * actual offset

    aicos_sem_t complete;
};

4.8.5.5. Driver 层接口设计

以下接口是 TSensor 设备驱动框架的标准接口。

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);
};

4.8.5.5.1. aic_tsen_fetch

函数原型

rt_size_t aic_tsen_fetch(struct rt_sensor_device *sensor, void *buf, rt_size_t len)

功能说明

读取TSensor温度数据

参数定义

sensor - 指向sensor设备
buf - 用来保存读取到的温度,是struct rt_sensor_data类型的数据结构
len - buf的长度

返回值

1,成功; <0,失败

注意事项

目前仅支持读取CPU位置处的TSensor

4.8.5.5.2. aic_tsen_control

函数原型

rt_err_t aic_tsen_control(struct rt_sensor_device *sensor, int cmd, void *args)

功能说明

TSensor 驱动的ioctl接口

参数定义

sensor - 指向sensor设备
cmd - ioctl 命令码
args - ioctl 命令相应的参数

返回值

-1,失败

注意事项

目前暂未实现此接口中的ioctl命令,所以统一返回-1。 不影响正常读数据功能

4.8.5.6. HAL 层接口设计

HAL 层的函数接口声明存放在 hal_tsen.h 中,主要接口有:

void hal_tsen_enable(int enable);
void hal_tsen_ch_enable(u32 ch, int enable);
int hal_tsen_ch_init(struct aic_tsen_ch *chan, u32 pclk);

int hal_tsen_get_temp(struct aic_tsen_ch *chan, s32 *val);
s32 hal_tsen_data2temp(struct aic_tsen_ch *chan);
u16 hal_tsen_temp2data(struct aic_tsen_ch *chan, s32 temp);
void hal_tsen_status_show(struct aic_tsen_ch *chan);

irqreturn_t hal_tsen_irq_handle(int irq, void *arg);

4.8.5.7. Demo

此Demo是 sensor_polling 命令的部分代码(详见kernel/rt-thread/components/drivers/sensors/sensor_cmd.c),可以作为 TSensor设备的使用参考:

static void sensor_polling(int argc, char **argv)
{
    rt_uint16_t num = 10;
    rt_device_t dev = RT_NULL;
    rt_sensor_t sensor;
    struct rt_sensor_data data;
    rt_size_t res, i;
    rt_int32_t delay;
    rt_err_t result;

    dev = rt_device_find(argv[1]);
    if (dev == RT_NULL)
    {
        LOG_E("Can't find device:%s", argv[1]);
        return;
    }
    if (argc > 2)
        num = atoi(argv[2]);

    sensor = (rt_sensor_t)dev;
    delay  = sensor->info.period_min > 100 ? sensor->info.period_min : 100;

    for (i = 0; i < num; i++)
    {
        res = rt_device_read(dev, 0, &data, 1);
        if (res != 1)
        {
            LOG_E("read data failed!size is %d", res);
        }
        else
        {
            sensor_show_data(i, sensor, &data);
        }
        rt_thread_mdelay(delay);
    }
    rt_device_close(dev);
}