TFT_ST7735 icon indicating copy to clipboard operation
TFT_ST7735 copied to clipboard

ESP32-PICO-D4 + ST7735 180x60 + deep sleep

Open biccius opened this issue 4 years ago • 3 comments

Hi,

I'm programming a LilyGo T-Wristband with Arduino core (no esp-idf) using ESP32-PICO-D4. A ST7735 0.96" 160x80 TFT screen is connected using SPI and TFT_eSPI is the graphical library used to manage the display. A TP button is used to wake up the chip from deep sleep mode. Schematics and more informations are at the end of this post.

My purpose is to try to:

a. init display at the start then fill the screen with a color A b. send the esp32 to deep sleep c. wake up with button press the esp32 and redraw the display with color A avoiding to re-initialize the display cause it's already set d. then change in progression colors to B, C , etc..

On "c" phase i don't want to re-initialize the display everytime i wake from a deep sleep because is a slow operation. I assume the display is already initialized and just wake it up from sleep as fast as possible. So i'm trying with this code to keep the RESET pin high (gpio_hold_en) and switch off the display (DISPOFF) and sending it to sleep (SLPIN)


#include <TFT_eSPI.h>            
#include <SPI.h>
#include <WiFi.h>
#include <Wire.h>
#include "sensor.h"
#include "esp_adc_cal.h"


#define TP_PIN_PIN          		33		// wakeup pin
#define TP_PWR_PIN 			25		// power for the touch button

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);	//backlight on

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

    tft.writecommand(ST7735_DISPON);	// display on
    delay(150);
    tft.writecommand(ST7735_SLPOUT);	// display sleep off
    delay(150);
}

void Sleep()
{
  tft.writecommand(ST7735_SLPIN);  // display sleep on
  delay(150);
  tft.writecommand(ST7735_DISPOFF);  // display off
  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);  //backlight off
  SPI.end();	// spi communication stopped

  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();
}

Code seems to work properly but in "d" phase i get the display not full filled by a new color like in figure: https://i.imgur.com/LYRMzat.jpeg

Is there something wrong? What can be the cause and how to fix it? Any code improvements?

Thank you

PIN DEFINITION

TFT_MOSI 19 TFT_SCLK 18 TFT_CS 5 TFT_DC 23 TFT_RST 26 TFT_BL 27 Touchpad 33 Touchpad Power 25

RESOURCES

-LilyGo T-Wristband : https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband -Schematics: https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/blob/master/schematic/T_Wristband_lsm9ds1_20200306.pdf -Issue description: https://github.com/Xinyuan-LilyGO/LilyGo-T-Wristband/issues/19

biccius avatar Oct 17 '20 22:10 biccius

Make sure the TFT_CS signal stays high otherwise the display can get garbage commands. I suspect the display may need to be re-initialised upon wake up. Unfortunately I am unable to advise further.

Bodmer avatar Oct 18 '20 00:10 Bodmer

Thank you very much for the advice. I tried them both.

  1. NOT WORKING: Added gpio_hold_en(GPIO_NUM_5) in Sleep function to keep CS signal high: same result of my previous code. After the wake up the display is not filled completely.
#include <TFT_eSPI.h>            
#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(80,160);       // Invoke library, pins defined in User_Setup.h

RTC_DATA_ATTR int boots = 0;
int color = 0x5555;



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


