If you have an E-Paper Display form Adafruit, this library will allow you to draw points, lines, circles, ellipses, ASCII text and Unicode text (thanks Roman Czyborra). Oh, and display images (in the WyoLum Image Format). Please consider this an alpha release and help us find the bugs.
Overview
Besides looking great in full sun, E-Paper requires very little power and can maintain an image for a very long time without any power at all. It costs energy only to turn the “page”. If low power is the reason you are considering E-Paper in your design, then you probably want to consider the power requirements of the whole system. If you can get by with an ATMEGA328 (like what is in most Arduino’s) your power requirements are greatly relaxed when compared to the more capable processors out there. My Arduino DUE running “blink.ino” uses 120 mA at 5V whereas my UNO uses six times less: only 20 mA.
The problem is that the ATMEGA328 does not have enough memory to display very much. That is where the SD card comes in. Even a small SD card by today’s standard has an unimaginable amount of space for an Arduino project. We use the SD to store, pre-formatted images (WIF) of any size, font files, and as the frame buffer for the display. The frame buffer allows you to configure the next image behind the scene and the update the display all at once. This is because the underlying EPD library does not support partial updates.
Build it.
Note: We will be using the AlaMode for this tutorial, but any Arduino compatible with an SD card connected should work.
1. Use spare male header pins to connect the AlaMode to the EPD display using the wiring bundle included with the EPD or use gender bender jumpers as pictured here. You can find the pin assignments here on the repaper.org site.
2. Create any images you’d like to be able to display using these instructions to WIF your images.
3. Store your images in the IMAGES/ directory on an SD card.
Software Installation.
Download the source code from GitHub and unzip it in a temporary location. This will create a directory called “EPD-master”. Move (or merge) the “libraries” directory to your “sketchbook location” which can be found in the “File->Preferences” dialog inside of the Arduino IDE. I am using /home/justin/sketchbook. The directory structure should look like this:
[sketchbook]/
—AlaModeEPD/
—libraries/
——EReader/
———examples/
————EReader_demo/
————IMAGES/
————unifont.wff
Restart Arduino after setting up your directory structure.
AlaModeEPD — Displays all WIF files in the /IMAGES directory of the SD card. This was the result of early experiments using the EPD. It does not use the EPaper library. You can safely ignore this sketch, but I left it as a reference.
EPaper_demo — This demonstrates some of the functionality in the EPaper library. It cycles through four screens displaying images, circles and text. The AlaMode is compatible with the UNO board when run from a laptop. Select “AlaMode” from the boards menu if you are programming from the Raspberry PI.
Copy the IMAGES/ directory to the root folder of your SD card. Copy the file called “unifont.wff” to the root directory of your SD card. Upload the program. The careful observer will notice that the “WyoLum ROCKS!!!” is at a new location each time the puzzle piece image comes up. This highlights the fact that the display contents are dynamic.
Code walk through
Imports. All the libraries you need either come standard with Arduino, or are infcluded in the zip file download.
#include <inttypes.h> #include <ctype.h> #include <SPI.h> #include <SD.h> #include "EPD.h" #include "S5813A.h" #include "EReader.h"
A global variable to store unicode data
uint16_t UNICODE_MSG[10];
Setup is simple. Just call the setup() method on the global ereader variable with one of the three predefined sizes.
// I/O setup void setup() { Serial.begin(115200); ereader.setup(EPD_2_7); // or EPD_2_0 or EPD_1_44 ...
The remainder of setup() is self explanatory.
All of the action resides in the loop() function. Pasted here in its entirity.
// main loop unsigned long int loop_count = 0; void loop() { if(loop_count % 4 == 0){ ereader.display_wif("/IMAGES/AANDJ.WIF", 0, 0); } else if(loop_count % 4 == 1){ ereader.display_wif("/IMAGES/WYOLUM.WIF", 0, 0); } else if(loop_count % 4 == 2){ ereader.display_wif("/IMAGES/LENA.WIF", -264/2, 0); ereader.display_wif("/IMAGES/LENA.WIF", 264/2, 0); } else{ ereader.display_wif("/IMAGES/AANDJ.WIF", -264 / 2, 176 / 2); ereader.display_wif("/IMAGES/AANDJ.WIF", 264 / 2, -176 / 2); ereader.display_wif("/IMAGES/CAT_SM.WIF", 264 / 2, 176 / 2); ereader.display_wif("/IMAGES/APHRODIT.WIF", 0, 0); ereader.toggle_ellipse(random(0, 264), random(0, 176), 20, 20); ereader.put_ascii(random(0, 200), random(16, 150), "WyoLum ROCKS!!", true); ereader.setpix(128, 0, true); ereader.setpix(128, 2, true); ereader.setpix(128, 6, true); ereader.put_unicode(10, 140, UNICODE_MSG, true); ereader.toggle_line(70, 0, 120, 50); } loop_count++; ereader.show(); ereader.sleep(1000); // allows EPD to power off gracefully }
Function descriptions
The first call you need to make on the global epaper variable is the setup method. This call takes a single argument that indicates one of currently three possible sizes: (small)EPD_1_44, (medium)EPD_2_0, and (Large)EPD_2_7.
void setup(EPD_size size);
Zero out the frame buffer to clear the display. You should not have to call this method explicitly. It is called after each show() in preparation for the next image. Each frame begins blank by default.
void clear();
Display a WIF image at the indicated x,y location. Partial images will be displayed by using negative x and or y coordinates. Path is the full path to the file, like “/IMAGES/AANDJ.WIF” for instance. Use the old 8.3 naming convention to save your self hassle.
bool display_wif(char *path, int16_t x, int16_t y);
Set a pixel located at x, y to indicated val: true=black, false=white.
void setpix(uint16_t x, uint16_t y, bool val);
Toggle the pixel located at x, y. If the pixel was white, it becomes black and vice versa.
void togglepix(uint16_t x, uint16_t y);
Draw a line from staring x,y to stopping x,y in indicated color:true=black, false=white.
void draw_line(int16_t startx, int16_t starty, int16_t stopx, int16_t stopy, bool color);
Draw a line from staring x,y to stopping x,y by toggling each pixel on the path.
void toggle_line(int16_t startx, int16_t starty, int16_t stopx, int16_t stopy);
Draw an ellipse centered at cx,cy with x-radius rx and y-radius ry in the indicated color:true=black, false=white.
void draw_ellipse(uint16_t cx, uint16_t cy, uint16_t rx, uint16_t ry, bool color);
Draw an ellipse centered at cx,cy with x-radius rx and y-radius ry by toggling each pixel on the path.
void toggle_ellipse(uint16_t cx, uint16_t cy, uint16_t rx, uint16_t ry);
Draw a single unicode character at location x, y in the indicated color:true=black, false=white. Location is the upper left hand corner of the character bitmap.
uint16_t put_char(uint16_t x, uint16_t y, uint16_t unic, bool color);
Put either an ASCII string (one byte per char) or a unicode string (two bytes per char) at the specified location and color:true=black, false=white.
uint16_t put_ascii(uint16_t x, uint16_t y, char * ascii, bool color); uint16_t put_unicode(uint16_t x, uint16_t y, uint16_t * unic, bool color);
Read the width and height dimensions of a WIF image stored in the provided File using “pass by reference”.
void SD_image_dims(File imgFile, unsigned short *h, unsigned short *w);
TODO:
- Filled rectangles, ellipses
- update EPD.h to handle partial updates
- hack EPD.h for 4-bit grey scale.