LTC3335 - Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter

Features

  • 680nA Input Quiescent Current (Output in Regulation at No Load)
  • 1.8V to 5.5V Input Operating Range
  • Selectable Output Voltages of 1.8V, 2.5V, 2.8V, 3V, 3.3V, 3.6V, 4.5V, 5V
  • Integrated Coulomb Counter Measures Accumulated Battery Discharge
  • ±5% Battery Discharge Measurement Accuracy
  • Programmable Peak Input Current of 5mA, 10mA, 15mA, 25mA, 50mA, 100mA, 150mA, 250mA
  • Up to 50mA of Output Current
  • Up to 90% Efficiency
  • Programmable Coulomb Counter Prescaler for Wide Range of Battery Sizes
  • Programmable Discharge Alarm Threshold
  • I2C Interface
  • Low Profile (0.75mm) 20-Lead (3mm × 4mm) QFN Package

Typical Application

LTC3335 Typical Application
LTC3335 Typical Application

Description

The LTC®3335 is a high efficiency, low quiescent current (680nA) buck-boost DC/DC converter with an integrated precision coulomb counter which monitors accumulated battery discharge in long life battery powered applications. The buck-boost can operate down to 1.8V on its input and provides eight pin-selectable output voltages with up to 50mA of output current.

The coulomb counter stores the accumulated battery discharge in an internal register accessible via an I2C interface. The LTC3335 features a programmable discharge alarm threshold. When the threshold is reached, an interrupt is generated at the IRQ pin.

To accommodate a wide range of battery types and sizes, the peak input current can be selected from as low as 5mA to as high as 250mA and the full-scale coulomb counter has a programmable range of 32,768:1.

The LTC3335 is available in a 3mm × 4mm QFN-20 package.

Packaging

For complete and up to date package information and drawings, please refer to our packaging page

Part Number Package Code Temp Package
Drawing
RoHS
LTC3335EUDC#PBF 3x4 QFN-20 UDC E 05-08-1742 Yes
LTC3335EUDC#TRPBF 3x4 QFN-20 UDC E 05-08-1742 Yes
LTC3335IUDC#PBF 3x4 QFN-20 UDC I 05-08-1742 Yes
LTC3335IUDC#TRPBF 3x4 QFN-20 UDC I 05-08-1742 Yes


LTC3335 Package Drawing

Order Info

  • Part numbers ending in PBF are lead free. Solder plated terminal finish (SnPb) versions are non-standard and special terms and conditions and pricing applies if available. Please contact LTC marketing for information.
  • Part numbers containing TR or TRM are shipped in tape and reel or 500 unit mini tape and reel, respectively
  • Please refer to our general ordering information or the product datasheet for more details

Package Variations and Pricing

Part Number Package Temp Price
(1-99)
Price
(1k)*
RoHS
LTC3335EUDC#PBF 3x4 QFN-20 E $4.79 $3.35 Yes
LTC3335EUDC#TRPBF 3x4 QFN-20 E $3.41 Yes
LTC3335IUDC#PBF 3x4 QFN-20 I $5.57 $3.90 Yes
LTC3335IUDC#TRPBF 3x4 QFN-20 I $3.96 Yes
Buy NowRequest Samples
* The USA list pricing shown is for BUDGETARY USE ONLY, shown in United States dollars (FOB USA per unit for the stated volume), and is subject to change. International prices may differ due to local duties, taxes, fees and exchange rates. For volume-specific price or delivery quotes, please contact your local Linear Technology sales office or authorized distributor.

Demo Boards

Linear Technology offers many demo boards free of charge to qualified customers. Contact your local sales office or distributor to inquire about a demo board. Certain demo boards are also available for sale via credit card on this website. Demo boards are for evaluation purposes only. It remains the customer’s responsibility to verify proper and reliable operation in the actual end application.

Part Number Description Price Documentation
DC2343A LTC3335 Demo Board | 680nA Iq Buck-Boost with Coulomb Counter, 1.8V ≤ VIN ≤ 5.5V, Vout = 1.8V to 5V @ 15mA $175.00
DC2369A DC2369A Low Power Wireless Current Sense $175.00
Buy Now

Companion Boards

Part Number Description Price Documentation
DC9021B SmartMesh IP Starter Kit $750.00
Buy Now
Click here to view our complete list of demo boards

Applications

  • Long Lifetime Primary Cell Battery Applications
  • Wireless Sensors
  • Remote Monitors
  • Dust Networks® SmartMesh® Applications

Product Notifications

Please login to your MyLinear account for notifications of datasheet updates, new document releases and LTspice model announcements for your favorite products. If you do not have a MyLinear account you may Sign Up Now.

Forgot your password? Click here.
Need help? Email mylinear@linear.com with questions and comments.

Design Tools

Linduino

Linduino is an Arduino compatible platform for developing and distributing firmware libraries and code for SPI and I²C-compatible integrated circuits. The Linduino One board interfaces to more than 300 QuikEval demonstration cards, supporting a variety of product types including analog-to-digital converters (ADCs)digital-to-analog converters (DACs)power monitors, and more. Firmware libraries for individual devices are written in C and designed to be portable to a wide variety of processors and microcontrollers. Each library has a demonstration program that can be uploaded to the Linduino One platform to allow the circuit and software to be quickly and easily verified.

Click here for more information on Linduino

Code

Linduino is Linear Technology's Arduino compatible system for developing and distributing firmware libraries and example code for Linear Technology’s integrated circuits. The code below can be downloaded or copied and pasted into your project. Please visit the Linduino Home Page for demo board, manual and setup information.

This part is Code Supported: There is example code available for this part. The code below may rely on other drivers available in the full library.

Download LTC3335 - DC2343A.ino

/*!
Linear Technology DC934 Demonstration Board.
LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter

@verbatim

This sketch demonstrates the LTC3335 using the DC2343A demo board.  The data read from
the data board is displayed on a serial terminal using 115200 baud, and newline terminations
for data input.

Code will build for configuration specified in LTC3335_Config.h.

 1. The selected output voltage is specified by LTC3335_OUTPUT_VOLTAGE.
 2. The LTC3335 prescaler will be chosen appropriately for the battery capacity specified
    by LTC3335_CAPACITY.
 3. The LTC3335 alarm will be chosen appropriately for the value specified by
    LTC3335_ALARM_CAPACITY.
 4. The coulomb count and battery current measurement will be scaled accordingly to the
    LTC3335 prescaler selected by LTC3335_CAPACITY and the LTC3335_IPEAK_CONFIGURATION,
    setting.
 5. Set LTC3335_USE_CURRENT_MEASUREMENT if you wish to use the LTC3335 battery current measurement.
 6. Set LTC3335_USE_SOFTWARE_CORRECTION if you wish to use correction of the LTC3335 coulomb
    count and battery current measurement.  A value of LTC3335_VBAT_TYP must be specified
    for this sketch as it can not measure the actual battery voltage, and must assume a constant
    value.  Applications reusing this code would improve performance if the actual battery voltage
    was measured and used for the correction functions.  See the DC2343A schematic for a circuit
    which measures the battery voltage with >10nA of average current drawn from the battery.

@endverbatim

To use the Linduino with the DC2343A, the PIC16 on the DC2343A must be disconnected by removing
the DC2343-ASSY1 PCB from JP5:
\image html "../../Part Number/3000/3300/3335/DC2343A/Assy_PCB_Removed.PNG"

A cable must then be constructed to connect the Linduino to the DC2343A as shown:
\image html "../../Part Number/3000/3300/3335/DC2343A/Linduino_Cable.png"

http://www.linear.com/product/LTC3335

http://www.linear.com/product/LTC3335#demoboards

REVISION HISTORY
$Revision: 4641 $
$Date: 2016-01-29 14:38:11 -0800 (Fri, 29 Jan 2016) $

Copyright (c) 2013, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/

/*! @file
    @ingroup LTC3335
*/

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Includes
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

#include <Arduino.h>
#include "Linduino.h"
#include "LT_I2C.h"
#include "LTC3335.h"
#include "printf.h"

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Definitions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// Controls rate at which LTC3335 is polled and rate at which terminal is updated.
#define REFRESH_INTERVAL          1000    //! in ms, the rate at which the LTC3335 is polled and data output to terminal screen.
#define CURRENT_REFRESH_INTERVAL  5000    //! in ms, the period over which the LTC3335 current measurement is averaged.

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Data
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Local Data
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

uint16_t refresh_time_last;               //!< Variable to schedule LTC3335 polling and data output at REFRESH_INTERVAL
uint16_t current_refresh_time_last;       //!< Variable to schedule LTC3335 current measurement averaging at CURRENT_REFRESH_INTERVAL.

uint32_t data_point_counter;              //!< counts the number of datapoints output to terminal screen.
uint32_t discharged_capacity;             //!< in mAs, the discharged capacity calculated from the LTC3335 accumulator and
//!<  quiescent losses (if software correction is enabled).
LTC3335_ALARM_TYPE alarms;                //!< active alarms read from the LTC3335.
#if LTC3335_USE_CURRENT_MEASUREMENT == true
uint16_t current;                         //!< the current measurement from the LTC3335's counter test mode.
#endif // #if LTC3335_USE_CURRENT_MEASUREMENT == true
#if LTC3335_USE_SOFTWARE_CORRECTION == true
uint16_t vbat = LTC3335_VBAT_TYP;         //!< battery voltage, optimally measured with an adc, set to a constant in this sketch
#endif // #if LTC3335_USE_CURRENT_MEASUREMENT == true

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Local Prototypes
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// \cond
void print_separator();                   // Prints line on terminal to separate other text blocks.
void print_config();                      // Prints configuration of LTC3335 set in LTC3335_Config.h.
void print_data_header();                 // Prints header for data displayed in terminal at runtime.
void print_data();                        // Prints data displayed in terminal at runtime.
// \endcond

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Functions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


//! Initialize Linduino
void setup()
{

  Serial.begin(115200);           //! Initialize the serial port to the PC.
  while (!Serial);                //! Wait for serial port to be opened in the case of Leonardo USB Serial.

  //! Wait for LTC3335 to initialize successfully.
  while ((LTC3335_Init() != 0))
  {
    print_error();                //! Show reasons why LTC3335 might not have initialized.
    delay(5000);
  }

  //! Display configuration set in LTC3335_Config.h.
  print_config();
  print_data_header();

  //! Set up timing for tasks in loop.
  data_point_counter = 0;
  refresh_time_last = millis();
  current_refresh_time_last = refresh_time_last;

  return;
}

//! Repeats Linduino Loop
void loop()
{
  uint16_t time_new = millis(); // ! Get new time

  //! Check if it's time to poll LTC3335 and update the terminal.
  if (time_new - refresh_time_last > REFRESH_INTERVAL)
  {
    //! Read the discharged capacity.
#if LTC3335_USE_SOFTWARE_CORRECTION == false
    LTC3335_Get_Discharged_Capacity(&discharged_capacity);
#else
    LTC3335_Get_Discharged_Capacity(&discharged_capacity, vbat);
#endif // LTC3335_USE_SOFTWARE_CORRECTION == false

    //! If current measurement is being used, read it.  If software correction is used, pass the battery voltage
    //! to the function so that the proper correction factor will be used.
#if LTC3335_USE_CURRENT_MEASUREMENT == true
#if LTC3335_USE_SOFTWARE_CORRECTION == false
    LTC3335_Get_Counter_Test_Current(&current);
#else
    LTC3335_Get_Counter_Test_Current(&current, vbat);
#endif // LTC3335_USE_SOFTWARE_CORRECTION == false
#endif // #if LTC3335_USE_CURRENT_MEASUREMENT == true

    //! Only need to read alarms unless nIRQ is active (although not when nIRQ is used for current measurement).
    if ((LTC3335_NIRQ_READ() == 0) || (LTC3335_USE_CURRENT_MEASUREMENT == true))
    {
      LTC3335_Get_Alarms(&alarms);
    }

    //! Update terminal.
    print_data();

    // Schedule next loop.
    refresh_time_last += REFRESH_INTERVAL;
    data_point_counter++;
  }

#if LTC3335_USE_CURRENT_MEASUREMENT == true
  //! If using the current measurement, clear it periodically.  The current measurement will be averaged over time until it is reset.
  if (time_new - current_refresh_time_last > CURRENT_REFRESH_INTERVAL)
  {
    LTC3335_Reset_Counter_Test_Current();
    current_refresh_time_last += CURRENT_REFRESH_INTERVAL;
  }

  //! Update the Counter Test current in the background.  Must be called more often than LTC3335_MIN_CURRENT_TASK_RATE.
  LTC3335_Counter_Test_Current_Task();
#endif // #if LTC3335_USE_CURRENT_MEASUREMENT == true

  //! If any character is entered, send command to clear interrupt.
  if (Serial.available())
  {
    LTC3335_Clear_Int(&alarms);
    Serial.read();    // Clear out character that caused Clear Int command to be sent.
  }

}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Local Functions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// \cond
// Code for displaying operation of sketch on a serial terminal.
// It is not intended for any of the functions below to be useful in a customer application,
// and no attempt was made to optimize it.

//! Constants defined so that other constants don't include unexplained numbers in them.
#define MV_PER_V            1000
#define MA_PER_A            1000
#define UA_PER_MA           1000
#define SEC_PER_HR          3600
#define MS_PER_SEC          1000

//! Macro prints a float to the serial port with the precision selected by the size of the number.
#define PRINT_PICK_DEC(v)   Serial.print(v, v >= 1 ? 3 : 6);

// Prints line on terminal to separate other text blocks.
void print_separator()
{
  Serial.println(F("=========================================================================================="));
}

// Prints message to terminal about reasons why the LTC3335 may have failed to communicate.
void print_error()
{
  Serial.println(F("Initialization of LTC3335 failed."));
  Serial.println(F("Ensure Linduino is connected correctly to DC2343A, "));
  Serial.println(F("DC2343A is connected to VBAT between 1.8V and 5.5V,"));
  Serial.println(F("and that EN jumper is in the ON position."));
  print_separator();
}

// Prints configuration of LTC3335 set in LTC3335_Config.h.
void print_config()
{
  // Describe the application.
  print_separator();
  Serial.println(F("Sample application for LTC3335 Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter."));
  print_separator();

  // Display the parameters set by user in LTC3335_Config.h.
  Serial.print(F("Capacity = "));
  Serial.print((uint32_t)(1L * LTC3335_CAPACITY * SEC_PER_HR));
  Serial.print(F("mAs ("));
  PRINT_PICK_DEC(1.0 * LTC3335_CAPACITY / MA_PER_A);
  Serial.print(F("Ah), IPeak = "));
  Serial.print(LTC3335_IPEAK_MA);
  Serial.print(F("mA, Output Voltage = "));
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
  Serial.print(1.8, 1);
#elif LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
  Serial.print(2.5, 1);
#elif LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
  Serial.print(2.8, 1);
#elif LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
  Serial.print(3.0, 1);
#elif LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
  Serial.print(3.3, 1);
#elif LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
  Serial.print(3.6, 1);
#elif LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
  Serial.print(4.5, 1);
#elif LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
  Serial.print(5.0, 1);
#endif
  Serial.println(F("V."));
  print_separator();

  // Display the prescaler and capacity range resulting from the parameters set by user in LTC3335_Config.h.
#if LTC3335_USE_SOFTWARE_CORRECTION == true
  if (LTC3335_Get_Software_Correction_Factor(LTC3335_VBAT_TYP) != LTC3335_CORRECTION_FACTOR_TYP)
  {
    Serial.println(F("LTC3335_CORRECTION_FACTOR_TYP in LTC3335_Config.h not set to value returned as LTC3335_Get_Software_Correction_Factor(LTC3335_VBAT_TYP)"));
    Serial.print(F("LTC3335_CORRECTION_FACTOR_TYP = "));
    Serial.print(LTC3335_CORRECTION_FACTOR_TYP);
    Serial.print(F(", LTC3335_VBAT_TYP = "));
    Serial.print(LTC3335_VBAT_TYP);
    Serial.println(F("V."));
    Serial.print(F("LTC3335_Get_Software_Correction_Factor(LTC3335_VBAT_TYP) = "));
    Serial.println(LTC3335_Get_Software_Correction_Factor(LTC3335_VBAT_TYP));
  }
  else
#endif // #if LTC3335_USE_SOFTWARE_CORRECTION == true
  {
    Serial.print(F("Prescaler Set to "));
    Serial.print(LTC3335_PRESCALER);
    Serial.print(F(" for a maximum accumulator range of "));
    Serial.print(LTC3335_RANGE(LTC3335_PRESCALER));
    Serial.print(F("mAs ("));
    PRINT_PICK_DEC(1.0 * LTC3335_RANGE(LTC3335_PRESCALER) / (1.0 * MA_PER_A * SEC_PER_HR));
    Serial.print(F("Ah)"));
#if LTC3335_USE_SOFTWARE_CORRECTION == false
    Serial.println(F("."));
    Serial.println(F("LTC3335_USE_SOFTWARE_CORRECTION not enabled"));
#else
    Serial.println(F(","));
    Serial.print(F("assuming an average battery voltage of "));
    Serial.print(1.0 * LTC3335_VBAT_TYP / MV_PER_V);
    Serial.println(F("V,"));
    Serial.print(F("resulting in an average correction of "));
    Serial.print(-100.0 * LTC3335_Get_Software_Correction_Factor(LTC3335_VBAT_TYP) / (1L << 16) );
    Serial.println(F("%."));
#endif // #if LTC3335_USE_SOFTWARE_CORRECTION == false
  }
  print_separator();

  // Display the alarm value selected to be closest by less than that set by user in LTC3335_Config.h.
#if LTC3335_USE_SOFTWARE_CORRECTION == false
  uint8_t alarm_reg = (1LL * LTC3335_ALARM_CAPACITY * SEC_PER_HR)/LTC3335_RESOLUTION(LTC3335_PRESCALER);
  uint32_t alarm_mas = alarm_reg * LTC3335_RESOLUTION(LTC3335_PRESCALER);
#else
  uint8_t alarm_reg = (1LL * LTC3335_ALARM_CAPACITY * SEC_PER_HR)/(LTC3335_RESOLUTION(LTC3335_PRESCALER) * ((1LL << 16) + LTC3335_CORRECTION_FACTOR_TYP) / (1L << 16));
  uint32_t alarm_mas = alarm_reg * LTC3335_RESOLUTION(LTC3335_PRESCALER) * ((1LL << 16) + LTC3335_CORRECTION_FACTOR_TYP) / (1L << 16);
#endif // #if LTC3335_USE_SOFTWARE_CORRECTION == false
  Serial.print(F("Alarm Register Set to "));
  Serial.print(alarm_mas);
  Serial.print(F("mAs ("));
  PRINT_PICK_DEC(1.0 * alarm_mas / (1.0 * MA_PER_A * SEC_PER_HR));
  Serial.println(F("Ah),"));
  Serial.print(F("which is "));
  Serial.print(100.0 * alarm_mas / (1L * LTC3335_CAPACITY * SEC_PER_HR), 2);
  Serial.println(F("% of the battery capacity."));
  print_separator();

#if LTC3335_USE_CURRENT_MEASUREMENT == true
  Serial.println(F("Counter Test mode used to measure battery current with nIRQ pin."));
  print_separator();
#endif // #if LTC3335_USE_CURRENT_MEASUREMENT == false

  Serial.println(F("Send any character to send a Clear Int command to the LTC3335."));
  print_separator();
}

// Prints header for data displayed in terminal at runtime.
void print_data_header()
{
  printf(F("Test Time (s), "));
  printf(F("Discharged Capacity (mAs), "));
#if LTC3335_USE_CURRENT_MEASUREMENT == true
  printf(F("Battery Current (mA), "));
#endif // #if LTC3335_USE_CURRENT_MEASUREMENT == true
  printf(F("Alarm Trip Alarm, "));
  printf(F("Coulomb Counter Overflow Alarm, "));
  printf(F("AC On Time Overflow Alarm, "));
  printf(F("PGOOD, "));
  printf(F("nIRQ\r\n"));
}

// Prints data displayed in terminal at runtime.
void print_data()
{
  printf(F("%13.2f,"), 1.0 * data_point_counter * REFRESH_INTERVAL / MS_PER_SEC);
  printf(F("%26d,"), discharged_capacity);
#if LTC3335_USE_CURRENT_MEASUREMENT == true
  printf(F("%21.3f,"), 1.0 * current / MA_PER_A);
#endif // #if LTC3335_USE_CURRENT_MEASUREMENT == true
  printf(F("%17b,"), alarms.alarm_trip);
  printf(F("%31b,"), alarms.coulomb_counter_overflow);
  printf(F("%26b,"), alarms.ac_on_time_overflow);
  printf(F("%6b,"), LTC3335_PGOOD_READ());
  printf(F("%5b\r\n"), LTC3335_NIRQ_READ());
}
// \endcond

Download LTC3335 - Linduino Header File

/*!
LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter

This header file contains the API to the LTC3335 driver.  A minimal
set of functions were declared to allow access to the features of the
part while abstracting away from the register transactions.

@verbatim
The LTC®3335 is a high efficiency, low quiescent current
(680nA) buck-boost DC/DC converter with an integrated
precision coulomb counter which monitors accumulated
battery discharge in long life battery powered applications.
The buck-boost can operate down to 1.8V on its input and
provides eight pin-selectable output voltages with up to
50mA of output current.

The coulomb counter stores the accumulated battery discharge
in an internal register accessible via an I2C interface.
The LTC3335 features a programmable discharge alarm
threshold. When the threshold is reached, an interrupt is
generated at the IRQ pin.

To accommodate a wide range of battery types and sizes,
the peak input current can be selected from as low as 5mA
to as high as 250mA and the full-scale coulomb counter
has a programmable range of 32,768:1.

@endverbatim

http://www.linear.com/product/LTC3335

http://www.linear.com/product/LTC3335#demoboards

REVISION HISTORY
 $Revision: 4641 $
 $Date: 2016-01-29 14:38:11 -0800 (Fri, 29 Jan 2016) $

Copyright (c) 2014, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/

/*! @file
    @ingroup LTC3335
    API Header File for LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter
*/

#ifndef LTC3335_H
#define LTC3335_H

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Includes
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "LTC3335_Config.h"

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Definitions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// \cond
//! @name General Purpose Macros
//! @{
//! Macros to return the number of bits needed to store a number
#define NBITS2(n)           ((n&2)?1:0)
#define NBITS4(n)           ((n&(0xC))?(2+NBITS2(n>>2)):(NBITS2(n)))
#define NBITS8(n)           ((n&0xF0)?(4+NBITS4(n>>4)):(NBITS4(n)))
#define NBITS16(n)          ((n&0xFF00)?(8+NBITS8(n>>8)):(NBITS8(n)))
#define NBITS32(n)          ((n&0xFFFF0000)?(16+NBITS16(n>>16)):(NBITS16(n)))
#define NBITS(n)            (n==0?0:NBITS32(1L*n)+1)

//! macro for bitmask.
#define MASK(size, shift)   (((1LL << (size)) - 1) << (shift))

//! Constants defined so that other constants don't include unexplained numbers in them.
#define MV_PER_V            1000
#define MA_PER_A            1000
#define UA_PER_MA           1000
#define SEC_PER_HR          3600
#define MS_PER_SEC          1000
//! @}
// \endcond

//! @name LTC3335 Driver Properties
//! @{
#define LTC3335_BAUD_RATE       400             //!< in kHz, Max Clock Operating Frequency (fSCL from datasheet page 5)
#define LTC3335_PRESCALER_MAX   15              //!< the maximum prescaler that be selected for the LTC3335.
#define LTC3335_TFS             (11.74e-6)      //!< in s, full scale ON time from page 15 of datasheet.
#define LTC3335_IQ              (680e-9)        //!< in A, Input Quiescent Current from page 1 of datasheet.
//! @}

//! @name Voltage Settings
//! @{
//! Options available for setting output voltage via I2C.
typedef enum { } LTC3335_OUTPUT_VOLTAGE_TYPE;
#define LTC3335_OUTPUT_VOLTAGE_1_8V 0
#define LTC3335_OUTPUT_VOLTAGE_2_5V 1
#define LTC3335_OUTPUT_VOLTAGE_2_8V 2
#define LTC3335_OUTPUT_VOLTAGE_3_0V 3
#define LTC3335_OUTPUT_VOLTAGE_3_3V 4
#define LTC3335_OUTPUT_VOLTAGE_3_6V 5
#define LTC3335_OUTPUT_VOLTAGE_4_5V 6
#define LTC3335_OUTPUT_VOLTAGE_5_0V 7
#define LTC3335_NUM_OUTPUT_VOLTAGES 8
//! @}

//! @name IPeak Settings
//! @{
//! Options available for IPeak setting.
//! NOTE! This can not be set via I2C.  It can only be set with resistors on pins 13-15
//! of the LTC3335, along with the an appropriately sized inductor.  In order to
//! translate accumulator values to coulombs, and Counter Test results to amps,
//! this setting must be known.
typedef enum { } LTC3335_IPEAK_CONFIGURATION_TYPE;
#define LTC3335_IPEAK_CONFIGURATION_5MA   0
#define LTC3335_IPEAK_CONFIGURATION_10MA  1
#define LTC3335_IPEAK_CONFIGURATION_15MA  2
#define LTC3335_IPEAK_CONFIGURATION_25MA  3
#define LTC3335_IPEAK_CONFIGURATION_50MA  4
#define LTC3335_IPEAK_CONFIGURATION_100MA 5
#define LTC3335_IPEAK_CONFIGURATION_150MA 6
#define LTC3335_IPEAK_CONFIGURATION_250MA 7
#define LTC3335_NUM_IPEAK                 8
//! @}

//! The alarm conditions which cause the LTC3335 to activate the /INT pin.
typedef struct
{
  unsigned ac_on_time_overflow        :1;     //!< AC(ON) time operating fault (tAC > tFS) due to improperly chosen inductor value timing out the AC(ON) measurement.
  unsigned coulomb_counter_overflow   :1;     //!< Coulomb counter operating fault due to an improperly chosen prescalar causing the ripple counter to overflow.
  unsigned alarm_trip                 :1;     //!< Accumulator value has met or exceeded the alarm threshold value.
  unsigned unused                     :5;
} LTC3335_ALARM_TYPE;

//!  counts for iq current to accumulate to 1 mAs
#define  LTC3335_TIMER_COUNTS_PER_IQ_MAS  ((uint32_t)(LTC3335_TIMER_COUNTS_PER_SEC/(LTC3335_IQ * MA_PER_A)))

//! LTC3335_Counter_Test_Current_Task() must be called often more often than this rate for hardware counter to not overflow
#define  LTC3335_MIN_CURRENT_TASK_RATE  ((1LL << LTC3335_COUNTER_SIZE) * 2 * LTC3335_TFS)

// Value of IPEAK in mA, used in calculations of coulomb count and current.
#if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_5MA
#define LTC3335_IPEAK_MA  5                   //!< mA = 5mA, used in calculations of coulomb count and current.
#elif LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_10MA
#define LTC3335_IPEAK_MA  10                  //!< mA = 10mA, used in calculations of coulomb count and current.  
#elif LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_15MA
#define LTC3335_IPEAK_MA  15                  //!< mA = 15mA, used in calculations of coulomb count and current.
#elif LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_25MA
#define LTC3335_IPEAK_MA  25                  //!< mA = 25mA, used in calculations of coulomb count and current.
#elif LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_50MA
#define LTC3335_IPEAK_MA  50                  //!< mA = 50mA, used in calculations of coulomb count and current.
#elif LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_100MA
#define LTC3335_IPEAK_MA  100                 //!< mA = 100mA, used in calculations of coulomb count and current.
#elif LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_150MA
#define LTC3335_IPEAK_MA  150                 //!< mA = 150mA, used in calculations of coulomb count and current.
#elif LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_250MA
#define LTC3335_IPEAK_MA  250                 //!< mA = 250mA, used in calculations of coulomb count and current.
#else
#error Must configure firmware for IPEAK value.
#endif

//! Macro to select the optimal prescaler for the specified battery capacity at compile time.
#define LTC3335_PRESCALER       (LTC3335_PRESCALER_MAX - NBITS( (uint32_t)(1L*LTC3335_CAPACITY*SEC_PER_HR/LTC3335_RANGE(LTC3335_PRESCALER_MAX)) ) )

//! Macro to retrieve the LTC3335 coulomb count range with a given prescaler.
#if LTC3335_USE_SOFTWARE_CORRECTION == true
#define LTC3335_RANGE(p)        ((uint32_t)(255LL * LTC3335_RESOLUTION(p) * ((1LL << 16) + LTC3335_CORRECTION_FACTOR_TYP) / (1L << 16)))
#else
#define LTC3335_RANGE(p)        ((uint32_t)(255LL * LTC3335_RESOLUTION(p)))
#endif

//! Macro to retrieve the LTC3335 coulomb count resolution with a given prescaler.
#define LTC3335_RESOLUTION(p)   ((uint32_t)(LTC3335_IPEAK_MA * LTC3335_TFS * (1LL << (42 - 1 - p)) / 255 + 0.5))

//! Verify that battery capacity isn't so gigantic that it would overflow a 32 bit number.
#if LTC3335_CAPACITY*SEC_PER_HR > ((1LL << 32) - 1)
#error Battery Capacity is larger than 32 bit number.  Change 32bit capacity variables into 64bit.
#endif

//! Verify that capacity resolution isn't so tiny that half bits in units of mAs result in 1% discretization error.
#if LTC3335_CAPACITY*SEC_PER_HR < ((1L << 8) * 100 / 2)
#error Battery Capacity is so small that units of mAs result in more than 1% discretization error.  Change code units to uAs.
#endif

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Data
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Functions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//! Initializes the LTC3335 driver, setting the prescaler, output voltage, and alarm threshold selected in LTC3335_Confg.h
//! @return 0 if the init was successful.
int8_t LTC3335_Init(void);

//! Enables/Disables software control of the LTC3335 output voltage.
//! If software control is enabled, the voltage is set to the specified setting.
//! @return 0 if the LTC3335 communication was successful.
int8_t LTC3335_Set_Voltage(boolean enabled,                      //!< TRUE to enable software control of output voltage, FALSE to disable software control (output voltage set by pins 3-5).
                           LTC3335_OUTPUT_VOLTAGE_TYPE voltage  //!< The output voltage setting if software control is enabled.
                          );

//! Gets the alarms active from the LTC3335.
//! @return 0 if the LTC3335 communication was successful.
int8_t LTC3335_Get_Alarms(LTC3335_ALARM_TYPE *alarms            //!< Bitmap containing the LTC3335 active alarms.
                         );

//! Sends the command to clear the INT condition.
//! NOTE!  Additional registers are rewritten in order for the INT condition to be reset.
//! @return 0 if the LTC3335 communication was successful.
int8_t LTC3335_Clear_Int(LTC3335_ALARM_TYPE *alarms
                        );

//! Enables/Disables the LTC3335 Counter Test feature.
//! @return 0 if the LTC3335 communication was successful.
int8_t LTC3335_Set_Counter_Test(boolean enabled                  //!< TRUE to enable Counter Test feature, FALSE to disable Counter Test feature.
                               );

#if LTC3335_USE_SOFTWARE_CORRECTION == false
//! Gets the discharged capacity from the battery in mAs.
//! @return 0 if the LTC3335 communication was successful.
int8_t LTC3335_Get_Discharged_Capacity(uint32_t *discharged_capacity    //!< Pointer to where discharged capacity will be returned.
                                      );
#else
//! Gets the discharged capacity from the battery in mAs.
//! @return 0 if the LTC3335 communication was successful.
int8_t LTC3335_Get_Discharged_Capacity(uint32_t *discharged_capacity,   //!< Pointer to where discharged capacity will be returned.
                                       uint16_t vbat                    //!< Battery voltage used to select software correction factor.
                                      );
#endif // LTC3335_USE_SOFTWARE_CORRECTION == false

#if LTC3335_USE_CURRENT_MEASUREMENT == true
#if LTC3335_USE_SOFTWARE_CORRECTION == false
//! Gets the battery current in uA.
//! @return 0 if the LTC3335 communication was successful.
int8_t LTC3335_Get_Counter_Test_Current(uint16_t *microamps             //!< Pointer to where current will be returned.
                                       );
#else
//! Gets the battery current in uA.
//! @return 0 if the LTC3335 communication was successful.
int8_t LTC3335_Get_Counter_Test_Current(uint16_t *microamps,            //!< Pointer to where current will be returned.
                                        uint16_t vbat                   //!< Battery voltage used to select software correction factor.
                                       );
#endif // LTC3335_USE_SOFTWARE_CORRECTION == false

//! Resets the number of edges and the amount of time stored for the Counter Test feature.
//! @return TRUE if the LTC3335 communication was successful.
int8_t LTC3335_Reset_Counter_Test_Current(void);

//! Task that must be run periodically, for the edges and time to be stored for the
//! LTC3335 Counter Test feature.
//! @return TRUE if the LTC3335 communication was successful.
void LTC3335_Counter_Test_Current_Task(void);
#endif // LTC3335_USE_CURRENT_MEASUREMENT == true

#if LTC3335_USE_SOFTWARE_CORRECTION == true
//! Returns the software correction factor for a specified LTC3335_IPEAK_CONFIGURATION, LTC3335_OUTPUT_VOLTAGE, and battery voltage.
//! Note! - These corrections factors are only valid at room temperature and for the recommended Coilcraft LPS5030-xxxMRB inductor.
//! @return TRUE if the LTC3335 communication was successful.
int16_t LTC3335_Get_Software_Correction_Factor(uint16_t vbat            //!< Battery voltage used to select software correction factor.
                                              );
#endif // LTC3335_USE_SOFTWARE_CORRECTION == true

#endif  // LTC3335_H

Download LTC3335 - Linduino.CPP File

/*!
LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter

This driver file defines a minimal set of functions to allow access to
the features of the LTC3335 part while abstracting away from the register
transactions.  Configuration of this driver is done by modifying the
definitions in LTC3335_Config.h.

@verbatim

The LTC®3335 is a high efficiency, low quiescent current
(680nA) buck-boost DC/DC converter with an integrated
precision coulomb counter which monitors accumulated
battery discharge in long life battery powered applications.
The buck-boost can operate down to 1.8V on its input and
provides eight pin-selectable output voltages with up to
50mA of output current.

The coulomb counter stores the accumulated battery discharge
in an internal register accessible via an I2C interface.
The LTC3335 features a programmable discharge alarm
threshold. When the threshold is reached, an interrupt is
generated at the IRQ pin.

To accommodate a wide range of battery types and sizes,
the peak input current can be selected from as low as 5mA
to as high as 250mA and the full-scale coulomb counter
has a programmable range of 32,768:1.

@endverbatim

http://www.linear.com/product/LTC3335

http://www.linear.com/product/LTC3335#demoboards

REVISION HISTORY
$Revision: 5074 $
$Date: 2016-05-09 16:57:13 -0700 (Mon, 09 May 2016) $

Copyright (c) 2013, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/
//! @defgroup LTC3335 LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter

/*! @file
    @ingroup LTC3335
    Driver File for LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter
*/

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Includes
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "LTC3335.h"

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Definitions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// \cond
//! @name I2C Address Definitions
//! @{
//! I2C address and format from datasheet page 5
#define LTC3335_BASE_ADDRESS    0x64 //!< BASE_ADDRESS for LTC3335.
#define LTC3335_WRITE_BIT       0    //!< I2C R/W bit value for WRITE.
#define LTC3335_READ_BIT        1    //!< I2C R/W bit value for READ.
//! @}

//! @name LTC3335 Register Definitions
//! @{
//! Register Map from datasheet table 3
#define LTC3335_REGISTER_A      01 //!< VOUT selection and prescaler selection register.
#define LTC3335_REGISTER_B      02 //!< Alarm threshold register.
#define LTC3335_REGISTER_C      03 //!< Accumulator register.
#define LTC3335_REGISTER_D      04 //!< Alarms register.
#define LTC3335_REGISTER_E      05 //!< Status register.
#define LTC3335_INVALID         0xFF //!< code to indicate that cached data has not be set yet.
//! @}
// \endcond

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Data
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Local Data
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//! @name Cached LTC3335 Data
//! @{
//! Cached copies of values in registers, so that they do not need to be read/modified/written each time a function is called to only set a portion of that register.
static uint8_t ltc3335_subaddress_last;                                //!<  last subaddress written, so that it is not repeatedly sent when the same register is polled.
static LTC3335_OUTPUT_VOLTAGE_TYPE ltc3335_voltage_selection_last;     //!<  last voltage selected through software.
static boolean ltc3335_voltage_selection_enabled_last;                 //!<  last enable for software selected voltage.
static uint8_t ltc3335_prescaler_last;                                 //!<  last prescaler selected.
static boolean ltc3335_counter_test_last;                              //!<  value of the counter test bit last written to the LTC3335.
//! @}

//! @name Counter Test Variables
//! Variables used to count edges per second when the Counter Test feature is turned on, providing an instantaneous measurement of the battery current.
#if LTC3335_USE_CURRENT_MEASUREMENT == true
static uint16_t ltc3335_hw_timer_last;                                 //!<  last value of the hardware timer accessed by LTC3335 driver.
static uint16_t ltc3335_hw_counter_last;                               //!<  last value of the hardware counter accessed by LTC3335 driver.
static uint32_t ltc3335_counter_test_edge_count;                       //!<  the number of rising edges on the /IRQ pin since the Counter Test results were last cleared.
static uint32_t ltc3335_counter_test_time;                             //!<  the amount of timer ticks since the Counter Test results were last cleared.
#endif // #if LTC3335_USE_CURRENT_MEASUREMENT == true
//! @}

//! @name
//!
#if LTC3335_USE_SOFTWARE_CORRECTION == true
static uint8_t ltc3335_accumulator_last;                                //!<
static uint32_t ltc3335_quiescent_current_timer;                        //!<
static uint32_t ltc3335_discharged_capacity;                            //!<
#endif // #if LTC3335_USE_SOFTWARE_CORRECTION == true
//! @}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Local Prototypes
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

static int8_t ltc3335_set_register(uint8_t subaddress, uint8_t *ltc3335_data);
static int8_t ltc3335_get_register(uint8_t subaddress, uint8_t *ltc3335_data);
static uint8_t ltc3335_encode_register_a(boolean enabled, LTC3335_OUTPUT_VOLTAGE_TYPE voltage, uint8_t prescaler);
static void ltc3335_decode_register_a(uint8_t register_a);

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Functions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// Initializes the LTC3335 driver.
int8_t LTC3335_Init(void)
{
  int8_t result;
  uint8_t ltc3335_data;

  // Init all of the microprocessor hardware used by the LTC3335 driver.
  LTC3335_MICRO_INIT();

  // Init to INVALID, so that subaddress will be sent for first right.  After this, subaddress will only be written if needed.
  ltc3335_subaddress_last = LTC3335_INVALID;

  // Send command to set the voltage and prescaler set in LTC3335_Config.h with one i2c transaction.
  ltc3335_data = ltc3335_encode_register_a(true, (LTC3335_OUTPUT_VOLTAGE_TYPE) LTC3335_OUTPUT_VOLTAGE, LTC3335_PRESCALER);
  result = ltc3335_set_register(LTC3335_REGISTER_A, &ltc3335_data);

  // Set cached values in case voltage or prescaler are changed during runtime.
  ltc3335_voltage_selection_last = (LTC3335_OUTPUT_VOLTAGE_TYPE) LTC3335_OUTPUT_VOLTAGE;
  ltc3335_prescaler_last = LTC3335_PRESCALER;
  ltc3335_voltage_selection_enabled_last = true;

  // Set the alarm threshold.  Round down so that set value is always <= to the desired value.
#if LTC3335_USE_SOFTWARE_CORRECTION == false
  ltc3335_data = (1LL * LTC3335_ALARM_CAPACITY * SEC_PER_HR)/LTC3335_RESOLUTION(LTC3335_PRESCALER);
#else
  ltc3335_data = (1LL * LTC3335_ALARM_CAPACITY * SEC_PER_HR)/(LTC3335_RESOLUTION(LTC3335_PRESCALER) * ((1LL << 16) + LTC3335_CORRECTION_FACTOR_TYP) / (1L << 16));
#endif // #if LTC3335_USE_SOFTWARE_CORRECTION == false
  result |= ltc3335_set_register(LTC3335_REGISTER_B, &ltc3335_data);

  // Turn counter test on or off given setting in in LTC3335_Config.h.
  result |= LTC3335_Set_Counter_Test(LTC3335_USE_CURRENT_MEASUREMENT);

#if LTC3335_USE_SOFTWARE_CORRECTION == true
  // Initialize the corrected discharged capacity and timer for quiescent current accumulation..
  ltc3335_discharged_capacity = 0;
  ltc3335_accumulator_last = 0;
  ltc3335_quiescent_current_timer = LTC3335_TIMER_GET();
  result |= LTC3335_Get_Discharged_Capacity(&ltc3335_discharged_capacity, LTC3335_VBAT_TYP);
#endif // #if LTC3335_USE_SOFTWARE_CORRECTION == true

  return result;
}

// Enables/Disables software control of the LTC3335 output voltage.
// If software control is enabled, the voltage is set to the specified setting.
int8_t LTC3335_Set_Voltage(boolean enabled, LTC3335_OUTPUT_VOLTAGE_TYPE voltage)
{
  int8_t result;
  uint8_t ltc3335_data;

  // Can not set out of range.
  if (LTC3335_NUM_OUTPUT_VOLTAGES <= voltage)
  {
    return 1;
  }

  // Send command to set the voltage.
  ltc3335_data = ltc3335_encode_register_a(enabled, voltage, ltc3335_prescaler_last);
  result = ltc3335_set_register(LTC3335_REGISTER_A, &ltc3335_data);

  return result;
}

// Gets the alarms active from the LTC3335.
int8_t LTC3335_Get_Alarms(LTC3335_ALARM_TYPE *alarms)
{
  int8_t result;
  uint8_t ltc3335_data;

  result = ltc3335_get_register(LTC3335_REGISTER_D, &ltc3335_data);

  if (result == 0)
  {
    // Decode the register into its alarm bits.
    if (ltc3335_data & MASK(1, 0))
    {
      alarms->ac_on_time_overflow = 1;
    }
    else
    {
      alarms->ac_on_time_overflow = 0;
    }

    if (ltc3335_data & MASK(1, 1))
    {
      alarms->coulomb_counter_overflow = 1;
    }
    else
    {
      alarms->coulomb_counter_overflow = 0;
    }

    if (ltc3335_data & MASK(1, 2))
    {
      alarms->alarm_trip = 1;
    }
    else
    {
      alarms->alarm_trip = 0;
    }
  }

  return result;
}

// Sends the command to clear the INT condition.
// NOTE!  Additional registers are rewritten in order for the INT condition to be reset.
int8_t LTC3335_Clear_Int(LTC3335_ALARM_TYPE *alarms)
{
  int8_t result = 0;
  uint8_t ltc3335_data;

  // Write to other registers required depending upon the specific type of alarm
  if (alarms->coulomb_counter_overflow)
  {
    // The accumulator must be rewritten in order for the clear int command to clear these alarms.
    result |= ltc3335_get_register(LTC3335_REGISTER_C, &ltc3335_data);
    if (result == 0)  result |= ltc3335_set_register(LTC3335_REGISTER_C, &ltc3335_data);
  }

  if (alarms->alarm_trip)
  {
    // Note that if the accumulator is >= the alarm value, the alarm_trip bit will immediately trip again.
  }

  if (alarms->ac_on_time_overflow)
  {
    //  Note AC ON Time Alarm can not be cleared until PK[2:0] (Pin 15, 14, 13) are changed to match inductor value.
  }

  // If currently doing a Counter Test, do not turn it off when clearing the int.
  ltc3335_data = 1;
  if (ltc3335_counter_test_last == true)
  {
    ltc3335_data |= 2;
  }

  result |= ltc3335_set_register(LTC3335_REGISTER_E, &ltc3335_data);
  ltc3335_data++;

  return result;
}

#if LTC3335_USE_SOFTWARE_CORRECTION == false
// Reads the accumulator and translates into discharged capacity.
int8_t LTC3335_Get_Discharged_Capacity(uint32_t *discharged_capacity)
{
  int8_t result = true;
  uint8_t ltc3335_data;

  result = ltc3335_get_register(LTC3335_REGISTER_C, &ltc3335_data);

  if (result == 0)
  {
    *discharged_capacity = ltc3335_data * LTC3335_RESOLUTION(LTC3335_PRESCALER);
  }

  return result;
}
#else
// Tracks changes in the accumulator and translates changes in discharged capacity, accounting
// for the resolution available at the current battery voltage, output voltage, and ipeak.
// The quiescent current is accumulated over time and used to update the discharged capacity.
int8_t LTC3335_Get_Discharged_Capacity(uint32_t *discharged_capacity, uint16_t vbat)
{
  int8_t result;
  uint8_t ltc3335_data;

  result = ltc3335_get_register(LTC3335_REGISTER_C, &ltc3335_data);

  if (result == 0)
  {
    if (ltc3335_data != ltc3335_accumulator_last)
    {
      // Add in changes in the accumulator, adjusted by the software correction factor.
      int16_t temp16 = LTC3335_Get_Software_Correction_Factor(vbat);
      uint32_t mAs = (uint8_t)(ltc3335_data - ltc3335_accumulator_last) * LTC3335_RESOLUTION(LTC3335_PRESCALER);
      mAs += ((mAs * temp16 + (1L << 15)) >> 16) | (temp16 < 0 ? 0xFFFF0000LL : 0);
      ltc3335_discharged_capacity += mAs;
      ltc3335_accumulator_last = ltc3335_data;
    }
  }

  // Look for enough time to pass to increment discharged capacity by 1mAs.
  if (LTC3335_TIMER_GET() - ltc3335_quiescent_current_timer > LTC3335_TIMER_COUNTS_PER_IQ_MAS)
  {
    ltc3335_discharged_capacity++;
    ltc3335_quiescent_current_timer += LTC3335_TIMER_COUNTS_PER_IQ_MAS;
  }

  *discharged_capacity = ltc3335_discharged_capacity;

  return result;

}
#endif // LTC3335_USE_SOFTWARE_CORRECTION == false

// Enables/Disables the LTC3335 Counter Test feature.  This can be used to verify the
// LTC3335 is functional, or it can be used to measure the battery current.
int8_t LTC3335_Set_Counter_Test(boolean enabled)
{
  int8_t result;
  uint8_t ltc3335_data;

  // Send command to start the test.
  ltc3335_data = ((enabled == true) ? MASK(1, 1) : 0);
  result = ltc3335_set_register(LTC3335_REGISTER_E, &ltc3335_data);

  // Store results of the test so that we don't need to poll the IC for that info.
  if (result == 0)
  {
    ltc3335_counter_test_last = enabled;
  }

#if LTC3335_USE_CURRENT_MEASUREMENT == true
  // Initialize after the command is sent, as the first edge that occurs
  // when the test is started should not be counted.
  if (enabled == true)
  {
    // Take initial readings when test is started.
    LTC3335_Counter_Test_Current_Task();
  }
  else
  {
    // Reset test results when test is stopped.
    LTC3335_Reset_Counter_Test_Current();
  }
#endif

  return result;
}


#if LTC3335_USE_CURRENT_MEASUREMENT == true
// Resets the number of edges and the amount of time stored for the Counter Test feature.
int8_t LTC3335_Reset_Counter_Test_Current(void)
{
  ltc3335_counter_test_edge_count = 0;
  ltc3335_counter_test_time = 0;
  ltc3335_hw_timer_last = LTC3335_TIMER_GET();
  ltc3335_hw_counter_last = LTC3335_COUNTER_GET();

  return 0;
}

// Accumulates the number of edges on the /IRQ pins provided by the LTC3335 Counter Test feature over a period of time,
// the ratio of which can be used to calculate battery current.
// Task that must be run periodically at a rate faster than LTC3335_MIN_CURRENT_TASK_RATE.
void LTC3335_Counter_Test_Current_Task(void)
{
  if (ltc3335_counter_test_last == true)
  {
    // Get new timer and counter values
    uint16_t hw_timer_new = LTC3335_TIMER_GET();
    uint16_t hw_counter_new = LTC3335_COUNTER_GET();

    // Add difference between last timer and counter to summations.
    ltc3335_counter_test_edge_count += (hw_counter_new - ltc3335_hw_counter_last);
    ltc3335_counter_test_time += (hw_timer_new - ltc3335_hw_timer_last);

    // Save new timer and counter values for next execution of task.
    ltc3335_hw_timer_last = hw_timer_new;
    ltc3335_hw_counter_last = hw_counter_new;
  }

  return;
}

#if LTC3335_USE_SOFTWARE_CORRECTION == false
// Calculates the battery current from the number of edges on the /IRQ pins over a period of time accumulated in LTC3335_Counter_Test_Current_Task.
int8_t LTC3335_Get_Counter_Test_Current(uint16_t *microamps)
{
  if ((ltc3335_counter_test_last == true) && ((ltc3335_counter_test_time != 0)))
  {
    if (ltc3335_counter_test_edge_count != 0)
    {
      uint64_t uAs = (uint64_t)(1LL * LTC3335_IPEAK_MA * UA_PER_MA * LTC3335_TFS * LTC3335_TIMER_COUNTS_PER_SEC) * ltc3335_counter_test_edge_count;
      uAs += ltc3335_counter_test_time/2;
      uAs /= ltc3335_counter_test_time;
      if (uAs >= (1L << 16))
      {
        *microamps = (1L << 16) - 1;
      }
      else
      {
        *microamps = (uint16_t) uAs;
      }
    }
    else
    {
      *microamps = 0;
    }
    return 0;
  }
  else
  {
    return 1;
  }
}
#else
// Calculates the battery current from the number of edges on the /IRQ pins over a period of time accumulated in,
// LTC3335_Counter_Test_Current_Task accounting for the resolution available at the current battery voltage, output voltage, and ipeak.
int8_t LTC3335_Get_Counter_Test_Current(uint16_t *microamps, uint16_t vbat)
{

  if ((ltc3335_counter_test_last == true) && ((ltc3335_counter_test_time != 0)))
  {
    if (ltc3335_counter_test_edge_count != 0)
    {
      int16_t temp16 = LTC3335_Get_Software_Correction_Factor(vbat);
      uint64_t uAs = (uint64_t)(1LL * LTC3335_IPEAK_MA * UA_PER_MA * LTC3335_TFS * LTC3335_TIMER_COUNTS_PER_SEC) * ltc3335_counter_test_edge_count;
      uAs += ((uAs * temp16 + (1L << 15)) >> 16) | (temp16 < 0 ? 0xFFFF000000000000LL : 0);
      uAs += ltc3335_counter_test_time / 2;
      uAs /= ltc3335_counter_test_time;
      if (uAs >= (1L << 16))
      {
        *microamps = (1L << 16) - 1;
      }
      else
      {
        *microamps = (uint16_t) uAs;
      }
    }
    else
    {
      *microamps = 0;
    }
    return 0;
  }
  else
  {
    return 1;
  }
}
#endif // #if LTC3335_USE_SOFTWARE_CORRECTION == false
#endif // #if LTC3335_USE_CURRENT_MEASUREMENT == true

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Local Functions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// Writes to an LTC3335 register.
static int8_t ltc3335_set_register(uint8_t subaddress, uint8_t *ltc3335_data_ptr)
{
  int8_t result = 0;
  result |= i2c_write_byte_data(LTC3335_BASE_ADDRESS, subaddress, *ltc3335_data_ptr);
  return result;
}

// Reads from a LTC3335 register.
static int8_t ltc3335_get_register(uint8_t subaddress, uint8_t *ltc3335_data_ptr)
{
  int8_t result = 0;
  if (subaddress != ltc3335_subaddress_last)
  {
    result |= i2c_write_byte(LTC3335_BASE_ADDRESS, subaddress);
  }

  result |= i2c_read_byte(LTC3335_BASE_ADDRESS, ltc3335_data_ptr);
  return result;
}

// Encodes elements of register A.
static uint8_t ltc3335_encode_register_a(boolean enabled, LTC3335_OUTPUT_VOLTAGE_TYPE voltage, uint8_t prescaler)
{
  return ((enabled == true) ? (1 << 7) : 0) | (voltage << 4) | prescaler;
}

// Decodes elements of register A.
static void ltc3335_decode_register_a(uint8_t register_a)
{
  ltc3335_voltage_selection_enabled_last = ((register_a & MASK(1, 7)) == MASK(1, 7));
  ltc3335_voltage_selection_last = (LTC3335_OUTPUT_VOLTAGE_TYPE) ((register_a & MASK(3, 4)) >> 4);
  ltc3335_prescaler_last = register_a & MASK(4, 0);
  return;
}

Download LTC3335_Config.h

/*!
LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter

This header file contains the definitions that allow configuration
of the LTC3335 driver.  The definitions belong to two groups:

  1. The first set of definitions configure the driver for the
     IPEAK, VOUT, and battery capacity for the application.  Advanced
     features such as a battery current measurement and software correction
     can also be enabled.

  2. The LTC3335 driver was written so that no hardware references are made
     in the .cpp file.  Instead, this file records what links to hardware
     functions must be defined for the LTC3335 driver to operate.  Change
     these definitions to configure the LTC3335.c driver for a microprocessor
     other than the Linduino.

@verbatim
The LTC®3335 is a high efficiency, low quiescent current
(680nA) buck-boost DC/DC converter with an integrated
precision coulomb counter which monitors accumulated
battery discharge in long life battery powered applications.
The buck-boost can operate down to 1.8V on its input and
provides eight pin-selectable output voltages with up to
50mA of output current.

The coulomb counter stores the accumulated battery discharge
in an internal register accessible via an I2C interface.
The LTC3335 features a programmable discharge alarm
threshold. When the threshold is reached, an interrupt is
generated at the IRQ pin.

To accommodate a wide range of battery types and sizes,
the peak input current can be selected from as low as 5mA
to as high as 250mA and the full-scale coulomb counter
has a programmable range of 32,768:1.

@endverbatim

http://www.linear.com/product/LTC3335

http://www.linear.com/product/LTC3335#demoboards

REVISION HISTORY
 $Revision: 4641 $
 $Date: 2016-01-29 14:38:11 -0800 (Fri, 29 Jan 2016) $

Copyright (c) 2014, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/

/*! @file
    @ingroup LTC3335
    Configuration Header File for LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter
*/

#ifndef LTC3335_CONFIG_H
#define LTC3335_CONFIG_H

#include <Arduino.h>                  // provides boolean type.
#include "Linduino.h"                 // provides common macros.
#include "LT_I2C.h"                   // provides interface to i2c.

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Configuration definitions for the LTC3335.c driver.
// Define this to specify the LTC3335 configuration, battery characteristics, and advanced features to be used.
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#define LTC3335_IPEAK_CONFIGURATION       LTC3335_IPEAK_CONFIGURATION_100MA //!< IPEAK setting from LTC3335_IPEAK_CONFIGURATION_TYPE in LTC3335.h
#define LTC3335_OUTPUT_VOLTAGE            LTC3335_OUTPUT_VOLTAGE_3_3V       //!< VOUT setting from LTC3335_NUM_OUTPUT_VOLTAGES in LTC3335.h
#define LTC3335_CAPACITY                  (2400)                            //!< in mAh, capacity of the battery
#define LTC3335_ALARM_CAPACITY            0.9*LTC3335_CAPACITY              //!< in mAh, the capacity at which the alarm should be activated.

#define LTC3335_USE_CURRENT_MEASUREMENT   true                              //!< Set to true to use the /IRQ pin to measure the battery current real time.

#define LTC3335_USE_SOFTWARE_CORRECTION   false                             //!< Set to true to use software correction of coulomb count and current measurement.
#define LTC3335_VBAT_TYP                  3600                              //!< in mV, the nominal battery voltage expected for the majority of the battery discharge.
#define LTC3335_CORRECTION_FACTOR_TYP     -487                              //!< Value of LTC3335_Software_Correction_Table[VBAT_TO_TABLE_INDEX(LTC3335_VBAT_TYP)].
//!< Arduino compiler is not smart enough to lookup the value in the const table when
//!< optimizing and makes a lot of runtime code if you don't #define the value manually.

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Hardware definitions for the LTC3335.c driver.
// Change these definitions to configure the LTC3335.c driver for a microprocessor other than the Linduino.
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//! @name Input Read Definitions
//! @{
//! Macros to read LTC3335 Inputs, defined to interface to the Arduino.
#define LTC3335_PGOOD_READ()             digitalRead(2)
#define LTC3335_NIRQ_READ()              digitalRead(5)
//! @}

//! @name I2C Operation Definitions
//! @{
//! Macros to perform basic i2c operations, defined to interface to the Linduino LTC_I2C driver.
//! LTC3335 driver expects functions that return 0 when operation is successful.
//! LTC3335 driver expects to always ACK when reading.
#define LTC3335_I2C_START()               i2c_start()
#define LTC3335_I2C_RESTART()             i2c_repeated_start()
#define LTC3335_I2C_WRITE(data_ptr)       i2c_write(*(data_ptr))
#define LTC3335_I2C_READ(data_ptr)        0; *(data_ptr) = i2c_read(0)
#define LTC3335_I2C_STOP()                0; i2c_stop()
//! @}

//! @name Timing Definitions
//! @{
//! Macro to get timing data from microprocessor, defined to interface to the Arduino function which uses ATMega328P Timer0.
//! The timer resolution is specified in timer counts per sec.
#define LTC3335_TIMER_GET()               micros()
#define LTC3335_TIMER_COUNTS_PER_SEC      1000000
//! @}

//! @name Counter Definitions
//! @{
//! Macro to get hardware counter data from microprocess, defined to interface to function in ATmega_Counter.h which uses ATMega328P Timer1.
//! The number of bits of the hardware timer is specified in number of bits.
#define LTC3335_COUNTER_GET()             TCNT1
#define LTC3335_COUNTER_SIZE              16
//! @}

//! @name Hardware Initialization
//! @{
//! Macro to init micro hardware that is used by LTC3335 driver.
#define LTC3335_MICRO_INIT()              {                                                                                       \
                                            /* Setup GPIO used by LTC3335  */                                                     \
                                            pinMode(2, INPUT);                                                                    \
                                            pinMode(5, INPUT);                                                                    \
                                            /* Setup ATMega counter counter according to Atmel datasheet 8271G, section 16.11. */ \
                                            /* Turn off output compare functions for counter. */                                  \
                                            TCCR1A = 0;                                                                           \
                                            /* Configure to count rising edges on T1 pin. */                                      \
                                            TCCR1B =  (1<<CS10) + (1<<CS11) + (1<<CS12);                                          \
                                            /* Start with counter cleared.*/                                                      \
                                            TCNT1 = 0;                                                                            \
                                            /* Enable I2C module.*/                                                               \
                                            i2c_enable();                                                                         \
                                          }
//! @}

#endif  // LTC3335_CONFIG_H



Download LTC3335_Correction_Tables.cpp

/*!
LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter

Graphs G37 - G44 in the LTC3335 datasheet show the typical error in the
coulomb counter and battery current measurement error for various IPEAK,
VOUT, and battery voltage conditions.  The LTC3335 accuracy is impressive
when configured for high values of IPEAK.  When configured with low values
of IPEAK, however, there can be up to 40% error.

This file contains the typical error for all IPEAK, VOUT, and battery voltage
conditions encoded as a signed 16bit integer.  An array of these errors will
build into the firmware as LTC3335_Software_Correction_Table[] for the IPEAK
and VOUT values specified in LTC3335_Config.h.  The index into this table
will be the battery voltage, which may vary over life of a product using the
LTC3335.

To use these correction factors to adjust the coulomb count and battery current
measurement, multiply the unadjusted value by the correction factor and shift
right by 16.  For example:

  If IPEAK = 10mA (LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_10MA),
  VOUT = 3.3V (LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V), and
  VBAT = 4.5V (vbat = 4500mV), then the LTC3335_Get_Software_Correction_Factor(uint16_t vbat)
  function will return 8826 as the software correction factor.  This value translates to
  8826/65536 = 13.4%, which matches the error shown in G43 of the datasheet.

  If a prescaler of 5 was selected for this example, then one count of the
  accumulator should represent 31638 mAs (0.0088 Ah) of charge.  To adjust for
  the expected error, we should add the fraction returned by the
  LTC3335_Get_Software_Correction_Factor(uint16_t vbat) function to the
  unadjusted coulomb count:

  31638mAs + (31638mAs * 8826)  >> 16 = 35899 mAs.

Note! - These correction factors are only valid at room temperature and for the recommended
Coilcraft LPS5030-xxxMRB inductor listed in the datasheet.  Contact LTC applications if
interested in generating the software correction factors for other tempeature conditions
and inductors.

@verbatim

The LTC®3335 is a high efficiency, low quiescent current
(680nA) buck-boost DC/DC converter with an integrated
precision coulomb counter which monitors accumulated
battery discharge in long life battery powered applications.
The buck-boost can operate down to 1.8V on its input and
provides eight pin-selectable output voltages with up to
50mA of output current.

The coulomb counter stores the accumulated battery discharge
in an internal register accessible via an I2C interface.
The LTC3335 features a programmable discharge alarm
threshold. When the threshold is reached, an interrupt is
generated at the IRQ pin.

To accommodate a wide range of battery types and sizes,
the peak input current can be selected from as low as 5mA
to as high as 250mA and the full-scale coulomb counter
has a programmable range of 32,768:1.

@endverbatim

http://www.linear.com/product/LTC3335

http://www.linear.com/product/LTC3335#demoboards

REVISION HISTORY
$Revision: 4641 $
$Date: 2016-01-29 14:38:11 -0800 (Fri, 29 Jan 2016) $

Copyright (c) 2013, Linear Technology Corp.(LTC)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.

The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community.  Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
*/

/*! @file
    @ingroup LTC3335
    Coulomb Counter and Current Correction Tables for LTC3335: Nanopower Buck-Boost DC/DC with Integrated Coulomb Counter
*/

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Includes
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

#include "LTC3335.h"

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Definitions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#define LTC3335_VBAT_MIN 1800 //! Battery voltage (in mV) corresponding to first index in table.
#define LTC3335_VBAT_STEP 100 //! Battery voltage (in mV) step between each index in table.
#define LTC3335_VBAT_NUM 38   //! Number of battery voltages in table.
#define LTC3335_VBAT_MAX (LTC3335_VBAT_MIN + LTC3335_VBAT_STEP * (LTC3335_VBAT_NUM - 1)) //! Battery voltage (in mV) corresponding to last index in table.
#define LTC3335_VBAT_TO_TABLE_INDEX(vbat) ((uint8_t)((vbat - LTC3335_VBAT_MIN) / LTC3335_VBAT_STEP)) //! Translates a battery voltage to a table index.

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Data
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Local Data
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//! Tables of typical error of LTC3335 at a given battery voltage, output voltage, and iPeak.
//! See Graphs G37 - G44 in LTC3335 datasheet.
#ifdef LTC3335_USE_SOFTWARE_CORRECTION
#if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_5MA
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {10886, 11274, 11652, 12022, 12387, 12748, 13108, 13467, 13826, 14187, 14549, 14915, 15282, 15653, 16027, 16403, 16781, 17162, 17545, 17929, 18314, 18700, 19087, 19473, 19860, 20247, 20634, 21021, 21409, 21798, 22188, 22581, 22979, 23381, 23791, 24210, 24640, 25085};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {9622, 9958, 10287, 10609, 10927, 11241, 11553, 11864, 12176, 12488, 12802, 13119, 13438, 13761, 14087, 14416, 14750, 15087, 15428, 15772, 16120, 16472, 16827, 17185, 17546, 17909, 18276, 18645, 19016, 19390, 19766, 20145, 20527, 20911, 21298, 21690, 22085, 22485};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {9114, 9461, 9794, 10116, 10430, 10737, 11040, 11340, 11638, 11937, 12237, 12540, 12845, 13153, 13465, 13781, 14102, 14427, 14756, 15089, 15427, 15768, 16113, 16461, 16813, 17167, 17524, 17883, 18244, 18608, 18974, 19343, 19714, 20088, 20466, 20848, 21235, 21627};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {8819, 9164, 9494, 9813, 10123, 10426, 10724, 11020, 11313, 11606, 11901, 12197, 12495, 12797, 13103, 13412, 13726, 14044, 14366, 14693, 15023, 15358, 15696, 16038, 16382, 16730, 17081, 17435, 17790, 18149, 18509, 18872, 19238, 19607, 19979, 20355, 20736, 21122};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {8426, 8759, 9080, 9392, 9696, 9994, 10288, 10579, 10868, 11157, 11446, 11736, 12029, 12324, 12622, 12923, 13228, 13537, 13850, 14167, 14488, 14813, 15141, 15473, 15809, 16149, 16491, 16837, 17185, 17537, 17891, 18248, 18607, 18969, 19335, 19703, 20075, 20451};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {8058, 8385, 8701, 9009, 9310, 9606, 9898, 10186, 10473, 10759, 11045, 11331, 11619, 11908, 12200, 12495, 12793, 13094, 13399, 13708, 14020, 14337, 14657, 14982, 15310, 15642, 15977, 16316, 16659, 17004, 17353, 17705, 18059, 18416, 18776, 19138, 19503, 19869};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {6891, 7319, 7709, 8068, 8401, 8713, 9010, 9294, 9569, 9839, 10106, 10372, 10639, 10908, 11181, 11457, 11738, 12024, 12315, 12610, 12910, 13215, 13523, 13835, 14151, 14469, 14789, 15111, 15436, 15763, 16092, 16424, 16760, 17101, 17447, 17802, 18166, 18542};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {6630, 6964, 7289, 7605, 7914, 8216, 8512, 8803, 9090, 9374, 9655, 9933, 10210, 10487, 10763, 11039, 11316, 11595, 11876, 12159, 12445, 12734, 13027, 13323, 13624, 13929, 14239, 14553, 14872, 15197, 15526, 15861, 16200, 16544, 16894, 17247, 17606, 17968};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
#endif // #if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_5MA
#if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_10MA
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {4951, 5152, 5354, 5559, 5766, 5977, 6191, 6410, 6633, 6860, 7092, 7328, 7569, 7815, 8065, 8320, 8580, 8844, 9112, 9384, 9661, 9941, 10225, 10512, 10803, 11097, 11394, 11694, 11997, 12302, 12610, 12921, 13234, 13550, 13869, 14191, 14516, 14844};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {4225, 4386, 4552, 4722, 4897, 5077, 5262, 5451, 5645, 5843, 6046, 6253, 6464, 6679, 6898, 7121, 7348, 7578, 7812, 8050, 8291, 8535, 8783, 9034, 9288, 9547, 9809, 10074, 10344, 10618, 10897, 11180, 11469, 11763, 12064, 12371, 12686, 13008};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {3832, 4025, 4213, 4398, 4580, 4762, 4944, 5127, 5312, 5500, 5691, 5885, 6083, 6285, 6491, 6702, 6917, 7136, 7360, 7588, 7820, 8056, 8295, 8539, 8786, 9037, 9291, 9549, 9810, 10075, 10344, 10617, 10895, 11177, 11466, 11761, 12063, 12373};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {3603, 3812, 4011, 4203, 4389, 4572, 4752, 4932, 5112, 5294, 5478, 5666, 5857, 6052, 6252, 6456, 6664, 6878, 7095, 7318, 7545, 7775, 8010, 8249, 8491, 8737, 8986, 9239, 9495, 9754, 10017, 10284, 10556, 10832, 11114, 11403, 11699, 12004};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {3312, 3533, 3741, 3937, 4126, 4308, 4486, 4662, 4837, 5013, 5191, 5371, 5555, 5742, 5934, 6131, 6332, 6538, 6748, 6964, 7183, 7407, 7634, 7866, 8101, 8339, 8581, 8826, 9074, 9325, 9580, 9839, 10103, 10372, 10646, 10928, 11219, 11519};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {3058, 3283, 3493, 3690, 3879, 4060, 4237, 4411, 4584, 4757, 4932, 5109, 5288, 5471, 5658, 5850, 6046, 6246, 6450, 6659, 6872, 7089, 7310, 7534, 7762, 7993, 8227, 8464, 8705, 8949, 9197, 9449, 9706, 9969, 10238, 10516, 10802, 11100};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {2148, 2424, 2678, 2913, 3132, 3338, 3534, 3723, 3905, 4084, 4261, 4438, 4614, 4792, 4972, 5154, 5340, 5529, 5722, 5918, 6118, 6321, 6529, 6739, 6953, 7171, 7391, 7614, 7841, 8071, 8304, 8540, 8781, 9026, 9276, 9532, 9796, 10068};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {1588, 1914, 2209, 2478, 2725, 2953, 3167, 3369, 3562, 3748, 3930, 4109, 4287, 4465, 4644, 4825, 5008, 5195, 5385, 5578, 5775, 5975, 6179, 6386, 6597, 6811, 7028, 7248, 7472, 7698, 7928, 8162, 8400, 8642, 8891, 9146, 9410, 9683};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
#endif // #if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_10MA
#if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_15MA
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {3046, 3189, 3325, 3457, 3587, 3717, 3850, 3986, 4126, 4272, 4425, 4583, 4749, 4921, 5100, 5286, 5478, 5675, 5878, 6086, 6298, 6514, 6734, 6956, 7182, 7410, 7640, 7873, 8109, 8349, 8592, 8841, 9095, 9358, 9630, 9914, 10211, 10526};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {2510, 2635, 2754, 2869, 2981, 3093, 3207, 3323, 3442, 3567, 3696, 3832, 3973, 4120, 4274, 4434, 4599, 4770, 4946, 5127, 5312, 5502, 5695, 5891, 6091, 6294, 6499, 6707, 6918, 7133, 7352, 7575, 7804, 8039, 8283, 8536, 8802, 9082};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {2346, 2455, 2561, 2666, 2772, 2879, 2988, 3100, 3216, 3337, 3462, 3592, 3728, 3869, 4015, 4167, 4323, 4484, 4651, 4821, 4996, 5174, 5357, 5543, 5732, 5925, 6121, 6321, 6524, 6731, 6942, 7158, 7380, 7608, 7843, 8087, 8340, 8606};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {2187, 2304, 2416, 2525, 2632, 2740, 2849, 2960, 3074, 3192, 3315, 3441, 3573, 3710, 3851, 3998, 4150, 4306, 4467, 4632, 4802, 4976, 5153, 5334, 5518, 5706, 5897, 6091, 6289, 6491, 6698, 6909, 7126, 7349, 7579, 7819, 8068, 8330};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {1888, 2037, 2173, 2299, 2418, 2533, 2645, 2756, 2869, 2983, 3101, 3222, 3348, 3479, 3615, 3756, 3902, 4053, 4208, 4369, 4533, 4702, 4874, 5049, 5228, 5409, 5594, 5782, 5973, 6167, 6366, 6570, 6779, 6996, 7221, 7457, 7705, 7968};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {1567, 1753, 1918, 2065, 2199, 2323, 2441, 2555, 2668, 2780, 2895, 3013, 3135, 3262, 3394, 3531, 3673, 3821, 3973, 4130, 4291, 4456, 4625, 4796, 4970, 5147, 5326, 5508, 5693, 5881, 6072, 6269, 6472, 6684, 6905, 7139, 7388, 7655};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {904, 1094, 1267, 1426, 1576, 1717, 1852, 1983, 2112, 2239, 2366, 2493, 2622, 2752, 2885, 3021, 3159, 3300, 3444, 3590, 3740, 3892, 4046, 4204, 4363, 4526, 4692, 4860, 5032, 5208, 5389, 5576, 5770, 5971, 6182, 6404, 6640, 6892};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {245, 579, 861, 1099, 1302, 1477, 1631, 1769, 1896, 2017, 2133, 2249, 2367, 2487, 2611, 2740, 2874, 3013, 3157, 3306, 3459, 3615, 3774, 3935, 4097, 4261, 4425, 4590, 4757, 4924, 5095, 5270, 5451, 5641, 5844, 6062, 6301, 6565};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
#endif // #if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_15MA
#if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_25MA
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {2264, 2228, 2213, 2216, 2236, 2272, 2321, 2383, 2456, 2539, 2631, 2731, 2838, 2952, 3071, 3196, 3325, 3458, 3596, 3736, 3880, 4027, 4177, 4330, 4486, 4645, 4808, 4973, 5142, 5315, 5491, 5672, 5858, 6049, 6245, 6447, 6656, 6871};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {1958, 1938, 1931, 1936, 1953, 1981, 2018, 2065, 2121, 2185, 2257, 2336, 2421, 2512, 2609, 2711, 2818, 2930, 3046, 3166, 3289, 3416, 3546, 3680, 3817, 3956, 4099, 4245, 4395, 4547, 4703, 4863, 5027, 5195, 5367, 5545, 5728, 5916};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {1648, 1689, 1727, 1765, 1802, 1842, 1885, 1933, 1985, 2043, 2107, 2178, 2255, 2338, 2427, 2523, 2624, 2731, 2843, 2959, 3080, 3204, 3332, 3462, 3595, 3730, 3868, 4007, 4149, 4293, 4440, 4590, 4744, 4903, 5068, 5240, 5421, 5614};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {1498, 1559, 1612, 1660, 1705, 1750, 1795, 1843, 1895, 1951, 2013, 2080, 2154, 2234, 2320, 2413, 2511, 2615, 2724, 2837, 2955, 3077, 3202, 3330, 3460, 3592, 3727, 3863, 4001, 4141, 4284, 4430, 4580, 4735, 4896, 5065, 5243, 5434};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {1359, 1418, 1471, 1519, 1566, 1612, 1659, 1708, 1761, 1817, 1879, 1946, 2018, 2096, 2179, 2268, 2363, 2462, 2567, 2676, 2789, 2905, 3025, 3148, 3274, 3402, 3533, 3665, 3800, 3937, 4077, 4220, 4366, 4517, 4674, 4837, 5008, 5190};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {1267, 1307, 1347, 1388, 1430, 1475, 1524, 1575, 1631, 1691, 1755, 1823, 1897, 1974, 2057, 2144, 2236, 2331, 2432, 2536, 2643, 2755, 2870, 2988, 3109, 3233, 3360, 3490, 3623, 3758, 3897, 4038, 4183, 4332, 4484, 4642, 4804, 4972};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {644, 746, 837, 920, 998, 1071, 1142, 1211, 1280, 1350, 1421, 1494, 1570, 1649, 1731, 1817, 1906, 1998, 2095, 2194, 2297, 2402, 2511, 2622, 2736, 2852, 2971, 3091, 3214, 3339, 3466, 3596, 3729, 3866, 4007, 4153, 4304, 4463};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {539, 591, 649, 712, 779, 850, 923, 1000, 1079, 1159, 1242, 1326, 1411, 1498, 1586, 1675, 1766, 1858, 1952, 2047, 2145, 2244, 2345, 2449, 2556, 2666, 2778, 2894, 3013, 3136, 3263, 3394, 3529, 3668, 3811, 3958, 4109, 4264};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
#endif // #if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_25MA
#if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_50MA
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {252, 168, 104, 60, 32, 20, 22, 36, 62, 98, 143, 196, 256, 323, 395, 472, 554, 639, 728, 820, 915, 1012, 1113, 1216, 1322, 1430, 1541, 1656, 1774, 1895, 2021, 2151, 2286, 2427, 2574, 2727, 2888, 3057};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-195, -220, -236, -245, -245, -237, -222, -199, -170, -133, -90, -41, 14, 74, 139, 208, 282, 359, 440, 525, 612, 702, 794, 889, 987, 1086, 1189, 1293, 1400, 1511, 1624, 1742, 1863, 1990, 2123, 2262, 2409, 2565};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-391, -375, -362, -348, -334, -317, -297, -273, -245, -211, -172, -128, -78, -23, 38, 103, 173, 247, 326, 407, 493, 580, 671, 764, 858, 955, 1054, 1154, 1257, 1362, 1470, 1582, 1698, 1820, 1948, 2084, 2231, 2389};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-510, -474, -445, -421, -398, -376, -352, -327, -298, -265, -227, -184, -136, -83, -25, 38, 107, 179, 256, 336, 420, 506, 595, 686, 779, 874, 971, 1069, 1169, 1271, 1376, 1485, 1599, 1718, 1844, 1979, 2126, 2285};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-672, -618, -574, -537, -505, -475, -446, -416, -384, -350, -311, -268, -221, -169, -112, -50, 16, 87, 161, 239, 321, 405, 491, 579, 670, 762, 855, 951, 1048, 1147, 1250, 1356, 1467, 1583, 1708, 1841, 1986, 2146};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-824, -762, -710, -665, -625, -587, -551, -515, -478, -438, -396, -350, -301, -248, -191, -129, -64, 5, 77, 153, 231, 312, 396, 482, 569, 659, 750, 844, 939, 1037, 1138, 1243, 1353, 1468, 1591, 1722, 1865, 2020};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-1329, -1232, -1145, -1066, -993, -926, -863, -802, -744, -687, -630, -574, -516, -458, -399, -337, -274, -209, -142, -72, 0, 74, 151, 230, 312, 396, 483, 573, 665, 761, 860, 963, 1070, 1181, 1298, 1422, 1551, 1689};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-1585, -1457, -1346, -1248, -1161, -1082, -1010, -942, -878, -815, -754, -693, -632, -569, -506, -441, -374, -306, -236, -165, -92, -18, 58, 135, 213, 292, 373, 456, 542, 630, 722, 818, 920, 1029, 1146, 1274, 1415, 1570};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
#endif // #if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_50MA
#if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_100MA
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {549, 287, 77, -88, -212, -302, -363, -399, -414, -411, -393, -362, -322, -274, -218, -157, -92, -23, 50, 125, 204, 285, 369, 455, 545, 638, 735, 834, 937, 1044, 1153, 1266, 1380, 1496, 1612, 1727, 1839, 1948};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-470, -604, -705, -778, -827, -855, -864, -858, -839, -809, -770, -724, -671, -613, -550, -484, -415, -344, -270, -194, -116, -35, 47, 132, 220, 311, 405, 502, 602, 706, 813, 923, 1037, 1153, 1271, 1391, 1512, 1632};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-763, -831, -882, -917, -938, -946, -944, -932, -911, -882, -846, -804, -756, -703, -645, -584, -518, -449, -376, -300, -221, -139, -53, 35, 126, 219, 316, 415, 517, 621, 727, 836, 946, 1057, 1170, 1282, 1395, 1507};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-935, -970, -995, -1010, -1016, -1013, -1003, -985, -960, -929, -893, -851, -803, -752, -695, -634, -570, -501, -429, -353, -274, -192, -106, -18, 73, 167, 264, 363, 464, 567, 672, 779, 887, 997, 1107, 1218, 1329, 1439};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-1163, -1170, -1171, -1165, -1152, -1134, -1111, -1082, -1048, -1010, -967, -920, -869, -814, -756, -693, -628, -559, -487, -412, -334, -253, -169, -83, 6, 98, 192, 288, 387, 487, 590, 695, 802, 910, 1020, 1132, 1244, 1358};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-1362, -1359, -1348, -1330, -1305, -1274, -1238, -1197, -1151, -1102, -1049, -993, -934, -873, -809, -742, -674, -603, -531, -456, -379, -300, -219, -136, -51, 36, 126, 219, 314, 412, 512, 615, 721, 830, 943, 1058, 1176, 1297};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-1905, -1859, -1809, -1753, -1695, -1633, -1569, -1503, -1436, -1367, -1297, -1226, -1155, -1083, -1010, -937, -863, -787, -711, -634, -555, -474, -392, -308, -222, -133, -42, 51, 147, 245, 346, 449, 555, 662, 771, 882, 994, 1106};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-2470, -2317, -2180, -2057, -1946, -1845, -1752, -1665, -1584, -1507, -1433, -1361, -1290, -1220, -1149, -1077, -1004, -930, -853, -775, -694, -612, -526, -439, -349, -258, -164, -69, 28, 126, 225, 326, 427, 529, 631, 734, 837, 941};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
#endif // #if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_100MA
#if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_150MA
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {476, 251, 58, -106, -244, -357, -449, -520, -573, -611, -633, -643, -641, -629, -609, -580, -544, -503, -456, -405, -351, -293, -232, -169, -104, -37, 32, 102, 174, 247, 322, 399, 478, 558, 641, 727, 816, 907};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-306, -464, -596, -704, -793, -862, -915, -953, -978, -991, -994, -988, -973, -951, -922, -888, -848, -804, -756, -704, -649, -590, -529, -465, -399, -330, -260, -187, -113, -38, 39, 116, 194, 272, 350, 427, 502, 575};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-492, -607, -707, -792, -864, -924, -971, -1006, -1031, -1045, -1051, -1047, -1036, -1017, -991, -959, -921, -878, -831, -780, -725, -666, -605, -542, -476, -409, -340, -269, -197, -123, -48, 28, 105, 185, 266, 349, 436, 525};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-625, -720, -803, -875, -935, -985, -1024, -1054, -1074, -1085, -1088, -1083, -1071, -1051, -1026, -994, -957, -916, -869, -819, -765, -709, -649, -587, -522, -456, -387, -318, -246, -173, -98, -22, 57, 137, 221, 307, 396, 490};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-845, -922, -986, -1038, -1081, -1113, -1136, -1152, -1159, -1159, -1153, -1140, -1122, -1099, -1071, -1038, -1001, -960, -916, -868, -817, -763, -707, -647, -585, -520, -453, -384, -312, -239, -162, -84, -4, 78, 163, 249, 338, 428};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-1068, -1133, -1183, -1219, -1244, -1258, -1264, -1263, -1255, -1242, -1224, -1201, -1175, -1146, -1114, -1079, -1041, -1001, -957, -912, -863, -812, -758, -701, -641, -578, -511, -442, -370, -295, -217, -137, -55, 28, 111, 194, 275, 355};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-1501, -1502, -1501, -1498, -1492, -1483, -1472, -1458, -1440, -1420, -1397, -1370, -1340, -1307, -1271, -1232, -1190, -1146, -1098, -1048, -995, -940, -883, -823, -762, -698, -633, -566, -498, -428, -357, -284, -210, -136, -60, 18, 96, 175};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-1790, -1791, -1784, -1769, -1747, -1720, -1688, -1653, -1615, -1574, -1531, -1487, -1441, -1395, -1349, -1301, -1254, -1205, -1157, -1107, -1057, -1007, -955, -901, -846, -790, -731, -670, -605, -538, -468, -394, -316, -234, -148, -57, 38, 138};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
#endif // #if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_150MA
#if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_250MA
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {1007, 754, 530, 332, 159, 10, -117, -224, -311, -381, -434, -473, -498, -511, -513, -505, -489, -466, -435, -400, -360, -316, -269, -219, -168, -115, -61, -6, 50, 107, 165, 224, 285, 348, 414, 484, 559, 639};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_1_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {308, 39, -184, -366, -514, -632, -724, -793, -844, -880, -901, -912, -914, -908, -897, -879, -858, -833, -804, -773, -739, -702, -662, -619, -574, -525, -473, -419, -361, -300, -236, -169, -101, -32, 37, 105, 171, 233};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {90, -128, -314, -473, -607, -717, -807, -879, -933, -974, -1001, -1017, -1023, -1020, -1010, -993, -971, -943, -912, -877, -840, -800, -757, -712, -666, -618, -567, -515, -461, -404, -345, -283, -218, -149, -77, 1, 83, 171};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_2_8V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-64, -247, -408, -548, -668, -769, -853, -922, -975, -1016, -1044, -1062, -1069, -1068, -1059, -1043, -1021, -994, -963, -928, -889, -848, -805, -760, -714, -665, -615, -564, -511, -456, -398, -337, -273, -203, -129, -48, 41, 139};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_0V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-301, -443, -570, -681, -778, -860, -930, -987, -1032, -1067, -1091, -1106, -1113, -1112, -1104, -1089, -1069, -1044, -1014, -981, -944, -905, -863, -818, -772, -724, -673, -621, -567, -511, -452, -390, -324, -254, -179, -97, -7, 91};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_3V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-518, -637, -742, -831, -907, -971, -1023, -1065, -1098, -1122, -1138, -1146, -1148, -1144, -1135, -1121, -1102, -1078, -1051, -1021, -986, -949, -909, -866, -820, -771, -720, -666, -610, -550, -488, -423, -354, -283, -208, -130, -48, 38};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_3_6V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-874, -988, -1082, -1160, -1223, -1272, -1309, -1336, -1352, -1361, -1361, -1355, -1343, -1326, -1305, -1279, -1251, -1219, -1184, -1146, -1107, -1065, -1021, -976, -928, -879, -827, -774, -718, -660, -600, -537, -472, -405, -334, -261, -185, -106};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_4_5V
#if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
const int16_t PROGMEM LTC3335_Software_Correction_Table[LTC3335_VBAT_NUM] = {-1252, -1277, -1299, -1319, -1335, -1349, -1358, -1364, -1366, -1365, -1359, -1350, -1337, -1321, -1302, -1279, -1254, -1227, -1197, -1165, -1131, -1095, -1058, -1019, -978, -936, -892, -846, -798, -747, -693, -636, -574, -507, -434, -354, -265, -167};
#endif // #if LTC3335_OUTPUT_VOLTAGE == LTC3335_OUTPUT_VOLTAGE_5_0V
#endif // #if LTC3335_IPEAK_CONFIGURATION == LTC3335_IPEAK_CONFIGURATION_250MA
#endif // #if LTC3335_USE_SOFTWARE_CORRECTION

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Local Prototypes
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Functions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//! Returns the software correction factor for a specified LTC3335_IPEAK_CONFIGURATION, LTC3335_OUTPUT_VOLTAGE, and battery voltage.
//! Note! - These corrections factors are only valid at room temperature and for the recommended Coilcraft LPS5030-xxxMRB inductor.
//! @return TRUE if the LTC3335 communication was successful.
int16_t LTC3335_Get_Software_Correction_Factor(uint16_t vbat)
{
  if (vbat <= LTC3335_VBAT_MIN)
  {
    return pgm_read_word(&LTC3335_Software_Correction_Table[LTC3335_VBAT_TO_TABLE_INDEX(LTC3335_VBAT_MIN)]);
  }
  else if (vbat >= LTC3335_VBAT_MAX)
  {
    return pgm_read_word(&LTC3335_Software_Correction_Table[LTC3335_VBAT_TO_TABLE_INDEX(LTC3335_VBAT_MAX)]);
  }
  else
  {
    uint8_t index = LTC3335_VBAT_TO_TABLE_INDEX(vbat);
    int16_t factor1 = pgm_read_word(&LTC3335_Software_Correction_Table[index]);
    int16_t factor2 = pgm_read_word(&LTC3335_Software_Correction_Table[index + 1]);
    return factor1 + ((int32_t) (factor2 - factor1) * (vbat - (LTC3335_VBAT_MIN + index * LTC3335_VBAT_STEP))  + LTC3335_VBAT_STEP/2) / (LTC3335_VBAT_STEP);
  }
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Local Functions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


Technical Support