void Sleep()
{
	digitalWrite( TFT_BL , LOW);
	tft.writecommand(ST7735_DISPOFF);
	SPI.end();
	digitalWrite(GPIO_NUM_5, HIGH);  // CS high after sleep
	gpio_hold_en(GPIO_NUM_5);

	digitalWrite(GPIO_NUM_26, HIGH);  //RESET high after sleep
	gpio_hold_en(GPIO_NUM_26);
	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)
{

	  Serial.begin(115200);

	  if(boots == 0) //Run this only the first time
	  {

		  pinMode(TP_PIN_PIN, INPUT_PULLDOWN);
		  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.println("first boot");
		  setupTFT();
		  tft.fillScreen(color);
		  color+=0x1000;
	  	  boots ++;
	  }
	  else
	  {
		  	Serial.println("wake");

		  	pinMode(TFT_BL, OUTPUT);
		  	digitalWrite( TFT_BL , HIGH);


		  	gpio_hold_dis(GPIO_NUM_5);		// CS hold disabled
		    gpio_hold_dis(GPIO_NUM_26);		// RESET hold disabled
		    gpio_deep_sleep_hold_dis();

		    SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, TFT_CS);  

		    tft.setRotation(1);
		    tft.writecommand(ST7735_DISPON);

		  delay(3000);
		  while (1)
		  {
			  Serial.println("changing color");
			  tft.fillScreen(color);
			  color+=10;
			  delay(10);
		  }
	  }//if boots
}




void loop()
{
	delay(5000);
	Sleep();
}
  1. WORKING : Added a tft_init() function that avoid to send software/hardware RESET signals to the display.
#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(80,160);       // Invoke library, pins defined in User_Setup.h

RTC_DATA_ATTR int boots = 0;
int color = 0x5555;


static const uint8_t PROGMEM
Rcmd1[] = {                 // Init for 7735R, part 1 (red or green tab)
			    14,                       // 14 commands in list:   !!! EDIT !!! removed SWRESET command
			    ST7735_SLPOUT ,   TFT_INIT_DELAY,  //  2: Out of sleep mode, 0 args, w/delay
			      255,                    //     500 ms delay
			    ST7735_FRMCTR1, 3      ,  //  3: Frame rate ctrl - normal mode, 3 args:
			      0x01, 0x2C, 0x2D,       //     Rate = fosc/(1x2+40) * (LINE+2C+2D)
			    ST7735_FRMCTR2, 3      ,  //  4: Frame rate control - idle mode, 3 args:
			      0x01, 0x2C, 0x2D,       //     Rate = fosc/(1x2+40) * (LINE+2C+2D)
			    ST7735_FRMCTR3, 6      ,  //  5: Frame rate ctrl - partial mode, 6 args:
			      0x01, 0x2C, 0x2D,       //     Dot inversion mode
			      0x01, 0x2C, 0x2D,       //     Line inversion mode
			    ST7735_INVCTR , 1      ,  //  6: Display inversion ctrl, 1 arg, no delay:
			      0x07,                   //     No inversion
			    ST7735_PWCTR1 , 3      ,  //  7: Power control, 3 args, no delay:
			      0xA2,
			      0x02,                   //     -4.6V
			      0x84,                   //     AUTO mode
			    ST7735_PWCTR2 , 1      ,  //  8: Power control, 1 arg, no delay:
			      0xC5,                   //     VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD
			    ST7735_PWCTR3 , 2      ,  //  9: Power control, 2 args, no delay:
			      0x0A,                   //     Opamp current small
			      0x00,                   //     Boost frequency
			    ST7735_PWCTR4 , 2      ,  // 10: Power control, 2 args, no delay:
			      0x8A,                   //     BCLK/2, Opamp current small & Medium low
			      0x2A,
			    ST7735_PWCTR5 , 2      ,  // 11: Power control, 2 args, no delay:
			      0x8A, 0xEE,
			    ST7735_VMCTR1 , 1      ,  // 12: Power control, 1 arg, no delay:
			      0x0E,
			    ST7735_INVOFF , 0      ,  // 13: Don't invert display, no args, no delay
			    ST7735_MADCTL , 1      ,  // 14: Memory access control (directions), 1 arg:
			      0xC8,                   //     row addr/col addr, bottom to top refresh
			    ST7735_COLMOD , 1      ,  // 15: set color mode, 1 arg, no delay:
			      0x05 },                 //     16-bit color

Rcmd2green[] = {            // Init for 7735R, part 2 (green tab only)
			    2,                        //  2 commands in list:
			    ST7735_CASET  , 4      ,  //  1: Column addr set, 4 args, no delay:
			      0x00, 0x02,             //     XSTART = 0
			      0x00, 0x7F+0x02,        //     XEND = 127
			    ST7735_RASET  , 4      ,  //  2: Row addr set, 4 args, no delay:
			      0x00, 0x01,             //     XSTART = 0
			      0x00, 0x9F+0x01 },      //     XEND = 159


Rcmd3[] = {                 // Init for 7735R, part 3 (red or green tab)
			    4,                        //  4 commands in list:
			    ST7735_GMCTRP1, 16      , //  1: 16 args, no delay:
			      0x02, 0x1c, 0x07, 0x12,
			      0x37, 0x32, 0x29, 0x2d,
			      0x29, 0x25, 0x2B, 0x39,
			      0x00, 0x01, 0x03, 0x10,
			    ST7735_GMCTRN1, 16      , //  2: 16 args, no delay:
			      0x03, 0x1d, 0x07, 0x06,
			      0x2E, 0x2C, 0x29, 0x2D,
			      0x2E, 0x2E, 0x37, 0x3F,
			      0x00, 0x00, 0x02, 0x10,
			    ST7735_NORON  ,    TFT_INIT_DELAY, //  3: Normal display on, no args, w/delay
			      10,                     //     10 ms delay
			    ST7735_DISPON ,    TFT_INIT_DELAY, //  4: Main screen turn on, no args w/delay
			      100 };                  //     100 ms delay





void tft_init()
{
			  	tft.start_tft();
			  	tft.commandList(Rcmd1);
			  	tft.commandList(Rcmd2green);
			  	tft.writecommand(TFT_INVON);
			  	tft.set_col_row(26,1);
			  	tft.commandList(Rcmd3);
			  	tft.end_tft();
}



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


void Sleep()
{
	digitalWrite( TFT_BL , LOW);
	tft.writecommand(ST7735_DISPOFF);
	SPI.end();
	digitalWrite(GPIO_NUM_5, HIGH);  // CS high after sleep
	gpio_hold_en(GPIO_NUM_5);

	digitalWrite(GPIO_NUM_26, HIGH);  //RESET high after sleep
	gpio_hold_en(GPIO_NUM_26);
	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)
{

	  Serial.begin(115200);

	  if(boots == 0) //Run this only the first time
	  {

		  pinMode(TP_PIN_PIN, INPUT_PULLDOWN);
		  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.println("first boot");
		  setupTFT();
		  tft.fillScreen(color);
		  color+=0x1000;
	  	  boots ++;
	  }
	  else
	  {
		  	Serial.println("wake");

		  	pinMode(TFT_BL, OUTPUT);
		  	digitalWrite( TFT_BL , HIGH);


		  	gpio_hold_dis(GPIO_NUM_5);		// CS hold disabled
		    gpio_hold_dis(GPIO_NUM_26);		// RESET hold siavled
		    gpio_deep_sleep_hold_dis();

		    SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, TFT_CS);

		    tft.writecommand(ST7735_DISPON);  // display is switched ON with last image loaded before sleep

		    tft_init(); // customi init without sw/hw reset


		  delay(3000);
		  while (1)
		  {
			  Serial.println("changing color");
			  tft.fillScreen(color);
			  color+=10;
			  delay(10);
		  }
	  }//if boots
}




void loop()
{
	delay(5000);
	Sleep();
}

It is not clear to me why method 1 is not sufficient, in any case method 2 seems to work.

Thanks for the suggestions. If there are no other improvements on the codes proposed for me you can close the issue.

Thank you very much.

biccius avatar Oct 18 '20 20:10 biccius

Unfortunately I was wrong. The screen fill seems to work but other functions such as writing text for example do not work properly so unfortunately it seems that something needs to be reset and re-initialized.

biccius avatar Oct 27 '20 22:10 biccius