Go Down

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

ZinggJM

#1695
Feb 17, 2020, 12:27 pm Last Edit: Feb 17, 2020, 01:43 pm by ZinggJM
@ds-1991,

I am too lazy to go searching which library G6EJD uses, although I think it is GxEPD, to answer your question.

Consider providing all information needed.

I would propose to use the library GxEPD2, to cope easily with not enough RAM.

You could also create your display instance in heap space. Try this:

Code: [Select]

GxGDEW075T7* pDisplay = new GxGDEW075T7(...);

GxGDEW075T7& display = *pDisplay;


not verified.

Should be GxGDEW075Z08 for your e-paper display. See also in GxGDEW075Z08.h:
Code: [Select]
// divisor for AVR or limited RAM, should be factor of GxGDEW075Z08_HEIGHT
// add conditional case if the compiler complains for your target


Could add divisor 2 for ESP32. This would need paged drawing.


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.

astr

#1696
Feb 17, 2020, 03:25 pm Last Edit: Feb 17, 2020, 03:26 pm by astr
Hey, im using GDEW075T7 panel from Good display.

I want to clearize some things:

to send an image data we use that code:
Code: [Select]

   EPD_SendCommand(0x13);

    for (unsigned short i = 0; i < 48000; i++){
        EPD_SendData(image[i]);
    }


but what the code below does?:
Code: [Select]

   EPD_SendCommand(0x10);

    for (unsigned short i = 0; i < 48000; i++){
        EPD_SendData(0xff);
    }


why we need write other chip memory?


Other question is how to power up display.
What difference between power off and deep sleep?
When we need go to deep sleep or power off?
And how working deep sleep and power off?

is that right func of deep sleep?:
Code: [Select]

void EPD_Sleep()
{
    EPD_SendCommand(0X02);  //power off
    EPD_7in5_V2_Readbusy();
    EPD_SendCommand(0X07);  //deep sleep
    EPD_SendData(0xA5);
}


and to woke up we use this, right?:
Code: [Select]

void power_on()
{
    EPD_SendCommand(0x04); //POWER ON
    EPD_7in5_V2_Readbusy();
}


but what will cause this func?:
Code: [Select]

void power_off()
{
    EPD_SendCommand(0X02);  //power off
    EPD_7in5_V2_Readbusy();
}


Thanks for any help :0)

ZinggJM

#1697
Feb 17, 2020, 04:11 pm Last Edit: Feb 17, 2020, 04:17 pm by ZinggJM
@astr,

Quote
but what the code below does?:
why we need write other chip memory?
The GDEW075T7 can do differential refresh. 0x10 is to write to the "previous buffer".

Even if you use only full refresh, the difference between the "current" and "previous" buffers is used in some phases of the waveform applied to do the refresh. Therefore the result is better if the previous buffer is initialized to white, and you don't see random pixels during refresh.

power_on() activates the voltage generation for the panel driving voltages.
power_off() stops the voltage generation.

EDP_Sleep() sends the controller to deep sleep (minimum current use). Only buffer content is retained.
Deep sleep needs the reset line pulled low to wake the controller. It doesn't listen to any command during deep sleep.

Quote
and to woke up we use this, right?:
No.

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.

KennyUA

Hello. Need advice.
I am using GxEPD2_3C display. Full refresh takes 27 seconds. Is it normal? i am printing 5 digit number only (big enough to fit screen).
Is it possible to make it faster? i tried partial update but got exactly same results.

Code: [Select]
void refresh()
{
 display.fillScreen(GxEPD_WHITE);
 display.setFullWindow();
 display.setRotation(3);
 
 display.setFont(&Arimo_Regular_100);

 display.setTextColor(GxEPD_BLACK);
 display.setCursor(5, 95);
 display.print(rtcMem.current);   // That is 5 digit value, like 94884
 while (display.nextPage());
 delay(100);
 display.powerOff();
 delay(100);
 Serial.print("UPDATE TIME: ");
 Serial.println(millis() / 1000);    // and here i got 27 second...
}

void partialrefresh()
{
 char text[5];
 sprintf(text,"%ul",rtcMem.current);
 Serial.println("PartialRefresh");
 display.setFont(&Arimo_Regular_100);
 display.setRotation(3);
 display.setTextColor(GxEPD_BLACK);
 int16_t tbx, tby; uint16_t tbw, tbh;
 display.getTextBounds(text, 0, 0, &tbx, &tby, &tbw, &tbh);
 // center bounding box by transposition of origin:
 uint16_t x = ((display.width() - tbw) / 2) - tbx;
 uint16_t y = ((display.height() - tbh) / 2) - tby;

 uint16_t wh = Arimo_Regular_100.yAdvance;
 uint16_t wy = (display.height() * 3 / 4) - wh / 2;
 display.setPartialWindow(0, wy, display.width(), wh);
 display.firstPage();
 do
 {
   display.fillScreen(GxEPD_WHITE);
   display.setCursor(x, y);
   display.print(rtcMem.current);
 }
 while (display.nextPage());
 Serial.print("UPDATE TIME: ");
 Serial.println(millis() / 1000);
}

ZinggJM

@KennyUA,

you are too lazy to tell what e-paper panel you use?

I am too lazy to explain, or to fix your code. Hint: search for "red particles".

You seem to have a 7.5" or 5.83" 3-color e-paper; see MyEPDs_UpdateInfos.pdf

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.

KennyUA

#1700
Feb 18, 2020, 09:07 am Last Edit: Feb 18, 2020, 09:12 am by KennyUA
Sorry, i thought i copied full init line from code, but no...
Its 2.9" 3 color display. And according to your information with update time is more or less normal operation, thanks.

ds-1991

Jean-Marc, thank you for your quick response.

G6EJD uses GxEPD2. You are right with the panel, it's a GDEW075Z08.

Is the divisor also available for GxEPD2? Or is, as I understood from the library description, paged drawing done automatically in this library?

ZinggJM

#1702
Feb 18, 2020, 09:52 am Last Edit: Feb 18, 2020, 10:16 am by ZinggJM
Jean-Marc, thank you for your quick response.

G6EJD uses GxEPD2. You are right with the panel, it's a GDEW075Z08.

Is the divisor also available for GxEPD2? Or is, as I understood from the library description, paged drawing done automatically in this library?
Yes, paged drawing is done automatically in GxEPD2.

This used to compile:
Code: [Select]
GxEPD2_3C<GxEPD2_750c_Z08, GxEPD2_750c_Z08::HEIGHT> display(GxEPD2_750c_Z08(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW075Z08 800x480

Maybe now you need to change to:
Code: [Select]
GxEPD2_3C<GxEPD2_750c_Z08, GxEPD2_750c_Z08::HEIGHT / 2> display(GxEPD2_750c_Z08(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW075Z08 800x480


But this is strange, the example GxEPD2_Example.ino still uses only 34% with full buffer:

Code: [Select]
Sketch uses 596253 bytes (45%) of program storage space. Maximum is 1310720 bytes.
Global variables use 111780 bytes (34%) of dynamic memory, leaving 215900 bytes for local variables. Maximum is 327680 bytes.


But this is misleading, I think only 96K is available for dram0_0_seg. This is a known ESP32 package issue.

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.

ds-1991

I've change that, but then only half of the screen gets drawn.

I played around with this number and figured out, that I can go up to 13/16. Any number bigger than that won't compile. This uses 120352 bytes (36%) of dynamic memory. I also read about a limitation of dram size on ESP32 which is 160KB.

I guess I need to find another way to show the data on the screen. Maybe I'm going to create the image on a server and load it from there. Hopefully this will work.

Thank you for your help

ZinggJM

@ds-1991,

did you understand how paged display works with GxEPD2?

the firstPage(); do{…} while (nextPage()); loop?

or are you using GxEPD instead?
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.

ds-1991

I thought paged drawing is done somehow automatically in the background, but now I looked back onto the example and figured out how it works. Everything works now as expected and I can go on as planned with the project.

Thanks a lot.

mattard

Jean-Marc,
Thank you for your work making the waveshare e-papers more accessible with your library and spending so much time on here answering questions.

I'm using a Waveshare 2.9 B/W/Red display on a custom ESP32-based PCB.  The display works perfectly but I am having a problem where after initializing the display, digitalWrite on pin 19 no longer works. I have a function that enables a voltage divider, takes a voltage reading, and outputs it to the screen.

I was trying to figure out why the getVbat function worked perfect in a standalone project but not at all in my epaper project so I inserted a bunch of labeled test points to determine when it stopped working.  Here is the condensed applicable sections of code (link to full code at the bottom):

Code: [Select]

#include <Adafruit_LIS3DH.h>
#include <SPI.h>
//#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>
#include <EEPROM.h>
#include <Wire.h>  
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
#include <Preferences.h>
#include <Fonts/Roboto8.h> //Roboto_Regular8pt7b
#include <Fonts/SpecialElite10.h> //SpecialElite_Regular10pt7b
Preferences preferences;

//Initialize display:
//GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> display(GxEPD2_290(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
GxEPD2_3C<GxEPD2_290c, GxEPD2_290c::HEIGHT> display(GxEPD2_290c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));

#define VOLTS 34
#define VBAT_EN 19
#define V_CAL_A 0.003578
#define V_CAL_B 0//0.3827

void getVbat(){
  int V1raw;
  digitalWrite(VBAT_EN,HIGH);
  V1raw=analogRead(VOLTS);
  Vbat=((float)V1raw)*V_CAL_A+V_CAL_B;
  Serial.print(VBAT_EN);Serial.print("=");
  Serial.print(digitalRead(VBAT_EN));Serial.print(" ");
  Serial.print(" Vraw=");Serial.print(V1raw);
  Serial.print(" Vbat=");Serial.print(Vbat);
  digitalWrite(VBAT_EN,LOW);
  Serial.print(" ");Serial.print(VBAT_EN);Serial.print("=");
  Serial.println(digitalRead(VBAT_EN));
}


void setup() {
  analogReadResolution(11);
  analogSetPinAttenuation(VOLTS, ADC_11db); //6db range 0-2.2v
  pinMode(VOLTS, INPUT);
  pinMode(VBAT_EN, OUTPUT);
  Serial.begin(115200);
  Serial.print("A ");  getVbat();
    // Initialize SPIFFS
  if(!SPIFFS.begin(true)){
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }
  Serial.print("B ");  getVbat();
  btStop();
  WiFi.mode(WIFI_OFF);
  //SERVER SETUP
  Serial.print("C ");  getVbat();
    // Route for root / web page
  server.on("/wifi.html", HTTP_GET, [](AsyncWebServerRequest *request){
    Serial.println("/wifi.html");

//... LOTS OF WEB SERVER CODE OMITTED

  Serial.print("K "); getVbat();    
  display.init();  //Initialize e-paper
  Serial.print("L "); getVbat();
 //Setup LIS3DH Accelerometer:
  lis.begin(0x19);
  lis.setRange(LIS3DH_RANGE_2_G);   // 2, 4, 8 or 16 G!
  lis.setDataRate(LIS3DH_DATARATE_100_HZ); //1,10,25,50,100,200,400,LIS3DH_DATARATE_POWERDOWN
  lis.setClick(2, CLICKTHRESHHOLD, TIMELIMIT, TIMELATENCY, TIMEWINDOW);
  Serial.print("M "); getVbat();
  loadData(); //Load data from SPIFFS
  Serial.print("N "); getVbat();
  refreshDisplay();
  WakeTime=millis();
}


The console output looks like this:
Code: [Select]

ets Jun  8 2016 00:22:57

rst:0x5 (DEEPSLEEP_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:10088
load:0x40080400,len:6380
entry 0x400806a4
A 19=1  Vraw=967 Vbat=3.46 19=0
B 19=1  Vraw=967 Vbat=3.46 19=0
C 19=1  Vraw=965 Vbat=3.45 19=0
D 19=1  Vraw=967 Vbat=3.46 19=0
E 19=1  Vraw=966 Vbat=3.46 19=0
F 19=1  Vraw=967 Vbat=3.46 19=0
G 19=1  Vraw=966 Vbat=3.46 19=0
H 19=1  Vraw=967 Vbat=3.46 19=0
I 19=1  Vraw=967 Vbat=3.46 19=0
J 19=1  Vraw=967 Vbat=3.46 19=0
K 19=1  Vraw=967 Vbat=3.46 19=0
L 19=0  Vraw=0 Vbat=0.00 19=0
M 19=0  Vraw=0 Vbat=0.00 19=0
Reading data from EEPROM...
Read cycle time: [E][Preferences.cpp:354] getUInt(): nvs_get_u32 fail: cycleTime NOT_FOUND
N 19=0  Vraw=0 Vbat=0.00 19=0
Starting to refresh display.

Loading image '/logo1.bmp'
File size: 19062
Image Offset: 118
Header size: 40
Bit Depth: 4
Image size: 128x296
loaded in 68 ms
Done refreshing display.



If you notice, between battery reads "K" and "L" the VOLTS_EN pin (19) is no longer HIGH.  The only thing that happens in the code between K and L is initializing the display:
Code: [Select]
Serial.print("K "); getVbat();    
  display.init();  //Initialize e-paper
  Serial.print("L "); getVbat();

Link to full code: here

Am I doing something wrong?

ZinggJM

#1707
Feb 19, 2020, 06:27 am Last Edit: Feb 19, 2020, 06:32 am by ZinggJM
@mattard,

to answer your question with certainty, I would need to know which board you select to compile for.

But most boards use the standard hardware SPI pins for the SPIClass.

See e.g. in C:\Users\xxx\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\variants\d32\d32_core.h

Code: [Select]
static const uint8_t SS    = 5;
static const uint8_t MOSI  = 23;
static const uint8_t MISO  = 19;
static const uint8_t SCK   = 18;


The SPIClass initializes pin 19 for use as MISO pin. After that it can't be used for anything else, until SPI.end() is called.

You can remap HW SPI pins on ESP32, see example GxEPD2_WS_ESP32_Driver.ino

Code: [Select]
 // *** special handling for Waveshare ESP32 Driver board *** //
  // ********************************************************* //
  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 *** //
  // **************************************************************** //


I think this should also work if you only change the pin for MISO; use any free pin for this.

You could also just edit d32_core.h; this should also work. But you would need to remember/redo after any platform update.

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.

ZinggJM

#1708
Feb 19, 2020, 09:55 am Last Edit: Feb 19, 2020, 09:55 am by ZinggJM
Version 1.2.6 of Library GxEPD2 is available through Library Manager.

- slightly improved differential refresh for GDEW1248T3
- minor fixes

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.

mattard

#1709
Feb 19, 2020, 01:38 pm Last Edit: Feb 19, 2020, 02:02 pm by mattard Reason: solution
@mattard,

to answer your question with certainty, I would need to know which board you select to compile for.

But most boards use the standard hardware SPI pins for the SPIClass.

See e.g. in C:\Users\xxx\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\variants\d32\d32_core.h

Code: [Select]
static const uint8_t SS    = 5;
static const uint8_t MOSI  = 23;
static const uint8_t MISO  = 19;
static const uint8_t SCK   = 18;


The SPIClass initializes pin 19 for use as MISO pin. After that it can't be used for anything else, until SPI.end() is called.

You can remap HW SPI pins on ESP32, see example GxEPD2_WS_ESP32_Driver.ino

Code: [Select]
// *** special handling for Waveshare ESP32 Driver board *** //
  // ********************************************************* //
  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 *** //
  // **************************************************************** //


I think this should also work if you only change the pin for MISO; use any free pin for this.

You could also just edit d32_core.h; this should also work. But you would need to remember/redo after any platform update.

Jean-Marc

Thanks for the reply! That certainly must be it,  I have compiled for "ESP32 Dev Module".  I am using the standard SPI pins except I had repurposed the MISO pin.  I have tried remapping MISO to 27 or 35 and adding a short delay but it still doesn't seem to be releasing pin 19:

Code: [Select]

  display.init();  //Initialize e-paper
  SPI.end();// release standard SPI pins, e.g. SCK(18), MISO(19), MOSI(23), SS(5)
  SPI.begin(18,27,23,5); // restart SPI on pins, SCK(18), MISO(27), MOSI(23), SS(5)
  delay(10);


EDIT:
I found by moving the custom SPI.begin statement to the top of the setup function that the SPI was initialized correctly.  I'm not sure what the difference is--in a test sketch, I initiated SPI on default pins, ended it, and then started again on custom pins and it worked fine.

Go Up