Power.h
  1  // Copyright (C) 2024, Mark Qvist
  2  
  3  // This program is free software: you can redistribute it and/or modify
  4  // it under the terms of the GNU General Public License as published by
  5  // the Free Software Foundation, either version 3 of the License, or
  6  // (at your option) any later version.
  7  
  8  // This program is distributed in the hope that it will be useful,
  9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11  // GNU General Public License for more details.
 12  
 13  // You should have received a copy of the GNU General Public License
 14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 15  
 16  #define PMU_TEMP_MIN -30
 17  #define PMU_TEMP_MAX 90
 18  #define PMU_TEMP_OFFSET 120
 19  bool pmu_temp_sensor_ready = false;
 20  float pmu_temperature = PMU_TEMP_MIN-1;
 21  
 22  #if BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1
 23    #include <XPowersLib.h>
 24    XPowersLibInterface* PMU = NULL;
 25  
 26    #ifndef PMU_WIRE_PORT
 27      #if BOARD_MODEL == BOARD_TBEAM_S_V1
 28        #define PMU_WIRE_PORT   Wire1
 29      #else
 30        #define PMU_WIRE_PORT   Wire
 31      #endif
 32    #endif
 33  
 34    #define BAT_V_MIN       3.15
 35    #define BAT_V_MAX       4.14
 36  
 37    void disablePeripherals() {
 38      if (PMU) {
 39        // GNSS RTC PowerVDD
 40        PMU->enablePowerOutput(XPOWERS_VBACKUP);
 41  
 42        // LoRa VDD
 43        PMU->disablePowerOutput(XPOWERS_ALDO2);
 44  
 45        // GNSS VDD
 46        PMU->disablePowerOutput(XPOWERS_ALDO3);
 47      }
 48    }
 49  
 50    bool pmuInterrupt;
 51    void setPmuFlag()
 52    {
 53        pmuInterrupt = true;
 54    }
 55  #elif BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1
 56    #define BAT_V_MIN       3.15
 57    #define BAT_V_MAX       4.3
 58    #define BAT_V_CHG       4.48
 59    #define BAT_V_FLOAT     4.33
 60    #define BAT_SAMPLES     5
 61    const uint8_t pin_vbat = 35;
 62    float bat_p_samples[BAT_SAMPLES];
 63    float bat_v_samples[BAT_SAMPLES];
 64    uint8_t bat_samples_count = 0;
 65    int bat_discharging_samples = 0;
 66    int bat_charging_samples = 0;
 67    int bat_charged_samples = 0;
 68    bool bat_voltage_dropping = false;
 69    float bat_delay_v = 0;
 70    float bat_state_change_v = 0;
 71  #elif BOARD_MODEL == BOARD_T3S3
 72    #define BAT_V_MIN       3.15
 73    #define BAT_V_MAX       4.217
 74    #define BAT_V_CHG       4.48
 75    #define BAT_V_FLOAT     4.33
 76    #define BAT_SAMPLES     5
 77    const uint8_t pin_vbat = 1;
 78    float bat_p_samples[BAT_SAMPLES];
 79    float bat_v_samples[BAT_SAMPLES];
 80    uint8_t bat_samples_count = 0;
 81    int bat_discharging_samples = 0;
 82    int bat_charging_samples = 0;
 83    int bat_charged_samples = 0;
 84    bool bat_voltage_dropping = false;
 85    float bat_delay_v = 0;
 86    float bat_state_change_v = 0;
 87  #elif BOARD_MODEL == BOARD_TDECK
 88    #define BAT_V_MIN       3.15
 89    #define BAT_V_MAX       4.3
 90    #define BAT_V_CHG       4.48
 91    #define BAT_V_FLOAT     4.33
 92    #define BAT_SAMPLES     5
 93    const uint8_t pin_vbat = 4;
 94    float bat_p_samples[BAT_SAMPLES];
 95    float bat_v_samples[BAT_SAMPLES];
 96    uint8_t bat_samples_count = 0;
 97    int bat_discharging_samples = 0;
 98    int bat_charging_samples = 0;
 99    int bat_charged_samples = 0;
