光傳感器和距離傳感器代碼分析【轉】


本文轉載自: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得到相關數字信息,並通過檢測內部算法得到最終“接近信息”。 

 

 

源代碼位置:kernel\lc1810\arch\arm\mach-comip\board-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

…….}

 

代碼位置:kernel\lc1810\drivers\misc\light_prox\Tmd22713.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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM