Go Down

Topic: Waveshare e-paper displays with SPI (Read 334786 times) previous topic - next topic

ZinggJM

#1920
Jul 02, 2020, 05:01 pm Last Edit: Jul 02, 2020, 05:06 pm by ZinggJM
@sremick,

Waveshare uses e-paper panels from Good Display, at least mostly.

Waveshare brought us e-paper panels mounted on boards for easy use. See my first post in this topic.

1.54 inch e-paper display module partial refresh E-ink screen panel, GDEH0154D67
is the actual version of the 1.54" 200x200 b/w panel also used by Waveshare.

Cool: I had not yet discovered that Good Display has re-activated their original internet address www.good-display.com
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

mrweles

Hi. I used 4 "displays that worked with the GxEPD library and everything was fine, but I needed to increase the size of the display, for this I bought a 12.48" display that works only with the GxEPD2 library.
Previously, I displayed the image of each pixel directly from the HTTP buffer, but in GxEPD2 display.drawPixel does not work.
The size of the image that I want to display does not allow me to store it in RAM and display each pixel separately, is the only solution.
Please tell me how to solve this problem? Sample code from my project below

Code: [Select]
uint8_t buff[128] = {0};
int len = http.getSize();
while (http.connected() && (len > 0 || len == -1)) {
  size_t size = stream->available();
  if (size) {
    // read up to 128 byte
    int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
    for (int offset = 0; offset < c; offset++) {
      eightPixels = buff[offset];
      if (cursor < X_RES * Y_RES) {
        for (uint8_t i = 0; i < 8; i++) {
          if ((eightPixels >> (7 - i)) & 0x01)
            display.drawPixel((cursor + i) % X_RES, (cursor + i) / X_RES, GxEPD_BLACK);
        }
        cursor += 8;
      }
    }
    if (len > 0) {
      len -= c;
    }
  }
  delay(1);
}

ZinggJM

#1922
Jul 04, 2020, 11:43 am Last Edit: Jul 04, 2020, 01:58 pm by ZinggJM
@mrweles,

Quote
but in GxEPD2 display.drawPixel does not work.
This is not correct. display.drawPixel() does work, but you need to use paged drawing for this huge display.

Try to re-code your application according to the example GxEPD2_WiFi_Example.ino

The idea is to transfer each line (or multiple lines) to the controller memory as a bitmap using display.writeImage().

Code: [Select]
         display.writeImage(output_row_mono_buffer, output_row_color_buffer, x, yrow, w, 1);

Jean-Marc
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

marco_99

Hi everyone! I'm trying to understand how e-papers works with my ESP32 Bluetooth/Wi-Fi. I'm using this screen (https://www.waveshare.com/1.54inch-e-paper-module-b.htm) and this board (https://www.waveshare.com/e-paper-esp32-driver-board.htm). This screen is just one I bought some times ago, i will use, for the definitive project, this screen (http://www.good-display.com/product/1.54-inch-e-paper-display-high-resolution-200x200-partial-refresh,-GDEW0154M09-206.html). The connection between the screen and the board is via the SPI connector integrated in the board (i detached the screen from its blue board). I found the attached .ino on the internet to try to understand how Gxepd2 library works. I modified the file to make it compatible with my screen and everything works but the screen refreshes continuously, and that's my problem. Looking at the code I found the display.hibernate() method that should block the screen from refreshing, so the screen should refresh only when something happens (like a pressed button ecc..). Can someone please help me with my problem? Another thing: I don't have an RTC connected to the board, but I don't think that this is the problem.

ZinggJM

#1924
Jul 04, 2020, 01:24 pm Last Edit: Jul 04, 2020, 01:40 pm by ZinggJM
@marco_99,

welcome to the forum. Please read General Guidance and How to use the Forum

Of course you may ask for help in the forum for your program, or for a program you found on the internet. You have a chance someone is willing to analyze such a program.

In general readers don't like if they have to download a program first to get an idea what it does.

But you should first check with examples that come with the library you use. Then try to find out the difference to your program.

It also helps if you explain more clearly what you expect from your program, and what the result is in contrast. At least for me this is not clear.

Addition: take a look at diagnostic output in Serial Monitor. Maybe your processor does a exception - reset loop.

Jean-Marc
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

mrweles

@mrweles,

This is not correct. display.drawPixel() does work, but you need to use paged drawing for this huge display.

Try to re-code your application according to the example GxEPD2_WiFi_Example.ino

The idea is to transfer each line (or multiple lines) to the controller memory as a bitmap using display.writeImage().

Code: [Select]
         display.writeImage(output_row_mono_buffer, output_row_color_buffer, x, yrow, w, 1);

Jean-Marc

Thanks, it works!
Are there any restrictions on file size?
At the moment, I have successfully displayed only a quarter of the picture

marco_99

Hi @ZinggJM, thank you for your reply. I already searched for information on the internet and this is the only forum I found that talks about GxEPD2 Library, so you are my only chance  :smiley-yell:. I tried to use the examples of the library but I find this code much simple and it works better for my purpose. In this example, fist of all i want to understand why the screen continuously refreshes because i want to make it refresh ONLY if a button is pressed, in order to show the updated writing, not refreshing for show the same writing, it doesn't make sense. Second I just want to run the hundleButton() function to make the screen display "BTN 3" if I press a button connected to the pin number 34 (actually i don't mind which button). I modified the code adding some comments with my questions on some display. methods and other things. Tell me if it's more clear and please let me know if you can help me!



