sensor BMA250源代碼執行分析

重力傳感器是根據壓電效應的原理來工做的。linux

 

  所謂的壓電效應就是 「對於不存在對稱中心的異極晶體加在晶體上的外力除了使晶體發生形變之外,還將改變晶體的極化狀態,在晶體內部創建電場,這種因爲機械力做用使介質發生極化的現象稱爲正壓電效應 」。android

 

  重力傳感器就是利用了其內部的因爲加速度形成的晶體變形這個特性。因爲這個變形會產生電壓,只要計算出產生電壓和所施加的加速度之間的關係,就能夠將加速度轉化成電壓輸出。固然,還有不少其它方法來製做加速度傳感器,好比電容效應,熱氣泡效應,光效應,可是其最基本的原理都是因爲加速度產生某個介質產生變形,經過測量其變形量並用相關電路轉化成電壓輸出。shell

BMA250E編程

10位,數字型,三軸加速度傳感器,運動觸發,中斷控制函數

主要特色:小封裝,數字接口,可編程功能,板上FIFO,板上中斷控制,低功耗。atom

I2C接口,2箇中斷Pin,電壓範圍1.2to3.6V線程

加速度範圍: 2g/4g/8g/16g調試

動力觸發中斷信號產生:新數據,檢測任何運動,單輸出和雙輸出,方位識別,flat detection,無運動檢測。低功耗,喚醒時間短,先進的系統電源管理orm

Vdd是內部塊的主電源htm

Vddio是分紅的電源供應Pin用於支持接口和內部塊

電源模式:

有六種電源模式,除了普通模式支持這個設備的操做外,還有其餘的五種節能模式:深度睡眠模式,睡眠模式,標準模式,低功耗模式一和低功耗模式二。

電源打開後就是普通模式。在deep-suspnd模式下,設備接近於最低功耗。只有接口保持活動。沒有數據請求被響應,配置寄存器is lost.

 

OffsetCompensation:慢速補償,快速補償,快速補償,在線校準

Non-volatile memory:三種寄存器:hardwired,volatile,non-volatile

 

 

BMA250_driver.c

 

BMA250_driver.c代碼分析:

 

 

一、static int bma250_smbus_read_byte(struct i2c_client *client,

                   unsigned char reg_addr, unsigned char *data)

   static int bma250_smbus_write_byte(struct i2c_client *client,

                   unsigned char reg_addr, unsigned char *data)

兩個函數分別調用

i2c_smbus_read_byte_data(client, reg_addr);

i2c_smbus_write_byte_data(client, reg_addr, *data);

而這兩個函數都調用i2c_smbus_xfer,函數原型爲:

s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,

               char read_write, u8 command, int protocol,

               union i2c_smbus_data *data)

兩個調用時就是參數char read_write這個參數有了改變,讀時參數爲I2C_SMBUS_READ,寫時參數爲:I2C_SMBUS_WRITE,其餘參數不變。參數 int protocol表示使用的協議。

在i2c-core.c中經過EXPORT_SYMBOL(i2c_smbus_read_byte_data);把這個函數導出來,而後在其餘文件中使用。

二、static DEVICE_ATTR(mode, S_IRUGO|S_IWUSR,  bma250_mode_show, bma250_mode_store);
   static DEVICE_ATTR(value, S_IRUGO,  bma250_value_show, NULL);
……;
   static DEVICE_ATTR(update, S_IRUGO|S_IWUSR,  NULL, bma250_update_store);
   static DEVICE_ATTR(selftest, S_IRUGO|S_IWUSR,  bma250_selftest_show, bma250_selftest_store);

完成了DEVICE_ATTR函數宏的填充,下面就須要建立接口了

static struct attribute *bma250_attributes[]= {
 &dev_attr_range.attr,
 ……

 &dev_attr_offset_filt_z.attr,
 &dev_attr_orientation.attr,
 NULL
};

當想要實現的接口名字是orientation的時候,須要實現結構體static struct attribute *bma250_attributes[]

其中成員變量的名字必須是&dev_attr_orientation.attr,而後再封裝

static struct attribute_group bma250_attribute_group = {
 .attrs = bma250_attributes
};

再利用sysfs_create_group(&data->input->dev.kobj,&bma250_attribute_group);建立接口.經過以上的幾個步驟,就能夠在adb shell 終端查看到接口了。當咱們將數據 echo 到接口中時,在上層實際上完成了一次 write 操做,對應到 kernel ,調用了驅動中的 「store」。同理,當咱們cat 一個 接口時則會調用 「show」 。到這裏,只是簡單的創建了 android 層到 kernel 的橋樑,真正實現對硬件操做的,仍是在 "show" 和 "store" 中完成的。這些接口也是調試接口。

程序執行過程:

板子信息:

struct bma250acc{

    s16 x,

       y,

       z;

} ;

struct bma250_data {/*kernel\lc1810\include\linux\Bmc.h*/

    struct i2c_client *bma250_client;//bma250設備

    atomic_t delay;                  //延遲 

    atomic_t enable;                 //使能

    unsigned char mode;              //工做模式 

    struct input_dev *input;         //input設備

    struct bma250acc value;          //上報的座標值

    struct mutex enable_mutex;        //互斥量 

    struct mutex mode_mutex;

    struct delayed_work work;        //

    struct work_struct irq_work;

 

#ifdef CONFIG_HAS_EARLYSUSPEND

    struct early_suspend early_suspend;

#endif

 

    atomic_t selftest_result;

    int orientation;

};

 

 

/*kernel\lc1810\arch\arm\mach-comip\board-lc1810.c*/

#if defined(CONFIG_SENSORS_BMA250)

static struct bma250_data bmc_bma250_data = {

