?? charge.c
字號:
/********************************************************/
/* charge.c: implementation of charging about As3603. */
/* Author : qzsu */
/* History : 2006-11-01 */
/********************************************************/
#define CHARGE_WINCE
//include
#include <stdlib.h>
#include <stdio.h>
#include ".\inc\wm97xx.h"
#include ".\inc\charge.h"
#include ".\inc\powermanagement.h"
#ifdef CHARGE_WINCE
#include "hw_lib.h"
#include <windows.h>
#endif
//#define _DEBUG
#define DWORD unsigned int
#define VOL_OFFSET 7
#define VOL_MAX 500
#define VOL_MIN 343
//global
unsigned char* g_AACI_BASE = NULL;
//function
//external
//bool NoSystemStart(void);
//unsigned char GetBatteryQAccPercent(void);
//internal
void Delay(unsigned int msec);
void UDelay(unsigned int us);
static int apAACI_ReadRegister(volatile int reg);
static int apAACI_WriteRegister(volatile int reg, int value);
int GetBatteryVoltage(unsigned int* vol);
/*****************************************
Fuction: delay msec
Input: unsigned int msec
Output: none
Return: none
Modify:
*******************************************/
void Delay(unsigned int msec)
{
int i;
i = msec *50000;
while(i--);
}
/*****************************************
Fuction: delay us
Input: unsigned int us
Output: none
Return: none
Modify:
*******************************************/
void UDelay(unsigned int us)
{
int i;
i = us *33;
while(i--);
}
/*****************************************
Fuction: Write a value to a CODEC control register
Input: volatile int reg -- register address
int value
Output: none
Return: ture -- success;false -- fail
Modify:
*******************************************/
// Write a value to a CODEC control register
static int apAACI_WriteRegister(volatile int reg, int value)
{
int timer;
if(!g_AACI_BASE)return FALSE;
//AACI_SLFR ---#define AACI_SL1TXBUSY 0x0002---Slot 1 transceive busy????
// Wait for TX1/2 not to be busy
timer = AACI_TIMEOUT;
while ((*((DWORD*)(AACI_SLFR)) & AACI_SL1TXBUSY) && timer) {//等待slot1 的傳送寄存器空閑
UDelay(10);
timer--;
}
// Note: the data value must be setup before the address
*((DWORD*)(AACI_SL2TX)) = value << 4;//數據寄存器
*((DWORD*)(AACI_SL1TX)) = reg << 12;//地址寄存器
if (timer)
return TRUE;
else
return FALSE;
}
/*****************************************
Fuction: Read a value from a CODEC control register
Input: volatile int reg -- register address
Output: none
Return: value readed from register
Modify:
*******************************************/
static int apAACI_ReadRegister(volatile int reg)
{
int timer;
unsigned int data;//, stat;
if(!g_AACI_BASE)return FALSE;
timer = AACI_TIMEOUT;
//先放數據,再放地址
while ((*((DWORD*)(AACI_SLFR)) & AACI_SL1TXBUSY) && timer) {//等待slot1 的傳送寄存器空閑
UDelay(10);
timer--;
}
//先放數據,再放地址
*((DWORD*)(AACI_SL2TX)) = 0;
//地址為8BIT,所以應該放在20位中的高8位,所以要向右移12位
*((DWORD*)(AACI_SL1TX)) = (reg << 12) | 0x80000;
timer = AACI_TIMEOUT;
while(((*((DWORD*)(AACI_SLFR)) & 0x100) == 0) && timer){//當退出這個循環的時候表示數據已經接收到了
UDelay(10);
timer--;
}
data = (*((DWORD*)(AACI_SL2RX)) >> 4);
return data;
}
/*****************************************
Fuction: check battery voltage
Input: none
Output: voltage value
Return: -1:address error
0:data error
1:success
Modify:
*******************************************/
int GetBatteryVoltage(unsigned int* vol)
{
unsigned int datax0,datay0;
unsigned int voltage0,voltage1,voltage2,voltage3;
unsigned int regValue;
if(!g_AACI_BASE || !vol)
{
return -1;
}
regValue = apAACI_ReadRegister(0x78);
#ifdef _DEBUG
printf("apAACI_ReadRegister(0x78):%x\r\n",regValue);
#endif
if(!(regValue == 0xc201 || regValue == 0xc001))
{
apAACI_WriteRegister(0x78, 0xc201);
return -2;
}
//comp1
apAACI_WriteRegister(0x76, 0xc006);
datax0 = apAACI_ReadRegister(0x7a)&0x0fff;
voltage0 = datax0*250*70/(4095*34);
#ifdef _DEBUG
printf("voltage0:%d\r\n",voltage0);
#endif
if(voltage0 < VOL_MIN-VOL_OFFSET || voltage0 > VOL_MAX-VOL_OFFSET)
{
return 0;
}
//comp2
apAACI_WriteRegister(0x76, 0xd006);
datay0 = apAACI_ReadRegister(0x7a)&0x0fff;
voltage1 = datay0*250*70/(4095*33);
#ifdef _DEBUG
printf("voltage1:%d\r\n",voltage1);
#endif
if(voltage1 < VOL_MIN-VOL_OFFSET || voltage1 > VOL_MAX-VOL_OFFSET)
{
return 0;
}
voltage2= (voltage0+voltage1)/2;
voltage3 = voltage2 + VOL_OFFSET;//銅線降壓偏差
#ifdef _DEBUG
printf("GetBatteryVoltage:%d\r\n",voltage3);
#endif
*vol = voltage3;
return 1;
}
/*****************************************
Fuction: get battery qacc percent using voltage check
Input: none
Output: none
Return: the percent of QAcc
Modify:
*******************************************/
unsigned char GetBatteryQAccPercent(void)
{
unsigned int vol;
unsigned int count = 0;
int ret;
ret = GetBatteryVoltage(&vol);
while(count++ < 100 && ret <= 0)
{
Sleep(20);
ret = GetBatteryVoltage(&vol);
}
if(ret == 1)
{
if(vol >= 420)
{
return 100;//100%
}
else if(vol >= 390 && vol < 420)
{
return (vol-390)*(100-80)/(420-390)+80;
}
else if(vol >= 360 && vol < 390)
{
return (vol-360)*(80-20)/(390-360)+20;
}
else if(vol > VOL_MIN && vol < 360)
{
return (vol-VOL_MIN)*(20-0)/(360-VOL_MIN);
}
else
{
return 0;
}
}
return 0;
}
/*****************************************
Fuction: judge if permit system start with check battery voltage
Input: none
Output: none
Return: true -- no permit;false -- permit
Modify:
*******************************************/
bool NoSystemStart(void)
{
unsigned int vol;
if(GetBatteryVoltage(&vol) && vol <= VOL_MIN)
{
return true;
}
return false;
}
bool InitCharge(void)
{
#ifdef CHARGE_WINCE
g_AACI_BASE = (unsigned char *)(hw_map_io(0x20037000, 0x1000, 0));
hw_delay(1);
#else
g_AACI_BASE = (unsigned char *)0x20037000;
#endif
if(!g_AACI_BASE)
{
return false;
}
#ifndef CHARGE_WINCE
//下面復位信號可以讓AACI 復位
*AACI_RESET = 0;
Delay(100);//復位等待
*AACI_RESET = 1;//置高電平讓外圍設備工作
Delay(1);//等待外圍設備工作穩定
*AACI_MAINCR = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 0);
#endif
apAACI_WriteRegister(0x78, 0xc201);
return true;
}
void DeInitCharge(void)
{
}
//======================Battery Charger Controller BEGIN=====================
void PM_ChargeInitial(void)
{
WriteAs3603(FUELGAUGE_REG, 0x00);
// WriteAs3603(CHARGECTRL_REG, 0x00);
PM_ChargeDefaultConfig();
}
U32 PM_ChargeFinish(void)
{
unsigned char ctrlreg;
ctrlreg = ReadAs3603(CHARGECTRL_REG);
ctrlreg &= 0xFE;
WriteAs3603(CHARGECTRL_REG, ctrlreg);
return 1;
}
U8 PM_ChargerDetected(void)
{
U8 value;
value = ReadAs3603(CHARGESTATUS_REG);
//printf("CHARGESTATUS_REG:%x\r\n",value);
if((value & 0x01) == 0x01)//chDet
{
return true;
}
return false;
}
void PM_ChargeDefaultConfig(void)
{
/* Sets charger config register
000 N/A
0 Enable battery presence indication
0 Enable operation without battery
0 Li+ battery with coke anode
0 Disable CVM testmode
*/
WriteAs3603(CHARGECONF_REG, 0x00);
/* Sets charger current
TrickleCurrent 2.5mV/RSENSE
ConstantCurrent 15mV/Rsense
*/
WriteAs3603(CHARGECURRENT_REG, 0x1d);//0x11);//700mA
WriteAs3603(PRECURDAC_REG, 0x32);//0.5v r=2k
}
#define FULLQ 2200000 //uAh
U8 PM_ChargeUpdate(int* avgCurrent,U32* uiQacc,U32* uiTime)
{
unsigned char value;
U32 deltaCount;
U32 deltaQ;
U32 deltaT;
static unsigned char trickleFlag = 0;
static unsigned char fullFlag = 0;
value = ReadAs3603(FUELGAUGE_REG);
value |= 0x02;
WriteAs3603(FUELGAUGE_REG, value);
do
{
value = ReadAs3603(FUELGAUGE_REG);
}while((value & 0x02) == 0x02);//wait update
//time
deltaT = ((U32)ReadAs3603(ELAPSEDMSB_REG)) << 8;
deltaT += ReadAs3603(ELAPSEDLSB_REG);
if(deltaT == 0)
{
return false;
}
deltaT = deltaT * 3600000;//8788;//0.8788s per count
deltaT /= 4096;//10;
//QACC
value = ReadAs3603(CHARGESTATUS_REG);
if(fullFlag == 0 && (value & 0x01) == 0x01)//charge
{
//charge check sign bit is 0
if((ReadAs3603(DELTAMSB_REG) & 0x80) != 0)
{
return false;
}
deltaCount = ((U32)(ReadAs3603(DELTAMSB_REG)&0x7f)) << 8;
deltaCount += ReadAs3603(DELTALSB_REG);
if(deltaCount == 0)
{
return false;
}
}
else//discharge
{
//charge check sign bit is 1
if((ReadAs3603(DELTAMSB_REG) & 0x80) == 0)
{
return false;
}
deltaCount = ((U32)(0x7f-(ReadAs3603(DELTAMSB_REG)&0x7f))) << 8;
deltaCount += 0xff-ReadAs3603(DELTALSB_REG);
if(deltaCount == 0 || deltaCount == 0x7fff)
{
return false;
}
}
deltaQ = deltaCount * 6103;//61.03uAh per count
deltaQ /= 100;//uAh
*uiTime = *uiTime + deltaT;//ms
if((value & 0x01) == 0x01)//charge
{
*uiQacc += deltaQ;//uAh
}
else
{
if(*uiQacc > deltaQ)
{
*uiQacc -= deltaQ;//uAh
}
else
{
*uiQacc = 0;
}
}
{double temp;
int iTemp;
// AVFC Rsense deltaT/1000 m歐 mA
temp = (double)deltaCount / ( (double)deltaT * 91.0 * 50.0) * 1000.0 * 1000.0 * 1000.0;
iTemp = (int)temp;
*avgCurrent = iTemp;
}
//*avgCurrent = (U32)((double)deltaCount*1000*1000*1000 / ( deltaT * 91 * 50));//mA
if(PM_ChargerDetected())
{
if(PM_ChargeIsFull() || (*uiQacc) > FULLQ)
{
*uiQacc = FULLQ;//uAh
if(PM_ChargeIsFull())
{
PM_ChargeFinish();
fullFlag = 1;
}
}
else if(!trickleFlag)
{
if(PM_ChargeIsTrickle())
{
*uiQacc = FULLQ / 100 * 95;
trickleFlag = 1;
}
else if((*uiQacc) > FULLQ / 100 * 94)
{
*uiQacc = FULLQ / 100 * 94;
}
}
//充滿后會放電,掉到98%以下重新啟動充電
if(fullFlag == 1 && (*uiQacc) < FULLQ / 100 * 98)
{
PM_ChargeStart();
fullFlag = 0;
}
}
return true;
}
U8 PM_IsCharging(void)
{
unsigned char status;
// Detectes battery
status = ReadAs3603(CHARGESTATUS_REG);
#ifdef _DEBUG
printf("CHARGESTATUS_REG:%.2x\r\n",status);
#endif
if((status & 0x03) == 0x03)//chDet,chAct
{
return true;
}
return false;
}
U8 PM_ChargeIsFull(void)
{
U8 value;
value = ReadAs3603(CHARGESTATUS_REG);
if(PM_ChargerDetected() && (value & 0x20) == 0x20)
{
return true;
}
else
{
return false;
}
}
U8 PM_ChargeIsTrickle(void)
{
U8 value;
value = ReadAs3603(CHARGESTATUS_REG);
if(PM_ChargerDetected() && (value & 0x10) == 0x10)
{
return true;
}
else
{
return false;
}
}
U8 PM_ChargeIsEmpty(void)
{
U8 value;
value = ReadAs3603(CHARGESTATUS_REG);
if(!PM_ChargerDetected() && (value & 0x20) == 0x20)
{
return true;
}
else
{
return false;
}
}
U8 PM_NoBattery(void)
{
unsigned char status;
// Detectes battery
status = ReadAs3603(CHARGESTATUS_REG);
if(status & 0x40)
{
//#ifdef _DEBUG
printf("Not detecte battery!--%x\r\n",status);
//#endif
return true;
}
return false;
}
U8 PM_ChargeStart(void)
{
/* Sets Fuel Gauge Register
1 Enables Fuel Gauge.
0 Controls the updates of the Delta Charge MSB/LSB registers and the Elapsed Time MSB/LSB registers
1 Request offset calibration.
0 Sets the offset calibration mode.
*/
WriteAs3603(FUELGAUGE_REG, 0x01);
/* Sets parameter of the charger
0 Disables charging
0 lithium-based battery
0 Selects Constant Current charge mode
0 Li+ battery with coke anode
0 Select constant voltage charging mode
0 Normal charger operation.
0 Nominal current
*/
/* Enable charger*/
// WriteAs3603(CHARGECTRL_REG, 0x41);//boost = 1
WriteAs3603(CHARGECTRL_REG,ReadAs3603(CHARGECTRL_REG)|0x01);
return true;
}
/************************************************************************/
//======================Battery Charger Controller END=====================
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -