powerpic

Replacement board for a Casio CA-53W

/** @file battery.c
 * 
 * This library implements functionality relating to the battery in the watch.
 * 
 * Currently, the voltage returned is within +-0.02 of the actual voltage, at
 * room temp. Further testing needs to be done across temperature ranges (Like
 * with wearing).
 * The ADC and FVR is only enabled when sampling. This might present issues by
 * introducing delays in the read_voltage() call, so plenty of time should be
 * given.
*/

#include <xc.h>

#include "drivers/adc.h"
#include "drivers/fvr.h"

#include "lib/battery.h"

#define LOG_TAG "lib.battery"
#include "lib/logging.h"


#define FIXED_VOLTAGE_REP   1024UL    // Should we calculate this based on temp?
#define MAX_VOLTAGE         4095UL    // Max ADC result.

// Configure ADC for battery use.
static void battery_adc_config (void);

void
battery_init (void)
{
    LOG_INFO("Initializing battery...");

    // Initialize ADC driver.
    adc_init();
}

float
battery_read_voltage (void)
{
    unsigned int average = 0;
    unsigned int voltage = 0;

    // Configure and enable needed modules and wait for them to start up.
    //
    battery_adc_config();
    fvr_enable();
    adc_enable();
    __delay_ms(1);

    // We take 10+1 samples to get a nice rolling average reading.
    // 
    
    // Initial reading.
    //
    adc_sample();
    while (1 == adc_status())
    {
        // Wait until conversion is complete
    }
    average = (unsigned int)adc_result();

    // 10 Samples
    //
    for (int res = 0; res < 10; res++)
    {
        adc_sample();
        
        while (1 == adc_status())
        {
            // Wait until conversion is complete
        }

        average = (average + (unsigned int)adc_result()) / 2;
    }

    // Turn off used peripherals
    adc_disable();
    fvr_disable();

    // Calculate voltage from average reading.
    //
    voltage = (unsigned int)((FIXED_VOLTAGE_REP * MAX_VOLTAGE) / average);

    LOG_DEBUG("Voltage: %u", voltage);

    return ((float)voltage / 1000);
}

static void
battery_adc_config (void)
{
    // Set our FVR to output 1.024V to the ADC, and our ADC channel to the FVR
    // buffer.
    //
    fvr_adc_set(FVR_GAIN_1X);
    adc_channel_set(ADC_CHAN_FVR_BUFFER_1);

    // Select Vdd as ADC reference.
    //
    adc_reference_set(ADC_REF_VDD);
}

// EOF //