100    bool bat_voltage_dropping = false;
101    float bat_delay_v = 0;
102    float bat_state_change_v = 0;
103  #elif BOARD_MODEL == BOARD_HELTEC32_V3
104    // Unless we implement some real voodoo
105    // on these boards, we can't say with
106    // any certainty whether we are actually
107    // charging and have reached a charge
108    // complete state. The *only* data point
109    // we have to go from is the bus voltage.
110    // The BAT_V_CHG and BAT_V_FLOAT values
111    // are set high here to avoid the display
112    // indication confusingly flapping
113    // between charge completed, charging and
114    // discharging states.
115    // Update: Vodoo implemented. Hopefully
116    // it will work accross different boards.
117    #define BAT_V_MIN       3.05
118    #define BAT_V_MAX       4.0
119    #define BAT_V_CHG       4.48
120    #define BAT_V_FLOAT     4.33
121    #define BAT_SAMPLES     7
122    const uint8_t pin_vbat = 1;
123    const uint8_t pin_ctrl = 37;
124    float bat_p_samples[BAT_SAMPLES];
125    float bat_v_samples[BAT_SAMPLES];
126    uint8_t bat_samples_count = 0;
127    int bat_discharging_samples = 0;
128    int bat_charging_samples = 0;
129    int bat_charged_samples = 0;
130    bool bat_voltage_dropping = false;
131    float bat_delay_v = 0;
132    float bat_state_change_v = 0;
133  #elif BOARD_MODEL == BOARD_HELTEC32_V4
134    #define BAT_V_MIN       3.05
135    #define BAT_V_MAX       4.0
136    #define BAT_V_CHG       4.48
137    #define BAT_V_FLOAT     4.33
138    #define BAT_SAMPLES     7
139    const uint8_t pin_vbat = 1;
140    const uint8_t pin_ctrl = 37;
141    float bat_p_samples[BAT_SAMPLES];
142    float bat_v_samples[BAT_SAMPLES];
143    uint8_t bat_samples_count = 0;
144    int bat_discharging_samples = 0;
145    int bat_charging_samples = 0;
146    int bat_charged_samples = 0;
147    bool bat_voltage_dropping = false;
148    float bat_delay_v = 0;
149    float bat_state_change_v = 0;
150  #elif BOARD_MODEL == BOARD_HELTEC_T114
151    #define BAT_V_MIN       3.15
152    #define BAT_V_MAX       4.165
153    #define BAT_V_CHG       4.48
154    #define BAT_V_FLOAT     4.33
155    #define BAT_SAMPLES     7
156    const uint8_t pin_vbat = 4;
157    const uint8_t pin_ctrl = 6;
158    float bat_p_samples[BAT_SAMPLES];
159    float bat_v_samples[BAT_SAMPLES];
160    uint8_t bat_samples_count = 0;
161    int bat_discharging_samples = 0;
162    int bat_charging_samples = 0;
163    int bat_charged_samples = 0;
164    bool bat_voltage_dropping = false;
165    float bat_delay_v = 0;
166    float bat_state_change_v = 0;
167  #elif BOARD_MODEL == BOARD_TECHO
168    #define BAT_V_MIN       3.15
169    #define BAT_V_MAX       4.16
170    #define BAT_V_CHG       4.48
171    #define BAT_V_FLOAT     4.33
172    #define BAT_SAMPLES     7
173    const uint8_t pin_vbat = 4;
174    float bat_p_samples[BAT_SAMPLES];
175    float bat_v_samples[BAT_SAMPLES];
176    uint8_t bat_samples_count = 0;
177    int bat_discharging_samples = 0;
178    int bat_charging_samples = 0;
179    int bat_charged_samples = 0;
180    bool bat_voltage_dropping = false;
181    float bat_delay_v = 0;
182    float bat_state_change_v = 0;
183  #endif
184  
185  uint32_t last_pmu_update = 0;
186  // Battery/temp sampling interval (ms); lower rate saves a little CPU/ADC without affecting radio.
187  #define PMU_UPDATE_INTERVAL_MS 2000
188  int pmu_update_interval = PMU_UPDATE_INTERVAL_MS;
189  uint8_t pmu_charged_ascertain = 0;
190  uint8_t pmu_rc = 0;
191  uint8_t pmu_sc = 0;
192  float bat_delay_diff = 0;
193  bool bat_diff_positive = false;
194  #define PMU_R_INTERVAL 5
195  #define PMU_SCV_RESET_INTERVAL 3
196  void kiss_indicate_battery();
197  void kiss_indicate_temperature();
198  
199  void measure_temperature() {
200    #if PLATFORM == PLATFORM_ESP32
201      if (pmu_temp_sensor_ready) { pmu_temperature = temperatureRead(); } else { pmu_temperature = PMU_TEMP_MIN-1; }
202    #endif
203  }
204  
205  void measure_battery() {
206    #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC_T114 || BOARD_MODEL == BOARD_TECHO
207      battery_installed = true;
208      #if BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4
209        battery_indeterminate = false;
210      #else
211        battery_indeterminate = true;
212      #endif
213  
214      #if BOARD_MODEL == BOARD_HELTEC32_V3
215        float battery_measurement = (float)(analogRead(pin_vbat)) * 0.0041;
216      #elif BOARD_MODEL == BOARD_HELTEC32_V4
217        float battery_measurement = (float)(analogRead(pin_vbat)) * 0.00418;
218      #elif BOARD_MODEL == BOARD_T3S3
219        float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*6.7828;
220      #elif BOARD_MODEL == BOARD_HELTEC_T114
221        float battery_measurement = (float)(analogRead(pin_vbat)) * 0.017165;
222      #elif BOARD_MODEL == BOARD_TECHO
223        float battery_measurement = (float)(analogRead(pin_vbat)) * 0.007067;
224      #else
225        float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*7.26;
226      #endif
227  
228      bat_v_samples[bat_samples_count%BAT_SAMPLES] = battery_measurement;
229      bat_p_samples[bat_samples_count%BAT_SAMPLES] = ((battery_voltage-BAT_V_MIN) / (BAT_V_MAX-BAT_V_MIN))*100.0;
230      
231      bat_samples_count++;
232      if (!battery_ready && bat_samples_count >= BAT_SAMPLES) {
233        battery_ready = true;
234      }
235  
236      if (battery_ready) {
237  
238        battery_percent = 0;
239        for (uint8_t bi = 0; bi < BAT_SAMPLES; bi++) {
240          battery_percent += bat_p_samples[bi];
241        }
242        battery_percent = battery_percent/BAT_SAMPLES;
243        
244        battery_voltage = 0;
245        for (uint8_t bi = 0; bi < BAT_SAMPLES; bi++) {
246          battery_voltage += bat_v_samples[bi];
247        }
248        battery_voltage = battery_voltage/BAT_SAMPLES;
249        
250        if (bat_delay_v == 0) bat_delay_v = battery_voltage;
251        if (bat_state_change_v == 0) bat_state_change_v = battery_voltage;
252        if (battery_percent > 100.0) battery_percent = 100.0;
253        if (battery_percent < 0.0) battery_percent = 0.0;
254  
255        if (bat_samples_count%BAT_SAMPLES == 0) {
256          pmu_sc++;
257          bat_delay_diff = battery_voltage-bat_state_change_v;
258  
259          if (battery_voltage < bat_delay_v && battery_voltage < BAT_V_FLOAT) {
260            if (bat_voltage_dropping == false) {
261              if (bat_delay_diff < -0.008) {
262                bat_voltage_dropping = true;
263                bat_state_change_v = battery_voltage;
264              }
265            } else {
266              if (pmu_sc%PMU_SCV_RESET_INTERVAL == 0) { bat_state_change_v = battery_voltage; }
267            }
268          } else {
269            if (bat_voltage_dropping == true) {
270              if (bat_delay_diff > 0.01) {
271                bat_voltage_dropping = false;
272                bat_state_change_v = battery_voltage;
273              }
274            }
275          }
276          bat_samples_count = 0;
277          bat_delay_v = battery_voltage;
278        }
279  
280        if (bat_voltage_dropping && battery_voltage < BAT_V_FLOAT) {
281          // if (battery_state != BATTERY_STATE_DISCHARGING) { SerialBT.printf("STATE CHANGE to DISCHARGING at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); }
282          battery_state = BATTERY_STATE_DISCHARGING;
283          pmu_charged_ascertain = 0;
284        } else {
285          if (pmu_charged_ascertain < 8) { pmu_charged_ascertain++; }
286          else {
287            if (battery_percent < 100.0) {
288              // if (battery_state != BATTERY_STATE_CHARGING) { SerialBT.printf("STATE CHANGE to CHARGING at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); }
289              battery_state = BATTERY_STATE_CHARGING;
290            } else {
291              // if (battery_state != BATTERY_STATE_CHARGED) { SerialBT.printf("STATE CHANGE to CHARGED at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); }
292              battery_state = BATTERY_STATE_CHARGED;
293            }
294          }
295        }
296  
297        #if MCU_VARIANT == MCU_NRF52
298          if (bt_state != BT_STATE_OFF) { blebas.write(battery_percent); }
299        #endif
300  
301        // if (bt_state == BT_STATE_CONNECTED) {
302        //   SerialBT.printf("\nBus voltage %.3fv. Unfiltered %.3fv. Diff %.3f", battery_voltage, bat_v_samples[BAT_SAMPLES-1], bat_delay_diff);
303        //   if (bat_voltage_dropping) { SerialBT.printf("\n Voltage is dropping. Percentage %.1f%%.", battery_percent); }
304        //   else                      { SerialBT.printf("\n Voltage is not dropping. Percentage %.1f%%.", battery_percent); }
305        //   if (battery_state == BATTERY_STATE_DISCHARGING) { SerialBT.printf("\n Battery discharging. delay_v %.3fv\nState change at %.3fv", bat_delay_v, bat_state_change_v); }
306        //   if (battery_state == BATTERY_STATE_CHARGING) { SerialBT.printf("\n Battery charging. delay_v %.3fv\nState change at %.3fv", bat_delay_v, bat_state_change_v); }
307        //   if (battery_state == BATTERY_STATE_CHARGED) { SerialBT.print("\n Battery is charged."); }
308        //   SerialBT.print("\n");
309        // }
310      }
311  
312    #elif BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1
313      if (PMU) {
314        float discharge_current = 0;
315        float charge_current    = 0;
316        float ext_voltage       = 0;
317        float ext_current       = 0;
318        if (PMU->getChipModel() == XPOWERS_AXP192) {
319          discharge_current       = ((XPowersAXP192*)PMU)->getBattDischargeCurrent();
320          charge_current          = ((XPowersAXP192*)PMU)->getBatteryChargeCurrent();
321          battery_voltage         = PMU->getBattVoltage()/1000.0;
322          // battery_percent         = PMU->getBattPercentage()*1.0;
323          battery_installed       = PMU->isBatteryConnect();
324          external_power          = PMU->isVbusIn();
325          ext_voltage             = PMU->getVbusVoltage()/1000.0;
326          ext_current             = ((XPowersAXP192*)PMU)->getVbusCurrent();
327        }
328        else if (PMU->getChipModel() == XPOWERS_AXP2101) {
329          battery_voltage         = PMU->getBattVoltage()/1000.0;
330          // battery_percent         = PMU->getBattPercentage()*1.0;
331          battery_installed       = PMU->isBatteryConnect();
332          external_power          = PMU->isVbusIn();
333          ext_voltage             = PMU->getVbusVoltage()/1000.0;
334        }
335  
336        if (battery_installed) {
337          if (PMU->isCharging()) {
338            battery_state = BATTERY_STATE_CHARGING;
339            battery_percent = ((battery_voltage-BAT_V_MIN) / (BAT_V_MAX-BAT_V_MIN))*100.0;
340          } else {
341            if (PMU->isDischarge()) {
342              battery_state = BATTERY_STATE_DISCHARGING;
343              battery_percent = ((battery_voltage-BAT_V_MIN) / (BAT_V_MAX-BAT_V_MIN))*100.0;
344            } else {
345              battery_state = BATTERY_STATE_CHARGED;
346              battery_percent = 100.0;
347            }
348          }
349        } else {
350          battery_state = BATTERY_STATE_UNKNOWN;
351          battery_percent = 0.0;
352          battery_voltage = 0.0;
353        }
354  
355        if (battery_percent > 100.0) battery_percent = 100.0;
356        if (battery_percent < 0.0) battery_percent = 0.0;
357  
358        float charge_watts    = battery_voltage*(charge_current/1000.0);
359        float discharge_watts = battery_voltage*(discharge_current/1000.0);
360        float ext_watts       = ext_voltage*(ext_current/1000.0);
361  
362        battery_ready = true;
363  
364        // if (bt_state == BT_STATE_CONNECTED) {
365        //   if (battery_installed) {
366        //     if (external_power) {
367        //       SerialBT.printf("External power connected, drawing %.2fw, %.1fmA at %.1fV\n", ext_watts, ext_current, ext_voltage);
368        //     } else {
369        //       SerialBT.println("Running on battery");
370        //     }
371        //     SerialBT.printf("Battery percentage %.1f%%\n", battery_percent);
372        //     SerialBT.printf("Battery voltage %.2fv\n", battery_voltage);
373        //     // SerialBT.printf("Temperature %.1f%\n", auxillary_temperature);
374  
375        //     if (battery_state == BATTERY_STATE_CHARGING) {
376        //       SerialBT.printf("Charging with %.2fw, %.1fmA at %.1fV\n", charge_watts, charge_current, battery_voltage);
377        //     } else if (battery_state == BATTERY_STATE_DISCHARGING) {
378        //       SerialBT.printf("Discharging at %.2fw, %.1fmA at %.1fV\n", discharge_watts, discharge_current, battery_voltage);
379        //     } else if (battery_state == BATTERY_STATE_CHARGED) {
380        //       SerialBT.printf("Battery charged\n");
381        //     }
382        //   } else {
383        //     SerialBT.println("No battery installed");
384        //   }
385        //   SerialBT.println("");
386        // }
387      }
388      else {
389        battery_ready = false;
390      }
391    #endif
392  
393    if (battery_ready) {
394      pmu_rc++;
395      if (pmu_rc%PMU_R_INTERVAL == 0) {
396        kiss_indicate_battery();
397        if (pmu_temp_sensor_ready) { kiss_indicate_temperature(); }
398      }
399    }
400  }
401  
402  void update_pmu() {
403    if (millis()-last_pmu_update >= pmu_update_interval) {
404      measure_battery();
405      measure_temperature();
406      last_pmu_update = millis();
407    }
408  }
409  
410  bool init_pmu() {
411    #if IS_ESP32S3
412      pmu_temp_sensor_ready = true;
413    #endif
414  
415    #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_TECHO
416      pinMode(pin_vbat, INPUT);
417      return true;
418    #elif BOARD_MODEL == BOARD_HELTEC32_V3
419      // there are three version of V3: V3, V3.1, and V3.2
420      // V3 and V3.1 have a pull up on pin_ctrl and are active low
421      // V3.2 has a transistor and active high
422      // put the pin input mode and read it.  if it's high, we have V3 or V3.1
423      // other wise, it's a V3.2
424      uint16_t pin_ctrl_value;
425      uint8_t pin_ctrl_active = LOW;
426      pinMode(pin_ctrl, INPUT);
427      pin_ctrl_value = digitalRead(pin_ctrl);
428      if(pin_ctrl_value == HIGH) {
429        // We have either a V3 or V3.1
430        pin_ctrl_active = LOW;
431      }
432      else {
433        // We have a V3.2
434        pin_ctrl_active = HIGH;
435      }
436      pinMode(pin_ctrl,OUTPUT);
437      digitalWrite(pin_ctrl, pin_ctrl_active);
438      return true;
439    #elif BOARD_MODEL == BOARD_HELTEC32_V4
440      pinMode(pin_ctrl,OUTPUT);
441      digitalWrite(pin_ctrl, HIGH);
442      return true;
443    #elif BOARD_MODEL == BOARD_HELTEC_T114
444      pinMode(pin_ctrl,OUTPUT);
445      digitalWrite(pin_ctrl, HIGH);
446      return true;
447    #elif BOARD_MODEL == BOARD_TBEAM
448      Wire.begin(I2C_SDA, I2C_SCL);
449  
450      if (!PMU) {
451          PMU = new XPowersAXP2101(PMU_WIRE_PORT);
452          if (!PMU->init()) {
453              delete PMU;
454              PMU = NULL;
455          }
456      }
457  
458      if (!PMU) {
459          PMU = new XPowersAXP192(PMU_WIRE_PORT);
460          if (!PMU->init()) {
461              delete PMU;
462              PMU = NULL;
463          }
464      }
465  
466      if (!PMU) {
467          return false;
468      }
469  
470      // Configure charging indicator
471      PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
472  
473      pinMode(PMU_IRQ, INPUT_PULLUP);
474      attachInterrupt(PMU_IRQ, setPmuFlag, FALLING);
475  
476      if (PMU->getChipModel() == XPOWERS_AXP192) {
477  
478        // Turn off unused power sources to save power
479        PMU->disablePowerOutput(XPOWERS_DCDC1);
480        PMU->disablePowerOutput(XPOWERS_DCDC2);
481        PMU->disablePowerOutput(XPOWERS_LDO2);
482        PMU->disablePowerOutput(XPOWERS_LDO3);
483  
484        // Set the power of LoRa and GPS module to 3.3V
485        // LoRa
486        PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
487        // GPS
488        PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
489        // OLED
490        PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
491  
492        // Turn on LoRa
493        PMU->enablePowerOutput(XPOWERS_LDO2);
494  
495        // Turn on GPS
496        //PMU->enablePowerOutput(XPOWERS_LDO3);
497  
498        // protected oled power source
499        PMU->setProtectedChannel(XPOWERS_DCDC1);
500        // protected esp32 power source
501        PMU->setProtectedChannel(XPOWERS_DCDC3);
502        // enable oled power
503        PMU->enablePowerOutput(XPOWERS_DCDC1);
504  
505        PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
506  
507        PMU->enableIRQ(XPOWERS_AXP192_VBUS_REMOVE_IRQ |
508                        XPOWERS_AXP192_VBUS_INSERT_IRQ |
509                        XPOWERS_AXP192_BAT_CHG_DONE_IRQ |
510                        XPOWERS_AXP192_BAT_CHG_START_IRQ |
511                        XPOWERS_AXP192_BAT_REMOVE_IRQ |
512                        XPOWERS_AXP192_BAT_INSERT_IRQ |
513                        XPOWERS_AXP192_PKEY_SHORT_IRQ
514                      );
515  
516      }
517      else if (PMU->getChipModel() == XPOWERS_AXP2101) {
518  
519        // Turn off unused power sources to save power
520        PMU->disablePowerOutput(XPOWERS_DCDC2);
521        PMU->disablePowerOutput(XPOWERS_DCDC3);
522        PMU->disablePowerOutput(XPOWERS_DCDC4);
523        PMU->disablePowerOutput(XPOWERS_DCDC5);
524        PMU->disablePowerOutput(XPOWERS_ALDO1);
525        PMU->disablePowerOutput(XPOWERS_ALDO2);
526        PMU->disablePowerOutput(XPOWERS_ALDO3);
527        PMU->disablePowerOutput(XPOWERS_ALDO4);
528        PMU->disablePowerOutput(XPOWERS_BLDO1);
529        PMU->disablePowerOutput(XPOWERS_BLDO2);
530        PMU->disablePowerOutput(XPOWERS_DLDO1);
531        PMU->disablePowerOutput(XPOWERS_DLDO2);
532        PMU->disablePowerOutput(XPOWERS_VBACKUP);
533  
534        // Set the power of LoRa and GPS module to 3.3V
535        // LoRa
536        PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
537        // GPS
538        PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
539        PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
540  
541        // ESP32 VDD
542        // ! No need to set, automatically open , Don't close it
543        // PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
544        // PMU->setProtectedChannel(XPOWERS_DCDC1);
545        PMU->setProtectedChannel(XPOWERS_DCDC1);
546  
547        // LoRa VDD
548        PMU->enablePowerOutput(XPOWERS_ALDO2);
549  
550        // GNSS VDD
551        //PMU->enablePowerOutput(XPOWERS_ALDO3);
552  
553        // GNSS RTC PowerVDD
554        //PMU->enablePowerOutput(XPOWERS_VBACKUP);
555      }
556  
557      PMU->enableSystemVoltageMeasure();
558      PMU->enableVbusVoltageMeasure();
559      PMU->enableBattVoltageMeasure();
560      // It is necessary to disable the detection function of the TS pin on the board
561      // without the battery temperature detection function, otherwise it will cause abnormal charging
562      PMU->disableTSPinMeasure();
563  
564      // Set the time of pressing the button to turn off
565      PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
566  
567      return true; 
568    #elif BOARD_MODEL == BOARD_TBEAM_S_V1
569      Wire1.begin(I2C_SDA, I2C_SCL);
570  
571      if (!PMU) {
572          PMU = new XPowersAXP2101(PMU_WIRE_PORT);
573          if (!PMU->init()) {
574              delete PMU;
575              PMU = NULL;
576          }
577      }
578  
579      if (!PMU) {
580        return false;
581      }
582  
583      /**
584       * gnss module power channel
585       * The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during
586       * initialization
587       */
588      PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
589      PMU->enablePowerOutput(XPOWERS_ALDO4);
590  
591      // lora radio power channel
592      PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
593      PMU->enablePowerOutput(XPOWERS_ALDO3);
594  
595      // m.2 interface
596      PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
597      PMU->enablePowerOutput(XPOWERS_DCDC3);
598  
599      /**
600       * ALDO2 cannot be turned off.
601       * It is a necessary condition for sensor communication.
602       * It must be turned on to properly access the sensor and screen
603       * It is also responsible for the power supply of PCF8563
604       */
605      PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
606      PMU->enablePowerOutput(XPOWERS_ALDO2);
607  
608      // 6-axis , magnetometer ,bme280 , oled screen power channel
609      PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
610      PMU->enablePowerOutput(XPOWERS_ALDO1);
611  
612      // sdcard power channle
613      PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
614      PMU->enablePowerOutput(XPOWERS_BLDO1);
615  
616      // PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
617      // PMU->enablePowerOutput(XPOWERS_DCDC4);
618  
619      // not use channel
620      PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited
621      PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited
622      PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist
623      PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist
624      PMU->disablePowerOutput(XPOWERS_VBACKUP);
625  
626      // Configure charging
627      PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
628      PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
629      // TODO: Reset
630      PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
631  
632      // Set the time of pressing the button to turn off
633      PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
634      PMU->setPowerKeyPressOnTime(XPOWERS_POWERON_128MS);
635  
636      // disable all axp chip interrupt
637      PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
638      PMU->clearIrqStatus();
639  
640      // It is necessary to disable the detection function of the TS pin on the board
641      // without the battery temperature detection function, otherwise it will cause abnormal charging
642      PMU->disableTSPinMeasure();
643      PMU->enableVbusVoltageMeasure();
644      PMU->enableBattVoltageMeasure();
645  
646  
647      return true; 
648    #else
649      return false;
650    #endif
651  }