Files
air-mouse/source/battery.cpp
2026-03-19 22:38:04 +01:00

55 lines
2.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "battery.h"
#ifdef FEATURE_BATTERY_MONITOR
#include <bluefruit.h>
extern BLEBas blebas;
// Battery ADC is kept permanently configured at 12-bit / AR_INTERNAL_3_0 to avoid
// the SAADC re-init cost of analogReference() changes, which blocks the CPU for
// several ms and causes BLE connection-interval violations (visible mouse freeze).
// PIN_VBAT_ENABLE is held LOW permanently once battery monitoring starts.
void initBatteryADC() {
pinMode(PIN_VBAT_ENABLE, OUTPUT); digitalWrite(PIN_VBAT_ENABLE, LOW);
pinMode(PIN_VBAT_READ, INPUT);
analogReference(AR_INTERNAL_3_0); analogReadResolution(12);
// Warm up with a few reads (no delay - just discard results)
for (int i=0; i<8; i++) analogRead(PIN_VBAT_READ);
}
float readBatteryVoltage() {
// 8 quick reads, no delay() calls, no analogReference() change
int32_t raw=0; for (int i=0; i<8; i++) raw += analogRead(PIN_VBAT_READ); raw /= 8;
// Seeed XIAO nRF52840 Sense: 1MΩ + 510kΩ voltage divider on VBAT.
// Theoretical ratio is 1510/510 = 2.961, but real resistor tolerances
// shift the actual ratio. Calibrated: 3.90V actual / 3.78V reported → ×1.0317.
return (raw / 4096.0f) * 3.0f * (1510.0f / 510.0f) * 1.0317f;
}
int batteryPercent(float v) {
return (int)constrain((v - BATT_EMPTY) / (BATT_FULL - BATT_EMPTY) * 100.f, 0, 100);
}
void updateBattery() {
float v = readBatteryVoltage(); int pct = batteryPercent(v);
bool chg = (digitalRead(PIN_CHG) == LOW);
ChargeStatus status = chg ? (pct >= 99 ? CHGSTAT_FULL : CHGSTAT_CHARGING) : CHGSTAT_DISCHARGING;
// Only write BLE Battery Service when connected - blebas.write() blocks on the
// SoftDevice ATT layer and causes 30-40ms loop stalls when called during advertising.
if (Bluefruit.connected()) blebas.notify(pct);
lastChargeStatus = status;
#ifdef FEATURE_TELEMETRY
telem.chargeStatus = (uint8_t)status;
#endif
const char* st[] = {"discharging","charging","full"};
Serial.print("[BATT] "); Serial.print(v,2); Serial.print("V ");
Serial.print(pct); Serial.print("% "); Serial.print(st[status]);
Serial.print(" (PIN_CHG="); Serial.print(digitalRead(PIN_CHG)); Serial.println(")");
// Critical battery alert - only blink when not connected to avoid blocking BLE scheduler.
// 6 × 160ms = 960ms hard block; skip during active connection.
if (status == CHGSTAT_DISCHARGING && v < BATT_CRITICAL && !Bluefruit.connected())
for (int i=0; i<6; i++) { digitalWrite(LED_RED,LOW); delay(80); digitalWrite(LED_RED,HIGH); delay(80); }
}
#endif // FEATURE_BATTERY_MONITOR