EC智能电池信息读取

本文介绍了智能电池的组成,包括电芯、电池保护板和电池外壳。详细讲解了智能电池如何通过SMBus与EC及OS通信,重点讨论了电池的连接方式、SBS命令以及EC代码实现。在解决问题的过程中,揭示了高低位调换导致的读数错误并提出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 前言

        最近在做EC方面的项目,客户需求带电池的方案。EC芯片用的是ITE的IT5571。

        本人刚毕业,对EC方面很多都不懂,以下内容是我在网上找的各种资料经过自己的理解所总结。如有错误请指正谢谢!

1.智能电池组成

        智能电池的构造简单来说主要分为电芯(cell)、电池保护板(bms)、电池外壳这几部分。

        电芯仅仅用来提供电压电流。几个电芯串联起来就是电池包(package)。若一个电芯的电压为3.7V,电池包为3个电芯串联,则电池包电压为3.7X3=11.1V。

        电池保护板则负责电池的充放电管理以及和OS数据通信。

2.智能电池和EC以及OS之间通信

        智能电池是一个SMBus设备,通过SMBus总线来进行数据传输。电池信息数据到操作系统的数据流向:SMART BATTERY->EC SMBUS->EC 62/66 PORT->BIOS->OS。既然智能电池是SMBus设备,那么要和智能电池通信就要知道其相对应的设备地址。以bq29330+bq20z70电池保护板为例,查询芯片手册可知bq20z70的从设备地址为0x16。

        下图为bq20z70 datasheet中提到的SMBus设备地址:

 3.智能电池与EC连接

        下图为某智能电池的保护电路原理图。我们需要注意PRES、SMBC、SMBD这三个引脚。SMBC与SMBD和EC上的一组SMBus channel直接相连。

        PRES(System Present Flag)脚的作用是用作EC检测电池是否插入的判断脚。PRES连接EC的GPIO脚,GPIO脚配置为输入模式,初始上拉为高电平,需要提前去抖。当智能电池接入座子,则EC检测到PRES脚拉低,在代码中通过判断得知电池的存在。

              保护电路板原理图:

4.智能电池标准SBS命令

        所有的智能电池都符合Smart Battery System(SBS)规范。在此规范中统一定义了智能电池标准的查询信息命令,这些标准命令是所有电池公用的。不同的电池除了标准的SBS命令以外还会有自己独有的命令,在手册中查询Extended SBS Commands来查看相对应功能。

        下图为智能电池规范中截取的标准SBS命令:

        通过命令获取电池所需充电电流和充电电压值,写入charger的寄存器中即可实现智能电池的智能充电。        

        下图为获取电池所需充电电流和充电电压命令:

        下图为截取的部分bq20z70 Extended SBS Commands:

        bq20z70生产厂商为德州仪器,在官网可以下载专门调试电池的软件bqstudio。不知道是不是型号太老的原因,bq20z70会被识别为bq40z50。

5.EC代码

        首先在EC的H2RAM中将电池相关的寄存器写入。

        关于H2RAM,在相关的文档中找到这段话:

        载板 EC 应该启用 256 个字节的 H2RAM 窗口以供 MMIO 中的 BIOS 访问 0xFE41_0400~0xFE41_04FF。

        在 ACPI OS 中,在收到 ACPI_ENABLE 0x86 EC 命令之后,载板 EC 固件必须公开以下必需的内存 MMIO,并可以选择公开 UCSI/WMI MMIO 以进行 BIOS 访问:
        • 强制 128 字节只读 ELM_EC MMIO 区域 0xFE41_0400~0xFE41_047F。
        • 强制 128 字节读/写 ELM_EC MMIO 区域 0xFE41_0480~0xFE41_04FF。
        • 载板 EC 固件和软件可以使用 0xFE41_0000~0xFE41_3FFF 之间的任何未使用区域。 BIOS 将不会访问未定义的 EC MMIO 区域。

Oem_memory.h