Code: [Select]
//every RTC thing is commented but the switch case 1 and default, so the code like this surely doesn't work, i just an example

//#include <DS3232RTC.h>
#include <GxEPD2_3C.h>
#include <GxEPD2_BW.h>
#include "DSEG7_Classic_Bold_48.h"
#include "DSEG14_Classic_Bold_18.h"

#define VIB_MOTOR_PIN 23 //this declaration is understandable, the pin number 23 is declared
#define RTC_PIN GPIO_NUM_33//this one i don't know what this means. This is just another way to declare the pin number 33? Or is something different?
#define BTN_1 GPIO_SEL_39
#define BTN_2 GPIO_SEL_36
#define BTN_3 GPIO_SEL_34
#define BTN_4 GPIO_SEL_35
#define BTN_PIN_MASK BTN_1|BTN_2|BTN_3|BTN_4

//DS3232RTC RTC(false);
#if defined(ESP32)
GxEPD2_3C<GxEPD2_154c, GxEPD2_154c::HEIGHT> display(GxEPD2_154c(/*CS=*/ 15, /*DC=*/ 27, /*RST=*/ 26, /*BUSY=*/ 25));
#endif
#include "bitmaps/Bitmaps3c200x200.h" // 1.54" b/w/r


void setup()
{
   Serial.begin(115200);
  Serial.println();
  Serial.println("setup");
  display.init(115200); // uses standard SPI pins, e.g. SCK(18), MISO(19), MOSI(23), SS(5)
 SPI.end(); // release standard SPI pins, e.g. SCK(18), MISO(19), MOSI(23), SS(5)
  //SPI: void begin(int8_t sck=-1, int8_t miso=-1, int8_t mosi=-1, int8_t ss=-1);
  SPI.begin(13, 12, 14, 15); // map and init SPI pins SCK(13), MISO(12), MOSI(14), SS(15)
  // *** end of special handling for Waveshare ESP32 Driver board *** //
 
  esp_sleep_wakeup_cause_t wakeup_reason; //i don't know what this means
 
  wakeup_reason = esp_sleep_get_wakeup_cause();//i don't know what this means. I think that is the wakeup reason of the ESP32 and so the reason why the screen refreshes
 

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0: updateTime(false); break; //RTC Alarm Interrupt
    case ESP_SLEEP_WAKEUP_EXT1: handleButton(); break; //Button Press. I just want to run this function, how can i transform this switch?
    default: updateTime(true); //Hard Reset
  }



  esp_sleep_enable_ext0_wakeup(RTC_PIN, 0); //enable deep sleep wake on RTC interrupt
  esp_sleep_enable_ext1_wakeup(BTN_PIN_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); //enable deep sleep wake on button press
  esp_deep_sleep_start();
}

void loop(){}

//i just want to run this function and display the number of the button i pressed
void handleButton()
{
  uint64_t wakeupBit = esp_sleep_get_ext1_wakeup_status();// also this is the wake up reason?

  pinMode(VIB_MOTOR_PIN, OUTPUT);//this is clear
  digitalWrite(VIB_MOTOR_PIN, HIGH);
  delay(100);
  digitalWrite(VIB_MOTOR_PIN, LOW);

  display.init();//Initialization of the screen?
  display.fillScreen(GxEPD_WHITE);//this is clear
  display.setTextColor(GxEPD_BLACK);
  display.setFont(&DSEG14_Classic_Bold_18);
 
  display.setCursor(15, 100);
  display.println("You  pressed");
  display.setCursor(65, 140);
  if (wakeupBit & BTN_4) {//What does this means? I think is something like if the button 4 is pressed and the ESP32 is waked then show "BTN_4". But this doesn't make much sense, i want the screen refresh when i press the button
    display.println("BTN 4");
  }
  else if (wakeupBit & BTN_3) {
    display.println("BTN 3");
  }
  else if (wakeupBit & BTN_2) {
    display.println("BTN 2");
  }
  else if (wakeupBit & BTN_1) {
    display.println("BTN 1");   
  }
  display.display(false);//don't know what is this
  display.hibernate();//Hibernate is different from sleep? How does this works?
}


