diff --git a/src/M5Unified.inl b/src/M5Unified.inl index 09fb97c..93d17b9 100644 --- a/src/M5Unified.inl +++ b/src/M5Unified.inl @@ -421,6 +421,23 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { }, #elif defined (CONFIG_IDF_TARGET_ESP32H2) #elif defined (CONFIG_IDF_TARGET_ESP32C5) +{ board_t::board_M5ToughC5, + 255 , GPIO_NUM_0 , + 255 , GPIO_NUM_1 , + 255 , 255 , + GPIO_NUM_7 , GPIO_NUM_4 , + GPIO_NUM_8 , GPIO_NUM_6 , + GPIO_NUM_9 , 255 , + GPIO_NUM_12, GPIO_NUM_11, + GPIO_NUM_12, GPIO_NUM_11, + GPIO_NUM_2 , GPIO_NUM_3 , + GPIO_NUM_2 , GPIO_NUM_3 , + GPIO_NUM_23, GPIO_NUM_24, + GPIO_NUM_27, GPIO_NUM_28, + 255 , GPIO_NUM_5 , + 255 , 255 , + 255 , 255 , +}, #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32) { board_t::board_M5Stack , 255 , GPIO_NUM_35, diff --git a/src/utility/Power_Class.inl b/src/utility/Power_Class.inl index 67386bd..840047e 100644 --- a/src/utility/Power_Class.inl +++ b/src/utility/Power_Class.inl @@ -938,6 +938,8 @@ namespace m5 _pmic = pmic_t::pmic_m5pm1; _wakeupPin = GPIO_NUM_1; // PY IQR + /// bring up the PM1 early so getWakeSource() sees WAKE_SRC before it is cleared below. + M5pm1.begin(); M5pm1.clearWakeSource(); M5pm1.clearIRQStatus(); M5pm1.setGPIOIRQMaskBits(0x1E); // enable GPIO0 interrupt, disable other GPIO IRQ diff --git a/src/utility/power/M5PM1_Class.hpp b/src/utility/power/M5PM1_Class.hpp index 411f299..538de35 100644 --- a/src/utility/power/M5PM1_Class.hpp +++ b/src/utility/power/M5PM1_Class.hpp @@ -158,6 +158,15 @@ namespace m5 bool setPwmDuty12bit(pwm_channel_t channel, std::uint32_t duty12, pwm_polarity_t polarity = pwm_polarity_t::normal, bool enable = true); + /// get the reason for this power-on, read once by the first begin(). + /// The bits match m5pm1_wake_src_t of the M5PM1 library: 0x01 timer, 0x02 VIN, 0x04 power + /// button, 0x08 reset button, 0x10 reset command, 0x20 external GPIO, 0x40 5VINOUT. + /// @return the bits, or 0 when no reason was recorded or the read failed. + /// @note On ToughC5 and PaperMono, M5.begin() clears the PM1 register, so a read through another + /// driver afterwards returns 0. Other boards leave the register as it is, and it can still + /// hold the previous reason after a reset of the ESP32 alone. + std::uint8_t getWakeSource(void) const { return _wake_source; } + /// clear PM1 wake source bits selected by mask. /// Single-write selective clear assuming the write-zero-to-clear behavior /// adopted by the official driver; the datasheet does not specify the write polarity. @@ -252,6 +261,7 @@ namespace m5 bool powerOff(void); private: + std::uint8_t _wake_source = 0; bool _pek_double_pending = false; }; } diff --git a/src/utility/power/M5PM1_Class.inl b/src/utility/power/M5PM1_Class.inl index f41c406..cbbf462 100644 --- a/src/utility/power/M5PM1_Class.inl +++ b/src/utility/power/M5PM1_Class.inl @@ -70,9 +70,22 @@ namespace m5 { if (!_init) { std::uint32_t val = 0; - auto res = readRegister(M5PM1_REG_DEVICE_ID, (uint8_t*)&val, 4); + // The first transfer after an idle period can be NACKed; the next one answers. + bool res = false; + for (int retry = 3; !(res = readRegister(M5PM1_REG_DEVICE_ID, (uint8_t*)&val, 4)) && --retry; ) + { + m5gfx::delay(1); + } if (res) { + // Power.begin() clears WAKE_SRC on some boards, so keep it for getWakeSource(). + std::uint8_t wake_source = 0; + for (int retry = 3; !readRegister(M5PM1_REG_WAKE_SRC, &wake_source, 1) && --retry; ) + { + wake_source = 0; + m5gfx::delay(1); + } + _wake_source = wake_source & 0x7F; writeRegister8(M5PM1_REG_I2C_CFG, 0x00); // disable I2C idle sleep writeRegister8(M5PM1_REG_WDT_CNT, 0x00); // disable watchdog }