M5Paper touchscreen wakeup on GPIO 36 constantly triggering

  • From the old topic M5paper touchscreen wakeup from sleep I got the following code to go into light sleep with wakeup on a touchscreen event:

    esp_sleep_enable_ext0_wakeup(GPIO_NUM_36, LOW); // TOUCH_INT

    However, the device immediately wakes with RTC_IO as reason. If I comment out the esp_sleep_enable_ext0_wakeup line, it stays in light sleep. I have no idea what is going on. The original (linked) topic mentions WiFi as a problem source, but I don't use WiFi in this project and so it is never enabled.

    I tried gpio_pullup_en(GPIO_NUM_36); before going to sleep but it makes no difference. I initialize the device using M5.begin(true, false, false, true, false); so the touch screen should be enabled and active.

    Any thoughts?

    EDIT: maybe worth noting: this happens both when using PlatformIO in VSCode as well as with Arduino IDE. I can reproduce it with just this sketch as an .ino, which shows "Wakeup <x>" with a continuously increasing number as fast as it can:

    #include <M5EPD.h>
    M5EPD_Canvas canvas(&M5.EPD);
    void setup(){
      canvas.createCanvas(540, 50);
      canvas.drawString("Hello World", 10, 20);
      canvas.pushCanvas(0, 960/2 - 50/2, UPDATE_MODE_DU4);
    void light_sleep_with_touch_wakeup() {
      esp_sleep_enable_ext0_wakeup(GPIO_NUM_36, LOW); // TOUCH_INT
    void loop(){
      static char buffer[128];
      static int i = 0;
      snprintf(buffer, sizeof(buffer), "Wakeup %d", ++i);
      canvas.drawString(buffer, 10, 20);
      canvas.pushCanvas(0, 960/2 - 50/2, UPDATE_MODE_DU4);

    EDIT2: I dug a little deeper, opened up the M5Paper and probed the INT pin with a scope. Apparently it's not an ESP32 issue but a GT911 issue! I guess I must be missing some configuration for it. When I'm not touching it, it pulses high at ~24Hz. When I touch it, it pulses at ~48Hz:

    not touching

    EDIT3: Aha, I finally cracked it! The scope plots made me look up the datasheet of the GT911, which states the following:

    The timing sequence for GT911 interrupt signal output (take the rising-edge triggered interrupt for example.
    The timing for falling-edge triggered interrupt is similar to this one):

    1. In standby mode, INT outputs low level.
    2. Output rising edge when any coordinate is updated.
    3. After output rising edge in step 2, INT will keep outing high level until next cycle (the cycle is configurable
      by setting Refresh_Rate). The host is supposed to finish the reading within one cycle and reset buffer status
      (0x814E) to 0.
    4. After output rising-edge in step 2, if the host fails to finish reading coordinates within one cycle, GT911 will
      output one INT pulse again instead of update coordinates even if it detects that the coordinate is updated.
    5. If the host still fails to read coordinate, GT911 will keep outputting INT pulse.

    In other words, if you don't read the coordinates from the touch screen, it will keep outputting an interrupt until you do

    So the solution ended up being to put M5.TP.flush() before going to sleep (or calling M5.TP.update() anywhere before going to sleep, which you would need to do anyway to respond to touch events).

    Case closed :-)

  • Hello @Remboooo

    I just came back to report a similar finding. I've added below lines before going to sleep:

      while(digitalRead(GPIO_NUM_36) == LOW)


  • Thanks, both, for these posts. I was able to resolve my issue with deep sleep by following your suggestions. I have created an issue in the M5 Unified issue tracker to solve this same bug in their M5.Power.deepSleep() implementation: https://github.com/m5stack/M5Unified/issues/91