# battery.c File Reference

## Detailed Description

Functions related to battery control and data acquisition.

Contains functions for enabling/disabling batteries, and looking up their status and specifications using the ADC.

Application note:
  AVR458: Charging Li-Ion Batteries with BC100
  AVR463: Charging NiMH Batteries with BC100

Documentation
  For comprehensive code documentation, supported compilers, compiler settings and supported devices see readme.html

Author:
  Atmel Corporation: http://www.atmel.com
  Support email: avr@atmel.com

$Name$

Revision
  4254

$RCSfile$

URL
  http://revisor.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/trunk/code/IAR/battery.c

Date
  2008-07-25 12:32:45 +0200 (fr, 25 jul 2008)

Definition in file battery.c.

`#include <ioavr.h>`
`#include <inavr.h>`
`#include "structs.h"`
`#include "enums.h"`
`#include "ADC.h"`
`#include "battery.h"`
`#include "main.h"`
`#include "OWI.h"`
`#include "time.h"`
`#include "LIIONspecs.h"`

Include dependency graph for battery.c:

Go to the source code of this file.

## Functions
unsigned char | BatteryCheck (void)
| Checks if battery has changed.
unsigned char | BatteryDataRefresh (void)
| Refreshes battery data in the EEPROM.
unsigned char | BatteryStatusRefresh (void)
| Refreshes battery status information.
void | DisableBatteries (void)
| Disables both batteries.
void | EnableBattery (unsigned char bat)
| Enables specified battery.
void | NTCLookUp (void)
| Calculates temperature from a lookup table.
unsigned char | RIDLookUp (void)
| Looks up battery data from RID table.
## Variables
unsigned char | BattActive
| Global that indicates current battery (0 = battery A, 1 = B).
__eeprom Battery_t | BattControl [2]
| Holds control data for both batteries.
Batteries_t | BattData
| Holds data for the current battery.
__eeprom unsigned char | BattEEPROM [4][32]
| Storage space for data from the batteries' own EPROMs.
const NTC_Lookup_t | NTC [NTC_TABLE_SIZE]
| NTC lookup-table.
const __eeprom RID_Lookup_t | RID [RID_TABLE_SIZE]
| RID lookup-table.

## Function Documentation

unsigned char BatteryCheck | ( | void |  | ) |

Checks if battery has changed.

Stores current capacity, then attempts to refresh battery status.
If the refresh is successful, old capacity is compared with the new one.

Return values:

  | FALSE | Battery is disconnected, or capacity has changed.
  | TRUE | All OK.

Definition at line 134 of file battery.c.

References BatteryStatusRefresh(), Batteries_struct::Capacity, FALSE, and TRUE.

Referenced by HaltNow().

    00135 {
    00136         unsigned char success = TRUE;
    00137         unsigned int  oldCapacity;
    00138
    00139         // Save to see if battery data has changed.
    00140         oldCapacity = BattData.Capacity;
    00141
    00142         if (!BatteryStatusRefresh()) {
    00143                 success = FALSE;              // Battery not present or RID was invalid.
    00144         }
    00145
    00146         if (oldCapacity != BattData.Capacity) {
    00147                 success = FALSE;              // Battery configuration has changed.
    00148         }
    00149
    00150         return(success);
    00151 }

Here is the call graph for this function:

unsigned char BatteryDataRefresh | ( | void |  | ) |

Refreshes battery data in the EEPROM.

