Bodmer / TFT_eSPI

Arduino and PlatformIO IDE compatible TFT library optimised for the Raspberry Pi Pico (RP2040), STM32, ESP8266 and ESP32 that supports different driver chips
Other
3.71k stars 1.07k forks source link

eInk display in overlap mode #193

Closed JamesNewton closed 6 years ago

JamesNewton commented 6 years ago

The ability to use the eInk displays is really nice, especially for low power monitoring operations. (see #105)

But we are again, out of pins. #74

Is there a way to get the eInk to work in overlap mode?

I've been trying but so far it's not working for me.

Bodmer commented 6 years ago

The SPI interface and pins are defined in the EPD library here and here. The TFT_eSPI library only provides the graphics functions.

The EPD library will thus need to be modified to use the overlap mode, in the TFT_eSPI library the required code is here.

JamesNewton commented 6 years ago

I'm trying to get the Floyd_Steinberg demo to work. Here is my code esp_ePaper.zip I get error: Floyd_Steinberg.ino:55:0: EPD_Support.h:88: error: 'blackFramePtr' was not declared in this scope void updateDisplay(uint8_t blackFrame = blackFramePtr, uint8_t redFrame = redFramePtr) EPD_Support.h:88: error: 'redFramePtr' was not declared in this scope void updateDisplay(uint8_t blackFrame = blackFramePtr, uint8_t redFrame = redFramePtr)

If I remove those default values, I get: In function 'void rotateTest()': Floyd_Steinberg:189: error: too few arguments to function 'void updateDisplay(uint8_t, uint8_t)' updateDisplay(); // Update display

I'm using the epd1in54b driver. The demo in that folder DOES work when modified as you suggested.

I admit that I have not updated the TFT_eSPI library to the latest version, but I don't see any definitions in the current version either. I always hate to do the update because I have to fix the ILI9341 setup back to overlap mode.

I guess I just want to check that you've run this code lately? Is it just that I need to update the TFT-eSPI library again?

Bodmer commented 6 years ago

I had a look and the support libraries for the different displays do not have a consistent set of functions and the example Floyd_Steinberg example was written for the 2.7in display. I will need to think on this further...

Bodmer commented 6 years ago

It was a variable name error in the end.

Try the attached sketch.

Floyd_Steinberg_1in54b.zip

JamesNewton commented 6 years ago

That works, with a couple of (minor) limitations:

  1. I don't see the tiger image at all. Just a blank screen, then the "cross hairs" then the "Rotation" text. Which is really exciting for us!

  2. It's only a single color (black) on the white background, and this is a color display.

Of the two, we care far more about the color.

Bodmer commented 6 years ago

Have you uploaded the tiger image to SPIFFS using the IDEs upload menu option? The image is already in the sketch data folder.

Add you code for the red frame graphics by selecting frame buffer 2 and then drawing/printing what you want, then use the display update function.

I will create an example later today.

Bodmer commented 6 years ago

Use INK or PAPER only for the graphics colours. INK will end up black in a black frame or red in a red frame.

JamesNewton commented 6 years ago

Doh! Of course. Works perfectly now. If it helps, here is the demo program I made:

// Test sketch for 1.54 two colour display using library modified for ESP8266 overlap mode

// Display grey-scale images on a Monchrome ePaper display using
// Floyd-Steinberg dithering
// https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering

// Example created by Bodmer 31/3/18 for TFT_eSPI library:
// https://github.com/Bodmer/TFT_eSPI
// Select the ePaper setup in library's "User_Setup_Select.h" file

// This sketch supports Waveshare 2 colour ePaper displays
// https://www.waveshare.com/product/modules/oleds-lcds/e-paper.htm

// Test images are in the Data folder with sketch (press Ctrl+k)
// Upload using the Tools menu "ESP8266 Sketch Data Upload" option

// READ THIS  READ THIS  READ THIS  READ THIS  READ THIS  READ THIS
// Install the ePaper library for your own display size and type
// from here:
// https://github.com/Bodmer/EPD_Libraries

// The following is for the Waveshare 2.7" colour ePaper display
// include <epd?in?.h>  where ?.?? is screen size in inches

//#include   <epd2in7.h>                  // Screen specific library
#include   <epd1in54b.h>                  // Screen specific library

Epd ePaper;                             // Create an instance ePaper

#include <TFT_eSPI.h>                   // Graphics library and Sprite class

TFT_eSPI      glc = TFT_eSPI();         // Invoke the graphics library class
TFT_eSprite frame = TFT_eSprite(&glc);  // Invoke the Sprite class for the image frame buffer

#define INK    COLORED                  // Black ink
#define PAPER  UNCOLORED                // 'paper' background colour

uint16_t epd_width  = EPD_WIDTH;        // Set the initial values, these are swapped
uint16_t epd_height = EPD_HEIGHT;       // in different landscape/portrait rotations
                                        // so call frame.width() or frame.height() to get new values

#define EPD_BUFFER 1                    // Label for the black frame buffer 1

uint8_t* framePtr = NULL;               // Pointer for the black frame buffer
uint8_t* redFramePtr = NULL;            // Pointer for the red frame buffer

#include "EPD_Support.h"                // Include sketch EPD support functions last!

int8_t limit = 5;                      // Limit the number of loops before halting
//------------------------------------------------------------------------------------
// Setup
//------------------------------------------------------------------------------------
void setup() {

  //       Invoke overlap mode
  //       CLK   SD0   SD1   D3     NodeMCU pin names
  //      SCLK  MISO  MOSI   SS     SPI signal names
  //       CLK         DIN   CS     ePaper signal names (MISO not connected)
  //        6     7     8     0     ESP8266 GPIO numbers
  SPI.pins( 6,    7,    8,    0);

  Serial.begin(250000); // Used for messages

  // Initialise the ePaper library
  if (ePaper.Init() != 0) {
    Serial.print("ePaper init failed");
    while (1) yield(); // Wait here until re-boot
  }

  Serial.println("\r\n ePaper initialisation OK");

  // Initialise the SPIFFS filing system
  if (!SPIFFS.begin()) {
    Serial.println("SPIFFS initialisation failed!");
    while (1) yield(); // Stay here twiddling thumbs
  }

  Serial.println(" SPIFFS initialisation OK");

  frame.setColorDepth(1); // Must set the bits per pixel to 1 for ePaper displays
                          // Set bit depth BEFORE creating Sprite, default is 16!

  // Create a frame buffer in RAM of defined size and save the pointer to it
  // RAM needed is about (EPD_WIDTH * EPD_HEIGHT)/8 , ~5000 bytes for 200 x 200 pixels
  // Note: always create the Sprite before setting the Sprite rotation
  framePtr = (uint8_t*) frame.createSprite(EPD_WIDTH, EPD_HEIGHT, 2);      // Create sprite with 2 frame buffers
  redFramePtr = (uint8_t*) frame.frameBuffer(2);                           // Pointer to frame buffer 2

  // Clear the two frame buffers
  frame.frameBuffer(1);
  frame.fillSprite(PAPER);
  frame.frameBuffer(2);
  frame.fillSprite(PAPER);

  Serial.println("\r\nInitialisation done.");

  listFiles();  // List all the files in the SPIFFS
}

//------------------------------------------------------------------------------------
// Loop
//------------------------------------------------------------------------------------
void loop() {
  // Select frame buffer 1 for the graphics
  frame.frameBuffer(1);
  frame.fillSprite(PAPER);  // Fill frame with white
  frame.frameBuffer(2);
  frame.fillSprite(PAPER);  // Fill frame with white

  frame.setRotation(random(4)); // Set the rotation to 0, 1, 2 or 3 ( 1 & 3 = landscape)

  frame.frameBuffer(1);
  // Draw 8 bit grey-scale bitmap using Floyd-Steinberg dithering at x,y
  //           /File name      x  y
  //drawFSBmp("/TestCard.bmp", 0, 0); // 176 x 264 pixels
  drawFSBmp("/Tiger.bmp", (frame.width()-176)/2, (frame.height()-234)/2); // 176 x 234 pixels

  updateDisplay();  // Send image to display and refresh

  delay(10000);

  frame.fillSprite(PAPER);  // Fill frame with white

  // Draw circle in frame buffer (x, y, r, color) in center of screen
  frame.frameBuffer(1);
  frame.drawCircle(frame.width()/2, frame.height()/2, frame.width()/6, INK);
  frame.frameBuffer(2);
  frame.drawCircle(frame.width()/2, frame.height()/2, frame.width()/8, INK);

  // Draw diagonal lines
  frame.frameBuffer(1);
  frame.drawLine(0 ,                0, frame.width()-1, frame.height()-1, INK);
  frame.frameBuffer(2);
  frame.drawLine(0 , frame.height()-1, frame.width()-1,                0, INK);

  updateDisplay();  // Send image to display and refresh

  delay(10000);

  // Run a rotation test
  rotateTest();

  delay(10000);

  // Put screen to sleep to save power (if wanted)
  ePaper.Sleep();

  if (--limit <= 0) while(1) yield(); // Wait here

  delay(10000); // Wait here for 10s

  // Wake up ePaper display so we can talk to it
  Serial.println("Waking up!");
  ePaper.Init();

} // end of loop()

//------------------------------------------------------------------------------------
// setRotation() actually rotates the drawing coordinates, not the whole display frame
// buffer so we can use this to draw text at right angles or upside down
//------------------------------------------------------------------------------------
void rotateTest(void)
{
  //frame.fillSprite(PAPER);             // Fill buffer with white to clear old graphics

  // Draw some text in frame buffer
  frame.setTextFont(4);                  // Select font 4
  frame.setTextColor(INK);               // Set colour to ink
  frame.setTextDatum(TC_DATUM);          // Middle centre text datum

  frame.setRotation(0);                  // Set the display rotation to 0, 1, 2 or 3 ( 1 & 3 = landscape)
  epd_width  = frame.width();            // Get the values for the current rotation
  epd_height = frame.height();           // epd_height is not used in this sketch

  frame.frameBuffer(1);
  frame.drawString("Rotation 0",   epd_width / 2, 10);

  frame.setRotation(1);                  // Set the display rotation to 1
  epd_width  = frame.width();            // Get the values for the current rotation
  epd_height = frame.height();           // epd_height is not used in this sketch

  frame.frameBuffer(2);
  frame.drawString("Rotation 1",   epd_width / 2, 10);

  frame.setRotation(2);                  // Set the display rotation to 2
  epd_width  = frame.width();            // Get the values for the current rotation
  epd_height = frame.height();           // epd_height is not used in this sketch

  frame.frameBuffer(1);
  frame.drawString("Rotation 2",   epd_width / 2, 10);

  frame.setRotation(3);                  // Set the display rotation to 3
  epd_width  = frame.width();            // Get the values for the current rotation
  epd_height = frame.height();           // epd_height is not used in this sketch

  frame.frameBuffer(2);
  frame.drawString("Rotation 3",   epd_width / 2, 10);

  Serial.println("Updating display");
  updateDisplay();  // Update display
}
Bodmer commented 6 years ago

I see you have cracked it!

Here is my updated example that draws a filled red circle during the test. Floyd_Steinberg_1in54b.zip

JamesNewton commented 6 years ago

Yep, thanks to your help. Now I just have to figure out how to do partial updates so I'm not sucking up so much RAM and I can change the data on the screen a little faster.

Bodmer commented 6 years ago

Partial update is not possible with the 1in54b but is with the single colour version.

It is tricky and there are quite a few gotchas. This is code for a 2in9 display that includes a partial update area and will give you clues.

Floyd_Steinberg_2in9.zip