日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

锂电池驱动分析

發布時間:2025/7/25 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 锂电池驱动分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

鋰電池的驅動程序要實現以下五個功能:

1.可以自動檢測到當前給電池充電的是USB還是AC

2.組織過大的充電電流

3.壞電池檢測

4.死亡溫度的檢測

5.電池電壓的測量

?

當我們要寫一個鋰電池的驅動程序的時候,首先要知道內核提供給驅動的接口,就是當驅動掛載到內核上的時候,內核是怎么知道驅動中的信息的,如何來控制驅動。而這個內核提供給驅動的接口就是一個結構體power_supply.

struct?power_supply?{

const?char?*name;

enum?power_supply_type?type;

enum?power_supply_property?*properties;//聲明了電源的屬性

size_t?num_properties;

?

char?**supplied_to;

size_t?num_supplicants;

?

int?(*get_property)(struct?power_supply?*psy,

????enum?power_supply_property?psp,

????union?power_supply_propval?*val);//得到電源的屬性

void?(*external_power_changed)(struct?power_supply?*psy);

void?(*set_charged)(struct?power_supply?*psy);

?

/*?For?APM?emulation,?think?legacy?userspace.?*/

int?use_for_apm;

?

/*?private?*/

struct?device?*dev;

struct?work_struct?changed_work;

?

#ifdef?CONFIG_LEDS_TRIGGERS

struct?led_trigger?*charging_full_trig;

char?*charging_full_trig_name;

struct?led_trigger?*charging_trig;

char?*charging_trig_name;

struct?led_trigger?*full_trig;

char?*full_trig_name;

struct?led_trigger?*online_trig;

char?*online_trig_name;

#endif

};

?

內核主要通過get_property這個函數指針來獲得驅動中的有關電池的信息,而這個函數在內核中只給出了其聲明,我們在寫驅動的時候要自己實現這個函數,即講自己寫的函數賦值給函數指針,當內核需要驅動中的電源的信息的時候,回調這個get_property即可。另外,我們寫驅動程序又要給用戶提供接口,內核中的提供給用戶的接口即sysfs,通過讀取其中的屬性就可以得到電源的信息。內核主要通過兩個文件power_supply_class.c和power_supply_core.c,我們調用其中的函數就可以把電源(電池,USB?power?supply或者AC?power?supply)的信息展現給用戶,有關電源的屬性寫在/sys/class/powersupply文件夾下。

?

這樣,按照內核提供的接口,驅動程序的書寫就很清晰了,結合鋰電池的驅動程序的源代碼,我們來看看驅動程序的執行過程。

?

當一個驅動被編譯好并被掛到內核上之后,會首先執行一個模塊的初始化函數,每個驅動都是統一的,在這里是module_init(stmp3xxx_bat_init);它代表首先執行stmp3xxx_bat_init,在驅動里它是這么定義的:

static?int?__init?stmp3xxx_bat_init(void)

{

return?platform_driver_register(&stmp3xxx_batdrv);

}

這個函數執行platform_driver_register(&stmp3xxx_batdrv);并將返回值返回。而platform_driver_register()是一個內核函數,它在內核中如下定義:

int?platform_driver_register(struct?platform_driver?*drv)

{

drv->driver.bus?=?&platform_bus_type;

if?(drv->probe)

drv->driver.probe?=?platform_drv_probe;//platform_drv_probe仍然是一個內核函數,、/*它在內核里定義如下:

static?int?platform_drv_probe(struct?device?*_dev)

{

struct?platform_driver?*drv?=?to_platform_driver(_dev->driver);

struct?platform_device?*dev?=?to_platform_device(_dev);

?

return?drv->probe(dev);

}*/

//上面的函數的作用就是將device的driver轉變成platform_driver。

if?(drv->remove)

drv->driver.remove?=?platform_drv_remove;

if?(drv->shutdown)

drv->driver.shutdown?=?platform_drv_shutdown;

?

return?driver_register(&drv->driver);

}

這個函數所完成的就是:首先將platform_driver的結構體變量driver的bus域初始化,然后將platform_driver的driver的函數指針probe等初始化為platform_driver的probe(如何完成的請看上面代碼中給出的注釋).然后執行driver_register(&drv->driver)(我們一會再分析driver_register(&drv->driver))。

?

platform_driver_register()在我們的驅動中,它的參數是一個結構體指針&stmp3xxx_batdrv,在我們的驅動里它是如下這么定義的:

static?struct?platform_driver?stmp3xxx_batdrv?=?{

.probe =?stmp3xxx_bat_probe,

.remove =?stmp3xxx_bat_remove,

.shutdown???????=?stmp3xxx_bat_shutdown,

.suspend =?stmp3xxx_bat_suspend,

.resume =?stmp3xxx_bat_resume,

.driver =?{

.name =?”stmp3xxx-battery”,

.owner =?THIS_MODULE,

},

};

?

下面講一下driver_register(&drv->driver),在這里我就不貼出其中的代碼了,它的過程比較復雜,可以用Source?Insight跟蹤其中的調用過程,在這里我就大致的介紹一下它的主要過程,一些不重要的東西略掉,首先它會遍歷在BUS上的所有設備,通過比較設備的名字和驅動的名字來進行匹配,如果名字相同才能注冊成功,當注冊成功后接下來會調用platform_driver結構中probe函數指針,在這里就是stmp3xxx_bat_probe,其函數原型static?int?stmp3xxx_bat_probe(struct?platform_device?*pdev),而此時stmp3xxx_bat_probe的參數就是我們在總線上找到的和驅動相匹配的設備,它是在驅動注冊的時候,找到和驅動匹配的設備后給pdev初始化的。

下面我們說一說stmp3xxx_bat_probe所完成的主要功能:獲取電源設備的中斷資源,代碼實現如下:

struct?resource?*vdd5v_irq;

info->vdd5v_irq?=?platform_get_resource(pdev,?IORESOURCE_IRQ,?0);

下面說一下resource,該元素存入了最為重要的設備資源信息,例如設備的地址,中斷號等,其定義如下:

struct?resource?{

resource_size_t?start;

resource_size_t?end;

const?char?*name;

unsigned?long?flags;

struct?resource?*parent,?*sibling,?*child;

};

下面舉s3c2410平臺的i2c驅動作為例子來說明:?

?

/*?arch/arm/mach-s3c2410/devs.c?*/
/*?I2C?*/
static?struct?resource?s3c_i2c_resource[]?=?{
?????????[0]?=?{
???????????????????.start?=?S3C24XX_PA_IIC,
???????????????????.end?=?S3C24XX_PA_IIC?+?S3C24XX_SZ_IIC?-?1,
???????????????????.flags?=?IORESOURCE_MEM,
?????????},
?????????[1]?=?{
???????????????????.start?=?IRQ_IIC,?//S3C2410_IRQ(27)
???????????????????.end?=?IRQ_IIC,
???????????????????.flags?=?IORESOURCE_IRQ,
?????????}
};

這里定義了兩組resource,它描述了一個I2C設備的資源,第1組描述了這個I2C設備所占用的總線地址范圍,IORESOURCE_MEM表示第1組描述的是內存類型的資源信息,第2組描述了這個I2C設備的中斷號,IORESOURCE_IRQ表示第2組描述的是中斷資源信息。設備驅動會根據flags來獲取相應的資源信息。

?

?

保存指向驅動特有信息的指針:platform_set_drvdata(pdev,?info);

?

對電源進行初始化,代碼如下:

info->bat.name???????????=?”battery”;//名字

info->bat.type???????????=?POWER_SUPPLY_TYPE_BATTERY;//類型

info->bat.properties?????=?stmp3xxx_bat_props;//屬性

info->bat.num_properties?=?ARRAY_SIZE(stmp3xxx_bat_props);//屬性的個數

info->bat.get_property???=?stmp3xxx_bat_get_property;//得到屬性的函數

主要是實現一些給電源名字類型等賦初值,最主要的是將get_property函數指向我們寫好的可以得到電源的屬性的函數的起始地址,以便當內核需要用到驅動的信息的時候進行回調。

?

接下來初始化timer,mutex,代碼如下:

init_timer(&info->sm_timer);

info->sm_timer.data?=?(unsigned?long)info;

info->sm_timer.function?=?state_machine_timer;

?

mutex_init(&info->sm_lock);

?

接下來將三種電源注冊,即把他們的屬性寫到sys文件系統里,以使用戶空間可以得到有關電源的信息,以其中的一個為例:

ret?=?power_supply_register(&pdev->dev,?&info->bat);//將電池注冊

power_supply_register調用內核提供的函數device_create()和power_supply_create_attrs來實現電池的注冊。

這里只寫出了驅動要完成的基本功能,至于如何完成的,即驅動與硬件之間的交互,對寄存器的操作,需要參考具體的硬件手冊。

?

這個文檔還有很多需要完善的地方,希望大家多提意見,我再繼續修改。

轉載于:https://www.cnblogs.com/armlinux/archive/2010/10/09/2396907.html

總結

以上是生活随笔為你收集整理的锂电池驱动分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。