TFT_ST7735
TFT_ST7735 copied to clipboard
ESP32-PICO-D4 + ST7735 180x60 + deep sleep
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
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.
Thank you very much for the advice. I tried them both.
- 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();
}
- 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.
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.