//batt1--------------------------------------------------------------------
extern ECRegW xwBatt1Temperature		   ;//_at_ (MEM_RO_CONFIG+0x50);
extern ECRegW xwBatt1Voltage			   ;//_at_ (MEM_RO_CONFIG+0x52);
extern ECRegW xwBatt1Current               ;//_at_ (MEM_RO_CONFIG+0x54);
extern ECRegW xwBatt1RemainingCapacity	   ;//_at_ (MEM_RO_CONFIG+0x56);
extern ECRegW xwBatt1FullChargeCapacity	   ;//_at_ (MEM_RO_CONFIG+0x58);
extern ECRegW xwBatt1DesignCapacity		   ;//_at_ (MEM_RO_CONFIG+0x5A);
extern ECRegW xwBatt1RelativeStateOfCharge ;//_at_ (MEM_RO_CONFIG+0x5C);
extern ECRegW xwBatt1ChargingCurrent       ;//_at_ (MEM_RO_CONFIG+0x5E);
extern ECRegW xwBatt1ChargingVoltage       ;//_at_ (MEM_RO_CONFIG+0x60);
extern XBITS_8 xbBatt1Status                 ;//_at_ (MEM_RO_CONFIG+0x62);
#define _xbBatt1Status         xbBatt1Status.byte
#define Batt1_AC_Present       xbBatt1Status.field.bit0
#define Batt1_Batt_Present     xbBatt1Status.field.bit1
#define Batt1_FullCharge       xbBatt1Status.field.bit2
#define Batt1_Chaging          xbBatt1Status.field.bit3
#define Batt1_Discharging      xbBatt1Status.field.bit4
#define Batt1_Critical_low     xbBatt1Status.field.bit5
#define Batt1_Over_Temperature xbBatt1Status.field.bit6
#define Batt1_Lid_Open         xbBatt1Status.field.bit7
//batt1--------------------------------------------------------------------
Oem_memory.c

//batt1-------------------------------------------------------------
ECRegW xwBatt1Temperature		    _at_ (MEM_RO_CONFIG+0x50);
ECRegW xwBatt1Voltage			    _at_ (MEM_RO_CONFIG+0x52);
ECRegW xwBatt1Current               _at_ (MEM_RO_CONFIG+0x54);
ECRegW xwBatt1RemainingCapacity	    _at_ (MEM_RO_CONFIG+0x56);
ECRegW xwBatt1FullChargeCapacity	_at_ (MEM_RO_CONFIG+0x58);
ECRegW xwBatt1DesignCapacity		_at_ (MEM_RO_CONFIG+0x5A);
ECRegW xwBatt1RelativeStateOfCharge _at_ (MEM_RO_CONFIG+0x5C);
ECRegW xwBatt1ChargingCurrent       _at_ (MEM_RO_CONFIG+0x5E);
ECRegW xwBatt1ChargingVoltage       _at_ (MEM_RO_CONFIG+0x60);
XBITS_8 xbBatt1Status               _at_ (MEM_RO_CONFIG+0x62);
//batt1-------------------------------------------------------------

        在battery.h文件中定义SBS命令,电池地址和SMBuschannel。

Oem_battery.h

#ifndef OEM_BATTERY_H
#define OEM_BATTERY_H

#define Battery_Addr		0x16
#define Battery_Channel	SMbusCh2
#define _SCIEVT_BATTERY              		0x09    //battery Q EVENT

//****************************************
//            SBS command list
//**************************************** 
#define    _CMD_Temperature			    0x08	
#define    _CMD_Voltage				    0x09	
#define    _CMD_Current				    0x0a	
#define    _CMD_RemainingCapacity		0x0f	
#define    _CMD_FullChargeCapacity		0x10	
#define    _CMD_DesignCapacity		    0x18	
#define    _CMD_RelativeStateOfCharge	0x0d	
#define    _CMD_ChargingCurrent		    0x14
#define    _CMD_ChargingVoltage		    0x15


extern void vBattery_Init(void);
extern void vBattery_GetInfo(void);

#endif

        在Oem_memory.c文件中写查询信息函数。由于SMBus查询函数已经写好,只要填入相关参数调用即可。

#include <CORE_INCLUDE.H>
#include <OEM_INCLUDE.H>