Attempts to read 4 pages of 32 bytes each from the battery's EPROM and store these data in on-chip EEPROM.
If unsuccessful (CRC doesn't check out), the on-chip EEPROM is cleared.

Todo:
  Updating BattData with these data. Specs needed.

Return values:

  | FALSE | Refresh failed.
  | TRUE | Refresh successful.

Definition at line 234 of file battery.c.

References BattEEPROM, Batteries_struct::Circuit, DS2505_DATA_READ, FALSE, OW_DS2505, OWI_ComputeCRC8(), OWI_DetectPresence(), OWI_ReceiveByte(), OWI_ROM_READ, OWI_SendByte(), OWIBUS, and TRUE.

Referenced by BatteryControl().

    00235 {
    00236         unsigned char offset;
    00237         unsigned char i, crc, family, temp, page;
    00238         unsigned char success;
    00239
    00240         // Look for EPROM and read 4 pages of 32 bytes each worth of data, if found.
    00241         for (page = 0; page < 4; page++)        {
    00242                 success = FALSE;
    00243
    00244                 if (OWI_DetectPresence(OWIBUS) == OWIBUS) {
    00245
    00246                         // Presence detected, check type and CRC.
    00247                         OWI_SendByte(OWI_ROM_READ, OWIBUS);
    00248                         family = OWI_ReceiveByte(OWIBUS);
    00249                         crc = OWI_ComputeCRC8(family,0);
    00250
    00251                         for (i = 0; i < 6; i++) {
    00252                                 crc = OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc);
    00253                         }
    00254
    00255                         // CRC ok, device found.
    00256                         if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) {
    00257                                 BattData.Circuit = family;
    00258
    00259                                 // For now, we only read data from DS2505 EPROMs.
    00260                                 if (BattData.Circuit == OW_DS2505) {
    00261                                         offset = page*32;
    00262                                         OWI_SendByte(DS2505_DATA_READ, OWIBUS);  // Command: read data.
    00263                                         OWI_SendByte(offset, OWIBUS);            // Data: low address.
    00264                                         OWI_SendByte(0, OWIBUS);                 // Data: high address.
    00265
    00266                                         // Calculate checksums.
    00267                                         crc = OWI_ComputeCRC8(DS2505_DATA_READ,0);
    00268                                         crc = OWI_ComputeCRC8(offset,crc);
    00269                                         crc = OWI_ComputeCRC8(0,crc);
    00270
    00271                                         // Command received succesfully, now start reading data
    00272                                         // and writing it to EEPROM.
    00273                                         if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) {
    00274                                                 crc = 0;
    00275
    00276                                                 // Fill page with data.
    00277                                                 for (i=0; i<32; i++) {
    00278                                                         temp = OWI_ReceiveByte(OWIBUS);
    00279                                                         crc = OWI_ComputeCRC8(temp, crc);
    00280                                                         BattEEPROM[page][i] = temp;
    00281                                                 }
    00282
    00283                                                 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) {
    00284                                                                 success = TRUE;  // Data read OK
    00285                                                 }
    00286                                         } else { // Not able to start reading data.
    00287                                         }
    00288                                 } else { // Wrong device type.
    00289                                 }
    00290                         } else { // No device found.
    00291                         }
    00292                 } else { // No presence detected on one-wire bus.
    00293                 }
    00294
    00295           // Erase local EEPROM page if there were any errors during transfer.
    00296                 if (!success) {
    00297                         for (i=0; i<32; i++) {
    00298                                 BattEEPROM[page][i] = 0;
    00299                         }
    00300                 }
    00301         }
    00302
    00303         return(success);
    00304 }

Here is the call graph for this function:

unsigned char BatteryStatusRefresh | ( | void |  | ) |

Refreshes battery status information.

Refreshes battery status information, if it is present, based on RID and NTC (read by ADC).
The battery must have been enabled and a complete set of ADC data must have been collected before calling.

Return values:

  | FALSE | No battery present.
  | TRUE | Battery present, status refreshed.

Note:
  If ALLOW_NO_RID is defined, charging will NOT stop if no fitting entry is found in the lookup table. Instead, default battery data will be used.

Todo:
  If ABORT_IF_PWM_MAX is defined this last check battery presence check is redundant since charging will be aborted due to low current at max duty cycle. That is preferrable since the charge current reading is not 100% proof.

Definition at line 167 of file battery.c.

