• 光传感器和距离传感器代码分析【转】


    本文转载自:http://blog.csdn.net/luobin1984/article/details/8132889

    Light Sensor& Proximity Sensor

    TMD27713T内部集成一个光传感器,一颗红外发射管和一颗红外接收极管。

    ALS环境光传感器,距离检测和红外灯在一个模块上,ALS:近似于人眼的反应,可编程积分时间,可编程的中断阀值,很高的灵敏度。距离检测:校准到100mm的精度,消除工厂校准,可编程的数字红外脉冲。可编程的电流源的红外灯,可编程的中断阀值,可编程的等待时间。带微光学透镜的装置为红外线能的发送和接收提供高能有效的能量,降低整体功耗。

    Detailed Description:光到数字的装置提供了片上光敏二极管,AD转换,时钟,累加器,缓存,校准,状态机和I2C接口。

    光传感器,根据光线强度输出模拟信号,按电压大小指示环境光线强度。配合LED驱动芯片,自动调整LCD的背光强度。光线传感器根据光线强度输出一个指示信号,然后经过放大器送出。

    Proximity Sensor是由一颗红外发射管和一颗红外接收极管组成。通电后,红外管发射的红外光由于没有遮挡物反射红外信号,红外接收管没有动作。当有遮挡物时,会反射红外光,接收管接收到信号后,红外管导通,发出中断信号给DBB。LC1810通过I2C接口控制Gsensor、ALS&PS、COMPASS、Gyroscope芯片,通过GPIO完成各芯片的中断处理。接近光检测器被配置好相关红外感知灵敏度,但红外LED反射收到时,接近光检测器内部光敏二极管产生对应强度的电流,并转化为相应的数字量,并产生中断给微控制器(LC1810),LC1810通过I2C得到相关数字信息,并通过检测内部算法得到最终“接近信息”。 

    源代码位置:kernellc1810archarmmach-comipoard-lc1810.c

    板子上的信息:

    /*ALS + PS*/tmd22713初始化时i2c_client的配置信息

    #if defined(CONFIG_LIGHT_PROXIMITY_TMD22713T)

    static structtaos_cfgcomip_i2c_tmd22713_info= {

            .calibrate_target = 300000,

            .als_time = 50,//200,

            .scale_factor = 1,

            .gain_trim = 512,

            .filter_history = 3,

            .filter_count = 1,

            .gain = 1,//2,

            .prox_threshold_hi = 500,//120,

            .prox_threshold_lo = 400,//80,

            .als_threshold_hi = 3000,

            .als_threshold_lo = 10,

            .prox_int_time = 0xee, /* 50ms */

            .prox_adc_time = 0xff,

            .prox_wait_time = 0xee,

            .prox_intr_filter = 0x11,//0x23,

            .prox_config = 0,

            .prox_pulse_cnt = 0x08,

            .prox_gain = 0x61,//0x62,

       .int_gpio = mfp_to_gpio(TMD22713T_INT_PIN),

    };

    #endif

    //TMD22713在板子上的I2C接口信息:

    static struct i2c_board_info comip_i2c1_board_info[] = {

    #if defined(CONFIG_LIGHT_PROXIMITY_TMD22713T)

            {

                      .type = "tritonFN",

                      .addr = 0x39,

                      .platform_data = &comip_i2c_tmd22713_info,

            },

    #endif

    #if defined(CONFIG_LIGHT_PROXIMITY_TAOS_TMD22713T)

            {

                      .type = "tritonFN",

                      .addr = 0x39,

            },

    #endif

    …….}

    代码位置:kernellc1810driversmisclight_proxTmd22713.c

    DECLARE_WAIT_QUEUE_HEAD(waitqueue_read);   //定义一个等待队列用于处理中断

    #define ALS_PROX_DEBUG

    static char pro_buf[4];

    static int mcount = 0;

    static char als_buf[4];

    static bool enable_irq_mask = (bool)0;

    // per-device data

    struct taos_data {                              //定义taos_data结构体

            struct i2c_client *client;                    //定义I2c_client表示用的实际设备

            struct taos_cfg *taos_cfg_data;              //初始化的配置信息

            struct work_struct work;                   //定义一个work_struct结构体处理任务

            struct wake_lock taos_wake_lock;           //定义一个锁

            struct semaphore update_lock;             //定义一个信号量

            struct miscdevice light_dev;               //定义一个misc的设备light_dev 

            struct miscdevice prox_dev;                //定义一个misc的设备prox_dev    

            wait_queue_head_t light_event_wait;        //定义一个光传感器的等待队列

            wait_queue_head_t proximity_event_wait;    //定义一个距离传感器的等待队列

            int lux_state;                            //lux的状态?

            int light_event;                          //light的事件

            int light_poll_delay;                      //light轮询时间

            int prox_state;                          //prox的状态

            int prox_event;                         //prox的事件

            int prox_poll_delay;                                          //prox的轮询时间

            int irq;                               //中断

    };

    程序执行时:

    1、 module_init(taos_init);调用taos_init

    2、 static int __init taos_init(void)调用 i2c_add_driver(&taos_driver)加载驱动;

    3、 驱动定义如下:

    static struct i2c_driver taos_driver = {

    .driver = {

                       .owner = THIS_MODULE,

                       .name = TAOS_DEVICE_NAME,

    },

    .suspend = taos_suspend,

    .resume = taos_resume,

    .id_table = taos_idtable,//用于I2C driver的probe函数调用                             

    .probe = taos_probe,    /* bus->match成功后调用 */                                  

    .remove = __devexit_p(taos_remove),

    }

    I2C_driver对应一套驱动方法,主要成员是probe()、remove()、suspend()等。另外id_table是该驱动所支持的I2C设备的ID表。I2C_client对应于真实的物理设备,每个I2C设备都需要一个I2C_client来描述。I2C_driver与I2c_client的关系是一对多,一个I2C设备上可以支持多个同类型的I2c_client.

    I2C_client的信息在BSP板文件board-lc1810.c中通过i2c_borad_info填充。

    在I2C总线驱动i2c_bus_type的match()函数i2c_device_match()中,会调用i2c_match_id()函数匹配板文件中定义的ID和i2c_driver所支持的ID表。通过bus->match()匹配成功后开始调用probe函数进行一系列初始化动作。

    4、 static int taos_probe(struct i2c_client *clientp, const struct i2c_device_id *idp)的执行过程。

    1)、读取chipID,检测是否正确。

    2)、为taos_data分配空间并利用memset清零。

    3)、使用函数wake_lock_init()新建wakelock,该函数设置锁的名字,类型,最后将新建的锁挂接到一个专门链接这些非锁状态的链表上

    4)、初始化taos_data中两个设备的轮询等待时间,获取client指针。

    5)、INIT_WORK(&(taos_datap->work),taos_work_func);

    第一个参数是初始化的一个工作队列,第二个参数是对这个工作队列的处理函数。INIT_WORK()函数把这个队列和处理函数绑定。

    处理函数如下:

    static void taos_work_func(struct work_struct * work)

    {

    struct taos_data *taos_data = container_of(work, struct taos_data, work);

    wake_lock(&taos_datap->taos_wake_lock);

    taos_get_data();

    /*<after read data done, taos will not clear interrupts self-motion>*/

    taos_interrupts_clear(taos_data);

    wake_unlock(&taos_datap->taos_wake_lock);

    }利用锁互斥访问,通过taos_get_data()获取数据。Taos_get_data()通过I2C命令读取寄存器和当前的状态设置距离传感器prox的阀值或者设置光传感器als的阀值,通过taos_als_get_data()最终获取数据。

    6)、通过init_waitqueue_head()函数分别初始化light和prox的等待队列。

    7)、填充light_dev和prox_dev的结构体,然后通过misc_register()函数注册两个设备,分别是light设备和prox设备。

    8)、通过i2c_smbus_write_byte操作控制寄存器。Sensor powerdown for init。

    9)、ret = gpio_request(taos_datap->taos_cfg_data->int_gpio, "taos irq");

    gpio_direction_input(taos_datap->taos_cfg_data->int_gpio);

    taos_datap->irq =gpio_to_irq(taos_datap->taos_cfg_data->int_gpio);

    ret =request_irq(taos_datap->irq,taos_irq_handler,

                                 IRQ_TYPE_EDGE_FALLING, "taos_irq", taos_datap);

    其中request_irq()函数通过中断申请,得到中断后用中断处理函数taos_irq_handler()进行处理。中断函数如下:

    static irqreturn_t taos_irq_handler(int irq, void *dev_id)

    {

    disable_irq_nosync(taos_datap->irq);

         schedule_work(&taos_datap->work);

    enable_irq(taos_datap->irq);

    return IRQ_HANDLED;

    }

    系统调用处理在等待队列中的work事件。

    其中:workqueue内核实现原理可以描述如下:

           在Workqueue机制中,提供了一个系统默认的workqueue队列——keventd_wq,这个队列是Linux系统在初始化的时候就创建的。用户可以直接初始化一个work_struct对象,然后在该队列中进行调度,使用更加方便。

     Workqueue编程接口序号接口函数说明:

          a、 create_workqueue 用于创建一个workqueue队列,为系统中的每个CPU都创建一个内核线程。

    输入参数:@name:workqueue的名称

          b、 create_singlethread_workqueue 用于创建workqueue,只创建一个内核线程。输入参数:@name:workqueue名称

          c、 destroy_workqueue 释放workqueue队列。输入参数:@ workqueue_struct:需要释放的workqueue队列指针

          d、 schedule_work 调度执行一个具体的任务,执行的任务将会被挂入Linux系统提供的workqueue——keventd_wq输入参数:@ work_struct:具体任务对象指针

          e、 schedule_delayed_work 延迟一定时间去执行一个具体的任务,功能与schedule_work类似,多了一个延迟时间,输入参数:@work_struct:具体任务对象指针@delay:延迟时间

          f、 queue_work 调度执行一个指定workqueue中的任务。输入参数:@ workqueue_struct:指定的workqueue指针@work_struct:具体任务对象指针

          g、 queue_delayed_work 延迟调度执行一个指定workqueue中的任务,功能与queue_work类似,输入参数多了一个delay

    在进行系统调用处理时用的是轮询处理的方法,程序中分别为light和prox定义了两个file_operations,连接如下:

    const structfile_operations taos_light_fops = {

    .owner = THIS_MODULE,

    .read = light_read,

         .poll = light_poll,//轮询函数

    .unlocked_ioctl = light_ioctl,

    .open = light_open,

    .release = light_release,

    };

    const structfile_operations taos_prox_fops= {

    .owner = THIS_MODULE,

    .read = prox_read,

         .poll = prox_poll,//轮询函数

    .unlocked_ioctl = prox_ioctl,

    .open = prox_open,

    .release = prox_release,

    };

     

    Select()和poll()是与设备阻塞与非阻塞访问息息相关的,使用非阻塞I/O的应用程序通常会使用select和poll()系统调用查询是否可对设备进行无阻塞的访问。

     

    static unsigned intlight_poll(struct file *file, struct poll_table_struct *poll)

    {

            int mask = 0;

            struct taos_data *data = (struct taos_data*)file->private_data;

     

            poll_wait(file, &data->light_event_wait, poll);

            if (data->light_event)

                      mask |= POLLIN | POLLRDNORM;

            return mask;

    }

     

    //第一个参数是file结构体指针,第二个为轮询表指针

    static unsigned intprox_poll(struct file *file, struct poll_table_struct *poll)

    {

            int mask = 0;

            struct taos_data *data = (struct taos_data*)file->private_data;

            poll_wait(file, &data->proximity_event_wait, poll);

            if (data->prox_event)

                      mask |= POLLIN | POLLRDNORM;

            return mask;

    }

    Poll()第一个参数是file的结构体指针,第二个参数是轮询表指针。这个函数的两项工作:

    、对可能引起的设备文件状态变化的等待队列调用poll_wait()函数,将对应的等待队列添加到poll_table。

    ②、返回表示是否能对设备进行无阻塞的读写访问的掩码。

    Poll_wait()的工作是把当前的进程添加到wait参数指定的等待列表(poll_table)中。

    阻塞和非阻塞访问时I/O操作的两种不同的模式,阻塞在I/O操作暂时不可进行时会让进程睡眠,非阻塞则不然。在设备驱动中阻塞I/O一般基于等待队列来实现,等待队列可用于同步驱动中事件发生的先后顺序。使用非阻塞I/O的应用程序也可借助轮询函数来查询设备是否能立即被访问,用户空间调用select()和poll()接口,设备驱动提供poll()函数。设备驱动的poll()本身不会阻塞,但是poll()和select()系统调用则会阻塞的等待文件描述集合中至少一个可访问或超时。

    10)、disable_irq_nosync(taos_datap->irq);

  • 相关阅读:
    .Net反编译软件
    Windows下Node.js安装及环境配置
    Servlet处理日期
    Servlet的文件上传
    Eclipse错误:Syntax error on tokens, delete these tokens问题解决
    Servlet中操作数据库
    Servlet的会话(Session)跟踪
    Servlet的Cookies处理
    Servlet的异常处理
    Servlet的过滤器(Filter)
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/6489191.html
Copyright © 2020-2023  润新知