E-ink Display doesnt Work


Thanks. Will dive into that this weekend and see where I end up.

If it get it work I’ll post a photo!



@ScruffR - I’ve no experience in this but do you have some basic steps to explain how to import the GxEPD library (or host of libraries as this includes GxFont, GxIO, and the specific library for each board)…

I understand this is not done through Web IDE (my primary usage for Particle). Would I need to use Desktop IDE?
Could I just use the Github link (https://github.com/ZinggJM/GxEPD.git) which would then do everything (i.e. the structure of the code below each folder etc.)?

I tried on Web IDE and battled once I realised the complex structure… and number of libraries. Surely someone has done most of this before…in the vastness of the interwebs!



Unfortunately not yet, but Particle is working on something that might go that way - final decissions weren’t made yet.

For such an undertaking I’m usually using CLI to compile the project.
Once you have a working project, you can then upload the library via CLI as private version (but please choose a privat name - e.g. with a personal prefix -, not to prevent someone who might intend to make the lib public from using a more common name).

But for your fist stab at getting your display to work you might rather want to start with the minimum approach


Success as per your instructions! Used the code from the wiki page (https://www.waveshare.com/w/upload/1/1c/2.13inch_e-Paper_HAT-code.7z), loaded all the libraries manually through Web IDE. Confirmed wiring and then it worked!

Next to solder it up, look at a 3D printed enclosure and work out what it is going to do! :smile:

Thanks @ScruffR


@ScruffR @imran445 @Creators Does anyone have a basic understanding of the x,y co-ordinate system these screens use?

Seeming to have some issues editing the basic file whilst not getting the results from a simple command… whilst rotation = 0.

paint.SetWidth(24);    // width should be the multiple of 8 
paint.DrawStringAt(30, 4, "Hello world!", &Font12, UNCOLORED);
epd.SetFrameMemory(paint.GetImage(), 0, 10, paint.GetWidth(), paint.GetHeight());

I thought it would be far simpler than it is however seems you specify the size of the “text box” then send that to memory (at a position), and then write to the screen with epd.DisplayFrame();

Seems to be some explanation here however nothing I’m making out any sense from… Anyone got an easy way to plan this… ideally looking for partial refresh, display numbers only…



I had similar issues with my ratation example.
Although it’s a while back - so I might be remembering wrong - you need to set the the orientation of the display and the paint object together.
You can have a look at my rotation sample any the implementation of the setRotate() function there.
IIRC the memory layout of the screen buffer needs adjusting - once the consecutive bits represent X coordinates while other times Y coordinates.
Since I can’t test it anymore (due to my dead display) I just assume the way I have implemented it in my lib should work for your display too.

I had another look in the library, and as it looks I opted to ignore the display rotation “feature” and just let the Paint class handle the orientation.
For that I had to adapt the width/height handling depending on the selected orientation as well as transforming the X/Y coordinates to map them onto the hardware (absolute) coordinates of the display.


The 1.54" Black/Red/White 200x200 display that I have uses a packed pixel format with one bit per pixel in each of the two color planes (black and red). You initialize the color planes to all 0xff for white and then write 0’s where you want to have black/red.

The packed format is 8 pixels per byte in the X direction so there are 200 pixels / 8pixels/byte = 25 bytes in X. There are 200 rows of these 25 bytes for the Y direction, so that total screen is an array of 5000 bytes for black and 5000 more for red.

In my code for my device, which does not support partial refresh, I just call the DisplayFrame() method with the black and red arrays.


@bko, @ScruffR… Hope you are all having a good weekend.

I seem to be making some progress here (screen will be displaying Thingspeak data off my Thunderboard Sense) however have only been able to manage half of the screen (see below).

I’ve done this from code :

paint.SetWidth(72);    // width should be the multiple of 8 

Seems, if I make SetWidth more than 72, that the code freaks out and I get a Red Flashing SOS light. I thought this might relate to a memory buffer of some sorts, and thought I could do the second half of the screen in another epd.DisplayFrame(); however that doesn’t seem to work.

A drawing of my understanding below…

And where I’m at today… close but not all the way there yet!

It seems that I cannot print anything in the bottom half of the screen, and the display doesn’t work properly (text is messed up, nothing lined up, etc.).

I’m also not sure on the small line of “static” at the bottom of the screen… am I overwriting some memory buffer and this is the extra?

Any ideas or direction as to get this to work? I thought it might be a simple (x,y) position however definitely seems there is a memory buffer which is limited my further input on the second half of the screen. Would this be true?



If you have your project in Web IDE, you could post a SHARE THIS REVISION link and I could try to find my way round your code without having a display to test, try some alterations and give it back to you to test.


I think you are missing this little tidbit on the Waveshare Wiki:

Display a Frame (DisplayFrame)
DisplayFrame is used to display the data from the frame memory.


The module has two memory areas. Once DisplayFrame is invoked, the following function SetFrameMemory >will set the other memory area, e.g. to set all the two memory areas, the process is: SetFrameMemory --> >DisplayFrame --> SetFrameMemory --> DisplayFrame, i.e. set and update twice.
The data from SPI interface is first saved into the memory and then updated if the module received the update >command.
The module will flicker during full update.
The module won’t flicker during partial update, however, it may retain a “ghost image” of the last page.


As requested. Thanks for the guidance here.


Essentially it would load up, download 6 or so numbers from Thingspeak and display them on the e-paper display. That I’m all happy with, it is the physical labelling etc. on the bottom half of the screen that’s got me.



@bko - Thanks for picking that up… so far in my code I SetFrameMemory for multiple labels, and then call DisplayFrame once.

Thereafter I start, in theory, on the below half / second frame. I call a SetFrameMemory and then DisplayFrame… however get the fuzz as described above.

paint.DrawStringAt(150, 20, String(pressure,1), &Font12, COLORED);
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());

paint.DrawStringAt(3, 55, String(db,1), &Font12, COLORED);
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());