References ADCS, ADC_Status_struct::avgIBAT, BAT_VOLTAGE_LOW, BAT_VOLTAGE_MIN, Batteries_struct::Capacity, Batteries_struct::Charged, Batteries_struct::Circuit, FALSE, Batteries_struct::HasRID, Batteries_struct::Low, Batteries_struct::MaxCurrent, Batteries_struct::MaxTime, Batteries_struct::MinCurrent, NTCLookUp(), OW_NONE, Batteries_struct::Present, RIDLookUp(), Batteries_struct::Temperature, TRUE, and ADC_Status_struct::VBAT.

Referenced by BatteryCheck(), BatteryControl(), Initialize(), and Sleep().

    00168 {
    00169         // Assume the worst..
    00170         unsigned char success = FALSE;
    00171
    00172         BattData.Present = FALSE;
    00173         BattData.Charged = FALSE;
    00174         BattData.Low = TRUE;
    00175         BattData.Circuit = OW_NONE;
    00176         BattData.Temperature = 0;
    00177         BattData.Capacity = 0;
    00178         BattData.MaxCurrent = 0;
    00179         BattData.MaxTime = 0;
    00180         BattData.MinCurrent = 0;
    00181
    00182         NTCLookUp();
    00183         BattData.HasRID = RIDLookUp();
    00184
    00185         // Is the battery voltage above minimum safe cell voltage?
    00186         if (ADCS.VBAT >= BAT_VOLTAGE_MIN) {
    00187                 BattData.Low = FALSE;
    00188         }
    00189
    00190         // Is the battery charged?
    00191         if (ADCS.VBAT >= BAT_VOLTAGE_LOW) {
    00192                 BattData.Charged = TRUE;
    00193         }
    00194
    00195         // If we are not charging, yet VBAT is above safe limit, battery is present.
    00196         // If we are charging and there's a current flowing, the battery is present.
    00197
    00203         if (((OCR1B == 0) && (!BattData.Low)) ||
    00204             ((OCR1B != 0) && (ADCS.avgIBAT > 0))) {
    00205                 BattData.Present = TRUE;
    00206                 success = TRUE;
    00207         } else {
    00208                 BattData.Low = FALSE;  // (This is just a technicality..)
    00209                 success = FALSE;
    00210         }
    00211
    00212 #ifndef ALLOW_NO_RID
    00213         // Return FALSE if no valid RID entry was found, to stop charging.
    00214         if(!BattData.HasRID) {
    00215                 success = FALSE;
    00216         }
    00217 #endif
    00218
    00219         return(success);
    00220 }

Here is the call graph for this function:

void DisableBatteries | ( | void |  | ) |

Disables both batteries.

Clears PB4 and PB5 in PORTB, disabling both batteries.

Definition at line 338 of file battery.c.

Referenced by BatteryControl(), Error(), Initialize(), JumperCheck(), and Sleep().

    00339 {
    00340         // Turn off LEDs and disconnect batteries.
    00341         PORTB &= ~((1<<PB4)|(1<<PB5));
    00342 }

void EnableBattery | ( | unsigned char | bat | ) |

Enables specified battery.

Updates BattActive to specified battery, then sets PB4/PB5 and clears PB5/PB4 in PORTB, depending on which battery is specified.
The function takes 100 ms to allow the port switch to settle.

Parameters:

  | bat | Specifies which battery to enable (0 = battery A, 1 = B)

Definition at line 315 of file battery.c.

References BattActive, Time_Left(), Time_Set(), and TIMER_GEN.

Referenced by BatteryControl(), Initialize(), and Sleep().

    00316 {
    00317         // Use general timer, set timeout to 100ms.
    00318         Time_Set(TIMER_GEN,0,0,100);
    00319
    00320         // Set specified battery as the active one.
    00321         BattActive = bat;
    00322
    00323         // Enable current battery in hardware, light LED & connect battery.
    00324         PORTB |= (1 << (PB4+bat));
    00325
    00326         // Disconnect other battery.
    00327         PORTB &= ~(1<<(PB5-bat));
    00328
    00329         do { // Let port switch settle.
    00330         } while (Time_Left(TIMER_GEN));
    00331 }

Here is the call graph for this function:

void NTCLookUp | ( | void |  | ) |

Calculates temperature from a lookup table.

Looks up the highest NTC value below or equal to the measured one.
With the current lookup table, temperature is calculated with the formula:
4*(index of entry) - 2*(measured NTC - NTC from entry) / (ADCsteps of entry)

Note:
  If the NTC-measurement is saturated (ADC gives a result greater than the first entry in NTC lookup-table), the temperature will be reported as negative.

  If no valid entry is found, the battery temperature is set to NTC_MAX_TEMPERATURE.

Definition at line 398 of file battery.c.

References NTC_Lookup_struct::ADC, ADCS, NTC_Lookup_struct::ADCsteps, Batteries_struct::ADCSteps, FALSE, NTC_MAX_TEMPERATURE, NTC_TABLE_SIZE, ADC_Status_struct::rawNTC, Batteries_struct::Temperature, and TRUE.

Referenced by BatteryStatusRefresh(), HaltNow(), and MaxVoltageAndCurrent().

    00399 {
    00400         unsigned char i;
    00401         unsigned char found = FALSE;
    00402
    00403         // Lookup in the NTC-table. Use the first entry which is equal or below
    00404         // sampled NTC. Calculate temperature by using the index number, and the
    00405         // difference between the measured NTC value and the one in the entry.
    00406         for (i = 0 ; (i < NTC_TABLE_SIZE) && (!found); i++)     {
    00407                 if (ADCS.rawNTC >= NTC[i].ADC) {
    00408                         BattData.Temperature = (i<<2) ;
    00409                         BattData.ADCSteps = NTC[i].ADCsteps;
    00410
    00411          // BattData.Temperature is a signed int, while all the operands in this
    00412          // calculation are unsigned. Casting for compiler safety..
    00413                         BattData.Temperature -= ( ( (signed int)ADCS.rawNTC
    00414                                      - (signed int)NTC[i].ADC ) << 1
    00415                                  ) / (signed int)BattData.ADCSteps;
    00416
    00417                         found = TRUE;  // Could be done with a break, but that violates MISRA.
    00418                 }
    00419         }
    00420
    00421         // For safety, if the battery temperature is greater than the NTC
    00422    // lookup-table has entries for, set it to a defined maximum.
    00423         if (!found) {
    00424                 BattData.Temperature = NTC_MAX_TEMPERATURE;
    00425         }
    00426 }

unsigned char RIDLookUp | ( | void |  | ) |

Looks up battery data from RID table.

Attempts to find data for the battery from the RID lookup-table.
If no valid entry is found, default data (defined in battery.h) are used.

Return values:

  | TRUE | Entry found, battery data updated.
  | FALSE | No entry found, using defaults for battery data.

Definition at line 354 of file battery.c.

References ADCS, RID_Lookup_struct::Capacity, Batteries_struct::Capacity, DEF_BAT_CAPACITY, DEF_BAT_CURRENT_MAX, DEF_BAT_CURRENT_MIN, DEF_BAT_TIME_MAX, FALSE, RID_Lookup_struct::High, RID_Lookup_struct::Icharge, RID_Lookup_struct::ICutOff, RID_Lookup_struct::Low, Batteries_struct::MaxCurrent, Batteries_struct::MaxTime, Batteries_struct::MinCurrent, ADC_Status_struct::rawRID, RID, RID_TABLE_SIZE, RID_Lookup_struct::tCutOff, and TRUE.