    .orientation = 0,

};

#endif

填充i2c_board_info:

static struct i2c_board_infocomip_i2c1_board_info[] = {

#if defined(CONFIG_SENSORS_BMA250)

    {

        I2C_BOARD_INFO("bma250", 0x18),

        .platform_data = &bmc_bma250_data,

    },

#endif

}

 

一、module_init(BMA250_init);

module_exit(BMA250_exit);

static int __init BMA250_init(void)

{

    return i2c_add_driver(&bma250_driver);//加載驅動程序bma250_driver

}

其中,驅動程序爲:

static struct i2c_driver bma250_driver = {

    .driver = {

        .owner  = THIS_MODULE,

        .name   = SENSOR_NAME,

    },

    .id_table  = bma250_id,//id_table是該驅動所支持的I2C設備的ID表

    .probe     = bma250_probe,/* bus->match成功後調用 */

    .remove     = bma250_remove,

 

};

二、bma250_probe(struct i2c_client *client,const struct i2c_device_id *id)函數的執行:

1)、利用i2c_check_functionality(client->adapter, I2C_FUNC_I2C)檢查I2C設備適配器工做是否正常。

2)、給bma250_data分配空間並清零。

3)、利用i2c_smbus_read_word_data(client, BMA250_CHIP_ID_REG);檢測bma250的ID號是否匹配,匹配繼續,不然失敗。

4)、讓client的data指向新分配的空間,初始化data.

5)、互斥訪問:利用

bma250_set_bandwidth(client, BMA250_BW_SET);

    bma250_set_range(client, BMA250_RANGE_SET);設置帶寬和範圍。

INIT_DELAYED_WORK(&data->work, bma250_work_func);動態初始化一個隊列的work,而且和隊列處理函數bma250_work_func()綁定在一塊兒。過一段延遲後處理work。

     而在static void bma250_work_func(struct work_struct *work)

{

    struct bma250_data *bma250 = container_of((struct delayed_work *)work,

            struct bma250_data, work);

    static struct bma250acc acc;

    unsigned long delay = msecs_to_jiffies(atomic_read(&bma250->delay));

 

    bma250_read_accel_xyz(bma250->bma250_client, &acc);

    input_report_abs(bma250->input, ABS_X, acc.x);

    input_report_abs(bma250->input, ABS_Y, acc.y);

    input_report_abs(bma250->input, ABS_Z, acc.z);

    input_sync(bma250->input);

    bma250->value = acc;

    printk("_______[%s]: acc.x=%d,y=%d,z=%d\n",__func__,acc.x,acc.y,acc.z);

    schedule_delayed_work(&bma250->work, delay);

}

首先是一段延遲msecs_to_jiffies(atomic_read(&bma250->delay)),而後經過

bma250_read_accel_xyz(bma250->bma250_client, &acc)讀取sensor的xyz的值,再經過input_report_abs()函數把這三個點報上去。再經過schedule_delayed_work()延遲一段時間後調度執行一個具體的任務,執行的任務將會被掛入Linux系統提供的workqueue。

INIT_DELAYED_WORK()和schedule_delayed_work()函數是成對出現的。

6)、經過bma250_input_init(data)函數初始化bma250_input。初始化時先經過input_allocate_device()分配空間。在設置報點範圍,而後註冊設備,讓bma250_input指向它。

7)、經過sysfs_create_group()函數建立sysfs接口。

8)、初始化bma250電源管理的掛起和打開。

static void bma250_early_suspend(struct early_suspend *h)

{

struct bma250_data *data =container_of(h, struct bma250_data, early_suspend);

 

mutex_lock(&data->enable_mutex);

if (atomic_read(&data->enable) == 1) {

     bma250_set_mode(data->bma250_client, BMA250_MODE_SUSPEND);

     cancel_delayed_work_sync(&data->work);

}

mutex_unlock(&data->enable_mutex);

}

互斥的設置bma250工做模式是suspend,而後執行cancel_delayed_work_sync()函數,對一個延遲執行的工做來講,這個函數的做用是在這個工做還未執行的時候就把它給取消掉.

工做時:static void bma250_late_resume(struct early_suspend *h)

{

  struct bma250_data *data =

         container_of(h, struct bma250_data, early_suspend);

 

  mutex_lock(&data->enable_mutex);

  if (atomic_read(&data->enable) == 1) {

         bma250_set_mode(data->bma250_client, BMA250_MODE_NORMAL);

         schedule_delayed_work(&data->work,

                       msecs_to_jiffies(atomic_read(&data->delay)));

  }

  mutex_unlock(&data->enable_mutex);

}resume時首先互斥把工做模式設爲普通工做模式,而後調用schedule_delayed_work()函數延遲一段時間後調用工做隊列中的work進行處理。

工做者線程(events),或者說worker threads,更確切的說,這些應該是缺省的工做者線程.而與工做者線程相關的一個概念就是工做隊列,或者叫work queue.events這麼一個線程,它其實和內核線程同樣,有事情就處理,沒事情就睡眠,也是一個死循環,而schedule_delayed_work()的做用就是喚醒這個線程,確切的說,是先把本身的這個struct work_struct插入workqueue_struct這個隊列裏,而後喚醒昏睡中的events.而後events就會去處理,要是有延時,那麼它就給安排延時之後執行,要是沒有延時,或者設了延時爲0,那就趕忙開始執行.

9)、初始化後經過函數bma250_set_mode(client, BMA250_MODE_SUSPEND);把sensor設置爲suspend狀態。若是出現錯誤就bma250_input_delete(data);釋放設備。

至此,bma250_probe執行完畢,sensor初始化完畢。

相關文章
相關標籤/搜索