M5Unified
Power_Class.cpp
Go to the documentation of this file.
1 // Copyright (c) M5Stack. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 #include "Power_Class.hpp"
5 
6 #include "../M5Unified.hpp"
7 
8 #if !defined (M5UNIFIED_PC_BUILD)
9 
10 #include <esp_log.h>
11 #include <esp_sleep.h>
12 #include <sdkconfig.h>
13 
14 #include <esp_adc_cal.h>
15 #include <soc/adc_channel.h>
16 
17 #if __has_include (<esp_idf_version.h>)
18  #include <esp_idf_version.h>
19  #if ESP_IDF_VERSION_MAJOR >= 4
20  #define NON_BREAK ;[[fallthrough]];
21  #endif
22 #endif
23 
24 #endif
25 
26 #ifndef NON_BREAK
27 #define NON_BREAK ;
28 #endif
29 
30 namespace m5
31 {
32  static constexpr const uint32_t i2c_freq = 100000;
33 #if defined (CONFIG_IDF_TARGET_ESP32S3)
34  static constexpr int aw9523_i2c_addr = 0x58;
35 
36 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
37  static constexpr int CoreInk_POWER_HOLD_PIN = 12;
38  static constexpr int M5Paper_POWER_HOLD_PIN = 2;
39  static constexpr int TimerCam_POWER_HOLD_PIN = 33;
40  static constexpr int TimerCam_LED_PIN = 2;
41  static constexpr int M5Paper_EXT5V_ENABLE_PIN = 5;
42  static constexpr int StickCPlus2_POWER_HOLD_PIN = 4;
43  static constexpr int StickCPlus2_LED_PIN = 19;
44 #endif
45 
46  bool Power_Class::begin(void)
47  {
48  _pmic = pmic_t::pmic_unknown;
49 
50 #if !defined (M5UNIFIED_PC_BUILD)
51 #if defined (CONFIG_IDF_TARGET_ESP32S3)
52 
54  switch (M5.getBoard())
55  {
56  default:
57  break;
58 
59  case board_t::board_M5StackCoreS3:
60  M5.In_I2C.bitOn(aw9523_i2c_addr, 0x03, 0b10000000, i2c_freq); // SY7088 BOOST_EN
61  _pmic = Power_Class::pmic_t::pmic_axp2101;
62  Axp2101.begin();
63  static constexpr std::uint8_t reg_data_array[] =
64  { 0x90, 0xBF // LDOS ON/OFF control 0
65  , 0x92, 18 -5 // ALDO1 set to 1.8v // for AW88298
66  , 0x93, 33 -5 // ALDO2 set to 3.3v // for ES7210
67  , 0x94, 33 -5 // ALDO3 set to 3.3v // for camera
68  , 0x95, 33 -5 // ALDO3 set to 3.3v // for TF card slot
69  , 0x27, 0x00 // PowerKey Hold=1sec / PowerOff=4sec
70  , 0x69, 0x11 // CHGLED setting
71  , 0x10, 0x30 // PMU common config
72  };
73  Axp2101.writeRegister8Array(reg_data_array, sizeof(reg_data_array));
74  break;
75 
76  case board_t::board_M5Dial:
77  _pwrHoldPin = GPIO_NUM_46;
78  break;
79 
80  case board_t::board_M5Capsule:
81  _pwrHoldPin = GPIO_NUM_46;
82  _batAdc = (adc1_channel_t) ADC1_GPIO6_CHANNEL;
83  _pmic = pmic_t::pmic_adc;
84  _adc_ratio = 2.0f;
85  break;
86 
87  case board_t::board_M5DinMeter:
88  _pwrHoldPin = GPIO_NUM_46;
89  NON_BREAK;
90  case board_t::board_M5Cardputer:
91  _batAdc = (adc1_channel_t) ADC1_GPIO10_CHANNEL;
92  _pmic = pmic_t::pmic_adc;
93  _adc_ratio = 2.0f;
94  break;
95  }
96 
97 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
98 
100  switch (M5.getBoard())
101  {
102  default:
103  break;
104 
105  case board_t::board_M5TimerCam:
106  _pwrHoldPin = TimerCam_POWER_HOLD_PIN;
107  m5gfx::pinMode(TimerCam_POWER_HOLD_PIN, m5gfx::pin_mode_t::output);
108  m5gfx::gpio_hi(TimerCam_POWER_HOLD_PIN);
109  m5gfx::pinMode(TimerCam_LED_PIN, m5gfx::pin_mode_t::output);
110  m5gfx::gpio_lo(TimerCam_LED_PIN); // system LED off
111  _batAdc = (adc1_channel_t) ADC1_GPIO38_CHANNEL;
112  _pmic = pmic_t::pmic_adc;
113  _adc_ratio = 1.513f;
114  break;
115 
116  case board_t::board_M5StackCoreInk:
117  _pwrHoldPin = CoreInk_POWER_HOLD_PIN;
118  _wakeupPin = GPIO_NUM_27; // power button;
119  _rtcIntPin = GPIO_NUM_19;
120  _batAdc = (adc1_channel_t) ADC1_GPIO35_CHANNEL;
121  _pmic = pmic_t::pmic_adc;
122  _adc_ratio = 25.1f / 5.1f;
123  break;
124 
125  case board_t::board_M5Paper:
126  _pwrHoldPin = M5Paper_POWER_HOLD_PIN;
127  m5gfx::pinMode(M5Paper_EXT5V_ENABLE_PIN, m5gfx::pin_mode_t::output);
128  _wakeupPin = GPIO_NUM_36; // touch panel INT;
129  _batAdc = (adc1_channel_t) ADC1_GPIO35_CHANNEL;
130  _pmic = pmic_t::pmic_adc;
131  _adc_ratio = 2.0f;
132  break;
133 
134  case board_t::board_M5Tough:
135  case board_t::board_M5StackCore2:
136  _wakeupPin = GPIO_NUM_39; // touch panel INT;
137  _pmic = Power_Class::pmic_t::pmic_axp192;
138  break;
139 
140  case board_t::board_M5Station:
141  m5gfx::pinMode(GPIO_NUM_12, m5gfx::pin_mode_t::output);
142  _pmic = Power_Class::pmic_t::pmic_axp192;
143  break;
144 
145  case board_t::board_M5StickC:
146  case board_t::board_M5StickCPlus:
147  _rtcIntPin = GPIO_NUM_35;
148  _pmic = Power_Class::pmic_t::pmic_axp192;
149  break;
150 
151  case board_t::board_M5StickCPlus2:
152  _pwrHoldPin = StickCPlus2_POWER_HOLD_PIN;
153  m5gfx::pinMode(StickCPlus2_LED_PIN, m5gfx::pin_mode_t::output);
154  _batAdc = (adc1_channel_t) ADC1_GPIO38_CHANNEL;
155  _pmic = pmic_t::pmic_adc;
156  _adc_ratio = 2.0f;
157  break;
158 
159  case board_t::board_M5Stack:
160  _pmic = pmic_t::pmic_ip5306;
161  Ip5306.begin();
162  {
163  static constexpr std::uint8_t reg_data_array[] =
172  { 0x00, 0b00110001 // reg00h SYS_CTL0
173 
182  , 0x01, 0b00011101 // reg01h SYS_CTL1
183 
189  , 0x02, 0b01101100 // reg02h SYS_CTL2
190 
194  , 0x20, 0b00000000 // reg20h
195 
201  , 0x21, 0b00001001 // reg21h Charger_CTL1 : 200mA ; 4.55V
202 
207  , 0x22, 0b00000010 // reg22h Charger_CTL2 : setChargeVoltage 4.2V + boost 28mV
208 
213  , 0x23, 0b10101110 // reg23h Charger_CTL3 : VIN CC
214 
218  , 0x24, 0b11000001 // reg24h CHG_DIG_CTL0 : setChargeCurrent 150mA
219  };
220  Ip5306.writeRegister8Array(reg_data_array, sizeof(reg_data_array));
221  }
222  break;
223  }
224 
225  if (_pmic == Power_Class::pmic_t::pmic_axp192) {
226  if (!Axp192.begin()) {
227  if (Axp2101.begin()) {
228  _pmic = Power_Class::pmic_t::pmic_axp2101;
229  }
230  }
231  }
232 
233  if (_pmic == Power_Class::pmic_t::pmic_axp192)
234  {
235  static constexpr std::uint8_t reg_data_array[] =
236  { 0x26, 0x6A // reg26h DCDC1 3350mV (ESP32 VDD)
237 
245  , 0x30, 0b00000010 // reg30h VBUS-IPSOUT Pass-Through Management
246 
251  , 0x31, 0b00000100 // reg31h VOFF Shutdown voltage setting ( 3.0V )
252 
260  , 0x32, 0b01000010 // reg32h Enable bat detection
261 
267  , 0x33, 0b11000000 // reg33h Charge control 1 (Charge 4.2V, 100mA)
268 
269  , 0x35, 0xA2 // reg35h Enable RTC BAT charge
270  , 0x36, 0x0C // reg36h 128ms power on, 4s power off
271  , 0x82, 0xFF // reg82h ADC all on
272  , 0x83, 0x80 // reg83h ADC temp on
273  , 0x84, 0x32 // reg84h ADC 25Hz
274  , 0x90, 0x07 // reg90h GPIO0(LDOio0) floating
275  , 0x91, 0xA0 // reg91h GPIO0(LDOio0) 2.8V
276  , 0x98, 0x00 // PWM1 X
277  , 0x99, 0xFF // PWM1 Y1
278  , 0x9A, 0xFF // PWM1 Y1
279 
280 // 2023/06/12 以下の指定は削除。
281 // , 0x12, 0x07 // reg12h enable DCDC1,DCDC3,LDO2 / disable LDO3,DCDC2,EXTEN
282 // 理由:Core2本体リセット操作後、起動時にEXTEN disableとなって外部機器への電源供給が一瞬途切れるため。
283  };
284  Axp192.writeRegister8Array(reg_data_array, sizeof(reg_data_array));
285 
286 
287  switch (M5.getBoard())
288  {
289  case board_t::board_M5StickC:
290  case board_t::board_M5StickCPlus:
291  Axp192.writeRegister8(0x30, 0b10000000); // reg30h VBUS-IPSOUT Pass-Through Management
292  Axp192.setDCDC3(0);
293  Axp192.setLDO3(3000); // LCD power
294  break;
295 
296  case board_t::board_M5StackCore2:
297  Axp192.setLDO2(3300); // LCD + SD peripheral power supply
298  Axp192.setLDO3(0); // VIB_MOTOR STOP
299  Axp192.setGPIO2(false); // SPEAKER STOP
300  Axp192.writeRegister8(0x9A, 255); // PWM 255 (LED OFF)
301  Axp192.writeRegister8(0x92, 0x02); // GPIO1 PWM
302  Axp192.setChargeCurrent(390); // Core2 battery = 390mAh
303  break;
304 
305  case board_t::board_M5Tough:
306  Axp192.setLDO2(3300); // LCD + SD peripheral
307  Axp192.setGPIO2(false); // SPEAKER STOP
308  Axp192.setDCDC3(0);
309  break;
310 
311  case board_t::board_M5Station:
312  {
313  static constexpr std::uint8_t reg92h_96h[] =
314  { 0x00 // GPIO1 NMOS OpenDrain
315  , 0x00 // GPIO2 NMOS OpenDrain
316  , 0x00 // GPIO0~2 low
317  , 0x05 // GPIO3 NMOS OpenDrain, GPIO4 NMOS OpenDrain
318  , 0x00 // GPIO3 low, GPIO4 low
319  };
320  Axp192.writeRegister(0x92, reg92h_96h, sizeof(reg92h_96h));
321  }
322  break;
323 
324  default:
325  break;
326  }
327  }
328  else if (_pmic == Power_Class::pmic_t::pmic_axp2101)
329  {
330  // for Core2 v1.1
331  static constexpr std::uint8_t reg_data_array[] =
332  { 0x27, 0x00 // PowerKey Hold=1sec / PowerOff=4sec
333  , 0x10, 0x30 // PMU common config (internal off-discharge enable)
334  , 0x12, 0x00 // BATFET disable
335  , 0x68, 0x01 // Battery detection enabled.
336  , 0x69, 0x13 // CHGLED setting
337  , 0x99, 0x00 // DLDO1 set 0.5v (vibration motor)
338  // , 0x18, 0x0E
339  };
340  Axp2101.writeRegister8Array(reg_data_array, sizeof(reg_data_array));
341 
342  // for Core2 v1.1 (AXP2101+INA3221)
343  if (Ina3221.begin())
344  {}
345  }
346 
347 
348 #endif
349 
350  if (_pwrHoldPin < GPIO_NUM_MAX)
351  {
352  gpio_hold_en( (gpio_num_t)_pwrHoldPin );
353  }
354 #endif
355  return (_pmic != pmic_t::pmic_unknown);
356  }
357 
358 #if defined (CONFIG_IDF_TARGET_ESP32S3)
359 
360  static constexpr const uint32_t _core_s3_bus_en = 0b00000010; // BUS EN
361  static constexpr const uint32_t _core_s3_usb_en = 0b00100000; // USB OTG EN
362  static void _core_s3_output(uint8_t mask, bool enable)
363  {
364  static constexpr const uint8_t port0_reg = 0x02;
365  //static constexpr const uint8_t port1_reg = 0x03;
366  static constexpr const uint32_t port1_bitmask_boost = 0b10000000; // BOOST_EN
367 
368  uint8_t buf[2];
369 
370  if (M5.In_I2C.readRegister(aw9523_i2c_addr, port0_reg, buf, sizeof(buf), i2c_freq))
371  {
372  uint8_t p0 = buf[0] | mask;
373  uint8_t p1 = buf[1] | port1_bitmask_boost;
374 
375  if (!enable) {
376  p0 = buf[0] & ~mask;
377  // if (0 == (p0 & (_core_s3_bus_en | _core_s3_usb_en))) // 両方が無効の場合のみ BOOST_EN を無効化する
378  if (0 == (p0 & _core_s3_bus_en))
379  {
380  p1 &= ~port1_bitmask_boost;
381  }
382  }
383 // M5.Display.printf("%02x %02x\n", p0, p1);
384  buf[0] = p0;
385  buf[1] = p1;
386  M5.In_I2C.writeRegister(aw9523_i2c_addr, port0_reg, buf, sizeof(buf), i2c_freq);
387  // M5.In_I2C.writeRegister8(aw9523_i2c_addr, port0_reg, p0, i2c_freq);
388  // M5.In_I2C.writeRegister8(aw9523_i2c_addr, port1_reg, p1, i2c_freq);
389  }
390 // Axp2101.setReg0x20Bit0(enable);
391  }
392 
393 #endif
394 
395  void Power_Class::setExtOutput(bool enable, ext_port_mask_t port_mask)
396  {
397  switch (M5.getBoard())
398  {
399 #if defined (M5UNIFIED_PC_BUILD)
400 #elif defined (CONFIG_IDF_TARGET_ESP32S3)
401  case board_t::board_M5StackCoreS3:
402  {
403  _core_s3_output(_core_s3_bus_en, enable);
404  }
405  break;
406 
407 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
408  case board_t::board_M5Paper:
409  if (enable) { m5gfx::gpio_hi(M5Paper_EXT5V_ENABLE_PIN); }
410  else { m5gfx::gpio_lo(M5Paper_EXT5V_ENABLE_PIN); }
411  break;
412 
413  case board_t::board_M5StackCore2:
414  case board_t::board_M5Tough:
415  {
416  bool cancel = false;
417  if (_pmic == pmic_axp2101) {
418  cancel = (enable && (Ina3221.getShuntVoltage(0) < 0.0f || Ina3221.getShuntVoltage(1) < 0.0f) && (8 >= Axp2101.getBatteryLevel()));
419  if (!cancel) {
420  Axp2101.setBLDO2(enable * 3300);
421  break;
422  }
423  } else {
424  // If ACIN is false and VBUS current is detected and the battery is low, power supply from Core to the outside is inhibited.
425  // This is because supplying power externally consumes battery power when there is no power supply from ACIN and power is supplied from VBUS.
426  // ※ If receiving power from M-Bus, PortA, etc., there is no need to setExtPower to true.
427  cancel = (enable && !Axp192.isACIN() && (0.0f < Axp192.getVBUSCurrent()) && (8 >= Axp192.getBatteryLevel()));
428  if (!cancel) {
429  Axp192.writeRegister8(0x90, enable ? 0x02 : 0x07); // GPIO0 : enable=LDO / disable=float
430  }
431  }
432  if (cancel)
433  {
434  ESP_LOGW("Power","setExtPower(true) is canceled.");
435  break;
436  }
437  }
438  NON_BREAK;
439 
440  case board_t::board_M5StickC:
441  case board_t::board_M5StickCPlus:
442  Axp192.setEXTEN(enable);
443  break;
444 
445  case board_t::board_M5Station:
446  for (int i = 0; i < 5; ++i)
447  {
448  if (port_mask & (1 << i)) { Axp192.setGPIO(i, enable); }
449  }
450  if (port_mask & ext_port_mask_t::ext_USB)
451  {
452  if (enable) { m5gfx::gpio_hi(GPIO_NUM_12); } // GPIO12 = M5Station USB power control
453  else { m5gfx::gpio_lo(GPIO_NUM_12); }
454  }
455  if (port_mask & ext_port_mask_t::ext_MAIN)
456  {
457  Axp192.setEXTEN(enable);
458  }
459 #endif
460 
461  default:
462  break;
463  }
464  }
465 
467  {
468  switch (M5.getBoard())
469  {
470 #if defined (M5UNIFIED_PC_BUILD)
471 #elif defined (CONFIG_IDF_TARGET_ESP32S3)
472  case board_t::board_M5StackCoreS3:
473  {
474  static constexpr const uint32_t port0_bitmask = 0b00000010; // BUS EN
475  static constexpr const uint8_t port0_reg = 0x02;
476  return M5.In_I2C.readRegister8(aw9523_i2c_addr, port0_reg, i2c_freq) & port0_bitmask;
477  }
478  break;
479 
480 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
481  case board_t::board_M5Paper:
482  return m5gfx::gpio_in(M5Paper_EXT5V_ENABLE_PIN);
483  break;
484 
485  case board_t::board_M5StackCore2:
486  if (_pmic == pmic_axp2101) {
487  return Axp2101.getBLDO2Enabled();
488  }
489  NON_BREAK;
490 
491  case board_t::board_M5Tough:
492  case board_t::board_M5StickC:
493  case board_t::board_M5StickCPlus:
494  case board_t::board_M5Station:
495  return Axp192.getEXTEN();
496  break;
497 #endif
498 
499  default:
500  break;
501  }
502  return false;
503  }
504 
505  void Power_Class::setUsbOutput(bool enable)
506  {
507 #if defined (CONFIG_IDF_TARGET_ESP32S3)
508  switch (M5.getBoard())
509  {
510  case board_t::board_M5StackCoreS3:
511  _core_s3_output(_core_s3_usb_en, enable);
512  break;
513 
514  default:
515  break;
516  }
517 #endif
518  }
519 
521  {
522 #if defined (CONFIG_IDF_TARGET_ESP32S3)
523  switch (M5.getBoard())
524  {
525  case board_t::board_M5StackCoreS3:
526  {
527  static constexpr const uint8_t reg = 0x02;
528  return M5.In_I2C.readRegister8(aw9523_i2c_addr, reg, i2c_freq) & _core_s3_usb_en;
529  }
530  break;
531 
532  default:
533  break;
534  }
535 #endif
536  return false;
537  }
538 
539  void Power_Class::setLed(uint8_t brightness)
540  {
541 #if defined (M5UNIFIED_PC_BUILD)
542 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
543  static std::unique_ptr<m5gfx::Light_PWM> led;
544 
545  switch (M5.getBoard())
546  {
547  case board_t::board_M5StackCore2:
548  Axp192.writeRegister8(0x9A, 255-brightness);
549  break;
550 
551  case board_t::board_M5StackCoreInk:
552  case board_t::board_M5StickC:
553  case board_t::board_M5StickCPlus:
554  case board_t::board_M5StickCPlus2:
555  case board_t::board_M5TimerCam:
556  {
557  if (led.get() == nullptr)
558  {
559  led.reset(new m5gfx::Light_PWM());
560  auto cfg = led->config();
561  cfg.invert = false;
562  cfg.pwm_channel = 7;
563 
565  switch (M5.getBoard()) {
566  case board_t::board_M5StickCPlus2:
567  cfg.pin_bl = StickCPlus2_LED_PIN;
568  cfg.pwm_channel = 6; // ch6を選択 (ch7はLCDのバックライトに使用しているため)
569  cfg.freq = 256; // ※バックライトと同じ周波数を指定する(ch6とch7はタイマ周期が共通のため)
570  break;
571 
572  case board_t::board_M5TimerCam:
573  cfg.pin_bl = TimerCam_LED_PIN;
574  break;
575 
576  default:
577  cfg.invert = true;
578  cfg.pin_bl = GPIO_NUM_10;
579  break;
580  }
581  led->config(cfg);
582  led->init(brightness);
583  }
584  led->setBrightness(brightness);
585  }
586  break;
587 
588  default:
589  break;
590  }
591 #endif
592  }
593 
594  void Power_Class::_powerOff(bool withTimer)
595  {
596 #if !defined (M5UNIFIED_PC_BUILD)
597  bool use_deepsleep = true;
598  if (withTimer && _rtcIntPin < GPIO_NUM_MAX)
599  {
600  gpio_num_t pin = (gpio_num_t)_rtcIntPin;
601 #if SOC_PM_SUPPORT_EXT_WAKEUP
602  if (ESP_OK != esp_sleep_enable_ext0_wakeup( pin, false))
603 #endif
604  {
605  gpio_wakeup_enable( pin, gpio_int_type_t::GPIO_INTR_LOW_LEVEL);
606  esp_sleep_enable_gpio_wakeup();
607  use_deepsleep = false;
608  }
609  }
610  else
611  {
612  switch (_pmic)
613  {
614 #if defined (CONFIG_IDF_TARGET_ESP32C3)
615 #else
616 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
617 
618  case pmic_t::pmic_axp192:
619  Axp192.powerOff();
620  break;
621 
622  case pmic_t::pmic_ip5306:
623  Ip5306.setPowerBoostKeepOn(withTimer);
624  break;
625 
626 #endif
627 
628  case pmic_t::pmic_axp2101:
629  Axp2101.powerOff();
630  break;
631 
632 #endif
633 
634  case pmic_t::pmic_unknown:
635  default:
636  break;
637  }
638  }
639 
640  if (_pwrHoldPin < GPIO_NUM_MAX)
641  {
642  m5gfx::gpio_lo( _pwrHoldPin );
643  }
644 
645  if (use_deepsleep) { esp_deep_sleep_start(); }
646  esp_light_sleep_start();
647  esp_restart();
648 #endif
649  }
650 
651  void Power_Class::_timerSleep(void)
652  {
653 #if !defined (M5UNIFIED_PC_BUILD)
654 
655  if (_pwrHoldPin < GPIO_NUM_MAX)
656  {
657  gpio_hold_dis( (gpio_num_t)_pwrHoldPin );
658  }
659  M5.Display.sleep();
660  M5.Display.waitDisplay();
661 
662 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
663  switch (M5.getBoard())
664  {
665  case board_t::board_M5StickC:
666  case board_t::board_M5StickCPlus:
671  m5gfx::pinMode(GPIO_NUM_35, m5gfx::pin_mode_t::input);
672  for (int i = 1; i >= 0; --i) {
674  if (m5gfx::gpio_in(GPIO_NUM_35)) { break; }
675  }
676  esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, 0);
677  esp_deep_sleep_start();
678  return;
679  break;
680 
681  case board_t::board_M5StackCore2:
682  case board_t::board_M5Tough:
683  // esp_sleep_enable_ext0_wakeup(GPIO_NUM_39, 0); // タッチパネルINT;
684  // Axp192.powerOff();
685  break;
686 
687  default:
688  break;
689  }
690 #endif
691 #endif
692  _powerOff(true);
693  }
694 
695  void Power_Class::deepSleep(std::uint64_t micro_seconds, bool touch_wakeup)
696  {
697  M5.Display.sleep();
698 #if !defined (M5UNIFIED_PC_BUILD)
699  ESP_LOGD("Power","deepSleep");
700 #if defined (CONFIG_IDF_TARGET_ESP32C3)
701 
702 #else
703 
704 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
705  if (_pmic == pmic_t::pmic_ip5306)
706  {
708  }
709 #endif
710 
711  uint_fast8_t wpin = _wakeupPin;
712  if (touch_wakeup && wpin < GPIO_NUM_MAX)
713  {
714  esp_sleep_enable_ext0_wakeup((gpio_num_t)wpin, false);
715  while (m5gfx::gpio_in(wpin) == false)
716  {
717  m5gfx::delay(10);
718  }
719  }
720  if (micro_seconds > 0)
721  {
722  esp_sleep_enable_timer_wakeup(micro_seconds);
723  }
724  else
725  {
726  esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
727  }
728 #endif
729  esp_deep_sleep_start();
730 #endif
731  }
732 
733  void Power_Class::lightSleep(std::uint64_t micro_seconds, bool touch_wakeup)
734  {
735 #if !defined (M5UNIFIED_PC_BUILD)
736  ESP_LOGD("Power","lightSleep");
737 #if defined (CONFIG_IDF_TARGET_ESP32C3)
738 
739 #else
740 
741 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
742  if (_pmic == pmic_t::pmic_ip5306)
743  {
745  }
746 #endif
747 
748  uint_fast8_t wpin = _wakeupPin;
749  if (touch_wakeup && wpin < GPIO_NUM_MAX)
750  {
751  esp_sleep_enable_ext0_wakeup((gpio_num_t)wpin, false);
752  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_AUTO);
753  while (m5gfx::gpio_in(wpin) == false)
754  {
755  m5gfx::delay(10);
756  }
757  }
758  if (micro_seconds > 0){
759  esp_sleep_enable_timer_wakeup(micro_seconds);
760  }else{
761  esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
762  }
763 #endif
764  esp_light_sleep_start();
765 #endif
766  }
767 
769  {
770  M5.Display.sleep();
771  M5.Display.waitDisplay();
772  _powerOff(false);
773  }
774 
775  void Power_Class::timerSleep( int seconds )
776  {
777  M5.Rtc.disableIRQ();
778  M5.Rtc.setAlarmIRQ(seconds);
779 #if !defined (M5UNIFIED_PC_BUILD)
780  esp_sleep_enable_timer_wakeup(seconds * 1000000ULL);
781 #endif
782  _timerSleep();
783  }
784 
785  void Power_Class::timerSleep( const rtc_time_t& time)
786  {
787  M5.Rtc.disableIRQ();
788  M5.Rtc.setAlarmIRQ(time);
789  _timerSleep();
790  }
791 
792  void Power_Class::timerSleep( const rtc_date_t& date, const rtc_time_t& time)
793  {
794  M5.Rtc.disableIRQ();
795  M5.Rtc.setAlarmIRQ(date, time);
796  _timerSleep();
797  }
798 
799 #if !defined (M5UNIFIED_PC_BUILD)
800 
801  static std::int32_t getBatteryAdcRaw(adc1_channel_t adc_ch)
802  {
803 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32) || defined (CONFIG_IDF_TARGET_ESP32S3)
804  static constexpr int BASE_VOLATAGE = 3600;
805 
806  static esp_adc_cal_characteristics_t* adc_chars = nullptr;
807  if (adc_chars == nullptr)
808  {
809  adc1_config_width(ADC_WIDTH_BIT_12);
810  adc1_config_channel_atten(adc_ch, ADC_ATTEN_DB_11);
811  adc_chars = (esp_adc_cal_characteristics_t*)calloc(1, sizeof(esp_adc_cal_characteristics_t));
812  esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, BASE_VOLATAGE, adc_chars);
813  }
814  return esp_adc_cal_raw_to_voltage(adc1_get_raw(adc_ch), adc_chars);
815 #else
816  return 0;
817 #endif
818  }
819 
820 #endif
821 
823  {
824 #if !defined (M5UNIFIED_PC_BUILD)
825  switch (_pmic)
826  {
827 
828 #if defined (CONFIG_IDF_TARGET_ESP32C3)
829 #else
830 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
831  case pmic_t::pmic_ip5306:
832  break;
833 
834  case pmic_t::pmic_axp192:
835  return Axp192.getBatteryVoltage() * 1000;
836 
837 #endif
838 
839  case pmic_t::pmic_axp2101:
840  return Axp2101.getBatteryVoltage() * 1000;
841 
842 #endif
843 
844  case pmic_t::pmic_adc:
845  return getBatteryAdcRaw(_batAdc) * _adc_ratio;
846 
847  default:
848  return 0;
849  }
850 #endif
851  return 0;
852  }
853 
854  std::int32_t Power_Class::getBatteryLevel(void)
855  {
856 #if defined (M5UNIFIED_PC_BUILD)
857  return 100;
858 #else
859  float mv = 0.0f;
860  switch (_pmic)
861  {
862 
863 #if defined (CONFIG_IDF_TARGET_ESP32C3)
864 #else
865 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
866  case pmic_t::pmic_ip5306:
867  return Ip5306.getBatteryLevel();
868 
869  case pmic_t::pmic_axp192:
870  mv = Axp192.getBatteryVoltage() * 1000;
871  break;
872 
873 #endif
874 
875  case pmic_t::pmic_axp2101:
876  return Axp2101.getBatteryLevel();
877  break;
878 
879 #endif
880 
881  case pmic_t::pmic_adc:
882  mv = getBatteryAdcRaw(_batAdc) * _adc_ratio;
883  break;
884 
885  default:
886  return -2;
887  }
888 
889  int level = (mv - 3300) * 100 / (float)(4150 - 3350);
890 
891  return (level < 0) ? 0
892  : (level >= 100) ? 100
893  : level;
894 #endif
895  }
896 
898  {
899  switch (_pmic)
900  {
901 #if defined (CONFIG_IDF_TARGET_ESP32C3)
902 #else
903 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
904  case pmic_t::pmic_ip5306:
905  Ip5306.setBatteryCharge(enable);
906  return;
907 
908  case pmic_t::pmic_axp192:
909  Axp192.setBatteryCharge(enable);
910  return;
911 
912 #endif
913 
914  case pmic_t::pmic_axp2101:
915  Axp2101.setBatteryCharge(enable);
916  break;
917 
918 #endif
919 
920  default:
921  return;
922  }
923  }
924 
925  void Power_Class::setChargeCurrent(std::uint16_t max_mA)
926  {
927  switch (_pmic)
928  {
929 #if defined (CONFIG_IDF_TARGET_ESP32C3)
930 #else
931 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
932  case pmic_t::pmic_ip5306:
933  Ip5306.setChargeCurrent(max_mA);
934  return;
935 
936  case pmic_t::pmic_axp192:
937  Axp192.setChargeCurrent(max_mA);
938  return;
939 
940 #endif
941 
942  case pmic_t::pmic_axp2101:
943  Axp2101.setChargeCurrent(max_mA);
944  break;
945 
946 #endif
947 
948  default:
949  return;
950  }
951  }
952 
954  {
955  switch (_pmic)
956  {
957 #if defined (CONFIG_IDF_TARGET_ESP32C3)
958 #else
959 
960 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
961  case pmic_t::pmic_axp192:
962  {
963  int32_t res = Axp192.getBatteryChargeCurrent();
964  int32_t dsc = Axp192.getBatteryDischargeCurrent();
965  if (res < dsc) res = -dsc;
966  return res;
967  }
968 #endif
969 
970  case pmic_t::pmic_axp2101:
971 
972 #if defined (CONFIG_IDF_TARGET_ESP32S3)
973  // for CoreS3
974  return 0;
975 
976 #else
977 
978  // for Core2 v1.1
979  return 1000.0f * Ina3221.getCurrent(0); // 0=CH1. CH1=BAT Current.
980 
981 #endif
982 
983 #endif
984 
985  default:
986  return 0;
987  }
988  }
989 
990  void Power_Class::setChargeVoltage(std::uint16_t max_mV)
991  {
992  switch (_pmic)
993  {
994 #if defined (CONFIG_IDF_TARGET_ESP32C3)
995 #else
996 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
997 
998  case pmic_t::pmic_ip5306:
999  Ip5306.setChargeVoltage(max_mV);
1000  return;
1001 
1002  case pmic_t::pmic_axp192:
1003  Axp192.setChargeVoltage(max_mV);
1004  return;
1005 
1006 #endif
1007 
1008  case pmic_t::pmic_axp2101:
1009  Axp2101.setChargeVoltage(max_mV);
1010  break;
1011 
1012 #endif
1013 
1014  default:
1015  return;
1016  }
1017  }
1018 
1020  {
1021  switch (_pmic)
1022  {
1023 #if defined (CONFIG_IDF_TARGET_ESP32C3)
1024 #else
1025 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
1026 
1027  case pmic_t::pmic_ip5306:
1028  return Ip5306.isCharging() ? is_charging_t::is_charging : is_charging_t::is_discharging;
1029 
1030  case pmic_t::pmic_axp192:
1031  return Axp192.isCharging() ? is_charging_t::is_charging : is_charging_t::is_discharging;
1032 
1033 #endif
1034 
1035  case pmic_t::pmic_axp2101:
1036  return Axp2101.isCharging() ? is_charging_t::is_charging : is_charging_t::is_discharging;
1037  // return Axp2101.getChargeDirection() ? is_charging_t::is_charging : is_charging_t::is_discharging;
1038 
1039 #endif
1040 
1041  default:
1042  return is_charging_t::charge_unknown;
1043  }
1044  }
1045 
1047  {
1048  switch (_pmic)
1049  {
1050 
1051 #if defined (CONFIG_IDF_TARGET_ESP32C3)
1052 #else
1053 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
1054 
1055  case pmic_t::pmic_axp192:
1056  return Axp192.getPekPress();
1057 
1058 #endif
1059 
1060  case pmic_t::pmic_axp2101:
1061  return Axp2101.getPekPress();
1062 
1063 #endif
1064 
1065  default:
1066  return 0;
1067  }
1068  }
1069 
1070  void Power_Class::setVibration(uint8_t level)
1071  {
1072 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
1073  if (M5.getBoard() == board_t::board_M5StackCore2)
1074  {
1075  uint32_t mv = level ? 480 + level * 12 : 0;
1076  switch (_pmic)
1077  {
1078  case pmic_t::pmic_axp192:
1079  Axp192.setLDO3(mv);
1080  break;
1081 
1082  case pmic_t::pmic_axp2101:
1083  Axp2101.setDLDO1(mv);
1084  break;
1085 
1086  default:
1087  break;
1088  }
1089  }
1090 #endif
1091  }
1092 
1093 }
m5::M5Unified M5
global instance.
Definition: M5Unified.cpp:32
#define NON_BREAK
Definition: Power_Class.cpp:27
float getBatteryVoltage(void)
bool begin(void)
void setDCDC3(int voltage)
void setLDO2(int voltage)
void setGPIO(uint8_t gpio_num, bool state)
std::int8_t getBatteryLevel(void)
std::uint8_t getPekPress(void)
float getVBUSCurrent(void)
void setLDO3(int voltage)
bool isCharging(void)
Get whether the battery is currently charging or not.
void setChargeCurrent(std::uint16_t max_mA)
void setBatteryCharge(bool enable)
void setChargeVoltage(std::uint16_t max_mV)
float getBatteryChargeCurrent(void)
void setGPIO2(bool state)
void setEXTEN(bool enable)
float getBatteryDischargeCurrent(void)
bool getEXTEN(void)
void powerOff(void)
float getBatteryVoltage(void)
std::uint8_t getPekPress(void)
bool isCharging(void)
Get whether the battery is currently charging or not.
void setBatteryCharge(bool enable)
std::int8_t getBatteryLevel(void)
void setChargeCurrent(std::uint16_t max_mA)
void setDLDO1(int voltage)
bool getBLDO2Enabled(void)
void setChargeVoltage(std::uint16_t max_mV)
void setBLDO2(int voltage)
std::uint8_t readRegister8(std::uint8_t address, std::uint8_t reg, std::uint32_t freq) const
Definition: I2C_Class.cpp:85
bool bitOn(std::uint8_t address, std::uint8_t reg, std::uint8_t data, std::uint32_t freq) const
Definition: I2C_Class.cpp:90
bool writeRegister(std::uint8_t address, std::uint8_t reg, const std::uint8_t *data, std::size_t length, std::uint32_t freq) const
Definition: I2C_Class.cpp:67
bool readRegister(std::uint8_t address, std::uint8_t reg, std::uint8_t *result, std::size_t length, std::uint32_t freq) const
Definition: I2C_Class.cpp:75
bool writeRegister8Array(const std::uint8_t *reg_data_array, std::size_t length) const
Definition: I2C_Class.cpp:109
bool writeRegister8(std::uint8_t reg, std::uint8_t data) const
Definition: I2C_Class.hpp:160
bool writeRegister(std::uint8_t reg, const std::uint8_t *data, std::size_t length) const
Definition: I2C_Class.hpp:172
bool setINTPinActiveLogic(bool level)
Definition: IMU_Class.cpp:472
float getShuntVoltage(uint8_t channel)
float getCurrent(uint8_t channel)
std::int8_t getBatteryLevel(void)
void setChargeVoltage(std::uint16_t max_mV)
void setBatteryCharge(bool enable)
void setChargeCurrent(std::uint16_t max_mA)
bool isCharging(void)
Get whether the battery is currently charging or not.
bool setPowerBoostKeepOn(bool en)
Set whether or not to continue supplying power even at low loads.
bool begin(void)
board_t getBoard(void) const
Definition: M5Unified.hpp:297
IMU_Class Imu
Definition: M5Unified.hpp:202
RTC8563_Class Rtc
Definition: M5Unified.hpp:205
I2C_Class & In_I2C
for internal I2C device
Definition: M5Unified.hpp:226
AXP2101_Class Axp2101
void setExtOutput(bool enable, ext_port_mask_t port_mask=(ext_port_mask_t) 0xFF)
void timerSleep(int seconds)
std::int32_t getBatteryLevel(void)
int32_t getBatteryCurrent(void)
void setChargeCurrent(std::uint16_t max_mA)
bool begin(void)
Definition: Power_Class.cpp:46
void setVibration(uint8_t level)
IP5306_Class Ip5306
void deepSleep(std::uint64_t micro_seconds=0, bool touch_wakeup=true)
void setLed(uint8_t brightness=255)
is_charging_t isCharging(void)
void lightSleep(std::uint64_t micro_seconds=0, bool touch_wakeup=true)
void setUsbOutput(bool enable)
int16_t getBatteryVoltage(void)
uint8_t getKeyState(void)
INA3221_Class Ina3221
void setBatteryCharge(bool enable)
bool getExtOutput(void)
bool getUsbOutput(void)
AXP192_Class Axp192
void powerOff(void)
all power off.
void setChargeVoltage(std::uint16_t max_mV)
int setAlarmIRQ(int afterSeconds)
Definition: M5Unified.cpp:48
ext_port_mask_t
Definition: Power_Class.hpp:25
@ ext_MAIN
Definition: Power_Class.hpp:33
@ ext_USB
Definition: Power_Class.hpp:32