Referenced by BatteryStatusRefresh().

    00355 {
    00356         unsigned char i, found = FALSE;
    00357
    00358         // Lookup in the RID-table. If measured RID is within the limits
    00359         // of an entry, those data are used, and TRUE is returned.
    00360         for (i = 0 ; i < RID_TABLE_SIZE; i++) {
    00361                 if (ADCS.rawRID >= RID[i].Low) {
    00362                         if (ADCS.rawRID <= RID[i].High) {
    00363                                 BattData.Capacity = RID[i].Capacity;
    00364                                 BattData.MaxCurrent = RID[i].Icharge;
    00365                                 BattData.MaxTime = RID[i].tCutOff;
    00366                                 BattData.MinCurrent = RID[i].ICutOff;
    00367
    00368                                 found = TRUE;
    00369                         }
    00370                 }
    00371         }
    00372
    00373         // If no valid entry is found, use defaults and return FALSE.
    00374         if (!found) {
    00375                 BattData.Capacity = DEF_BAT_CAPACITY;
    00376                 BattData.MaxCurrent = DEF_BAT_CURRENT_MAX;
    00377                 BattData.MaxTime = DEF_BAT_TIME_MAX;
    00378                 BattData.MinCurrent = DEF_BAT_CURRENT_MIN;
    00379         }
    00380
    00381         return(found);
    00382 }

## Variable Documentation

unsigned char BattActive

Global that indicates current battery (0 = battery A, 1 = B).

Definition at line 75 of file battery.c.

Referenced by Charge(), ConstantCurrent(), ConstantVoltage(), EnableBattery(), Error(), HaltNow(), Initialize(), MaxVoltageAndCurrent(), and USI_OVF_ISR().

__eeprom Battery_t BattControl[2]

Initial value:

     {{TRUE, TRUE, FALSE},
                                         {TRUE, TRUE, FALSE}}

Holds control data for both batteries.

Note:
  Stored in EEPROM.

Definition at line 60 of file battery.c.

Referenced by BatteryControl(), Charge(), ConstantCurrent(), ConstantVoltage(), Error(), HaltNow(), MaxVoltageAndCurrent(), and USI_OVF_ISR().

Batteries_t BattData

Holds data for the current battery.

Definition at line 64 of file battery.c.

Referenced by BatteryControl(), Charge(), Error(), HaltNow(), MaxVoltageAndCurrent(), Sleep(), and USI_OVF_ISR().

__eeprom unsigned char BattEEPROM[4][32]

Storage space for data from the batteries' own EPROMs.

Note:
  Stored in EEPROM.

Definition at line 71 of file battery.c.

Referenced by BatteryDataRefresh(), and Initialize().

const NTC_Lookup_t NTC[NTC_TABLE_SIZE]

Initial value:

     {
            {1002, 23}, {953, 25}, {902, 26}, {849, 27}, {796, 27},
            {742, 27}, {689, 26}, {637, 26}, {587, 25}, {539, 24},
            {494, 22}, {451, 21}, {412, 19}, {375, 18}, {341, 17},
            {310, 15}, {282, 14}, {256, 13}, {233, 11}, {212, 10}
    }

NTC lookup-table.

The first entry is 0 degrees. For every entry after, temperature increases with 4 degrees. With 20 entries, the last one equals (20-1)*4 = 76 degrees.
It must be sorted in descending ADC order.

Note:
  NTCLookUp() must be modified if this table is changed so that:
  - first entry is no longer 0 degrees.
  - temperature difference between entries is no longer 4 degrees.
  - ADCsteps no longer specifies ADC steps per half degree.

Definition at line 104 of file battery.c.

const __eeprom RID_Lookup_t RID[RID_TABLE_SIZE]

Initial value:

     {
      {558, 659, 3900, 550, 260, 300, 10},
      {744, 843, 6800, 750, 360, 300, 14},
      {869, 958, 10000, 1000, 475, 300, 19},
      {1097, 1153, 24000, 2000, 475, 420, 38}
    }

RID lookup-table.

Contains Resistor ID data specified by manufacturer.

Note:
  Values have been calculated assuming a +/- 15% tolerance.

Definition at line 84 of file battery.c.

Referenced by RIDLookUp().