//Below the 2 functions for RTC, i don't need them for now
//void updateTime(bool reset)
//{
//  RTC.begin();
//  if(reset){
//    RTC.squareWave(SQWAVE_NONE); //disable square wave output
//    RTC.set(compileTime()); //set RTC time to compile time
//    RTC.setAlarm(ALM2_EVERY_MINUTE, 0, 0, 0, 0);
//    RTC.alarmInterrupt(ALARM_2, true); //enable alarm interrupt
//  }
//  RTC.alarm(ALARM_2); //resets the alarm flag in the RTC
//  tmElements_t currentTime;
//  RTC.read(currentTime);
//
//  display.init(0, reset); //_initial_refresh to false to prevent full update on init
//  display.setFullWindow();
//  display.fillScreen(GxEPD_BLACK);
//  display.setTextColor(GxEPD_WHITE);
//  display.setFont(&DSEG7_Classic_Bold_48);
//  display.setCursor(15, 120);
//
//  if(currentTime.Hour < 10){
//    display.print('0');
//  }
//  display.print(currentTime.Hour);
//  display.print(':');
//  if(currentTime.Minute < 10){
//    display.print('0');
//  }   
//  display.print(currentTime.Minute);
//  display.display(true); //partial refresh
//  display.hibernate();
//}
//
//time_t compileTime()
//{
//    const time_t FUDGE(10);    //fudge factor to allow for upload time, etc. (seconds, YMMV)
//    const char *compDate = __DATE__, *compTime = __TIME__, *months = "JanFebMarAprMayJunJulAugSepOctNovDec";
//    char compMon[3], *m;
//
//    strncpy(compMon, compDate, 3);
//    compMon[3] = '\0';
//    m = strstr(months, compMon);
//
//    tmElements_t tm;
//    tm.Month = ((m - months) / 3 + 1);
//    tm.Day = atoi(compDate + 4);
//    tm.Year = atoi(compDate + 7) - 1970;
//    tm.Hour = atoi(compTime);
//    tm.Minute = atoi(compTime + 3);
//    tm.Second = atoi(compTime + 6);
//
//    time_t t = makeTime(tm);
//    return t + FUDGE;        //add fudge factor to allow for compile time
//}




ZinggJM

@mrweles,

Quote
Thanks, it works!
Thanks, but this is not quite specific! What does actually work for you?

Code: [Select]
// Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3
// general constructor for use with all parameters, e.g. for Waveshare ESP32 driver board mounted on connection board
//GxEPD2_BW < GxEPD2_1248, GxEPD2_1248::HEIGHT / 4 >
//display(GxEPD2_1248(/*sck=*/ 13, /*miso=*/ 12, /*mosi=*/ 14, /*cs_m1=*/ 23, /*cs_s1=*/ 22, /*cs_m2=*/ 16, /*cs_s2=*/ 19,
//                             /*dc1=*/ 25, /*dc2=*/ 17, /*rst1=*/ 33, /*rst2=*/ 5, /*busy_m1=*/ 32, /*busy_s1=*/ 26, /*busy_m2=*/ 18, /*busy_s2=*/ 4));


The ESP32 driver board has only enough RAM to buffer a quarter of a picture on that display.
Your picture shows content on a quarter of the display.
Looks you have used buffered drawing, e.g. using drawPixel(), but not using paged drawing.
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

mrweles

@ZinggJM

Now the code that I use to display the image looks like this.
First, I get data from the server, as long as it is available, then transfer it pixel by pixel to the library and after that I refresh the page.
Maybe I missed something, but in the examples everything works just like that

Code: [Select]

#define X_RES 1304
#define Y_RES 984
uint32_t cursor = 0;
uint8_t eightPixels;
int len = http.getSize();
uint8_t buff[128] = { 0 };
WiFiClient * stream = http.getStreamPtr();
display.setFullWindow();
display.firstPage();
do
{
  while (http.connected() && (len > 0 || len == -1)) {
    size_t size = stream->available();
    if (size) {
      int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
      for (int offset = 0; offset < c; offset++) {
        eightPixels = buff[offset];
        if (cursor < X_RES * Y_RES) {
          for (uint8_t i = 0; i < 8; i++) {
            if ((eightPixels >> (7 - i)) & 0x01)
              display.drawPixel((cursor + i) % X_RES, ((cursor + i) / X_RES), GxEPD_BLACK);
          }
          cursor += 8;
        }
      }
      if (len > 0) {
        len -= c;
      }
    }
    delay(1);
  }
}
while (display.nextPage());

