diff --git a/ion/src/device/battery.cpp b/ion/src/device/battery.cpp index 1a84f7242..7a90de928 100644 --- a/ion/src/device/battery.cpp +++ b/ion/src/device/battery.cpp @@ -2,6 +2,14 @@ #include "battery.h" #include "regs/regs.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 { @@ -19,7 +27,6 @@ float voltage() { return Device::ADCDividerBridgeRatio*(Device::ADCReferenceVoltage * value)/0xFFF; } - } } @@ -43,6 +50,10 @@ void 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. */ ADCGPIO.MODER()->setMode(ADCPin, GPIO::MODER::Mode::Analog); + + ADC.SMPR()->setSamplingTime(ADCChannel, ADC::SMPR::SamplingTime::Cycles480); + // ADC.SQR1()->setL(0); // Default + ADC.SQR3()->setSQ1(ADCChannel); } void initADC() { diff --git a/ion/src/device/battery.h b/ion/src/device/battery.h index d057583ed..cc4e0fa77 100644 --- a/ion/src/device/battery.h +++ b/ion/src/device/battery.h @@ -9,19 +9,20 @@ namespace Device { /* Pin | Role | Mode | Function * -----+-------------------+-----------------------+---------- - * PA0 | BAT_SNS | Analog | ADC1_0 - * PC2 | BAT_CHRG | Input, pulled up | + * PA0 | BAT_CHRG | Input, pulled up | Low = charging, high = full + * PA1 | VBAT_SNS | Analog | ADC1_1 */ void init(); void initGPIO(); void initADC(); -constexpr GPIO ChargingGPIO = GPIOC; -constexpr uint8_t ChargingPin = 2; +constexpr GPIO ChargingGPIO = GPIOA; +constexpr uint8_t ChargingPin = 0; constexpr GPIO ADCGPIO = GPIOA; -constexpr uint8_t ADCPin = 0; +constexpr uint8_t ADCPin = 1; +constexpr uint8_t ADCChannel = 1; constexpr float ADCReferenceVoltage = 2.8f; constexpr float ADCDividerBridgeRatio = 2.0f; diff --git a/ion/src/device/regs/adc.h b/ion/src/device/regs/adc.h index 1c79145d4..2881cf23b 100644 --- a/ion/src/device/regs/adc.h +++ b/ion/src/device/regs/adc.h @@ -19,7 +19,7 @@ public: REGS_BOOL_FIELD(ADON, 0); REGS_BOOL_FIELD(SWSTART, 30); }; -#if 0 + class SMPR : Register64 { /* The SMPR register doesn't exist per-se in the documentation. It is the * consolidation of SMPR1 and SMPR2 which are two 32-bit registers. */ @@ -34,14 +34,23 @@ public: Cycles144 = 6, Cycles480 = 7 }; - SamplingTime setSamplingTime(int channel) { - return (SamplingTime)getBitRange(3*index+2, 3*index); + SamplingTime getSamplingTime(int channel) { + return (SamplingTime)getBitRange(3*channel+2, 3*channel); } void setSamplingTime(int channel, SamplingTime t) volatile { - setBitRange(3*index+2, 3*index, (uint64_t)t); + setBitRange(3*channel+2, 3*channel, (uint64_t)t); } }; -#endif + + class SQR1 : Register32 { + public: + REGS_FIELD(L, uint8_t, 23, 20); + }; + + class SQR3 : Register32 { + public: + REGS_FIELD(SQ1, uint8_t, 4, 0); + }; class DR : public Register16 { }; @@ -49,6 +58,9 @@ public: constexpr ADC() {}; REGS_REGISTER_AT(SR, 0x0); REGS_REGISTER_AT(CR2, 0x08); + REGS_REGISTER_AT(SMPR, 0x0C); + REGS_REGISTER_AT(SQR1, 0x2C); + REGS_REGISTER_AT(SQR3, 0x34); REGS_REGISTER_AT(DR, 0x4C); private: constexpr uint32_t Base() const {