|
8 | 8 |
|
9 | 9 | static bool wireInitialized = false; |
10 | 10 |
|
11 | | -// From https://www.diodes.com/datasheet/download/PI4IOE5V6408.pdf |
| 11 | +// IO expander datasheet from https://www.diodes.com/datasheet/download/PI4IOE5V6408.pdf |
| 12 | +// Battery charger datasheet from https://www.awinic.com/en/productDetail/AW32001ACSR |
| 13 | +// battery gauge datasheet from https://www.ti.com/product/BQ27220 |
| 14 | + |
12 | 15 | static void writeRegister(uint8_t address, uint8_t reg, uint8_t value) { |
13 | 16 | WireInternal.beginTransmission(address); |
14 | 17 | WireInternal.write(reg); |
@@ -85,37 +88,215 @@ int digitalRead(ExpanderPin pin) { |
85 | 88 | return readBitRegister(pin.address, 0xF, pin.pin); |
86 | 89 | } |
87 | 90 |
|
| 91 | +void NessoBattery::begin(uint16_t current, uint16_t voltage, UnderVoltageLockout uvlo, uint8_t timeout) { |
| 92 | + if (!wireInitialized) { |
| 93 | + WireInternal.begin(SDA, SCL); |
| 94 | + wireInitialized = true; |
| 95 | + } |
| 96 | + |
| 97 | + setChargeCurrent(current); |
| 98 | + setChargeVoltage(voltage); |
| 99 | + setWatchdogTimer(timeout); |
| 100 | + setBatUVLO(uvlo); |
| 101 | + setHiZ(false); |
| 102 | + setChargeEnable(true); |
| 103 | +} |
| 104 | + |
88 | 105 | void NessoBattery::enableCharge() { |
89 | | - // AW32001E - address 0x49 |
90 | | - // set CEB bit low (charge enable) |
| 106 | + setChargeEnable(true); |
| 107 | +} |
| 108 | + |
| 109 | +void NessoBattery::setChargeEnable(bool enable) { |
| 110 | + if (!wireInitialized) { |
| 111 | + WireInternal.begin(SDA, SCL); |
| 112 | + wireInitialized = true; |
| 113 | + } |
| 114 | + // bit 3 set charge enable |
| 115 | + writeBitRegister(AW32001_I2C_ADDR, AW3200_POWER_ON_CFG, 3, !enable); |
| 116 | +} |
| 117 | + |
| 118 | +void NessoBattery::setBatUVLO(UnderVoltageLockout uvlo) { |
| 119 | + if (!wireInitialized) { |
| 120 | + WireInternal.begin(SDA, SCL); |
| 121 | + wireInitialized = true; |
| 122 | + } |
| 123 | + uint8_t reg_value = readRegister(AW32001_I2C_ADDR, AW3200_POWER_ON_CFG); |
| 124 | + // bits 2-0 set UVLO |
| 125 | + reg_value &= ~0b00000111; |
| 126 | + reg_value |= (uvlo & 0b00000111); |
| 127 | + writeRegister(AW32001_I2C_ADDR, AW3200_POWER_ON_CFG, reg_value); |
| 128 | +} |
| 129 | + |
| 130 | +void NessoBattery::setChargeCurrent(uint16_t current) { |
| 131 | + if (!wireInitialized) { |
| 132 | + WireInternal.begin(SDA, SCL); |
| 133 | + wireInitialized = true; |
| 134 | + } |
| 135 | + if (current < 8) { |
| 136 | + current = 8; |
| 137 | + } |
| 138 | + if (current > 456) { |
| 139 | + current = 456; |
| 140 | + } |
| 141 | + uint8_t reg_value = readRegister(AW32001_I2C_ADDR, AW3200_CHG_CURRENT); |
| 142 | + // bits 5-0 set charge current |
| 143 | + reg_value &= ~0b00111111; |
| 144 | + reg_value |= ((current - 8) / 8) & 0b00111111; |
| 145 | + writeRegister(AW32001_I2C_ADDR, AW3200_CHG_CURRENT, reg_value); |
| 146 | +} |
| 147 | + |
| 148 | +void NessoBattery::setDischargeCurrent(uint16_t current) { |
| 149 | + if (!wireInitialized) { |
| 150 | + WireInternal.begin(SDA, SCL); |
| 151 | + wireInitialized = true; |
| 152 | + } |
| 153 | + if (current < 200) { |
| 154 | + current = 200; |
| 155 | + } |
| 156 | + if (current > 3200) { |
| 157 | + current = 3200; |
| 158 | + } |
| 159 | + uint8_t reg_value = readRegister(AW32001_I2C_ADDR, AW3200_TERM_CURRENT); |
| 160 | + // bits 7-4 set discharge current |
| 161 | + reg_value &= ~0b11110000; |
| 162 | + reg_value |= (((current - 200) / 200) & 0b00001111) << 4; |
| 163 | + writeRegister(AW32001_I2C_ADDR, AW3200_TERM_CURRENT, reg_value); |
| 164 | +} |
| 165 | + |
| 166 | +void NessoBattery::setChargeVoltage(uint16_t voltage) { |
| 167 | + if (!wireInitialized) { |
| 168 | + WireInternal.begin(SDA, SCL); |
| 169 | + wireInitialized = true; |
| 170 | + } |
| 171 | + if (voltage < 3600) { |
| 172 | + voltage = 3600; |
| 173 | + } |
| 174 | + if (voltage > 4545) { |
| 175 | + voltage = 4545; |
| 176 | + } |
| 177 | + uint8_t reg_value = readRegister(AW32001_I2C_ADDR, AW3200_CHG_VOLTAGE); |
| 178 | + // bits 7-2 set charge voltage |
| 179 | + reg_value &= ~0b11111100; |
| 180 | + reg_value |= ((voltage - 3600) / 15) << 2; |
| 181 | + writeRegister(AW32001_I2C_ADDR, AW3200_CHG_VOLTAGE, reg_value); |
| 182 | +} |
| 183 | + |
| 184 | +void NessoBattery::setWatchdogTimer(uint8_t sec) { |
| 185 | + if (!wireInitialized) { |
| 186 | + WireInternal.begin(SDA, SCL); |
| 187 | + wireInitialized = true; |
| 188 | + } |
| 189 | + |
| 190 | + uint8_t reg_value = readRegister(AW32001_I2C_ADDR, AW3200_TIMER_WD); |
| 191 | + uint8_t bits = 0; |
| 192 | + switch (sec) { |
| 193 | + case 0: |
| 194 | + bits = 0b00; // disable watchdog |
| 195 | + break; |
| 196 | + case 40: bits = 0b01; break; |
| 197 | + case 80: bits = 0b10; break; |
| 198 | + case 160: bits = 0b11; break; |
| 199 | + default: bits = 0b11; break; |
| 200 | + } |
| 201 | + // bits 6-5 set watchdog timer |
| 202 | + reg_value &= ~(0b11 << 5); |
| 203 | + reg_value |= (bits << 5); |
| 204 | + writeRegister(AW32001_I2C_ADDR, AW3200_TIMER_WD, reg_value); |
| 205 | +} |
| 206 | + |
| 207 | +void NessoBattery::feedWatchdog() { |
| 208 | + if (!wireInitialized) { |
| 209 | + WireInternal.begin(SDA, SCL); |
| 210 | + wireInitialized = true; |
| 211 | + } |
| 212 | + // bit 6 set feed watchdog |
| 213 | + writeBitRegister(AW32001_I2C_ADDR, AW3200_CHG_CURRENT, 6, true); |
| 214 | +} |
| 215 | + |
| 216 | +void NessoBattery::setShipMode(bool en) { |
| 217 | + if (!wireInitialized) { |
| 218 | + WireInternal.begin(SDA, SCL); |
| 219 | + wireInitialized = true; |
| 220 | + } |
| 221 | + // bit 5 set ship mode |
| 222 | + writeBitRegister(AW32001_I2C_ADDR, AW3200_MAIN_CTRL, 5, en); |
| 223 | +} |
| 224 | + |
| 225 | +NessoBattery::ChargeStatus NessoBattery::getChargeStatus() { |
| 226 | + if (!wireInitialized) { |
| 227 | + WireInternal.begin(SDA, SCL); |
| 228 | + wireInitialized = true; |
| 229 | + } |
| 230 | + uint8_t status = readRegister(AW32001_I2C_ADDR, AW3200_SYS_STATUS); |
| 231 | + // bits 4-3 set charge status |
| 232 | + uint8_t charge_status = (status >> 3) & 0b11; |
| 233 | + return static_cast<ChargeStatus>(charge_status); |
| 234 | +} |
| 235 | + |
| 236 | +void NessoBattery::setHiZ(bool enable) { |
91 | 237 | if (!wireInitialized) { |
92 | 238 | WireInternal.begin(SDA, SCL); |
93 | 239 | wireInitialized = true; |
94 | 240 | } |
95 | | - writeBitRegister(0x49, 0x1, 3, false); |
| 241 | + // bit 4 set Hi-Z mode |
| 242 | + writeBitRegister(AW32001_I2C_ADDR, AW3200_POWER_ON_CFG, 4, enable); |
96 | 243 | } |
97 | 244 |
|
98 | 245 | float NessoBattery::getVoltage() { |
99 | | - // BQ27220 - address 0x55 |
100 | 246 | if (!wireInitialized) { |
101 | 247 | WireInternal.begin(SDA, SCL); |
102 | 248 | wireInitialized = true; |
103 | 249 | } |
104 | | - uint16_t voltage = (readRegister(0x55, 0x9) << 8) | readRegister(0x55, 0x8); |
| 250 | + uint16_t voltage = (readRegister(BQ27220_I2C_ADDR, BQ27220_VOLTAGE + 1) << 8) | readRegister(BQ27220_I2C_ADDR, BQ27220_VOLTAGE); |
105 | 251 | return (float)voltage / 1000.0f; |
106 | 252 | } |
107 | 253 |
|
| 254 | +float NessoBattery::getCurrent() { |
| 255 | + if (!wireInitialized) { |
| 256 | + WireInternal.begin(SDA, SCL); |
| 257 | + wireInitialized = true; |
| 258 | + } |
| 259 | + int16_t current = (readRegister(BQ27220_I2C_ADDR, BQ27220_CURRENT + 1) << 8) | readRegister(BQ27220_I2C_ADDR, BQ27220_CURRENT); |
| 260 | + return (float)current / 1000.0f; |
| 261 | +} |
| 262 | + |
108 | 263 | uint16_t NessoBattery::getChargeLevel() { |
109 | | - // BQ27220 - address 0x55 |
110 | 264 | if (!wireInitialized) { |
111 | 265 | WireInternal.begin(SDA, SCL); |
112 | 266 | wireInitialized = true; |
113 | 267 | } |
114 | | - uint16_t current_capacity = readRegister(0x55, 0x11) << 8 | readRegister(0x55, 0x10); |
115 | | - uint16_t total_capacity = readRegister(0x55, 0x13) << 8 | readRegister(0x55, 0x12); |
| 268 | + uint16_t current_capacity = readRegister(BQ27220_I2C_ADDR, BQ27220_REMAIN_CAPACITY + 1) << 8 | readRegister(BQ27220_I2C_ADDR, BQ27220_REMAIN_CAPACITY); |
| 269 | + uint16_t total_capacity = readRegister(BQ27220_I2C_ADDR, BQ27220_FULL_CAPACITY + 1) << 8 | readRegister(BQ27220_I2C_ADDR, BQ27220_FULL_CAPACITY); |
116 | 270 | return (current_capacity * 100) / total_capacity; |
117 | 271 | } |
118 | 272 |
|
| 273 | +uint16_t NessoBattery::getAvgPower() { |
| 274 | + if (!wireInitialized) { |
| 275 | + WireInternal.begin(SDA, SCL); |
| 276 | + wireInitialized = true; |
| 277 | + } |
| 278 | + uint16_t avg_power = readRegister(BQ27220_I2C_ADDR, BQ27220_AVG_POWER + 1) << 8 | readRegister(BQ27220_I2C_ADDR, BQ27220_AVG_POWER); |
| 279 | + return avg_power; |
| 280 | +} |
| 281 | + |
| 282 | +float NessoBattery::getTemperature() { |
| 283 | + if (!wireInitialized) { |
| 284 | + WireInternal.begin(SDA, SCL); |
| 285 | + wireInitialized = true; |
| 286 | + } |
| 287 | + uint16_t temp = readRegister(BQ27220_I2C_ADDR, BQ27220_TEMPERATURE + 1) << 8 | readRegister(BQ27220_I2C_ADDR, BQ27220_TEMPERATURE); |
| 288 | + return ((float)temp / 10.0f) - 273.15f; |
| 289 | +} |
| 290 | + |
| 291 | +uint16_t NessoBattery::getCycleCount() { |
| 292 | + if (!wireInitialized) { |
| 293 | + WireInternal.begin(SDA, SCL); |
| 294 | + wireInitialized = true; |
| 295 | + } |
| 296 | + uint16_t cycle_count = readRegister(BQ27220_I2C_ADDR, BQ27220_CYCLE_COUNT + 1) << 8 | readRegister(BQ27220_I2C_ADDR, BQ27220_CYCLE_COUNT); |
| 297 | + return cycle_count; |
| 298 | +} |
| 299 | + |
119 | 300 | ExpanderPin LORA_LNA_ENABLE(5); |
120 | 301 | ExpanderPin LORA_ANTENNA_SWITCH(6); |
121 | 302 | ExpanderPin LORA_ENABLE(7); |
|
0 commit comments