ZinggJM

@mrweles

you would need to reset or re-open the stream for the remaining 3 loops:

Code: [Select]
    size_t size = stream->available();
    if (size) {


is false after the first loop, most likely.

Did you take a look at the GxEPD2_WiFi_Example.ino?
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

ZinggJM

#1930
Jul 04, 2020, 04:31 pm Last Edit: Jul 04, 2020, 06:56 pm by ZinggJM
@marco_99,

add some Serial.print("here we are #x"); statements to trace your code. Look at Serial Monitor.

Added: the purpose of the program you took is to work with processor deep sleep, to update time from a RTC device. The purpose of the program you want to create seems to be quite different.

You want to use the Waveshare ESP32 Driver board. It uses uncommon SPI pins.
I provide an example for this board: GxEPD2_WS_ESP32_Driver.ino

If this example is too complicated for you, then I can't help you.

BTW: now there is also a minimum example: GxEPD2_MinimumExample.ino

But you have to copy the appropriate constructor to it, and add the special handling for the ESP32 Driver board.

Additional addition: if you want to handle button pressed by processor wakeup from deep sleep, you need to make sure your button(s) are not constantly active. This is not an issue with the e-paper library.
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

marco_99

@ZinggJM

Hi, I studied the code and now I understand why the screen keeps refreshing. There was a line that makes the screen refreshing every time the RTC update, so every second. Now the screen refreshes only on button pressed.
And here is another problem, probably related to what you said in the "Additional addition": I modified the code and to make it more simple i leave just one button, connected to the pin number 35. If i leave the pin without a connector the screen doesn't sow anything (correct) but if i connect to the pin a cable that is not connected to anything on the other side, the screen shows "You pressed BTN 4". If i connect the cable to a button it doesn't work.

ZinggJM

@marco_99,

Code: [Select]
esp_sleep_enable_ext1_wakeup(BTN_PIN_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); //enable deep sleep wake on button press

I am not familiar with deep sleep handling on ESP32.
But obviously you pin needs be pulled high to cause wake up. Or you could change the second parameter.
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

zentfr

#1933
Jul 07, 2020, 09:48 am Last Edit: Jul 07, 2020, 10:18 am by zentfr
Hello everyone.

I'm using a 2.9inch e-Paper Module from Waveshare
(Screen Size: 2.9" - Color: Black and White - Display Resolution: 296*128)
with a Mega pro CH340G /ATmega2560.

I found on the constructor wiki that the e-Paper module can take 5V so I'm not using any resistor. Should I use some despite what the constructor says ?

I'm also using those libraries :
CAN_BUS_Shield-master
OneWire-master
SPIExtension
Adafruit_BusIO (required)
Adafruit_GFX_Library (required)

Are there any conflict with those ?

I'm using the mapping suggested for Arduino MEGA - BUSY -> 7, RST -> 9, DC -> 8, CS-> 53, CLK -> 52, DIN -> 51
I did achieve to make the screen work with your GxEPD2-master library. Thank you for this one.

I'm planning on using the screen with a CAN bus module on the same SPI bus. Should/can I do 2 separate buses ?

Thank you

ZinggJM

#1934
Jul 07, 2020, 11:02 am Last Edit: Jul 07, 2020, 11:07 am by ZinggJM
@zentfr,

welcome to the forum. Did you read General Guidance and How to use the Forum?

It would be preferable if you provide a link to the display and processor you use.
I assume 296x128, 2.9inch E-Ink display module

Quote
I found on the constructor wiki that the e-Paper module can take 5V so I'm not using any resistor. Should I use some despite what the constructor says ?
If you look at the back side of the board, or on the picture of it, you see a level converter chip, and an LDO and some transistors on the connector side. For details consult the schematics from the wiki page.
Therefore no, you don't need any additional resistors for use with 5V.

Quote
Are there any conflict with those ?
I don't know, I wouldn't expect.

Quote
I'm planning on using the screen with a CAN bus module on the same SPI bus. Should/can I do 2 separate buses ?
You should be able to use both on the same SPI bus, with separate CS pins. GxEPD2 uses SPI transactions, so it uses a suitable SPI speed for the e-paper display.
If the CAN driver doesn't use SPI transactions, it might be affected by the lower SPI speed.
Quote
Should/can I do 2 separate buses ?
I don't understand this question, as the ATmega2560 has only one HW SPI, I think.

Jean-Marc
No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

Go Up