Files
Upsilon/ion/src/device/shared/drivers/battery.cpp
2019-02-13 15:08:10 +01:00

95 lines
2.8 KiB
C++

#include "battery.h"
#include <ion/battery.h>
#include <drivers/config/battery.h>
/* To measure the battery voltage, we're using the internal ADC. The ADC works
* by comparing the input voltage to a reference voltage. The only fixed voltage
* we have around is 2.8V, so that's the one we're using as a refrence. However,
* and ADC can only measure voltage that is lower than the reference voltage. So
* we need to use a voltage divider before sampling Vbat.
* To avoid draining the battery, we're using an high-impedence voltage divider,
* so we need to be careful when sampling the ADC. See AN2834 for more info. */
namespace Ion {
namespace Battery {
using namespace Device::Battery;
using namespace Device::Regs;
bool isCharging() {
return !Config::ChargingPin.group().IDR()->get(Config::ChargingPin.pin());
}
Charge level() {
if (voltage() < 3.2f) {
return Charge::EMPTY;
}
if (voltage() < 3.5f) {
return Charge::LOW;
}
if (voltage() < 3.8f) {
return Charge::SOMEWHERE_INBETWEEN;
}
return Charge::FULL;
}
float voltage() {
ADC.CR2()->setSWSTART(true);
while (ADC.SR()->getEOC() != true) {
}
uint16_t value = ADC.DR()->get();
// The ADC is 12 bits by default
return Config::ADCDividerBridgeRatio*(Config::ADCReferenceVoltage * value)/0xFFF;
}
}
}
namespace Ion {
namespace Device {
namespace Battery {
using namespace Regs;
void init() {
initGPIO();
/* The BAT_SNS pin is connected to Vbat through a divider bridge. It therefore
* has a voltage of Vbat/2. We'll measure this using ADC channel 0. */
Config::ADCPin.group().MODER()->setMode(Config::ADCPin.pin(), GPIO::MODER::Mode::Analog);
// Step 2 - Enable the ADC
RCC.APB2ENR()->setADC1EN(true);
ADC.CR2()->setADON(true);
// Configure the ADC channel
ADC.SQR1()->setL(0); // Always sample the same channel
ADC.SQR3()->setSQ1(Config::ADCChannel);
ADC.SMPR()->setSamplingTime(Config::ADCChannel, ADC::SMPR::SamplingTime::Cycles480); // Use the max sampling time
}
void initGPIO() {
/* Step 1 - Configure the GPIOs
* The BAT_CHRG pin is connected to the Li-Po charging IC. That pin uses an
* open-drain output. Open-drain output are either connected to ground or left
* floating. To interact with such an output, our input must therefore be
* pulled up. */
Config::ChargingPin.group().MODER()->setMode(Config::ChargingPin.pin(), GPIO::MODER::Mode::Input);
Config::ChargingPin.group().PUPDR()->setPull(Config::ChargingPin.pin(), GPIO::PUPDR::Pull::Up);
}
void shutdown() {
Config::ChargingPin.group().MODER()->setMode(Config::ChargingPin.pin(), GPIO::MODER::Mode::Analog);
Config::ChargingPin.group().PUPDR()->setPull(Config::ChargingPin.pin(), GPIO::PUPDR::Pull::None);
// Disable the ADC
ADC.CR2()->setADON(false);
RCC.APB2ENR()->setADC1EN(false);
}
}
}
}