paint.DrawStringAt(115, 55, String(light,1), &Font12, COLORED);
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());

paint.DrawLine(1,33, 500, 34, COLORED);
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());

paint.DrawLine(1,68, 500, 69, COLORED);
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());

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

paint.DrawStringAt(1, 1, "TEST", &Font24, COLORED);
epd.SetFrameMemory(paint.GetImage(), 75, 75, paint.GetWidth(), paint.GetHeight());

Should I be using the ClearFrameMemory to clear out the initial batch and then move on to the second?

It is the TEST that is not coming out correctly… I’ve tried most iterations of x,y coords, etc.


Hi @neal_tommy

I think you need two frame buffers in your code, one for the top half of the display and one for the bottom half (or one big one that you use in halves).

The code for DisplayFrame says:

 *  @brief: update the display
 *          there are 2 memory areas embedded in the e-paper display
 *          but once this function is called,
 *          the the next action of SetFrameMemory or ClearFrame will 
 *          set the other memory area.
void Epd::DisplayFrame(void) {

So you want to do:



Thanks for the quick reply.

I understand that part of the code, and hence the question on the two halves (initially I thought I could do it all at once, but clearly not).

At the moment my basic code does the following :

  1. Start, clear, rotate and set width / height

     epd.ClearFrameMemory(0xFF);   // bit set = white, bit reset = black
     paint.SetWidth(64);    // width should be the multiple of 8 
  2. Then I do multiple of these as I set up labels, units, etc.

     paint.DrawStringAt(1, 0, "Temp.", &Font24, COLORED);
     epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
     paint.DrawStringAt(35, 20, "C", &Font12, COLORED);
     epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
  3. Finally, at the end of this, and with everything still within the Width / Height as set above, I


… which I would understands sends that “chunk” of data / image / etc. to the screen.

  1. Then I’d like to move on to the second half of the screen (the lower half).

Should I :

  1. Do step 1 again to reinitiate the block / data / image?
  2. Do I set width and height again?

I’ve tried to simply start another Step 2 however it appears to be off the original Width/Height block, and so doesn’t display.

Look forward to your direction here.


This part pulls the frame buffer memory pointer out of the paint object where you have been drawing into that memory and passes it epd.SetFrameMemory. You need to do this twice either by making two paint objects or by using one paint object and breaking up the image memory yourself. Two paint objects is probably easier but you can do math on the pointer returned paint.GetImage() and the value returned paint.GetHeight().


@bko - Thanks for the response, and totally makes sense to use a separate image / paint objects.

Any chance you could step me through how to do this? I thought it would be as easy as the below :

unsigned char image[1024];
Paint paint(image, 0, 0);
Paint paint_1(image_1,0,0);
Epd epd;

However considering the labelling in the libraries, would this work? Would appreciate your guidance here, seems otherwise I’ve come unstuck here.



Hi all, I’ve just received a waveshare 2.9 module and have been going through the sample code. I’m able to get a Hello World demo to run and want to do more. Does anyone know if there is a reference for the library? I’m struggling a little understanding some of the functions. I’ve gone through the examples ‘EPaper29b.ino’ and EPaper29bRotate.ino’ and I can somewhat follow what is going on, but I can’t seem to find much documentation on the complete functions and how to use them. Anyone know if this exists?


There isn’t a lot of documentation in the original code I used to port this library from either.

What exactly are don’t you understand?


It looks like you set everything you want to display with the paint methods like DrawString, DrawLine, etc. and then use SetPartialWindow[black or red] to actually send it to the display. Is that correct?

Or you build a number of windows with SetPartialWindow[whatever color] and then push it to the display with epd.DisplayFrame()?


That’s pretty much so.