android电池充电以及电量检测驱动分析

本文介绍了在飞思卡尔IMX6Q平台上,使用MAX8903和MAX11801芯片进行电池充电和电量检测的调试过程。内容包括电量检测驱动的添加,电池电压的校正参数设定,以及电池充电状态的检测。通过i2c设备添加,中断处理和电源供应设备文件读取电压值,实现系统对电池状态的实时监控。
摘要由CSDN通过智能技术生成

   前段时间比较烦躁,各种不想学习不想工作,于是休息了几天。这几天又下来任务了--调试充电电路和电池电量检测电路,于是又开始工作,顺便把调试过程记录下来。

  平台: cpu        飞思卡尔imx6q 4核

        充电芯片     MAX8903

        电量检测芯片  MAX11801

        android版本  android4.0

一、电量检测

   我们用的电池电量检测芯片MAX11801其实是一款电阻触摸屏的驱动芯片,它外带一个AD采集引脚,因此我们用这个引脚来检测电池电压。MAX11801电源为3.3V而电池电压范围可能是0~4.2V,因此我们需要给电池电压分压。我们所用的电路如下



  知道了硬件电路下面来 添加这个芯片的驱动,这是一个i2c的芯片,因此首先在board文件中添加i2c设备

		I2C_BOARD_INFO("max11801", 0x48),
		.platform_data = (void *)&max11801_mode,
		.irq = gpio_to_irq(SABRESD_TS_INT),
	},
  然后添加这个芯片的驱动文件放在/drivers/input/touchiscreen/max11801_ts.c

  对于这个驱动文件我们只要读取出AD的值就可以了,对于触摸屏部分我们并不需要,因此主要是下面几个函数

static u32 max11801_dcm_sample_aux(struct i2c_client *client)
{
	u8 temp_buf;
	int ret;
	int aux = 0;
	u32 sample_data = 0;
	/* AUX_measurement*/
	max11801_dcm_write_command(client, AUX_measurement);//发送AD采集命令
	mdelay(5);
	ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_MSB, //读取高字节数据
						1, &temp_buf);
	if (ret < 1)
		printk(KERN_DEBUG "FIFO_RD_AUX_MSB read fails\n");
	else
		aux_buf[0] = temp_buf;
	mdelay(5);
	ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_LSB,    //读取低字节数据
						1, &temp_buf);
	if (ret < 1)
		printk(KERN_DEBUG "FIFO_RD_AUX_LSB read fails\n");
	else
		aux_buf[1] = temp_buf;
	aux = (aux_buf[0] << 4) +           //视最低4位无效并去掉
					(aux_buf[1] >> 4);

	/*
	10k和18.7k并联后电阻 
	R=18.7*10/(18.7+10)=6.516
	V(aux) = V(bat)*6.516/(6.516+18.7)
	V(aux) = aux*3300/0xfff
	V(bat) = aux*1386880/444717
	*/
	sample_data = (aux*1386880)/444717;	//计算出电池电压
	return sample_data;
}

u32  max11801_read_adc(void)
{
	u32 adc_data;
	adc_data = max11801_dcm_sample_aux(max11801_client);
//	printk("----%s %d\n",__func__,adc_data);	//lijianzhang
	return adc_data;
}
EXPORT_SYMBOL_GPL(max11801_read_adc);

由于电池电量检测的驱动非常简单,而且和充电驱动关系非常密切,因此一般都卸载充电驱动里面,我们也是这么做的。下面的代码都是从充电驱动中摘出来的,因此当大家看到,一些设备文件和函数参数类型 都是充电驱动中的  时候不要太奇怪。

通过上面的max11801_read_adc函数我们已经得到了理论计算的电池的电压,但实际应用中由于分压电阻误差,焊接问题等,这个电压会有一定的误差因此需要一个校正函数

u32 calibration_voltage(struct max8903_data *data)
{
	int volt[ADC_SAMPLE_COUNT];
	u32 voltage_data;
	int i;
		for (i = 0; i < ADC_SAMPLE_COUNT; i++) {    //多次采样,防止AD误差
			if (data->charger_online == 0 && data->usb_charger_online == 0) {
				/* ADC offset when battery is discharger*/
				volt[i] = max11801_read_adc()-offset_discharger;    //没有充电情况下 电压误差
				} else {
						if (data->charger_online == 1)
						volt[i] = max11801_read_adc()-offset_charger;//DC充电式 电压误差
						else if (data->usb_charger_online == 1)
						volt[i] = max11801_read_adc()-offset_usb_charger;//usb充电  电压误差
						else if (data->charger_online == 1 && data->usb_charger_online == 1)
						volt[i] = max11801_read_adc()-offset_charger;
				}
		
	}
	sort(volt, i, 4, cmp_func, NULL);//对电压排序
	for (i = 0; i < ADC_SAMPLE_COUNT; i++)
		pr_debug("volt_sorted[%2d]: %d\n", i, volt[i]);
	/* get the average of second max/min of remained. */
	voltage_data = (volt[2] + volt[ADC_SAMPLE_COUNT - 3]) / 2;//去掉最大值最小值 并对剩余数据求平均
	return voltage_data;
}
从上面函数我们读取到了正确的电压值。电池电压是随时变化的,我们要检测电池电量,必须随时采集,因此用一个定时器来做这件事情,代码如下:

INIT_DELAYED_WORK(&data->work, max8903_battery_work);
	schedule_delayed_work(&data->work, data->interval);

电压采集完成后就是将电压上报出去,上报的过程是:我们读取到电压变化->告诉android端电池电压变化了->android会通过power_supply设备文件来读取具体的电压值。
我们来看定时器回调函数

static void max8903_battery_wo
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值