Xinyuan-LilyGO / T-Wristband

DIY Programmable Bracelet
311 stars 98 forks source link

tft reinit after deep sleep #19

Open biccius opened 3 years ago

biccius commented 3 years ago

Hi

This is meant to be an attempt of improvement on the display drawing speed after the ESP32 wakes up from deep sleep. In all the sources I've seen, the display call tft.init() at every wake of the microcontroller. This include a hardware or software reset that blank the screen for some milliseconds.

The ST7735 display has sleep and shutdown commands, preserving the contents of the on-screen buffer in memory.

My purpose is to try to:

Here's the code i'm working on:

#include <pcf8563.h>
#include <TFT_eSPI.h>            // Graphics and font library for ST7735 driver chip
#include <SPI.h>
#include <WiFi.h>
#include <Wire.h>
#include "sensor.h"
#include "esp_adc_cal.h"

#define TP_PIN_PIN          33
#define TP_PWR_PIN          25

TFT_eSPI tft = TFT_eSPI();       // Invoke library, pins defined in User_Setup.h
RTC_DATA_ATTR int boots = 0;

void setupTFT()
{
  tft.init();
  tft.setRotation(1);
  tft.setSwapBytes(true);
}

int color = 0x5555;

void Wake()
{
    SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);
    pinMode(TFT_CS, OUTPUT);
    pinMode(TFT_DC, OUTPUT);
    pinMode(TFT_BL, OUTPUT);
    tft.writecommand(ST7735_DISPON);
    tft.writecommand(ST7735_SLPOUT);
}

void Sleep()
{
  tft.writecommand(ST7735_SLPIN);
  tft.writecommand(ST7735_DISPOFF);
  delay(200);

  digitalWrite(GPIO_NUM_26, HIGH);  // keep GPIO_26 high state after deep sleep reset
  gpio_hold_en(GPIO_NUM_26);        // display is preserved
  gpio_deep_sleep_hold_en();

  esp_sleep_enable_ext1_wakeup(GPIO_SEL_33, ESP_EXT1_WAKEUP_ANY_HIGH);
  esp_deep_sleep_start();
}

void setup(void)
{
      pinMode(TP_PIN_PIN, INPUT);
      pinMode(TP_PWR_PIN, PULLUP);
       //! Must be set to pull-up output mode in order to wake up in deep sleep mode
       digitalWrite(TP_PWR_PIN, HIGH);

      Serial.begin(115200);

      if(boots == 0) //Run this only the first time
      {
          Serial.println("first boot");
          setupTFT();
          tft.fillScreen(color);
          color+=0x1000;
          boots ++;
      }
      else
      {
          Serial.println("wake");
          Wake();
          tft.setRotation(1);
          tft.setSwapBytes(1);
          while (1)
          {
              Serial.println("changing color");
              tft.fillScreen(color);
              color+=0x1000;
              delay(1000);
          }
      }//if boots
}

void loop()
{
    delay(5000);
    Serial.println("sleep");
    Sleep();
}

Can't understand why after the wake up the display is not working as expected

genotix commented 3 years ago

Not fully into this but looking at your code some questions pop-up which might help you:

  1. Isn't there an SPI.end() or SPI.stop() or something that you should induce on sleep?
  2. I would first power the display, pause and then initialise SPI.
  3. What happens to your PULLUP value on the TP_PWR_PIN after a reboot and the pwer state of this pin (HIGH?)
  4. If you maintain the display to show it's last state in deep-sleep mode perhaps it loses sync with SPI or something so perhaps a short power off followed by short delay and power on is required?

Would like to know your outcome.

Regards,

Eric

Op 3 okt. 2020, om 19:07 heeft Fabrizio Benatti notifications@github.com het volgende geschreven:

Hi

This is meant to be an attempt to try and improve the display drawing speed after the ESP32 wakes up from deep sleep. In all the sources I've seen, the display call tft.init() at every wake of the microcontroller. This include a hardware or software reset that blank the screen for some milliseconds.

The ST7735 display has sleep and shutdown commands, preserving the contents of the on-screen buffer in memory.

My purpose is to try to:

fill the screen with a color A send the esp32 to deep sleep wake up with button press the esp32 and redraw the display with color A then change in progression colors to B, C , etc.. Here's the code i'm working on:

include

include // Graphics and font library for ST7735 driver chip

include

include

include

include "sensor.h"

include "esp_adc_cal.h"

define TP_PIN_PIN 33

define TP_PWR_PIN 25

TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h RTC_DATA_ATTR int boots = 0;

void setupTFT() { tft.init(); tft.setRotation(1); tft.setSwapBytes(true); }

int color = 0x5555;

void Wake() { SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); pinMode(TFT_CS, OUTPUT); pinMode(TFT_DC, OUTPUT); pinMode(TFT_BL, OUTPUT); tft.writecommand(ST7735_DISPON); tft.writecommand(ST7735_SLPOUT); }

void Sleep() { tft.writecommand(ST7735_SLPIN); tft.writecommand(ST7735_DISPOFF); delay(200);

digitalWrite(GPIO_NUM_26, HIGH); // keep GPIO_26 high state after deep sleep reset gpio_hold_en(GPIO_NUM_26); // display is preserved gpio_deep_sleep_hold_en();

esp_sleep_enable_ext1_wakeup(GPIO_SEL_33, ESP_EXT1_WAKEUP_ANY_HIGH); esp_deep_sleep_start(); }

void setup(void) { pinMode(TP_PIN_PIN, INPUT); pinMode(TP_PWR_PIN, PULLUP); //! Must be set to pull-up output mode in order to wake up in deep sleep mode digitalWrite(TP_PWR_PIN, HIGH);

Serial.begin(115200);

if(boots == 0) //Run this only the first time
{
    Serial.println("first boot");
    setupTFT();
    tft.fillScreen(color);
    color+=0x1000;
    boots ++;
}
else
{
    Serial.println("wake");
    Wake();
    tft.setRotation(1);
    tft.setSwapBytes(1);
    while (1)
    {
        Serial.println("changing color");
        tft.fillScreen(color);
        color+=0x1000;
        delay(1000);
    }
}//if boots

}

void loop() { delay(5000); Serial.println("sleep"); Sleep(); } Can't understand why after the wake up the display is not working as expected

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/issues/19, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACCG53QHUCPODCDSGNCRALLSI5K6DANCNFSM4SDEFIGA.

[ { "@context": "http://schema.org", "@type": "EmailMessage", "potentialAction": { "@type": "ViewAction", "target": "https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/issues/19", "url": "https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/issues/19", "name": "View Issue" }, "description": "View this Issue on GitHub", "publisher": { "@type": "Organization", "name": "GitHub", "url": "https://github.com" } } ]

biccius commented 3 years ago

Hi Eric

  1. SPI.end() detach all SPI pins (MISO,MOSI,CLOCK,CS) previously attached by SPI.begin() to signals events. I think is useless add it before the sleep because at restart the peripheral is uninitialized because the chip is reset by the deep sleep.
  2. According to schematics of the display ( https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/blob/master/schematic/T_Wristband_lsm9ds1_20200306.pdf) we can just send a RESET signal on RES pin. I want to avoid this because the display is already initialized.

In the sleep phase we use

 tft.writecommand(ST7735_SLPIN);
  delay(150);
  tft.writecommand(ST7735_DISPOFF);
  delay(200);

In wake up we have to do the same with SLPOUT and DISPON but before do that we have to re-initialize the SPI perpipheral

  1. This pin is used by touchpad to wakeup the device. Actually I find this pointless because the sleep is working correctly for me.
  2. If we do a tft.init() everything restart to work correctly. This method called at every wake is very slow so avoid the re-init of the display with all SPI commands is what i'm trying to do. I already do DISPON and DISPOFF commands on the display and the display turn on correctly after the sleep for me.

Here's my last source revision

#include <pcf8563.h>
#include <TFT_eSPI.h>            // Graphics and font library for ST7735 driver chip
#include <SPI.h>
#include <WiFi.h>
#include <Wire.h>
#include "sensor.h"
#include "esp_adc_cal.h"

#define TP_PIN_PIN          33
#define TP_PWR_PIN          25

TFT_eSPI tft = TFT_eSPI();       // Invoke library, pins defined in User_Setup.h
RTC_DATA_ATTR int boots = 0;

void setupTFT()
{
  tft.init();
  tft.setRotation(1);
  tft.setSwapBytes(true);
}

int color = 0x5555;

void Wake()
{

    pinMode(TFT_CS, OUTPUT);
    pinMode(TFT_DC, OUTPUT);
    pinMode(TFT_BL, OUTPUT);

    digitalWrite( TFT_BL , HIGH);

    SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);

    tft.writecommand(ST7735_DISPON);
    delay(150);
    tft.writecommand(ST7735_SLPOUT);
    delay(150);
}

void Sleep()
{
  tft.writecommand(ST7735_SLPIN);
  delay(150);
  tft.writecommand(ST7735_DISPOFF);
  delay(200);

  digitalWrite(GPIO_NUM_26, HIGH);  // keep GPIO_26 high state after deep sleep reset
  gpio_hold_en(GPIO_NUM_26);        // display is preserved
  gpio_deep_sleep_hold_en();

  digitalWrite( TFT_BL , LOW);

  SPI.end();

  esp_sleep_enable_ext1_wakeup(GPIO_SEL_33, ESP_EXT1_WAKEUP_ANY_HIGH);
  esp_deep_sleep_start();
}

void setup(void)
{
      pinMode(TP_PIN_PIN, INPUT);
      pinMode(TP_PWR_PIN, PULLUP);
      //! Must be set to pull-up output mode in order to wake up in deep sleep mode
      digitalWrite(TP_PWR_PIN, HIGH);

      Serial.begin(115200);

      if(boots == 0) //Run this only the first time
      {
          Serial.println("first boot");
          setupTFT();
          tft.fillScreen(color);
          color+=0x1000;
          boots ++;
      }
      else
      {
          Serial.println("wake");
          Wake();
          tft.setRotation(1);
          tft.setSwapBytes(1);
          delay(3000);
          while (1)
          {
              Serial.println("changing color");
              tft.fillScreen(color);
              color+=10;
              delay(10);
          }
      }//if boots
}

void loop()
{
    delay(5000);
    Serial.println("sleep");
    Sleep();
}

What the code do is :

  1. display start with cyan screen
  2. deepsleep after 5 seconds
  3. wakeup at button press with immediate display cyan screen shown
  4. after the wakeup the display start cycling redrawing the display with differents colors

Everything works, but at point 4 i have the display like in figure

IMAGE

So i think the tft library restart in a wrong state or the display need to be re-initialized in some way

genotix commented 3 years ago

Hi!

See inline my response

Op 4 okt. 2020, om 18:46 heeft Fabrizio Benatti notifications@github.com het volgende geschreven:

Hi Eric

SPI.end() detach all SPI pins (MISO,MOSI,CLOCK,CS) previously attached by SPI.begin() to signals events. I think is useless add it before the sleep because at restart the peripheral is uninitialized because the chip is reset by the deep sleep. I know that normally a return from a deep sleep is a full reset. You don't notify the display of this though. I'm not sure what happens to the bus connection of the display once you stop the clock. The clock of the SPI interface will likely stop on deep sleep. It is likely that the display will need some kind of "kick" to make sure it accepts data again.

Since you explicitly -disconnect- from the display without really letting it know that SPI might become reset and the clock being stopped this might cause the SPI bus of the display to crash and show a noisy framebuffer image. (which looks fairly like the image you get)

According to schematics of the display ( https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/blob/master/schematic/T_Wristband_lsm9ds1_20200306.pdf https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/blob/master/schematic/T_Wristband_lsm9ds1_20200306.pdf) we can just send a RESET signal on RES pin. I want to avoid this because the display is already initialized. Hmm check out this document; it's the display datasheet: https://datasheetspdf.com/pdf-file/694957/SitronixTechnology/ST7735/1 https://datasheetspdf.com/pdf-file/694957/SitronixTechnology/ST7735/1

From the display sheet i see it can also have a Parallel interface active. Perhaps that one kicks in after the reset causing the issues.

In the sleep phase we use

tft.writecommand(ST7735_SLPIN); delay(150); tft.writecommand(ST7735_DISPOFF); delay(200); In wake up we have to do the same with SLPOUT and DISPON but before do that we have to re-initialize the SPI perpipheral

  1. This pin is used by touchpad to wakeup the device. Actually I find this pointless because the sleep is working correctly for me.
  2. If we do a tft.init() everything restart to work correctly. This method called at every wake is very slow so re-init the display with all SPI commands is what i'm trying to do. I already do DISPON and DISPOFF commands on the display and the display turn on correctly after the sleep for me.

Hmm have you by any chance tried to change the order of the write commands to turn the display on again perhaps to see if this has a positive effect? Here's my last source revision

include

include // Graphics and font library for ST7735 driver chip

include

include

include

include "sensor.h"

include "esp_adc_cal.h"

define TP_PIN_PIN 33

define TP_PWR_PIN 25

TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h RTC_DATA_ATTR int boots = 0;

void setupTFT() { tft.init(); tft.setRotation(1); tft.setSwapBytes(true); }

int color = 0x5555;

void Wake() {

pinMode(TFT_CS, OUTPUT);
pinMode(TFT_DC, OUTPUT);
pinMode(TFT_BL, OUTPUT);

digitalWrite( TFT_BL , HIGH);

SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);

tft.writecommand(ST7735_DISPON);
delay(150);

tft.writecommand(ST7735_SLPOUT); delay(150); }

void Sleep() { tft.writecommand(ST7735_SLPIN); delay(150); tft.writecommand(ST7735_DISPOFF); delay(200);

digitalWrite(GPIO_NUM_26, HIGH); // keep GPIO_26 high state after deep sleep reset gpio_hold_en(GPIO_NUM_26); // display is preserved gpio_deep_sleep_hold_en();

digitalWrite( TFT_BL , LOW);

SPI.end();

esp_sleep_enable_ext1_wakeup(GPIO_SEL_33, ESP_EXT1_WAKEUP_ANY_HIGH); esp_deep_sleep_start(); }

void setup(void) { pinMode(TP_PIN_PIN, INPUT); pinMode(TP_PWR_PIN, PULLUP); //! Must be set to pull-up output mode in order to wake up in deep sleep mode Where did you get this from? I would not do that unless you're absolutely correct on this one. Since the pull-up is something like a 4k7 resistor it might wake up the chip of the TFT yet not sufficient enough perhaps corrupting the existing memory. Are you positive on this one?

I hope you get it fixed! Good luck!

digitalWrite(TP_PWR_PIN, HIGH);

Serial.begin(115200);

if(boots == 0) //Run this only the first time
{
    Serial.println("first boot");
    setupTFT();
    tft.fillScreen(color);
    color+=0x1000;
    boots ++;
}
else
{
    Serial.println("wake");
    Wake();
    tft.setRotation(1);
    tft.setSwapBytes(1);
    delay(3000);
    while (1)
    {
        Serial.println("changing color");
        tft.fillScreen(color);
        color+=10;
        delay(10);
    }
}//if boots

}

void loop() { delay(5000); Serial.println("sleep"); Sleep(); } What the code do is :

display start with cyan screen deepsleep after 5 seconds wakeup at button press with immediate display cyan screen shown after the wakeup the display start cycling redrawing the display with differents colors Everything works, but at point 4 i have the display like in figure

IMAGE https://i.ibb.co/nMWTMLX/Whats-App-Image-2020-10-04-at-18-39-30.jpg So i think the tft library restart in a wrong state or the display need to be re-initialized in some way

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/issues/19#issuecomment-703282742, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACCG53Q2ZLA7NXKWX6X4QK3SJCRGRANCNFSM4SDEFIGA.

[ { "@context": "http://schema.org", "@type": "EmailMessage", "potentialAction": { "@type": "ViewAction", "target": "https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/issues/19#issuecomment-703282742", "url": "https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/issues/19#issuecomment-703282742", "name": "View Issue" }, "description": "View this Issue on GitHub", "publisher": { "@type": "Organization", "name": "GitHub", "url": "https://github.com" } } ]

biccius commented 3 years ago

I think you may be right about asynchronously blocking communication between ESP32 and the display. Just adding SPI.end doesn't seem to give improvements

Not even changing the order of the write commands seems to change anything either

It could be that restarting the ESP32 at reset sends something strange to the already configured display and causes that horizontal bar not to be redrawn.

I can't understand what you're referring to in the last part of the post.

genotix commented 3 years ago

Give my code a try: https://github.com/genotix/LilyGO-T-Wristband

Verstuurd vanaf mijn iPad

Op 3 okt. 2020 om 19:08 heeft Fabrizio Benatti notifications@github.com het volgende geschreven:

SPI.begin(