BUG: in Power.timerSleep() UIFlow2.0 for Core-INK



  • I think there is a bug in the timerSleep() function in UIFlow 2.0 for CORE-INK.
    0_1715000853459_0f010509-2d06-41fa-9bc3-6ed2bfd08074-image.png

    I assume the Power.timerSleep() function is replacing the UIFlow 1.x.. power.restart_after_seconds() which works as expected.

    The new function seems to only put the ESP32 in sleep mode and not switching off the hole board. It does work partly as it do restart the board after the given amount of seconds.
    As far as I have figured out it do in fact initialize the BM8365 RTC to interrupt at the given seconds but it does not (probably) set GPIO12 low to switch off the "board-power".



  • Hello @Cognitive5525

    as far as I can test the Turn off the device... block works as it should an turns the device fully off (except for the RTC clock IC). You can verify that yourself by setting a longer turn off time, let's say 60 seconds, and then when it has turned off, try to power it on with the power button. If that works, then it was actually fully shutdown.

    Please note: M5CoreInk only can go into full shutdown when run from battery. (USB power keeps it on all the time.)

    BTW: I also confirmed that the 5 V on the Groove port are gone during full shutdown.

    Thanks
    Felix



  • Thanks Felix,
    I'll try to increase the sleep time tomorrow when I'm back in the office.

    I have however made the exact test you suggest and I could not switch on with the power button during the sleep time unless I pressed the reset button first. And if I only pressed the reset button during the sleep time it would still wake up after 10 sec.

    If increasing the sleep time helps I then wonder: What is the minimum sleep time (apparently > 10 sec)? And why would it be so long?



  • Hello @Cognitive5525

    I've selected 60 seconds arbitrarily - so no, I don't think a longer shutdown time will change things.

    That said, if you are running your M5CoreInk from battery but it still doesn't do a full shutdown then I am afraid I am out of ideas at this point in time.

    Thanks
    Felix



  • OK this is really strange!

    First: The length of the sleeping period does not matter....

    I'm using the following short test code in main.py (and boot.py is empty):

    import M5
    import time
    
    M5.begin()
    M5.Widgets.fillScreen(0xffffff)
    label0 = M5.Widgets.Label("label0", 61, 55, 1.0, 0xffffff, 0x000000, M5.Widgets.FONTS.DejaVu18)
    time.sleep(3)
    #M5.Power.powerOff()
    M5.Power.timerSleep(20)
    

    I have put the above code on four different CORE-INK devices (by cloning the first to the three others) and two of them are working and two are are not working. "Working" means switch off board power (5Vout -> 0) and wakes up after 20 seconds. "Not working" means still "wakes up" after 20 sec. but 5Vout remains on all the time.

    However if I change the code on the two "bad" devices to use Power.powerOff() (i.e. un-comment the second last line) they switch off correctly (5Vout -> 0 ) and then (of course) remain switched off.
    (All tests performed while running on the internal battery only)

    I assume that Power.timerSleep(20) basically do something like the following:

    • #1. set the registers in the RTC (via I2C) with the correct timeout and put it in "INT-mode"
    • #2. set pin12 low to switch of the hole board.

    and Power.powerOff() do just #2.

    Do the two functions set pin12 low in different ways? Or is it some kind of critical timing? Or is #1 step affecting the "low signaling" of pin12 in some unknown way?



  • Further testing with the Arduino libraries and with the following code:

    #include "M5Unified.h"
    
    void setup() {
        M5.begin();
        //M5.Power.powerOff();
         delay(10000);
        M5.Power.timerSleep(12);
      }
    
    void loop() {}
    

    I can replicate the problem exactly as in my previous post. So the the two good devices still work as expected and the two bad one does not work. And the bad ones also do work with the Power.powerOff();

    So I searched up the code for Power.timerSleep() and Power.powerOff() in the M5Unified library and they are defined in the file Power_Class.cpp

    There is a lot of code here that I struggle to get my head around but both functions do "their stuff" and then both ends up calling the private function void _powerOff(bool withTimer) but Power.timerSleep() sets withTimer "true" whereas Power.powerOff() sets it "false" Which seems reasonable taking the variable name into account.

    So I changed[1] _powerOff(true); call to _powerOff(false); for the Power.timerSleep() case and then the two "bad" devices started to work with Power.timerSleep() as well

    [1] line 709 in Power_Class.cpp if anyone is interested.



  • Hello @Cognitive5525

    interesting. Thanks for sharing. If you revert your change do the two 'bad' boards start to fail again or are they 'cured' now?

    Thanks
    Felix



  • @felmue said in BUG: in Power.timerSleep() UIFlow2.0 for Core-INK:

    If you revert your change do the two 'bad' boards start to fail again or are they 'cured' now?

    They start to fail again. At least some kind of consistence 😏

    We have 30+ Core INK running on battery as "IoT-devices". The program is written in Micropython on the UiFlow 1.x firmware but also here some devices does not always work well with the old/current m5stack.power.restart_after_seconds(sec)
    So I had hoped this would be better in UIFlow2.0 so we could port the program - but no.

    Now my dilemma is whether to stay on UIFlow 1.x or wait for M5Stack to maybe solve this issue in UIFlow2.0 (I hope you are reading this thread M5StackπŸ˜‰) or to port the hole thing to C++ where I have some more freedom to fix "low-level" issues like this.



  • Update.
    After many tests I think I have pinpointed where it goes wrong but not exactly why.

    With the "bad" devices when driving pin 12 low the device does not turn off as expected while the "good" devices do. With the "good" devices I even get a serial monitor message saying "Brown??" (or sometimes partly, like "Bro") which I assume is a "Brown out" message generated "deep" in Espressif's libraries. I think that make sense since the power supply is kind of "brutally" removed from the ESP when pin 12 is driven low.

    So basically on some "bad" M5 Core INK devices this piece of C++ code that should shut down the board by driving pin 12 low does not work:

    m5gfx::gpio_lo( pwrHoldPin );
    

    (Line #672 in PowerClass.cpp)

    I have also verified it in UIFlow2.0 by "manually" pulling pin 12 low:

    import M5
    import time
    import hardware
    
    M5.begin()
    
    pin12 = hardware.Pin(12, mode=hardware.Pin.OUT, pull=hardware.Pin.PULL_UP)
    time.sleep(3)
    pin12.off()
    

    With above UIFlow2.0 python code the "good" devices shut down completely as expected, while the "bad" ones does not.

    But there is more. While troubleshooting I (for other reasons) updated the platform.io version from 6.3.0 to 6.6.0 (I'm using Platform.IO with Vs-code to compile C++ code for the CoreINK) and then the "bad" devices began to work as expected i.e. they were shutting down by pulling pin 12 low. I noticed that the ESP-IDF version is 5.2.1 in Platform.io version 6.6.0 but t is version 5.1.1 in version 6.4.0 (for some reason Platform.io V 6.3.x is not listed on GitHub).



  • Here is a workaround for UIFLow2.0:

    import M5
    import hardware
    import time
    
    # UIFlow2.0 workaround for M5.Power.timerSleep() not working properly
    # on SOME CoreINK devices. On these decvices the board-power is not
    # proberly turned off. However, the M5.Power.powerOff() does work
    # for these devices, i.e. turning board-power properly off
     
    M5.begin()
    #init i2c bus with pins connected to the RTC
    i2c0 = hardware.I2C(0, scl=hardware.Pin(22), sda=hardware.Pin(21), freq=400000)
    
    ##### Put your code here.
    time.sleep(3)      
    
    
    ##### code substitution the timerSleep() function
    # Set registers of the RTC. ref datasheet for BM8563 RTC for further info
    # reg 0x00  always 00h
    # reg 0x01  bit 2-7: always 0, bit 0: enable/disable timer int
    #           0x01 = timer enabled           
    reg00_01 = bytearray([0x00, 0x01])
    
    # reg 0x0D  always 00h - clock out disabled
    # reg 0x0E  bit 7: endable/disable timer, bit 0-1 timer resolution
    #           10=sec  11 = min
    #           0x82 = int enabled and seconds resolution
    # reg 0x0F  timer value 0-255
    #           0x14 = 20d = 20 sec. if reg 0x0E = 0x83 then 20 min
    reg0D_0F = bytearray([0x00, 0x82, 0x14])
    
    # i2c device address of RTC is 0x51
    # Write to register address 0x00-0x01
    i2c0.writeto_mem(0x51,0x00, reg00_01)
    
    # Write to register adsress 0x0D-0x0F
    i2c0.writeto_mem(0x51,0x0D, reg0D_0F)
    
    M5.Power.powerOff()
    ##### end of code substitution the timerSleep() function