Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions lib/hal/HalGPIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<int16_t>(raw);
Expand All @@ -75,25 +68,27 @@ 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;
}

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;
}

bool probeQMI8658Signature() {
Expand All @@ -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();
Expand Down
21 changes: 21 additions & 0 deletions lib/hal/HalGPIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 (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 command code (BCD)

// 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;
Expand Down
14 changes: 4 additions & 10 deletions lib/hal/HalPowerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -84,16 +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;
return _batteryCachedPercent;
}
Expand All @@ -102,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);
Expand Down
9 changes: 3 additions & 6 deletions lib/hal/HalPowerManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ class HalPowerManager {
bool isLowPower = false;

// 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;
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;
Expand Down