int vCheck_BattPlugIn(void)
{
	if(IS_MASK_CLEAR(GPDRA, BIT(0)) // 这里应检测pres对应脚是否位低电平,如果为低则表示电池接入
		{
			Batt1_Batt_Present = 1;
			WriteBatterySCI_Buffer(_SCIEVT_BATTERY);
		}
	else
		{
			Batt1_Batt_Present = 0;
		}
	return Batt1_Batt_Present;
}

void vBattery_Init(void)
{
	vCheck_BattPlugIn();
}

void vBattery_GetInfo(void)
 
{
	if(Batt1_Batt_Present)
		{
//函数参数分别为channel,protocol,addr,CMD,*var
if(bRWSMBus(Battery_Channel,SMbusRW,Battery_Addr,_CMD_Temperature,&xwBatt1Temperature,SMBus_NoPEC))
			{	
//读取电池温度
			}

	if(bRWSMBus(Battery_Channel,SMbusRW,Battery_Addr,_CMD_Voltage,&xwBatt1Voltage,SMBus_NoPEC))
			{
//读取电压
			}

		if(bRWSMBus(Battery_Channel,SMbusRW,Battery_Addr,_CMD_Current,&xwBatt1Current,SMBus_NoPEC))
			{
//读取电流
			}

		if(bRWSMBus(Battery_Channel,SMbusRW,Battery_Addr,_CMD_RemainingCapacity,&xwBatt1RemainingCapacity,SMBus_NoPEC))
			{
//读取剩余容量	
			}

		if(bRWSMBus(Battery_Channel,SMbusRW,Battery_Addr,_CMD_FullChargeCapacity,&xwBatt1FullChargeCapacity,SMBus_NoPEC))
			{
//读取充满电容量
			}

		if(bRWSMBus(Battery_Channel,SMbusRW,Battery_Addr,_CMD_DesignCapacity,&xwBatt1DesignCapacity,SMBus_NoPEC))
			{
//读取设计容量
			}

		if(bRWSMBus(Battery_Channel,SMbusRW,Battery_Addr,_CMD_RelativeStateOfCharge,&xwBatt1RelativeStateOfCharge,SMBus_NoPEC))
			{
//读取相对容量
			}

		if(bRWSMBus(Battery_Channel,SMbusRW,Battery_Addr,_CMD_ChargingCurrent,&xwBatt1ChargingCurrent,SMBus_NoPEC))
			{
//读取充电电流
			}

		if(bRWSMBus(Battery_Channel,SMbusRW,Battery_Addr,_CMD_ChargingVoltage,&xwBatt1ChargingVoltage,SMBus_NoPEC))
			{
//读取充电电压
			}
		}
}

        初始化SMBus主设备,在相关文档找到SMBus的操作频率:

         在init文件中写入电池SMBus主设备初始化。

Oem_init.c

void Init_SMBus_Regs(void)
{
    vSMBus_SW_Timing(_i2c_100k);
    vSMBus_Master_Enable(_SMBusChC, _SMB2, _i2c_fix_100k, _FifoSize_256_Byte);//Battery
 
}

          一切都写好,正当我沾沾自喜时,突然出现一个致命的问题,在系统下读取的电池温度,容量等等数值都是不正确的!用ITE专门的调试软件NewWinECU连接EC后,直接查看H2RAM中关于电池寄存器的值。发现数值读取出来怪怪的不对劲。琢磨了很久终于发现是高低位调换了所导致读数不正确!

        正常情况下应该在代码中将高低位的数值调换一下,不过我选择了一个很投机取巧的方法(笑)将电池所用的这组channel中的数据寄存器高低位直接调换即可。

Oem_smbus.c

const sSMBus code asSMBus[]=
{
	{ &HOCTL_C, &TRASLA_C, &HOCMD_C, &HOSTA_C, &D1REG_C, &D0REG_C,	&HOBDB_C,	&IER2,	&ISR2,	Int_SMBUS2,   &PECERC_C},//用的这个channel接的电池,将数据寄存器高低位调换位置,即D1REG_C和D0REG_C
	{ &HOCTL_D, &TRASLA_D, &HOCMD_D, &HOSTA_D, &D0REG_D, &D1REG_D,	&HOBDB_D,	&IER0,	&ISR0,	Int_SMBUS3,   &PECERC_D},//这是没改的
};

        大功告成。这次确实读数正确了! 关于电池充电方面后续研究。目前这样写是能够在windows下读取到电池的信息了。 

6.关于各种电量指标理解 

         下图为在acpi config power interface spec文档中找到各种电量的示意图:

        关于相对容量和绝对容量的计算方法:

Relative State Of Charge = Remaining Capacity/Full Charge Capacity

Absolute State Of Charge = Remaining Capacity/Design Capacity

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值