From 997282390789b32ad3c6725e8c80a0e6603febb0 Mon Sep 17 00:00:00 2001 From: Vincent Politzer Date: Sun, 22 Feb 2026 11:24:16 -0800 Subject: [PATCH 1/3] DS3231 probe fix and constants cleanup --- lib/hal/HalGPIO.cpp | 23 +++++++++-------------- lib/hal/HalGPIO.h | 21 +++++++++++++++++++++ lib/hal/HalPowerManager.cpp | 11 ++++------- lib/hal/HalPowerManager.h | 2 -- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/lib/hal/HalGPIO.cpp b/lib/hal/HalGPIO.cpp index 1c0e7171c4..f6457e5782 100644 --- a/lib/hal/HalGPIO.cpp +++ b/lib/hal/HalGPIO.cpp @@ -9,13 +9,6 @@ HalGPIO gpio; namespace { -constexpr uint8_t I2C_ADDR_BQ27220 = 0x55; -constexpr uint8_t I2C_ADDR_DS3231 = 0x68; -constexpr uint8_t I2C_ADDR_QMI8658 = 0x6B; -constexpr uint8_t I2C_ADDR_QMI8658_ALT = 0x6A; -constexpr uint8_t QMI8658_WHO_AM_I_REG = 0x00; -constexpr uint8_t QMI8658_WHO_AM_I_VALUE = 0x05; - constexpr char HW_NAMESPACE[] = "cphw"; constexpr char NVS_KEY_DEV_OVERRIDE[] = "dev_ovr"; // 0=auto, 1=x4, 2=x3 constexpr char NVS_KEY_DEV_CACHED[] = "dev_det"; // 0=unknown, 1=x4, 2=x3 @@ -65,7 +58,7 @@ bool readI2CReg16LE(uint8_t addr, uint8_t reg, uint16_t* outValue) { bool readBQ27220CurrentMA(int16_t* outCurrent) { uint16_t raw = 0; - if (!readI2CReg16LE(I2C_ADDR_BQ27220, 0x0C, &raw)) { + if (!readI2CReg16LE(I2C_ADDR_BQ27220, BQ27220_CUR_REG, &raw)) { return false; } *outCurrent = static_cast(raw); @@ -75,13 +68,13 @@ bool readBQ27220CurrentMA(int16_t* outCurrent) { bool probeBQ27220Signature() { uint16_t soc = 0; uint16_t voltageMv = 0; - if (!readI2CReg16LE(I2C_ADDR_BQ27220, 0x2C, &soc)) { + if (!readI2CReg16LE(I2C_ADDR_BQ27220, BQ27220_SOC_REG, &soc)) { return false; } if (soc > 100) { return false; } - if (!readI2CReg16LE(I2C_ADDR_BQ27220, 0x08, &voltageMv)) { + if (!readI2CReg16LE(I2C_ADDR_BQ27220, BQ27220_VOLT_REG, &voltageMv)) { return false; } return voltageMv >= 2500 && voltageMv <= 5000; @@ -89,11 +82,13 @@ bool probeBQ27220Signature() { bool probeDS3231Signature() { uint8_t sec = 0; - if (!readI2CReg8(I2C_ADDR_DS3231, 0x00, &sec)) { + if (!readI2CReg8(I2C_ADDR_DS3231, DS3231_SEC_REG, &sec)) { return false; } - const uint8_t secBcd = sec & 0x7F; - return secBcd <= 0x59; + const uint8_t tensDigit = (sec >> 4) & 0x07; + const uint8_t onesDigit = sec & 0x0F; + + return (tensDigit > 5 || onesDigit > 9) ? false : true; } bool probeQMI8658Signature() { @@ -109,7 +104,7 @@ bool probeQMI8658Signature() { X3ProbeResult runX3ProbePass() { X3ProbeResult result; - Wire.begin(20, 0, 400000); + Wire.begin(X3_I2C_SDA, X3_I2C_SCL, X3_I2C_FREQ); Wire.setTimeOut(6); result.bq27220 = probeBQ27220Signature(); diff --git a/lib/hal/HalGPIO.h b/lib/hal/HalGPIO.h index ff6ed74fb7..0208388f81 100644 --- a/lib/hal/HalGPIO.h +++ b/lib/hal/HalGPIO.h @@ -17,6 +17,27 @@ #define UART0_RXD 20 // Used for USB connection detection +// Xteink X3 Hardware +#define X3_I2C_SDA 20 +#define X3_I2C_SCL 0 +#define X3_I2C_FREQ 400000 + +// TI BQ27220 Fuel gauge I2C +#define I2C_ADDR_BQ27220 0x55 // Fuel gauge I2C address +#define BQ27220_SOC_REG 0x2C // StateOfCharge() command code (%) +#define BQ27220_CUR_REG 0x0C // Current() command code 0x08 (signed mA) +#define BQ27220_VOLT_REG 0x08 // Voltage() command code (mV) + +// Analog DS3231 RTC I2C +#define I2C_ADDR_DS3231 0x68 // RTC I2C address +#define DS3231_SEC_REG 0x00 // seconds + +// QST QMI8658 IMU I2C +#define I2C_ADDR_QMI8658 0x6B // IMU I2C address +#define I2C_ADDR_QMI8658_ALT 0x6A // IMU I2C fallback address +#define QMI8658_WHO_AM_I_REG 0x00 // WHO_AM_I command code +#define QMI8658_WHO_AM_I_VALUE 0x05 // WHO_AM_I expected value + class HalGPIO { #if CROSSPOINT_EMULATED == 0 InputManager inputMgr; diff --git a/lib/hal/HalPowerManager.cpp b/lib/hal/HalPowerManager.cpp index 95f24d7713..df0d71824d 100644 --- a/lib/hal/HalPowerManager.cpp +++ b/lib/hal/HalPowerManager.cpp @@ -14,12 +14,9 @@ void HalPowerManager::begin() { if (gpio.deviceIsX3()) { // X3 uses an I2C fuel gauge for battery monitoring. // I2C init must come AFTER gpio.begin() so early hardware detection/probes are finished. - Wire.begin(20, 0, 400000); + Wire.begin(X3_I2C_SDA, X3_I2C_SCL, X3_I2C_FREQ); Wire.setTimeOut(4); _batteryUseI2C = true; - _batteryI2cAddr = 0x55; - // TI BQ27220: StateOfCharge() command code - _batterySocRegister = 0x2C; } else { pinMode(BAT_GPIO0, INPUT); } @@ -84,14 +81,14 @@ uint16_t HalPowerManager::getBatteryPercentage() const { // Read SOC directly from I2C fuel gauge (16-bit LE register). // On I2C error, keep last known value to avoid UI jitter/slowdowns. - Wire.beginTransmission(_batteryI2cAddr); - Wire.write(_batterySocRegister); + Wire.beginTransmission(I2C_ADDR_BQ27220); + Wire.write(BQ27220_SOC_REG); if (Wire.endTransmission(false) != 0) { _batteryI2cFailCount++; _batteryLastPollMs = now; return _batteryCachedPercent; } - Wire.requestFrom(_batteryI2cAddr, (uint8_t)2); + Wire.requestFrom(I2C_ADDR_BQ27220, (uint8_t)2); if (Wire.available() < 2) { _batteryI2cFailCount++; _batteryLastPollMs = now; diff --git a/lib/hal/HalPowerManager.h b/lib/hal/HalPowerManager.h index 5bebd6c31d..78fbe8269d 100644 --- a/lib/hal/HalPowerManager.h +++ b/lib/hal/HalPowerManager.h @@ -20,8 +20,6 @@ class HalPowerManager { // I2C fuel gauge configuration for X3 battery monitoring bool _batteryUseI2C = false; - uint8_t _batteryI2cAddr = 0; - uint8_t _batterySocRegister = 0; mutable int _batteryCachedPercent = 0; mutable unsigned long _batteryLastPollMs = 0; mutable uint8_t _batteryI2cFailCount = 0; From 89e648defd4efd9bf450e1ec783d02d71f52ad5d Mon Sep 17 00:00:00 2001 From: Vincent Politzer Date: Mon, 23 Feb 2026 22:21:45 -0800 Subject: [PATCH 2/3] Remove unused write-only variable, improve comments --- lib/hal/HalGPIO.h | 4 ++-- lib/hal/HalPowerManager.cpp | 3 --- lib/hal/HalPowerManager.h | 7 +++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/hal/HalGPIO.h b/lib/hal/HalGPIO.h index 0208388f81..f9ecb0dfb3 100644 --- a/lib/hal/HalGPIO.h +++ b/lib/hal/HalGPIO.h @@ -25,12 +25,12 @@ // TI BQ27220 Fuel gauge I2C #define I2C_ADDR_BQ27220 0x55 // Fuel gauge I2C address #define BQ27220_SOC_REG 0x2C // StateOfCharge() command code (%) -#define BQ27220_CUR_REG 0x0C // Current() command code 0x08 (signed mA) +#define BQ27220_CUR_REG 0x0C // Current() command code (signed mA) #define BQ27220_VOLT_REG 0x08 // Voltage() command code (mV) // Analog DS3231 RTC I2C #define I2C_ADDR_DS3231 0x68 // RTC I2C address -#define DS3231_SEC_REG 0x00 // seconds +#define DS3231_SEC_REG 0x00 // Seconds command code (BCD) // QST QMI8658 IMU I2C #define I2C_ADDR_QMI8658 0x6B // IMU I2C address diff --git a/lib/hal/HalPowerManager.cpp b/lib/hal/HalPowerManager.cpp index df0d71824d..584ee06d9c 100644 --- a/lib/hal/HalPowerManager.cpp +++ b/lib/hal/HalPowerManager.cpp @@ -84,13 +84,11 @@ uint16_t HalPowerManager::getBatteryPercentage() const { Wire.beginTransmission(I2C_ADDR_BQ27220); Wire.write(BQ27220_SOC_REG); if (Wire.endTransmission(false) != 0) { - _batteryI2cFailCount++; _batteryLastPollMs = now; return _batteryCachedPercent; } Wire.requestFrom(I2C_ADDR_BQ27220, (uint8_t)2); if (Wire.available() < 2) { - _batteryI2cFailCount++; _batteryLastPollMs = now; return _batteryCachedPercent; } @@ -99,7 +97,6 @@ uint16_t HalPowerManager::getBatteryPercentage() const { const uint16_t soc = (hi << 8) | lo; _batteryCachedPercent = soc > 100 ? 100 : soc; _batteryLastPollMs = now; - _batteryI2cFailCount = 0; return _batteryCachedPercent; } static const BatteryMonitor battery = BatteryMonitor(BAT_GPIO0); diff --git a/lib/hal/HalPowerManager.h b/lib/hal/HalPowerManager.h index 78fbe8269d..bf78623ca3 100644 --- a/lib/hal/HalPowerManager.h +++ b/lib/hal/HalPowerManager.h @@ -19,10 +19,9 @@ class HalPowerManager { bool isLowPower = false; // I2C fuel gauge configuration for X3 battery monitoring - bool _batteryUseI2C = false; - mutable int _batteryCachedPercent = 0; - mutable unsigned long _batteryLastPollMs = 0; - mutable uint8_t _batteryI2cFailCount = 0; + bool _batteryUseI2C = false; // True if using I2C fuel gauge (X3), false for ADC (X4) + mutable int _batteryCachedPercent = 0; // Last read battery percentage (0-100) + mutable unsigned long _batteryLastPollMs = 0; // Timestamp of last battery read in milliseconds enum LockMode { None, NormalSpeed }; LockMode currentLockMode = None; From bfc656f3933d87dfa47d9b15953bc321dd6c0ca5 Mon Sep 17 00:00:00 2001 From: Vincent Politzer Date: Mon, 23 Feb 2026 22:32:33 -0800 Subject: [PATCH 3/3] Simplify digit validation logic --- lib/hal/HalGPIO.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hal/HalGPIO.cpp b/lib/hal/HalGPIO.cpp index f6457e5782..4a2c8e01e9 100644 --- a/lib/hal/HalGPIO.cpp +++ b/lib/hal/HalGPIO.cpp @@ -88,7 +88,7 @@ bool probeDS3231Signature() { const uint8_t tensDigit = (sec >> 4) & 0x07; const uint8_t onesDigit = sec & 0x0F; - return (tensDigit > 5 || onesDigit > 9) ? false : true; + return tensDigit <= 5 && onesDigit <= 9; } bool probeQMI8658Signature() {