/* *************************************************************************
*
* Individual handlers for SMBus WRITE-type commands
*
************************************************************************* */
unsigned char SMBW_MfrAccess(void) // 0
{
unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
SMBvar_int[SMBV_MfrAccess] = temp | (TW_RxBuf[TW_RxBufIndex]<<8);
SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0; //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
return 0;
}
unsigned char SMBW_RemCapAlm(void) // 1
{
unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
SMBvar_int[SMBV_RemCapAlm] = temp | (TW_RxBuf[TW_RxBufIndex]<<8);
SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0; //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
return 0;
}
unsigned char SMBW_RemTimeAlm(void) // 2
{
unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
SMBvar_int[SMBV_RemTimeAlm] = temp | (TW_RxBuf[TW_RxBufIndex]<<8);
SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0; //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
return 0;
}
unsigned char SMBW_BattMode(void) // 3
{
unsigned char tempH = TW_RxBuf[TW_RxBufIndex+1];
unsigned char tempL;
tempL = SMBvariables[SMBV_BattMode][lobyte] & 0xF0;
if(tempH & 0x1C)
return SMBerr_AccessDenied; //attempt to write to reserved bits!
if(~(tempL & INTERNAL_CHARGE_CONTROLLER))
{
tempH &= ~CHARGE_CONTROLLER_ENABLED; //feature not present, don't let it get turned on.
}
if(tempH & PRIMARY_BATTERY)
{
; //let the Host do what it wants with this flag; we ignore it.
}
//if(tempH & ALARM_MODE)
// SetAlarmMode; //this DISABLES sending alarm msgs for 60 secs
if(tempH & CHARGER_MODE)
{
; //Allow Host to enable us to send Master-mode Charger-Voltage/Current msgs to the Charger
}
if(tempH & CAPACITY_MODE)
{
; //Host must be allowed to control this bit (report in mAH or 10mWH)
}
SMBvar_int[SMBV_BattMode] = tempL | (tempH<<8); //write the modified bits.
return 0;
}
unsigned char SMBW_AtRate(void) // 4
{
unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
SMBvar_int[SMBV_AtRate] = temp | (TW_RxBuf[TW_RxBufIndex++]<<8);
SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0; //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
return 0;
}
unsigned char SMBW_CalibV(void) // 0x1E
{
// unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
//unsigned int tempI = temp|(TW_RxBuf[TW_RxBufIndex] << 8);
return 0; // Return OK.
}
unsigned char SMBW_CalibC(void) // 0x1F
{
//unsigned int temp = TW_RxBuf[TW_RxBufIndex++];
//temp = (signed int)(temp | (TW_RxBuf[TW_RxBufIndex]<<8));
//__disable_interrupt();
//CalibrateCCoffset_1A((signed int)temp);
//__enable_interrupt();
return 0;
}
unsigned char SMBW_Opt6(void) // 0x2e 3 addrh addrl optlen
{
unsigned int temp = TW_RxBuf[3];
if(UsePEC == 0)
return(1);
Flash_Addr = (temp<<8)|(unsigned int)TW_RxBuf[4];
if(TW_RxBuf[2] == 3)
{
Flash_Cnt = TW_RxBuf[5];
if((TW_RxBuf[5] == 0xff)&&(Flash_Addr>0x5fff)) // 12 ~ 15 扇区
{
EA = 0;
FlashErase(Flash_Addr); //0x0000 ~ 0x7fff
EA = 1;
}
}
//FillWriteStr(&SMBstring[0][0]);
return 0;
}
unsigned char SMBW_Opt5(void) // 0x2F
{
unsigned char j=0;
//__disable_interrupt();
if(UsePEC == 0)
return(1);
EA = 0;
//MCUSR = 0x1F; //clear all reset sources before jumping to bootloader code.
// __watchdog_reset; //
//asm("jmp 0x9000"); // Byte adress
// __watchdog_reset; // reset watchdog
for(j=0;j<TW_RxBuf[2];j++)
{
Flash_Write((Flash_Addr + j), TW_RxBuf[3+j]);
}
EA = 1;
return(0); // to avoid compiler warning, should never be reached
// return SMBerr_ReservedCommand; // <-- Compiler generates warning if return statement is missing.
}
unsigned char SMBW_Opt4(void) // 0x3C
{
//calibration_state_req = TW_RxBuf[TW_RxBufIndex++];
//calibration_state_req |= (unsigned int)TW_RxBuf[TW_RxBufIndex++] << 8; // Store request details.
SetCalibRequest; // Set action flag so that main loop starts calibrating.
return 0; // Return OK.
}
unsigned char SMBW_Opt3(void) // 0x3D
{
return SMBerr_ReservedCommand;
}
unsigned char SMBW_Opt2(void) // 0x3E
{
return SMBerr_ReservedCommand;
}
unsigned char SMBW_Opt1(void) // 0x3F
{
return SMBerr_ReservedCommand;
}
unsigned char SMBW_Invalid(void) //This should never execute, if error is caught early!
{
return SMBerr_AccessDenied;
}
//Table of pointers to functions, indexed from the received SMBus Command byte.
ptr2funcUC_V SMB_WriteCmd[HIGHEST_SMB_CMD+1] =
{
SMBW_MfrAccess, // 0
SMBW_RemCapAlm, // 1
SMBW_RemTimeAlm, // 2
SMBW_BattMode, // 3
SMBW_AtRate, // 4
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid, //0x0F
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid, //0x1F
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Opt6,
SMBW_Opt5, // 0x2F
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Invalid,
SMBW_Opt4, // 0x3C
SMBW_Opt3, // 0x3D
SMBW_Opt2, // 0x3E
SMBW_Opt1 // 0x3F
};
/* *************************************************************************
*
* Utilities for SMBus commmunications
*
************************************************************************* */
code const unsigned char crctable[16] = {0,0x07,0x0E,0x09, 0x1c,0x1b,0x12,0x15, 0x38,0x3F,0x36,0x31, 0x24,0x23,0x2A,0x2D};
code const unsigned char crctable2[16] = {0,0x70,0xE0,0x90, 0xC1,0xB1,0x21,0x51, 0x83,0xF3,0x63,0x13, 0x42,0x32,0xA2,0xD2};
unsigned char FastCRC(unsigned char LastCRC, unsigned char newbyte)
{
unsigned char idata index;
index = newbyte;
index ^= LastCRC;
index >>= 4;
LastCRC &= 0x0F;
LastCRC ^= crctable2[index];
index = LastCRC;
index ^= newbyte;
index &= 0x0F;
LastCRC &= 0xF0;
LastCRC ^= crctable[index];
return(LastCRC);
}
void SMBvariablesFlash(void)
{
unsigned char index;
unsigned char wbuffer[2];
unsigned char flag;
flag =1;
while(flag)
{
if(1 == flag)
{
FlashErase(0x7000); //0x0000 ~ 0x7fff
flag = 2;
//delay();
}
Flash_Write((SMB_DataFlashAddr + index*2), SMBvariables[index][hibyte]);
Flash_Write((SMB_DataFlashAddr + 1 + index*2), SMBvariables[index][lobyte]);
wbuffer[hibyte] = Flash_Read(SMB_DataFlashAddr + index*2); //扇区14
wbuffer[lobyte] = Flash_Read(SMB_DataFlashAddr + 1 + index*2); //扇区14
if((SMBvariables[index][hibyte] != wbuffer[hibyte])||(SMBvariables[index][lobyte] != wbuffer[lobyte]))
{
flag = 1;
index = 0;
continue;
}
if(index > SMBV_SerialNo)
break;
//if()
}
}
//! \todo This can be modified to load defaults from EEPROM rather than fixed values to the SMB variables.
// This sets power-up defaults.
void InitSMBvariables(void)
{
unsigned char i;
for(i=0; i<0x20; i++)
{
SMBvariables[i][hibyte] = Flash_Read(SMB_DataFlashAddr + i*2); //扇区14
SMBvariables[i][lobyte] = Flash_Read(SMB_DataFlashAddr + 1 + i*2); //扇区14
}
if((SMBvariables[SMBV_PackStackWidth] [hibyte]> 4)||(SMBvariables[SMBV_PackStackWidth][hibyte] < 2))
SMBvariables[SMBV_PackStackWidth ][hibyte] = 3; //
if((SMBvariables[SMBV_PackStackWidth][lobyte] > 5)||(SMBvariables[SMBV_PackStackWidth][lobyte] < 1))
SMBvariables[SMBV_PackStackWidth ] [lobyte]= 2; //
if((SMBvar_int[SMBV_DesignCap] > 10000)||(SMBvar_int[SMBV_DesignCap] < 2000))
SMBvar_int[SMBV_DesignCap ] = 4400; //
//SMBvar_int[SMBV_MfrAccess] = 0x4060;
if((SMBvar_int[SMBV_RemCapAlm] > 1200)||(SMBvar_int[SMBV_RemCapAlm] < 200))
SMBvar_int[SMBV_RemCapAlm] = (SMBvar_int[SMBV_DesignCap ] / 10); // per sbdat110, 4.4.1
if((SMBvar_int[SMBV_RemTimeAlm] > 20)||(SMBvar_int[SMBV_RemTimeAlm] < 3))
SMBvar_int[SMBV_RemTimeAlm] = 10;
SMBvar_int[SMBV_BattMode ] = 0x0000;
SMBvar_int[SMBV_AtRate ] = 0x0000;
/* For testing with no calcs
SMBvar_int[SMBV_AtRateTTF ] = 0x0000; //
SMBvar_int[SMBV_AtRateTTE ] = 0x0000; //
SMBvar_int[SMBV_AtRateOK ] = 0x0000; //
SMBvar_int[SMBV_Temperature] = 0x0000; //
SMBvar_int[SMBV_Voltage ] = 0x0000; //
SMBvar_int[SMBV_Current ] = 0x0000; //
SMBvar_int[SMBV_AvgCurrent ] = 0x0000; //
SMBvar_int[SMBV_MaxError ] = 0x0000; //
SMBvar_int[SMBV_RelSOC ] = 0x0000; //
SMBvar_int[SMBV_AbsSOC ] = 0x0000; //
SMBvar_int[SMBV_RemCap ] = 0x0000; //
SMBvar_int[SMBV_FullChgCap] = 0x0000; //
SMBvar_int[SMBV_RunTTE ] = 0x0000; //
SMBvar_int[SMBV_AvgTTE ] = 0x0000; //
SMBvar_int[SMBV_AvgTTF ] = 0x0000; //
SMBvar_int[SMBV_ChgCurrent] = 0x0000; //
SMBvar_int[SMBV_ChgVoltage] = 0x0000; //
*/
if((SMBvar_int[SMBV_ChgCurrent] > 6000)||(SMBvar_int[SMBV_ChgCurrent] < 800))
SMBvar_int[SMBV_ChgCurrent] = CELL_CCCV_C*SMBvariables[SMBV_PackStackWidth][lobyte];
if((SMBvar_int[SMBV_ChgVoltage] > 17000)||(SMBvar_int[SMBV_ChgVoltage] < 8000))
SMBvar_int[SMBV_ChgVoltage] = CELL_CCCV_V*SMBvariables[SMBV_PackStackWidth ][hibyte];
SMBvar_int[SMBV_BattStatus] = 0x0080; //per sbdat110, 4.4.1
if(SMBvar_int[SMBV_CycleCount] > 300)
SMBvar_int[SMBV_CycleCount] = 0x0000; //per sbdat110, 4.4.1
if((SMBvar_int[SMBV_DesignVolt] > 16800)||(SMBvar_int[SMBV_DesignVolt] < 7000))
SMBvar_int[SMBV_DesignVolt] = 11100; //
if((SMBvar_int[SMBV_SpecInfo] != 0x0021)||(SMBvar_int[SMBV_SpecInfo] != 0x0031))
SMBvar_int[SMBV_SpecInfo ] = 0x0031; // no scaling of I or V; we support PEC, and we're V1.1
if(SMBvar_int[SMBV_MfrDate] > ((2050-1980)<<9)+(12<<5)+(31))
SMBvar_int[SMBV_MfrDate ] = ((2015-1980)<<9)+(8<<5)+(31); //! \todo Fill in current year, month, day. Values are octal
/* For testing with no calcs
SMBvar_int[SMBV_SerialNo ] = 12345; // arbitrary...
*/
SMBvar_int[SMBV_Current ] = 0x0000; //
SMBvar_int[SMBV_AvgCurrent ] = 0x0000; //
SMBvar_int[SMBV_MaxError ] = 0x0001; //
SMBvar_int[SMBV_RelSOC ] = 0x0000; //
SMBvar_int[SMBV_AbsSOC ] = 0x0000; //
SMBvar_int[SMBV_RemCap ] = 1000; //
if((SMBvar_int[SMBV_FullChgCap] > SMBvar_int[SMBV_DesignCap ]*2)||(SMBvar_int[SMBV_FullChgCap] < SMBvar_int[SMBV_DesignCap ]/2))
SMBvar_int[SMBV_FullChgCap] = SMBvar_int[SMBV_DesignCap ];
//Note that for the Block-Read variables, we copy those into a RAM buffer only as needed.
// These are MfrName, DeviceName, DeviceChem, and MfrData.
SetMaxTopAcc((long)SMBvar_int[SMBV_DesignCap ]*3600); //! \todo for testing, initialized value before reaching fully charged, 6600mAh * 10727
RunningAcc = (long)1000*3600; //for testing, to start at other point than 0, 1000 * 10727
}
|