HEXIWEAR Battery driver and example.

Dependencies:   Hexi_OLED_SSD1351

Hexi_Battery/hexi_battery.cpp

Committer:
fredlak
Date:
2016-10-29
Revision:
0:579e15da3834

File content as of revision 0:579e15da3834:


#include "hexi_battery.h"
#include "mbed.h"

#define BITBAND_ACCESS32(Reg,Bit) (*((uint32_t volatile*)(0x42000000u + (32u*((uintptr_t)(Reg) - (uintptr_t)0x40000000u)) + (4u*((uintptr_t)(Bit))))))
#define ADC_SC1_REG(base,index)                  ((base)->SC1[index])
#define ADC_WR_SC1(base, index, value) (ADC_SC1_REG(base, index) = (value))
#define ADC_BRD_SC1_COCO(base, index) (BITBAND_ACCESS32(&ADC_SC1_REG(base, index), ADC_SC1_COCO_SHIFT))
#define ADC_RD_R_D(base, index) ((ADC_R_REG(base, index) & ADC_R_D_MASK) >> ADC_R_D_SHIFT)
#define ADC_BRD_R_D(base, index) (ADC_RD_R_D(base, index))
#define ADC_R_REG(base,index)                    ((base)->R[index])
#define SIM_BWR_SCGC_BIT(base, index, value) (BITBAND_ACCESS32(&SIM_SCGC_BIT_REG((base), (index)), SIM_SCGC_BIT_SHIFT(index)) = (uint32_t)(value))
#define SIM_SCGC_BIT_SHIFT(index)            ((uint32_t)(index) & ((1U << 5) - 1U))
#define SIM_SCGC_BIT_REG(base, index)        (*((volatile uint32_t *)&SIM_SCGC1_REG(base) + (((uint32_t)(index) >> 5) - 0U)))
#define SIM_SCGC1_REG(base)                      ((base)->SCGC1)

#define ADC_RD_CFG1(base)        (ADC_CFG1_REG(base))
#define ADC_WR_CFG1(base, value) (ADC_CFG1_REG(base) = (value))

#define ADC_CFG1_REG(base)                       ((base)->CFG1)
#define ADC_WR_CFG2(base, value) (ADC_CFG2_REG(base) = (value))
#define ADC_CFG2_REG(base)                       ((base)->CFG2)

#define ADC_WR_CV1(base, value)  (ADC_CV1_REG(base) = (value))
#define ADC_CV1_REG(base)                        ((base)->CV1)
#define ADC_WR_CV2(base, value)  (ADC_CV2_REG(base) = (value))
#define ADC_CV2_REG(base)                        ((base)->CV2)

#define ADC_WR_SC2(base, value)  (ADC_SC2_REG(base) = (value))
#define ADC_SC2_REG(base)                        ((base)->SC2)

#define ADC_WR_SC3(base, value)  (ADC_SC3_REG(base) = (value))
#define ADC_SC3_REG(base)                        ((base)->SC3)

#define ADC_RD_SC2(base)         (ADC_SC2_REG(base))
#define ADC_RD_CFG2(base)        (ADC_CFG2_REG(base))
#define ADC_CFG2_REG(base)                       ((base)->CFG2)

#define ADC_RD_SC3(base)         (ADC_SC3_REG(base))
#define ADC_SC3_REG(base)                        ((base)->SC3)

#define ADC_INSTANCE_COUNT (2U) /*!< Number of instances of the ADC module. */
const IRQn_Type g_adcIrqId[ADC_INSTANCE_COUNT] = ADC_IRQS;

typedef enum _adc16_chn {
    kAdc16Chn0  = 0U,  /*!< AD0. */
    kAdc16Chn1  = 1U,  /*!< AD1. */
    kAdc16Chn2  = 2U,  /*!< AD2. */
    kAdc16Chn3  = 3U,  /*!< AD3. */
    kAdc16Chn4  = 4U,  /*!< AD4. */
    kAdc16Chn5  = 5U,  /*!< AD5. */
    kAdc16Chn6  = 6U,  /*!< AD6. */
    kAdc16Chn7  = 7U,  /*!< AD6. */
    kAdc16Chn8  = 8U,  /*!< AD8.  */
    kAdc16Chn9  = 9U,  /*!< AD9.  */
    kAdc16Chn10 = 10U, /*!< AD10. */
    kAdc16Chn11 = 11U, /*!< AD11. */
    kAdc16Chn12 = 12U, /*!< AD12. */
    kAdc16Chn13 = 13U, /*!< AD13. */
    kAdc16Chn14 = 14U, /*!< AD14. */
    kAdc16Chn15 = 15U, /*!< AD15. */
    kAdc16Chn16 = 16U, /*!< AD16. */
    kAdc16Chn17 = 17U, /*!< AD17. */
    kAdc16Chn18 = 18U, /*!< AD18. */
    kAdc16Chn19 = 19U, /*!< AD19. */
    kAdc16Chn20 = 20U, /*!< AD20. */
    kAdc16Chn21 = 21U, /*!< AD21. */
    kAdc16Chn22 = 22U, /*!< AD22. */
    kAdc16Chn23 = 23U, /*!< AD23. */
    kAdc16Chn24 = 24U, /*!< AD24. */
    kAdc16Chn25 = 25U, /*!< AD25. */
    kAdc16Chn26 = 26U, /*!< AD26. */
    kAdc16Chn27 = 27U, /*!< AD27. */
    kAdc16Chn28 = 28U, /*!< AD28. */
    kAdc16Chn29 = 29U, /*!< AD29. */
    kAdc16Chn30 = 30U, /*!< AD30. */
    kAdc16Chn31 = 31U,  /*!< AD31. */

    kAdc16Chn0d = kAdc16Chn0,  /*!< DAD0. */
    kAdc16Chn1d = kAdc16Chn1,  /*!< DAD1. */
    kAdc16Chn2d = kAdc16Chn2,  /*!< DAD2. */
    kAdc16Chn3d = kAdc16Chn3,  /*!< DAD3. */
    kAdc16Chn4a = kAdc16Chn4,  /*!< AD4a. */
    kAdc16Chn5a = kAdc16Chn5,  /*!< AD5a. */
    kAdc16Chn6a = kAdc16Chn6,  /*!< AD6a. */
    kAdc16Chn7a = kAdc16Chn7,  /*!< AD7a. */
    kAdc16Chn4b = kAdc16Chn4,  /*!< AD4b. */
    kAdc16Chn5b = kAdc16Chn5,  /*!< AD5b. */
    kAdc16Chn6b = kAdc16Chn6,  /*!< AD6b. */
    kAdc16Chn7b = kAdc16Chn7   /*!< AD7b. */

} adc16_chn_t;

typedef enum _adc16_status {
    kStatus_ADC16_Success         = 0U, /*!< Success. */
    kStatus_ADC16_InvalidArgument = 1U, /*!< Invalid argument existed. */
    kStatus_ADC16_Failed          = 2U  /*!< Execution failed. */
} adc16_status_t;

typedef struct Adc16ChnConfig {
    adc16_chn_t chnIdx;          /*!< Select the sample channel index. */
    bool convCompletedIntEnable; /*!< Enable the conversion complete interrupt. */
#if FSL_FEATURE_ADC16_HAS_DIFF_MODE
    bool diffConvEnable;         /*!< Enable the differential conversion. */
#endif  /** FSL_FEATURE_ADC16_HAS_DIFF_MODE */
} adc16_chn_config_t;

extern const adc16_chn_config_t BATTERY_ADC_ChnConfig;

const adc16_chn_config_t BATTERY_ADC_ChnConfig = {
    .chnIdx = kAdc16Chn16,
    .convCompletedIntEnable = false,
    .diffConvEnable = false
};

ADC_Type * const g_adcBase[] = ADC_BASE_PTRS;


void ADC16_HAL_ConfigChn(ADC_Type * base, uint32_t chnGroup, const adc16_chn_config_t *configPtr)
{
    uint16_t tmp = 0U;

    /** Interrupt enable. */
    if (configPtr->convCompletedIntEnable) {
        tmp |= ADC_SC1_AIEN_MASK;
    }

    /** Differential mode enable. */
#if FSL_FEATURE_ADC16_HAS_DIFF_MODE
    if (configPtr->diffConvEnable) {
        tmp |= ADC_SC1_DIFF_MASK;
    }
#endif  /** FSL_FEATURE_ADC16_HAS_DIFF_MODE */

    /** Input channel select. */
    tmp |= ADC_SC1_ADCH((uint32_t)(configPtr->chnIdx));

    ADC_WR_SC1(base, chnGroup, tmp);
}

adc16_status_t ADC16_DRV_ConfigConvChn(uint32_t instance,
                                       uint32_t chnGroup, const adc16_chn_config_t *configPtr)
{
    ADC_Type * base = g_adcBase[instance];

    if (!configPtr) {
        return kStatus_ADC16_InvalidArgument;
    }

    ADC16_HAL_ConfigChn(base, chnGroup, configPtr);

    return kStatus_ADC16_Success;
}

static inline bool ADC16_HAL_GetChnConvCompletedFlag(ADC_Type * base, uint32_t chnGroup)
{
    return (1U == ADC_BRD_SC1_COCO(base, chnGroup) );
}

void ADC16_DRV_WaitConvDone(uint32_t instance, uint32_t chnGroup)
{
    ADC_Type * base = g_adcBase[instance];

    while ( !ADC16_HAL_GetChnConvCompletedFlag(base, chnGroup) )
        {}
}

static inline uint16_t ADC16_HAL_GetChnConvValue(ADC_Type * base, uint32_t chnGroup )
{
    return (uint16_t)(ADC_BRD_R_D(base, chnGroup) );
}

uint16_t ADC16_DRV_GetConvValueRAW(uint32_t instance, uint32_t chnGroup)
{

    ADC_Type * base = g_adcBase[instance];

    return ADC16_HAL_GetChnConvValue(base, chnGroup);
}

int16_t ADC16_DRV_GetConvValueSigned(uint32_t instance, uint32_t chnGroup)
{
    return (int16_t)ADC16_DRV_GetConvValueRAW(instance, chnGroup);
}

void ADC16_DRV_PauseConv(uint32_t instance, uint32_t chnGroup)
{
    adc16_chn_config_t configStruct;

    configStruct.chnIdx = kAdc16Chn31;
    configStruct.convCompletedIntEnable = false;
#if FSL_FEATURE_ADC16_HAS_DIFF_MODE
    configStruct.diffConvEnable = false;
#endif
    ADC16_DRV_ConfigConvChn(instance, chnGroup, &configStruct);
}

typedef enum _adc16_clk_divider {
    kAdc16ClkDividerOf1 = 0U, /*!< For divider 1 from the input clock to ADC16. @internal gui name="1" */
    kAdc16ClkDividerOf2 = 1U, /*!< For divider 2 from the input clock to ADC16. @internal gui name="2" */
    kAdc16ClkDividerOf4 = 2U, /*!< For divider 4 from the input clock to ADC16. @internal gui name="4" */
    kAdc16ClkDividerOf8 = 3U  /*!< For divider 8 from the input clock to ADC16. @internal gui name="8" */
} adc16_clk_divider_t;

typedef enum _adc16_resolution {
    kAdc16ResolutionBitOf8or9 = 0U,
    /*!< 8-bit for single end sample, or 9-bit for differential sample. @internal gui name="" */
    kAdc16ResolutionBitOfSingleEndAs8 = kAdc16ResolutionBitOf8or9, /*!< 8-bit for single end sample. @internal gui name="8 bit in single mode" */
    kAdc16ResolutionBitOfDiffModeAs9 = kAdc16ResolutionBitOf8or9, /*!< 9-bit for differential sample. @internal gui name="9 bit in differential mode" */

    kAdc16ResolutionBitOf12or13 = 1U,
    /*!< 12-bit for single end sample, or 13-bit for differential sample. @internal gui name="" */
    kAdc16ResolutionBitOfSingleEndAs12 = kAdc16ResolutionBitOf12or13, /*!< 12-bit for single end sample. @internal gui name="12 bit in single mode" */
    kAdc16ResolutionBitOfDiffModeAs13 = kAdc16ResolutionBitOf12or13, /*!< 13-bit for differential sample. @internal gui name="13 bit in differential mode" */

    kAdc16ResolutionBitOf10or11 = 2U,
    /*!< 10-bit for single end sample, or 11-bit for differential sample. @internal gui name="" */
    kAdc16ResolutionBitOfSingleEndAs10 = kAdc16ResolutionBitOf10or11, /*!< 10-bit for single end sample. @internal gui name="10 bit in single mode" */
    kAdc16ResolutionBitOfDiffModeAs11 = kAdc16ResolutionBitOf10or11 /*!< 11-bit for differential sample. @internal gui name="11 bit in differential mode" */
#if (FSL_FEATURE_ADC16_MAX_RESOLUTION >= 16U)
    , kAdc16ResolutionBitOf16 = 3U,
    /*!< 16-bit for both single end sample and differential sample. @internal gui name="16-bit" */
    kAdc16ResolutionBitOfSingleEndAs16 = kAdc16ResolutionBitOf16, /*!< 16-bit for single end sample. @internal gui name="" */
    kAdc16ResolutionBitOfDiffModeAs16 = kAdc16ResolutionBitOf16 /*!< 16-bit for differential sample. @internal gui name="" */

#endif  /** FSL_FEATURE_ADC16_MAX_RESOLUTION */
} adc16_resolution_t;

typedef enum _adc16_long_sample_cycle {
    kAdc16LongSampleCycleOf24 = 0U, /*!< 20 extra ADCK cycles, 24 ADCK cycles total. */
    kAdc16LongSampleCycleOf16 = 1U, /*!< 12 extra ADCK cycles, 16 ADCK cycles total. */
    kAdc16LongSampleCycleOf10 = 2U, /*!< 6 extra ADCK cycles, 10 ADCK cycles total. */
    kAdc16LongSampleCycleOf4  = 3U  /*!< 2 extra ADCK cycles, 6 ADCK cycles total. */
} adc16_long_sample_cycle_t;

typedef enum _adc16_clk_src_mode {
    kAdc16ClkSrcOfBusClk  = 0U, /*!< For input as bus clock. @internal gui name="Bus clock" */
    kAdc16ClkSrcOfAltClk2 = 1U, /*!< For input as alternate clock 2 (AltClk2). @internal gui name="Alternate clock 2" */
    kAdc16ClkSrcOfAltClk  = 2U, /*!< For input as alternate clock (ALTCLK). @internal gui name="Alternate clock 1" */
    kAdc16ClkSrcOfAsynClk = 3U  /*!< For input as asynchronous clock (ADACK). @internal gui name="Asynchronous clock" */
} adc16_clk_src_mode_t;

typedef enum _adc16_ref_volt_src {
    kAdc16RefVoltSrcOfVref = 0U, /*!< For external pins pair of VrefH and VrefL. @internal gui name="Vref pair" */
    kAdc16RefVoltSrcOfValt = 1U  /*!< For alternate reference pair of ValtH and ValtL. @internal gui name="Valt pair" */
} adc16_ref_volt_src_t;

typedef struct Adc16ConverterConfig {
    bool                    lowPowerEnable; /*!< Enable low power. @internal gui name="Low power mode" id="LowPowerMode" */
    adc16_clk_divider_t     clkDividerMode; /*!< Select the divider of input clock source. @internal gui name="Clock divider" id="ClockDivider" */
    bool                    longSampleTimeEnable; /*!< Enable the long sample time. @internal gui name="Long sample time" id="LongSampleTime" */
    adc16_resolution_t      resolution; /*!< Select the sample resolution mode. @internal gui name="Resolution" id="Resolution" */
    adc16_clk_src_mode_t    clkSrc; /*!< Select the input clock source to converter. @internal gui name="Clock source" id="ClockSource" */
    bool                    asyncClkEnable; /*!< Enable the asynchronous clock inside the ADC. @internal gui name="Internal async. clock" id="InternalAsyncClock" */
    bool                    highSpeedEnable; /*!< Enable the high speed mode. @internal gui name="High speed mode" id="HighSpeed" */
    adc16_long_sample_cycle_t longSampleCycleMode; /*!< Select the long sample mode. @internal gui name="Long sample mode" id="LongSampleMode" */
    bool                    hwTriggerEnable; /*!< Enable hardware trigger function. @internal gui name="Hardware trigger" id="HwTrigger" */
    adc16_ref_volt_src_t    refVoltSrc; /*!< Select the reference voltage source. @internal gui name="Voltage reference" id="ReferenceVoltage" */
    bool                    continuousConvEnable; /*!< Enable continuous conversion mode. @internal gui name="Continuous mode" id="ContinuousMode" */
#if FSL_FEATURE_ADC16_HAS_DMA
    bool                    dmaEnable; /*!< Enable the DMA for ADC converter. @internal gui name="DMA mode" id="DMASupport" */
#endif  /** FSL_FEATURE_ADC16_HAS_DMA */
} adc16_converter_config_t;

const adc16_converter_config_t BATTERY_ADC_InitConfig = {
    .lowPowerEnable = false,
    .clkDividerMode = kAdc16ClkDividerOf1,
    .longSampleTimeEnable = false,
    .resolution = kAdc16ResolutionBitOf16,
    .clkSrc = kAdc16ClkSrcOfBusClk,
    .asyncClkEnable = false,
    .highSpeedEnable = true,
    .longSampleCycleMode = kAdc16LongSampleCycleOf4,
    .hwTriggerEnable = false,
    .refVoltSrc = kAdc16RefVoltSrcOfVref,
    .continuousConvEnable = false,
    .dmaEnable = false,
};

#define FSL_SIM_SCGC_BIT(SCGCx, n) (((SCGCx-1U)<<5U) + n)

typedef enum _sim_clock_gate_name {
    kSimClockGateI2c2      = FSL_SIM_SCGC_BIT(1U, 6U),
    kSimClockGateUart4     = FSL_SIM_SCGC_BIT(1U, 10U),
    kSimClockGateUart5     = FSL_SIM_SCGC_BIT(1U, 11U),
    kSimClockGateEnet0     = FSL_SIM_SCGC_BIT(2U, 0U),
    kSimClockGateDac0      = FSL_SIM_SCGC_BIT(2U, 12U),
    kSimClockGateDac1      = FSL_SIM_SCGC_BIT(2U, 13U),
    kSimClockGateSpi2      = FSL_SIM_SCGC_BIT(3U, 12U),
    kSimClockGateSdhc0     = FSL_SIM_SCGC_BIT(3U, 17U),
    kSimClockGateFtm3      = FSL_SIM_SCGC_BIT(3U, 25U),
    kSimClockGateAdc1      = FSL_SIM_SCGC_BIT(3U, 27U),
    kSimClockGateEwm0      = FSL_SIM_SCGC_BIT(4U, 1U),
    kSimClockGateCmt0      = FSL_SIM_SCGC_BIT(4U, 2U),
    kSimClockGateI2c0      = FSL_SIM_SCGC_BIT(4U, 6U),
    kSimClockGateI2c1      = FSL_SIM_SCGC_BIT(4U, 7U),
    kSimClockGateUart0     = FSL_SIM_SCGC_BIT(4U, 10U),
    kSimClockGateUart1     = FSL_SIM_SCGC_BIT(4U, 11U),
    kSimClockGateUart2     = FSL_SIM_SCGC_BIT(4U, 12U),
    kSimClockGateUart3     = FSL_SIM_SCGC_BIT(4U, 13U),
    kSimClockGateUsbfs0    = FSL_SIM_SCGC_BIT(4U, 18U),
    kSimClockGateCmp       = FSL_SIM_SCGC_BIT(4U, 19U),
    kSimClockGateVref0     = FSL_SIM_SCGC_BIT(4U, 20U),
    kSimClockGateLptmr0    = FSL_SIM_SCGC_BIT(5U, 0U),
    kSimClockGatePortA     = FSL_SIM_SCGC_BIT(5U, 9U),
    kSimClockGatePortB     = FSL_SIM_SCGC_BIT(5U, 10U),
    kSimClockGatePortC     = FSL_SIM_SCGC_BIT(5U, 11U),
    kSimClockGatePortD     = FSL_SIM_SCGC_BIT(5U, 12U),
    kSimClockGatePortE     = FSL_SIM_SCGC_BIT(5U, 13U),
    kSimClockGateFtf0      = FSL_SIM_SCGC_BIT(6U, 0U),
    kSimClockGateDmamux0   = FSL_SIM_SCGC_BIT(6U, 1U),
    kSimClockGateFlexcan0  = FSL_SIM_SCGC_BIT(6U, 4U),
    kSimClockGateRnga0     = FSL_SIM_SCGC_BIT(6U, 9U),
    kSimClockGateSpi0      = FSL_SIM_SCGC_BIT(6U, 12U),
    kSimClockGateSpi1      = FSL_SIM_SCGC_BIT(6U, 13U),
    kSimClockGateSai0      = FSL_SIM_SCGC_BIT(6U, 15U),
    kSimClockGateCrc0      = FSL_SIM_SCGC_BIT(6U, 18U),
    kSimClockGateUsbdcd0   = FSL_SIM_SCGC_BIT(6U, 21U),
    kSimClockGatePdb0      = FSL_SIM_SCGC_BIT(6U, 22U),
    kSimClockGatePit0      = FSL_SIM_SCGC_BIT(6U, 23U),
    kSimClockGateFtm0      = FSL_SIM_SCGC_BIT(6U, 24U),
    kSimClockGateFtm1      = FSL_SIM_SCGC_BIT(6U, 25U),
    kSimClockGateFtm2      = FSL_SIM_SCGC_BIT(6U, 26U),
    kSimClockGateAdc0      = FSL_SIM_SCGC_BIT(6U, 27U),
    kSimClockGateRtc0      = FSL_SIM_SCGC_BIT(6U, 29U),
    kSimClockGateFlexbus0  = FSL_SIM_SCGC_BIT(7U, 0U),
    kSimClockGateDma0      = FSL_SIM_SCGC_BIT(7U, 1U),
    kSimClockGateMpu0      = FSL_SIM_SCGC_BIT(7U, 2U),
#if (defined(DOXYGEN_OUTPUT) && (DOXYGEN_OUTPUT))
} sim_clock_gate_name_k64f12_t;
#else
} sim_clock_gate_name_t;
#endif

static const sim_clock_gate_name_t adcGateTable[] = {
    kSimClockGateAdc0,
    kSimClockGateAdc1
};

static inline void SIM_HAL_EnableClock(SIM_Type * base, sim_clock_gate_name_t name)
{
    SIM_BWR_SCGC_BIT(base, name, 1U);
}

void CLOCK_SYS_EnableAdcClock(uint32_t instance)
{
    SIM_HAL_EnableClock(SIM, adcGateTable[instance]);
}

void ADC16_HAL_Init(ADC_Type * base)
{
    ADC_WR_CFG1(base, 0U);
    ADC_WR_CFG2(base, 0U);
    ADC_WR_CV1(base, 0U);
    ADC_WR_CV2(base, 0U);
    ADC_WR_SC2(base, 0U);
    ADC_WR_SC3(base, 0U);
#if FSL_FEATURE_ADC16_HAS_PGA
    ADC_WR_PGA(base, 0U);
#endif  /** FSL_FEATURE_ADC16_HAS_PGA */
}

void ADC16_HAL_ConfigConverter(ADC_Type * base, const adc16_converter_config_t *configPtr)
{
    uint16_t cfg1, cfg2, sc2, sc3;

    cfg1 = ADC_RD_CFG1(base);
    cfg1 &= ~(  ADC_CFG1_ADLPC_MASK
                | ADC_CFG1_ADIV_MASK
                | ADC_CFG1_ADLSMP_MASK
                | ADC_CFG1_MODE_MASK
                | ADC_CFG1_ADICLK_MASK );

    /** Low power mode. */
    if (configPtr->lowPowerEnable) {
        cfg1 |= ADC_CFG1_ADLPC_MASK;
    }
    /** Clock divider. */
    cfg1 |= ADC_CFG1_ADIV(configPtr->clkDividerMode);
    /** Long sample time. */
    if (configPtr->longSampleTimeEnable) {
        cfg1 |= ADC_CFG1_ADLSMP_MASK;
    }
    /** Sample resolution mode. */
    cfg1 |= ADC_CFG1_MODE(configPtr->resolution);
    /** Clock source input. */
    cfg1 |= ADC_CFG1_ADICLK(configPtr->clkSrc);

    cfg2 = ADC_RD_CFG2(base);
    cfg2 &= ~( ADC_CFG2_ADACKEN_MASK
               | ADC_CFG2_ADHSC_MASK
               | ADC_CFG2_ADLSTS_MASK );
    /** Asynchronous clock output enable. */
    if (configPtr->asyncClkEnable) {
        cfg2 |= ADC_CFG2_ADACKEN_MASK;
    }
    /** High speed configuration. */
    if (configPtr->highSpeedEnable) {
        cfg2 |= ADC_CFG2_ADHSC_MASK;
    }
    /** Long sample time select. */
    cfg2 |= ADC_CFG2_ADLSTS(configPtr->longSampleCycleMode);

    sc2 = ADC_RD_SC2(base);
    sc2 &= ~( ADC_SC2_ADTRG_MASK
              | ADC_SC2_REFSEL_MASK
#if FSL_FEATURE_ADC16_HAS_DMA
              | ADC_SC2_DMAEN_MASK
#endif  /** FSL_FEATURE_ADC16_HAS_DMA */
            );
    /** Conversion trigger select. */
    if (configPtr->hwTriggerEnable) {
        sc2 |= ADC_SC2_ADTRG_MASK;
    }
    /** Voltage reference selection. */
    sc2 |= ADC_SC2_REFSEL(configPtr->refVoltSrc);
#if FSL_FEATURE_ADC16_HAS_DMA
    /** DMA. */
    if (configPtr->dmaEnable) {
        sc2 |= ADC_SC2_DMAEN_MASK;
    }
#endif  /** FSL_FEATURE_ADC16_HAS_DMA */

    sc3 = ADC_RD_SC3(base);
    sc3 &= ~( ADC_SC3_ADCO_MASK
              | ADC_SC3_CALF_MASK );
    /** Continuous conversion enable. */
    if (configPtr->continuousConvEnable) {
        sc3 |= ADC_SC3_ADCO_MASK;
    }

    ADC_WR_CFG1(base, cfg1);
    ADC_WR_CFG2(base, cfg2);
    ADC_WR_SC2(base, sc2);
    ADC_WR_SC3(base, sc3);
}

static inline void INT_SYS_EnableIRQ(IRQn_Type irqNumber)
{
    /** call core API to enable the IRQ*/
    NVIC_EnableIRQ(irqNumber);
}

adc16_status_t ADC16_DRV_Init(uint32_t instance, const adc16_converter_config_t *userConfigPtr)
{
    ADC_Type * base = g_adcBase[instance];

    if (!userConfigPtr) {
        return kStatus_ADC16_InvalidArgument;
    }
    /** Enable clock for ADC. */
    CLOCK_SYS_EnableAdcClock(instance);

    /** Reset all the register to a known state. */
    ADC16_HAL_Init(base);
    ADC16_HAL_ConfigConverter(base, userConfigPtr);

    /** Enable ADC interrupt in NVIC level.*/
    INT_SYS_EnableIRQ(g_adcIrqId[instance] );

    return kStatus_ADC16_Success;
}

static uint8_t bat_convert_data(uint16_t input)
{
    uint8_t output = 0;

    uint16_t bat_mvolts = (uint16_t)( ( (float)input * ( 3.3 / 65535.0 ) ) * 1000 );

    if ( bat_mvolts > 2670 ) {
        output = 100;
    }

    else if ( bat_mvolts > 2500 ) {
        output = (uint8_t)( 50 + 50.0 * ( ( bat_mvolts - 2500 ) / 170.0 ) );
    } else if ( bat_mvolts > 2430 ) {
        output = (uint8_t)( 30 + 20.0 * ( ( bat_mvolts - 2430 ) / 70.0 ) );
    } else if ( bat_mvolts > 2370 ) {
        output = (uint8_t)( 10 + 20.0 * ( ( bat_mvolts - 2370 ) / 60.0 ) );
    } else {
        output = 0;
    }
    return output;

}

HexiwearBattery::HexiwearBattery()
{
    batCharging = new DigitalIn(PTC12);
    batSensSwitch = new DigitalOut(PTC14);
    ADC16_DRV_Init(0, &BATTERY_ADC_InitConfig);
    ADC16_DRV_ConfigConvChn(0, 0U, &BATTERY_ADC_ChnConfig);
}

HexiwearBattery::~HexiwearBattery()
{
    delete batSensSwitch;
    delete batCharging;
}

void HexiwearBattery::sensorOn()
{
    *batSensSwitch = 0;
};


void HexiwearBattery::sensorOff()
{
    *batSensSwitch = 1;
};

bool HexiwearBattery::isBatteryCharging()
{
    return *batCharging == 0;
}

uint8_t HexiwearBattery::readLevelPercent()
{
    ADC16_DRV_ConfigConvChn( 0, 0, &BATTERY_ADC_ChnConfig);
    ADC16_DRV_WaitConvDone ( 0, 0 );
    int16_t result = ADC16_DRV_GetConvValueSigned( 0, 0 );
    ADC16_DRV_PauseConv(0, 0 );
    return bat_convert_data(result);
}