锂电池驱动分析

news/2024/11/29 7:56:49/

锂电池的驱动程序要实现以下五个功能:

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来实现电池的注册。

这里只写出了驱动要完成的基本功能,至于如何完成的,即驱动与硬件之间的交互,对寄存器的操作,需要参考具体的硬件手册。

 

这个文档还有很多需要完善的地方,希望大家多提意见,我再继续修改。


http://www.ppmy.cn/news/830988.html

相关文章

宁德时代换挡,钠电池“接力”锂电池?

宁德时代以一己之力将钠电池推上了台前,钠电池量产被提上日程,钠离子电池产业化将进一步加速。 去年7月,宁德时代在发布会上宣布,其开发的第一代钠离子电池,电芯单体能量密度已经达到了160Wh/kg,为目前全球…

2022年全球及中国储能锂电BMS市场产业链发展结构分析及投资规模竞争格局研究预测

2022年全球及中国储能锂电BMS市场产业链发展结构分析及投资规模竞争格局研究预测 1、电池安全管理行业的界定: (1)电池安全管理系统的作用及定位:电池安全管理系统是电源系统的重要组成部分,主要用于智能化管理及维护…

3.7V锂电池供电方案探讨

随着现在物联网、可穿戴、互联网、移动型等设备的深入发展,越来越多的小型化嵌入式设备必不可少的要采用锂电池供电,由此产生的电路板供电问题也五花八门,大家也是根据自身的应用场合和特点仁者见仁智者见智的设计自己的电路,这里…

18650锂电池充电方案及保护板电路构思

18650锂电池充电方案及保护板电路构思 一、电路参数 1、充电电源为USB电源,额定电压为5V。 2、蓄电池为18650锂电池 3.7V,容量2600mAh 3、负载电机参数 二、电路板功能要求 1、充电电压保护、防止因选用错误的充电器(过高的输入电压&#xf…

锂电池充放电管理芯片,整套IC组合,长篇文章

关乎锂电池供电的产品,在锂电池上,需要三个电路系统:1,锂电池保护电路,2,锂电池充电电路,3,锂电池输出电路。 内容目录: 1, 单节的锂电池保护电路单节为3.7…

高耐压锂电池充电管理芯片CL4054H CL4056H CL4267H CL4051M CL4064M

产品介绍 CL4056H是一款性能优异的单节锂离子电池恒流/恒压线性充电器。CL4056H采用ESOP8封装配合较少的外围原件使其非常适用于便携式产品,并且适合给USB电源以及适配器电源供电。 基于特殊的内部MOSFET架构以及防倒充电路,CL4056H不需要外接检测电阻和…

【单双节锂电池6-8.4V升压9V,12V,24V快充PD升压系统解决方案】

在许多应用场合,都需要将低电压升至适合用电设备使用的较高电压。如单节和双节锂电池供电电路,常需要将其2.8~4.2V的低电压升至可供使用的5V,9V,12V,甚至更高的电压。再如双节锂电池6.0V-8.4V电压升压到9V,12V,15V,20V…

【新能源】新能源之锂电池产业链梳理

随着新能源行业一系列政策的落地,以及新能源汽车的快速成长,锂电池需求随之快速增长,今天就对锂电池行业全产业链进行梳理分析。 一、锂电池行业现状与需求分析 锂电池在传统领域主要应用于数码产品,在新能源长足发展的今天&#…