📄 analog.c
字号:
//Divide uWmins by uW and you get minutes.
cap = cap / presentrate;
}
else
{
cap = GetChgUntilFull_mAmins() / rate; // (mAmins / mA) = minutes
}
return (unsigned int) cap;
}
/* =====================================================================================
=====================================================================================
===================================================================================== */
//Local 'helper' functions (not exposed in analog.h)
//! \todo NOTE: the signature/fab.calibration bytes definitions assume Rev *E* silicon ONLY.
//! Earlier revisions will require changes.
#define FAST_RC_CAL (sig_array[0x01])
#define SLOW_RC_LO_CAL (sig_array[0x06])
#define SLOW_RC_HI_CAL (sig_array[0x07])
#define BG_C_CAL (sig_array[0x09])
#define CELL1_LO_CAL (sig_array[0x10])
#define CELL1_HI_CAL (sig_array[0x11])
#define CELL2_LO_CAL (sig_array[0x12])
#define CELL2_HI_CAL (sig_array[0x13])
#define CELL3_LO_CAL (sig_array[0x14])
#define CELL3_HI_CAL (sig_array[0x15])
#define CELL4_LO_CAL (sig_array[0x16])
#define CELL4_HI_CAL (sig_array[0x17])
#define ADC0_LO_CAL (sig_array[0x18]) // currently not used
#define ADC0_HI_CAL (sig_array[0x19]) // currently not used
#define VPTAT_LO_CAL (sig_array[0x1A])
#define VPTAT_HI_CAL (sig_array[0x1B])
// Old defines (for rev.D), not fully compatible with new routines
/*
#define FAST_RC_CAL (sig_array[0x01])
#define SLOW_RC_CAL (sig_array[0x03])
#define BG_C_CAL (sig_array[0x09])
#define BG_R_CAL (sig_array[0x0B])
#define VPTAT_HI_CAL (sig_array[0x0D])
#define VPTAT_LO_CAL (sig_array[0x0F])
#define CELL1_CAL (sig_array[0x11])
#define CELL2_CAL (sig_array[0x13])
#define CELL3_CAL (sig_array[0x15])
#define CELL4_CAL (sig_array[0x17])
*/
void ReadFactoryCalibration(void)
{
unsigned char __flash * ptr = 0;
char i;
char flags = SREG;
char temp;
unsigned char sig_array[0x1C]; //Array with signature/fab.calibration bytes
__disable_interrupt();
for(i=0; i< 0x1C; i++)
{
SPMCSR = (1<<SIGRD) | (1<<SPMEN);
temp = *ptr++;
sig_array[i] = temp;
}
if(flags & 0x80)
__enable_interrupt();
//Now apply the Cal values we just read out.
// SlowRCCal = SLOW_RC_CAL;
SlowRCCal = (SLOW_RC_HI_CAL << 8)|(SLOW_RC_LO_CAL);
FastRCCal = FAST_RC_CAL;
//Calibrate bandgap (fab. or battery factory)
BGCCRCal = BG_C_CAL| 0x80;
if (ReadVrefCalibration()) {
calibration_state &= ~CAL_VREF_MASK;
calibration_state |= CAL_VREF_OK;
} else {
calibration_state &= ~CAL_VREF_MASK;
}
//Save the Cell1-Cell4 gain values
ADCgain[0] = (CELL1_HI_CAL << 8)|(CELL1_LO_CAL);
ADCgain[1] = (CELL2_HI_CAL << 8)|(CELL2_LO_CAL);
ADCgain[2] = (CELL3_HI_CAL << 8)|(CELL3_LO_CAL);
ADCgain[3] = (CELL4_HI_CAL << 8)|(CELL4_LO_CAL);
//On-chip temperature sensor calibration value
VTgain = (VPTAT_HI_CAL<<8) | VPTAT_LO_CAL; //on-chip temp sensor
// Calibration values for CCoffset and CCIoffset?
if (ReadCCOffsetCalibration()) {
calibration_state &= ~CAL_CC_MASK;
calibration_state |= CAL_CC_OK;
} else {
calibration_state &= ~CAL_CC_MASK;
}
}
unsigned char ReadVrefCalibration(void)
{
unsigned char temp;
while(EECR & (1<<EEPE));
EEAR = EESTORAGE_BGCCR;
EECR = (1<<EERE); //read
temp = EEDR;
if (temp != 0xFF) {
BGCCR = temp;
while(EECR & (1<<EEPE));
EEAR = EESTORAGE_BGCRR;
EECR = (1<<EERE); //read
BGCRR = EEDR;
return(1);
} else {
BGCRR = 0x0F;
BGCCR = BGCCRCal; // signature value (with Band gap enabled)
return(0);
}
}
unsigned char ReadCCOffsetCalibration(void)
{
signed char temp;
while(EECR & (1<<EEPE));
EEAR = EESTORAGE_CC_valid;
EECR = (1<<EERE); //read
temp = EEDR;
if (temp != -1) {
do {} while(EECR & (1<<EEPE));
EEAR = EESTORAGE_CCoffset;
EECR = (1<<EERE); //read
temp = EEDR;
CCoffset = (signed int)temp;
do {} while(EECR & (1<<EEPE));
EEAR = EESTORAGE_CCIoffset;
EECR = (1<<EERE); //read
temp=EEDR;
CCIoffset = (signed long)temp;
return(1);
} else {
CCIoffset = 0;
CCoffset = 0;
return(0);
}
}
/* =====================================================================================
=====================================================================================
===================================================================================== */
/* Calibration routines for VREF and CC/CCIoffset
*/
unsigned char CalibrateVREF(void) // calibration of VREF
{
long int V_error; // Variable to keep error after conversion
long int old_V_error; // Value used to keep old error value during linear scan
unsigned char ratio_counter; // Value used to count up the BGCCR value
unsigned char loopcount; // Value used during temperature calibration
volatile unsigned int vui_temp; // Dummy variable used to ensure correct reading of VADC
BGCRR = 0x0f; // Load Factory calibration
BGCCR = BGCCRCal; // Load Factory calibration (with Band gap enabled)
VADMUX = CAL_CHANNEL; // Select terminal input defined in calibration.h
VADCSR = (1 << VADEN); // Enable the VADC
vui_temp = VADC; // Dummy read(s) to ensure proper operation
loopcount = CAL_WAIT; // Wait for error from CellBalancing to cancel
while (loopcount--) {
VADCSR |= (1 << VADSC) | (1 << VADCCIF);// Start a VADC conversion and clear any pending interrupts
do {} while(!(VADCSR & (1 << VADCCIF)));// Wait while conversion in progress
vui_temp = VADC; // Dummy read(s) to ensure proper operation
}
VADCSR |= (1 << VADSC) | (1 << VADCCIF);// Start a VADC conversion and clear any pending interrupts
do {} while(!(VADCSR & (1 << VADCCIF)));// Wait while conversion in progress
V_error = VADC; // Calculate the error of the measured value
V_error = V_error * CAL_GAIN;
V_error = V_error - Vcalibration_value;
loopcount = 8; // Check for all different test limits
while (V_error < vcalibration_level[loopcount]) {
loopcount--;
if (!loopcount) {
break;
}
}
BGCRR = tempcal[loopcount]; // Set BGCRR to correct setting
V_error = vcalibration_level[7]; // Init old_V_errror
ratio_counter = (1 << BGEN) - 1; // Reset ratio counter (keep Band gap enabled), -1 because of increment
do // Repeat until VADC value becomes larger than reference
{
ratio_counter++; // Select next BGCCR value;
BGCCR = ratio_counter; // Set new BGCCR value
old_V_error = V_error; // Calulate the error of the measured value
if(ratio_counter & 0x40) // Ratio_counter bit 6 set means calibration failed
{
BGCRR = 0x0f; // Load Factory calibration
BGCCR = BGCCRCal; // Load Factory calibration (with Band gap enabled)
return 0; // Return with fail flag
}
vui_temp = VADC; // Dummy read to ensure proper operation
VADCSR |= (1 << VADSC) | (1 << VADCCIF);// Start a VADC conversion and clear any pending interrupts
do {} while(!(VADCSR & (1 << VADCCIF)));// Wait while conversion in progress
V_error = VADC; // Calulate the error of the measured value
V_error = V_error * CAL_GAIN;
V_error = V_error - Vcalibration_value;
} while(V_error > 0); // Loop until VADC output is larger than the reference setting
if(old_V_error < (-V_error)) { // Select the best value out of the last two BGCCR values
ratio_counter--; // Value below the reference setting is closest to the reference
}
BGCCR = ratio_counter; // Set the correct BGCCR value
do {} while(EECR & (1<<EEPE));
do {} while(SPMCSR & (1<<SPMEN));
EEAR = EESTORAGE_BGCRR;
EEDR = tempcal[loopcount];
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE); //arm
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE); //go
do {} while(EECR & (1<<EEPE));
EEAR = EESTORAGE_BGCCR;
EEDR = ratio_counter;
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE); //arm
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE); //go
return 1;
}
unsigned char CalibrateCCoffset(void) // calibration of CC offset
{ // assumes 0 current through shunt for minimum 1 second before calibration
unsigned char index = CCindex;
volatile signed long cc_temp; // for dummy reads
index--;
index &= 63;
CCIoffset = CCarray[index];
ChangePowerMode(POWERMODE_ACTIVE,0);
while (CC_delay_acc--) { // check if we need to discard samples
do {} while (!(CADCSRB & (1<<CADACIF)));
cc_temp = CADAC;
CADCSRB = (1<<CADACIE) | (1<<CADICIE) | (1<<CADACIF) | (1<<CADRCIF) | (1<<CADICIF);
}
CCoffset = CADAC;
if ((CCoffset > CCoffset_limit) || (CCIoffset > CCIoffset_limit) ||
(CCoffset < -CCoffset_limit) || (CCIoffset < -CCIoffset_limit)) { // Max offset limits to avoid wrong calibration
CCoffset = 0;
CCIoffset = 0;
return(0);
} else {
do {} while(EECR & (1<<EEPE));
do {} while(SPMCSR & (1<<SPMEN));
EEAR = EESTORAGE_CC_valid;
EEDR = 0x00;
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE); //arm
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE); //go
do {} while(EECR & (1<<EEPE));
EEAR = EESTORAGE_CCIoffset;
EEDR = (unsigned char)CCIoffset;
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE); //arm
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE); //go
do {} while(EECR & (1<<EEPE));
EEAR = EESTORAGE_CCoffset;
EEDR = (unsigned char)CCoffset;
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (0<<EEPE) | (0<<EERE); //arm
EECR = (0<<EEPM1) | (0<<EEPM0) | (0<<EERIE) | (1<<EEMPE) | (1<<EEPE) | (0<<EERE); //go
return(1);
}
}
/* =====================================================================================
=====================================================================================
===================================================================================== */
/* General description of Coulomb Counter usage:
*
* The Coulomb Counter must be running whenever the chip is not
* in deep sleep mode. The interrupt is used to perform software
* accumulation & must also handle analog offset voltage correction
* for the input stage.
*
*/
void CCmode(unsigned char mode)
{
switch (mode)
{
default:
case CC_DISABLED:
CCSR = 0; //switch to the Slow RC Oscillator to save power
CCarray_Init();
CADCSRA = 0;
break;
case CC_ACCUMULATE: //enable both Accumulate and Instantaneous
if(CCSR != ((1<<XOE)|(1<<ACS))) //if the 32KHz xtal isn't already in use, start it up.
{
Timer32KHz = 9;
CCSR = (1<<XOE);
}
BGCCR |= (1<<BGEN); //ensure that the bandgap is enabled
CADCSRB = (1<<CADACIE) | (1<<CADICIE) | (1<<CADACIF) | (1<<CADRCIF) | (1<<CADICIF);
while ( CADCSRA & (1<<CADUB) ); //wait for clock domain sync
CADCSRA = (1<<CADEN) | ACCUM_CONV_TIME; //! \todo See ANALOG.H to choose your interval for CC_ACCUMULATE
CC_delay_acc = 4; //must ignore the first 4 readings!
CC_delay_inst = 4; //must ignore the first 4 readings!
CCarray_Init();
break;
case CC_REGULAR: //enable ONLY Regular mode is enabled
if(CCSR != ((1<<XOE)|(1<<ACS))) //if the 32KHz xtal isn't already in use, start it up.
{
Timer32KHz = 9;
CCSR = (1<<XOE);
}
CCarray_Init();
BGCCR |= (1<<BGEN); //ensure that the bandgap is enabled
CADRDC = -(ACTIVE_CURRENT_THRESHOLD + (CCIoffset>>4));
CADCSRB = (1<<CADRCIE) | (1<<CADACIF) | (1<<CADRCIF) | (1<<CADICIF);
while ( CADCSRA & (1<<CADUB) ); //wait for clock domain sync
CADCSRA = (1<<CADSE) | REG_CONV_TIME; //! \todo See ANALOG.H to choose your interval for CC_REGULAR
break;
}
}
void CCinit(void)
{
CCmode(CC_DISABLED);
}
/* =====================================================================================
=====================================================================================
===================================================================================== */
//Call this at startup to ensure the buffer is cleared.
void CCarray_Init(void)
{
CCvalidsamples = 0; //reset the # of valid samples
CCindex = 0; //reset the insertion index
}
//This inserts a new sample into the circular buffer.
void CCarray_AddSample(signed int newsample)
{
if(CC_delay_inst)
{
CC_delay_inst--;
return;
}
CCarray[CCindex++] = newsample;
CCindex &= 63;
if(CCvalidsamples < 64)
CCvalidsamples++;
}
//This retrieves the most recent sample out of the circular buffer.
signed int Current1Sec(void) //! \todo NOTE: This could produce a bad result within the first 1Sec of operation.
{
unsigned char temp = CCindex;
temp--;
temp &= 63;
return CCarray[temp];
}
//Note: the data source here is INSTANTANEOUS CURRENT readings, not the Accumulator.
// Although it is not as precise as the Accum, it is accurate within 0.5% of full-scale.
signed int CCarray_Average(void) //this will accurately reflect up to 64 seconds of data.
{
signed long avg = 0;
unsigned char ctr = CCvalidsamples; //grab a local copy since CCvalidsamples is modified by an INTERRUPT
unsigned char temp;
signed int * ptr = CCarray; //the same as saying &CCarray[0]
if(0 == ctr)
return 0;
temp = ctr;
while(temp--) //add up ONLY the valid samples!
avg += *ptr++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -