Test ePaper Waveshare 1.54

amithlon:
...partial-Refresh damit es nicht flackert. /quote]

Was ist das? Wie geht das?

Hallo,

stoni99:

amithlon:
...partial-Refresh damit es nicht flackert. /quote]

Was ist das? Wie geht das?

Das Display muß das können, prinzipiell wohl sowieso nur die s/w, die 3-farbigen generell nicht.
Ich habe jtzt nur in meiner alten Version der GcEPD-Lib geschaut, Dein Display dürfte dort ja das GxGDEP015OC1 sein, das scheint es zu können:
// paged drawing to screen rectangle at (x,y) using partial update
void drawPagedToWindow(void (*drawCallback)(void), uint16_t x, uint16_t y, uint16_t w, uint16_t h);
Ab und an muß man einen kompletten Refresh machen, sonst vergisst es einzelne Pixel bzw. der Kontrast wird ungleichmäßig. Ich mache den so alle 5 Minuten, ich habe es nicht weiter ausgetestet, bleibenden Schaden richtet es ja nicht an, nur die aktuelle Darstellung kann leiden.

Gruß aus Berlin
Michael

Ich habe in meiner Wühlkiste noch einen Mega 2560 gefunden. Ich möchte das ePaper mal am Mega probieren. Hat ja auch mehr SRam.

Wie ist das dort mit dem SPI Bus? Gleiche Anschlüsse wie beim UNO? Oder müssen Anpassungen vorgenommen werden? Anschluß Uno hier.

Ich habe bisher noch nix weiter mit dem Mega gemacht.

Hi

Nein, die Anschlüsse sind Andere.
Siehe hierzu
Arduino Reference, SPI

MfG

Edit
Rechtschreibung ... Vorschau rules ...

Danke!

Geht aber leider auch nicht.
Pin 12 ist im Beispielanschluss mit dem UNO nicht belegt?!

Hi

Pin12 ist beim Uno MISO - Master IN, Slave OUT.
Da das Display keine Daten zurück gibt, muß der Uno Da auch nicht mitlesen.

MfG

Ich habe es mal am ICSP angeschlossen - jetzt geht es. THX!

Mit den Mega kann ich auch im Sketch mehr Speicher reservieren und damit auch das Display mit einmal vollschreiben.

...
unsigned char image[4096];
...
...
  //2x löschen notwendig damit Display frei wird
  epd.ClearFrameMemory(0xFF);   // bit set = white, bit reset = black
  epd.DisplayFrame();
  epd.ClearFrameMemory(0xFF);   // bit set = white, bit reset = black
  epd.DisplayFrame();

  paint.SetWidth(200);
  paint.SetHeight(160);
  
  paint.Clear(UNCOLORED);
  epd.DisplayFrame();   //Anzeigen
  paint.DrawStringAt(0, 0, "1 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 12, "2 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 24, "3 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 36, "4 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 48, "5 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 60, "6 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 72, "7 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 84, "8 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 96, "9 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 108, "10 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 120, "11 Schiebetor", &Font16, COLORED);
  paint.DrawStringAt(0, 132, "12 Schiebetor", &Font16, COLORED);
  epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
  epd.DisplayFrame();   //Anzeigen
...

Was mich noch stört ist dieses Geflacker beim Neuschreiben einer Displayanzeige.

Das macht der merkwürdiger Weise im Democode nicht wenn das Hintergrundbild geladen ist und die Zeit angezeigt wird.

In welchem Verzeichnis steht denn eigentlich diese imagedata.h?

#include <SPI.h>
#include <epd1in54.h>
#include <epdpaint.h>
#include "imagedata.h"

#define COLORED     0
#define UNCOLORED   1
epd.SetFrameMemory(IMAGE_DATA);
  epd.DisplayFrame();
  epd.SetFrameMemory(IMAGE_DATA);
  epd.DisplayFrame();

Ich habe mal versucht dieses vorgegebene Hintergrundbild (IMAGE_DATA) durch ein eigenes zu ersetzen.

Wird leider nur gequirlte Sch... angezeigt. :grin:

Was mache ich falsch?

.....

#include <SPI.h>
#include <epd1in54.h>
#include <epdpaint.h>
//#include "imagedata.h"

#define COLORED     0
#define UNCOLORED   1


const unsigned char gImage_weiss[3556] = { 0X00,0X01,0XC7,0X00,0X8E,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
.......
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,};


unsigned char image[1024];
Paint paint(image, 0, 0);    // width should be the multiple of 8 
Epd epd;
unsigned long time_start_ms;
unsigned long time_now_s;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  if (epd.Init(lut_full_update) != 0) {
      Serial.print("e-Paper init failed");
      return;
  }

 
 
  epd.ClearFrameMemory(0xFF);   // bit set = white, bit reset = black
  epd.DisplayFrame();
  epd.ClearFrameMemory(0xFF);   // bit set = white, bit reset = black
  epd.DisplayFrame();

......

  /** 
   *  there are 2 memory areas embedded in the e-paper display
   *  and once the display is refreshed, the memory area will be auto-toggled,
   *  i.e. the next action of SetFrameMemory will set the other memory area
   *  therefore you have to set the frame memory and refresh the display twice.
   */
  epd.SetFrameMemory(gImage_weiss);
  epd.DisplayFrame();
  epd.SetFrameMemory(gImage_weiss);
  epd.DisplayFrame();

  time_start_ms = millis();
}

void loop() {
  // put your main code here, to run repeatedly:
  time_now_s = (millis() - time_start_ms) / 1000;
  char time_string[] = {'0', '0', ':', '0', '0', '\0'};
  time_string[0] = time_now_s / 60 / 10 + '0';
  time_string[1] = time_now_s / 60 % 10 + '0';
  time_string[3] = time_now_s % 60 / 10 + '0';
  time_string[4] = time_now_s % 60 % 10 + '0';

  paint.SetWidth(32);
  paint.SetHeight(96);
  paint.SetRotate(ROTATE_270);

  paint.Clear(UNCOLORED);
  paint.DrawStringAt(0, 4, time_string, &Font24, COLORED);
  epd.SetFrameMemory(paint.GetImage(), 80, 72, paint.GetWidth(), paint.GetHeight());
  epd.DisplayFrame();

  delay(500);
}

Wir wissen ja nicht, was Du getan hast. Woher sollen wir da wissen, was Du falsch machst?

Gruß Tommy

Steht doch da Tommy! :grin:

Nee. ich hatte ein paar Probleme beim Kürzen des Codes - passen nur 9000 Zeichen ins Forum - habe es jetzt nachgereicht.

Bei der EPD-Lib bekomm ich kein Bild zu laden.

Die imagedata.h habe ich nach langem Suchen gefunden: Merkwürdigerweise im Ordner der Sketche. Die Suche im Datei-Explorer hat sie komischerweise nicht gefunden.

Die GxEPD habe ich jetzt zum Laufen gebracht.
Wie? Keine Ahnung! :grin:
Ich habe die GxEPD2 & GxEPD nochmal gelöscht (aus dem Sketch Ordner) und neu installiert, dann am Mega nochmal neu verkabelt und plötzlich funzt es.

Ob die Lib besser ist muss ich erst noch testen. Im Beispielcode gibt es aber einen Sketch zur partiellen Änderung ohne Flackern.

stoni99:
Steht doch da Tommy! :grin:

Nee. ich hatte ein paar Probleme beim Kürzen des Codes - passen nur 9000 Zeichen ins Forum - habe es jetzt nachgereicht.

Dann hänge den Sketch als File an.

Die GxEPD funktioniert bei mir nicht richtig.

Schon im Demo soll sich ein Boot bewegen von dem man nur den Bug sieht.

Partielle Textänderung (ohne Flackern) funktioniert zwar, aber der Text wird nach 4 Zeichen abgeschnitten (Wie auch der Rest beim Boot-Beispiel).

Drehe ich den Bildschirm erscheint zwar der volle Text aber die partielle Änderung funktioniert dann nicht mehr.

Ich habe jetzt auch nochmal die GxEPD2 Lib geladen.

Das Demo funktioniert super. Beeindruckend was dann alles machbar ist. Partielle Textänderung ist auch fehlerfrei. Leider ist der Programmieraufwand seeeehr hoch um "nur mal ein paar Infos auf dem Bildschirm auszugeben"!

Hi

Der 'sehr hohe Aufwand' ist aber überall - nur nehmen Dir im Groben und Ganzen diverse Lib's diesen ganzen Aufwand ab - Sie verstecken Diesen sogar vor Dir.
Selbst das schnöde Auslesen eines I²C-Sensor ist 'zu Fuß' eine ganz andere Hausnummer.
Denke, die von Dir benutzte Lib kann Das nicht mehr großartig zusammen pressen, da dann die Flexibilität verloren geht - dann passt die Lib nur noch zu einem einzigem Problem - und somit ist dann diese Lib für den Rest der Menschheit Müll.

Der ganze Programmier-Aufwand kann in einer Funktion ausgelagert zwar immer noch so aufwändig sein, für Deinen Aufruf aber ein Einzeiler werden.
Das spezialisiert Das dann zwar auf Dein Problem - aber wenn Du Das nicht für Dein Problem baust, für Welches sonst?

MfG

Ja, als Funktion auslagern habe ich auch schon überlegt.

Ich kapier aber noch nicht so ganz was die da machen.

Z.B.

// Adafruit_GFX has a handy method getTextBounds() to determine the boundary box for a text for the actual font
  int16_t tbx, tby; uint16_t tbw, tbh; // boundary box window
  display.getTextBounds(text, 0, 0, &tbx, &tby, &tbw, &tbh); // it works for 0, 0, fortunately (negative tby!)

oder

display.setFullWindow();
  display.firstPage();
  do
  {
    display.fillScreen(GxEPD_WHITE);
    display.setCursor(x, y);
    display.print(HelloWorld);
  }
  while (display.nextPage());
  //Serial.println("helloWorld done");

Eigentlich habe die ja extra für Typen wie mich ein Erklärungscode geschrieben:

void helloWorldForDummies()
{
  //Serial.println("helloWorld");
  const char text[] = "Hello World!";
  // most e-papers have width < height (portrait) as native orientation, especially the small ones
  // in GxEPD2 rotation 0 is used for native orientation (most TFT libraries use 0 fix for portrait orientation)
  // set rotation to 1 (rotate right 90 degrees) to have enough space on small displays (landscape)
  display.setRotation(1);
  // select a suitable font in Adafruit_GFX
  display.setFont(&FreeMonoBold9pt7b);
  // on e-papers black on white is more pleasant to read
  display.setTextColor(GxEPD_BLACK);
  // Adafruit_GFX has a handy method getTextBounds() to determine the boundary box for a text for the actual font
  int16_t tbx, tby; uint16_t tbw, tbh; // boundary box window
  display.getTextBounds(text, 0, 0, &tbx, &tby, &tbw, &tbh); // it works for 0, 0, fortunately (negative tby!)
  // center the boundary box of the text
  uint16_t x = (display.width() - tbw) / 2;
  uint16_t y = (display.height() + tbh) / 2; // y is base line!
  // full window mode is the initial mode, set it anyway
  display.setFullWindow();
  // here we use paged drawing, even if the processor has enough RAM for full buffer
  // so this can be used with any supported processor board.
  // the cost in code overhead and execution time penalty is marginal
  // tell the graphics class to use paged drawing mode
  display.firstPage();
  do
  {
    // this part of code is executed multiple times, as many as needed,
    // in case of full buffer it is executed once
    // IMPORTANT: each iteration needs to draw the same, to avoid strange effects
    // use a copy of values that might change, don't read e.g. from analog or pins in the loop!
    display.fillScreen(GxEPD_WHITE); // set the background to white (fill the buffer with value for white)
    display.setCursor(x, y); // set the postition to start printing text
    display.print(text); // print some text
    // end of part executed multiple times
  }
  // tell the graphics class to transfer the buffer content (page) to the controller buffer
  // the graphics class will command the controller to refresh to the screen when the last page has been transferred
  // returns true if more pages need be drawn and transferred
  // returns false if the last page has been transferred and the screen refreshed for panels without fast partial update
  // returns false for panels with fast partial update when the controller buffer has been written once more, to make the differential buffers equal
  // (for full buffered with fast partial update the (full) buffer is just transferred again, and false returned)
  while (display.nextPage());
  //Serial.println("helloWorld done");
}

Aber ehrlich gesagt habe ich ihn noch nicht ganz kapiert. :slight_smile: Bin ich jetzt schlimmer als ein Dummie....? :cry:

Hi

Werde mir Das 'Morgen' noch Mal anschauen - heute wird Das wohl Nichts mehr.
Der schlimmste Feind des Progger ist der Dau :wink:
Das aber nicht, weil der Dau blöd wäre, sondern weil der Progger viel mehr Wissen voraussetzt - weil Er eben den ganzen Kram lange 'gefressen' hat und Ihm Das 'in Fleisch und Blut' über gegangen ist.
Wo der Progger gar nicht mehr drüber nachdenke, muß der Dau zig Gedankensprünge bewältigen, Die der Progger gar nicht mehr sieht - ok, macht's dem Dau nicht leichter :wink:

Wird wohl mit 'betriebsblind' ganz gut umschrieben.

MfG

Falls es jemanden hilft: ich hab ein Waveshare Epaper Display auch mit der Originallib von Waveshare zum Laufen gebracht.
Ist eigentlich ganz einfach wenn man die Verkabelung mal raus hat:

Schema ist Folgendes:

Busy => D7
RST => D8
DC => D9
CS => D10

CLK => SCK
DIN => MOSI

GND => GND
VCC => 3.3V

Die ersten vier sind bei der Originallib in der library/epdif.h definiert (die liegt nach dem Importieren unter Linux in ~/Arduino/libraries/libraries.

SCK und MOSI finded man in der Pindefinition im Hardwarepackage der Arduino IDE

Die letzten beiden dürften selbsterklärend sein.

Achja nehmt nicht die Version der Lib und Demo aus dem Waveshare Wiki, die ist völlig broken. Nehmt die aktuelle aus deren Gitlab-Repo: https://github.com/waveshare/e-Paper/tree/master/Arduino%20UNO/epd2in9

Ich meine das dann weil die das mit Windoofs machen mich unter Linux bei zwei Headerfiles die Grosskleinschreibung getrollt hat (arduino.h statt Arduino.h und spi.h statt SPI.h). Aber danach lief das Ding....

Grüsse
Sebastian