Interface an MCU to an E-Ink Display Module
You can interface a microcontroller to a 2.7” e-ink display module (consisting of the display and associated circuitry). The application displays a menu of selections via the microcontroller’s console I/O.
Electronic displays of all sizes are a part of our everyday lives. You can’t even get gas without the pump’s display touting the “hot coffee” or other enticing products located inside the associated convenience store. Personally, while I dislike the unstoppable intrusion of my personal space that displays seem to achieve, I appreciate the dimension a display gives me when I need to convey more than an On or Off state. For those of you who have included a display in any of your projects that must be “low power,” you realize that low power and display are opposing requirements. If the display must remain on, your circuit can hardly be considered low power. Even with back lighting off, the display requires constant power that will soon suck your circuit dry.
You might own a paper-white e-reader, which is a special display has the unique property of remembering its forced state, even when the display has been turned off. This technology is only about 20 years old, but it isn’t widely used because of its present drawbacks. For instance, the display requires special handling, it has a relatively slow refresh process, and it’s limited to black and white. Forget using this for any kind of video presentation; however, if you need a “no power” display, then check it out.
In this article, I’ll explain how I interfaced an Arduino MEGA 2560 microcontroller to a 2.7” e-ink display module. Consisting of the display and associated circuitry, the application displays a menu of selections via the microcontroller’s console I/O.
Obviously, there is no real ink involved in “e-ink.” The reflective technology increases contrast as ambient light increases. The pixel concept is similar to that of a graphic LCD. The user is responsible for determining the state of each pixel. Unlike a character LCD where the pixels are used in a fixed (usually 5 × 7) array of pixels to create simple alphanumeric characters, the display’s entire array of pixels are treated as one image. To display text, you must draw the text into the picture to display it. This is generally done externally and the result is displayed as a picture. When using a graphic LCD, you can in fact alter individual pixels on the LCD to change part of a displayed image. Partial image updates are not as easy with an electrophoretic display (EPD).
We should start with a look into the technology used here. You have most likely seen some of the portable and fixed signage on today’s highways that gives information warnings. Designed to be electronically updated, the display system doesn’t require power for static conditions. It is a mechanical system of flipping pixels with contrasting colored surfaces. Each pixel is controlled by an electromagnet that can flip the pixel exposing either its dark or light surface. Similar to a character LCD, the pixels are placed in groups of 5 × 7 pixels. Thus, text messages can be displayed by selecting the appropriate pixel combinations. The EPDs have the same characteristics in the static mode. They use no power to remain in a set state. Instead of electromagnets, e-ink pixels respond to positive and negative charges placed between an outer transparent front electrode and an inner back electrode. Between the electrode pairs are microcapsules containing many tiny back and white spheres. The white spheres are positively charged, while the black particles are negatively charged. These spheres are suspended in a viscous liquid that enables them to migrate within the capsule based on the external charge present at the electrodes (see Figure 1).
An EPD requires more than binary data to affect the state of a pixel: 0, 1, and nothing. A charged state is used to reverse a pixel’s color, while the nothing state is used to leave the state unchanged. There is no reason to expend energy on a pixel when a change in pixel state is unnecessary—in fact, it’s harmful! Since an EPD pixel is actually made up of many tiny white or black spheres, you can imagine that it might be possible for some of the spheres to get a bit confused about the direction they should move, especially when adjacent pixels have been charged with an opposing polarity. Should this happen, you get a pixel that can be something other than white or black. In a controlled way, this allows for shades of gray. And when it happens on its own, it produces shadows or ghosting. Eliminating this artifact is presently accomplished by adhering to a prescribed routine of charge canceling or refreshing.
EMBEDDED ARTISTS & PERVASIVE DISPLAY
I often peruse distributor websites for interesting technologies. I purchased an e-ink display and interface from Embedded Artists for one main reason. The interface PCB was designed to mount easily in a project. While this incarnation is of a slightly older ilk, it serves as a good testbed for this discussion.
The display on this interface is a Pervasive Display 2.71” active matrix thin-film transistor (TFT) panel. It has a 117-dpi resolution. The flexible printed circuit (FPC) tail requires a 40-pin, 0.5-mm connector that’s similar to most large-format displays. Communication with the Chip on Glass (CoG) G1/2 processor is through SPI. The numerous connections to the FPC are mostly for external capacitors that are physically too large for the thin-film display. Besides the capacitors and SPI connections, there are a few other control lines that enable the display to be powered up and down to achieve zero-power operation once the display has been updated.
Figure 2 shows the display’s support circuitry, which includes a temperature sensor and mass storage device. The Rev B board uses a 2 × 7 0.1“ square pin header for power and control signals. The NXP Semiconductors LM75B I2C temperature sensor requires two control lines. Temperature is important to the display as it is used to control the refresh cycles. Lower temperatures require multiple writing cycles. Excluding power, temperature, and SPI signals, the leftover pins handle the aforementioned display power functions (see Figure 2).
An Arduino MEGA 2560 drives the display (see Photo 1). All routines are written in simple code without the use of any libraries. I rarely begin using any library until I understand how a device works. So many libraries have gotchas, or insulate you from the status of things, that when they don’t work, you’re at a loss for how to proceed.
Most e-ink display interfaces come with a graphic image prestored to the display, as well as a number of additional images stored in the mass-storage device. Having a printed copy of the displayed image will go a long way in helping with any debugging you might need to do. Once you delve into the process of trying to display an image, it’s a help to be able to compare what you are seeing to the original image. You can often determine where to look in your code when you can see the differences.
A good place to start is by dumping the storage device. You want to know how images are stored so that you can move the image data correctly. The Arduino’s serial monitor has its issues, but it can be informative if used correctly. I use this to present a user with a menu of options and allow them to input selections (see Table 1). We are going to begin with menu item 5.
For the 2.71” display the pixel dimensions are 264 horizontal (33 bytes) × 176 vertical for a total of 46,464 pixels, or 5,808 bytes. A Winbond W25Q80BVSS 8-Mb serial flash memory device is used for mass storage, which has a 4-KB sector as the minimum erase block size, so using multiples of this make good boundaries. Otherwise, you’ll need to take additional steps when erasing a sector that might contain parts of multiple images. With a display image requiring more than 4 KB, it will require two sectors for each image. Therefore, an 8-Mb (1-MB) device has room for 1 M/8 KB or 128 (two sector) images.
With two sectors at 8,196 bytes and an image at 5,808 bytes, we need to know where the image is positioned within the allocated space. As it turns out, the image data is not at the beginning! Most image files contain some kind of information prior to the actual data. This information would be used as a guide to how to interpret the data. It is beyond the scope of this discussion to delve into image formats. However, since the pixel data is one bit, we know the data must be in binary, black/white format. The images prestored in memory have an offset of 0x100 from the sector start. These 0x100 bytes could be used for anything. Perhaps you might wish to store the image name here and use it to offer the user a list of stored images.
The Dump routine will begin at an offset of 0x100 and display 176 lines of 33-byte data. Each data byte will be sent as eight characters, a “.” for “0” data and an “X” for “1” data. A “space” character is placed between each byte so they can be easily identified. The Arduino serial monitor comes in handy here because you can move the viewable area within the image area and “see” any part of the total image (see Photo 2a).
When you look at the image defined as bytes left to right numbered 0–32, something doesn’t look quite right. The bits of each byte as displayed bit7–bit0 seem reversed. If we reverse these in code, we see a slightly different image in Photo 2b. This exercise is important as it can bust assumptions you may make and allow you to program a change in how the data is used (dumped in this case).
Before we get started transferring data between the storage device and the display we need to understand how this display technology should be used. I’ve already discussed the display mechanism and alluded to some rules for enable/disabling the display, so let’s build on that base.
For now, we’ll skip over “new” images and work with just what is preprogrammed into the serial memory. To transfer an image, we need to perform four steps, power up the display driver (COG), initialize it properly, transfer the data, and power down the display driver. The display driver requires 2.7 to 3.3 VDC; however, the interface board will accept 5 V and there is sufficient protection on it to interface directly with 5-V microcontroller. Early 2.71” displays like this one prior to V230 require a 100-kHz PWM input to assure the inverter creates the necessary negative voltage. This isn’t necessary on the newer displays, but it is worth noting that there have been improvements made to make the display more user friendly. Toggling the reset line assures the COG is set to a known state and is ready to accept the initialization step. Note: the COG controls the busy output line that indicates its state. Always check the busy output before initiating any COG communications.
There are two SPI commands to speak with any of the COG’s registers (0x01–0x0F). Setting a COG’s register with a value (or values for those registers that accept multiple bytes) requires two SPI commands. Command 0x70 sets the value of the COG’s register select pointer. Command 0x72 will write value(s) to the selected register. For instance, to tell the COG that it will be controlling the 2.71” display, 8 bytes must be sent to register 1 (see Listing 1).
Listing 1 Eight bytes are sent to register 1 to notify the COG that it will be controlling the 2.71” display. ; Check for Busy SPI Write 0x70, 0x01 (selects register 1) Check for Busy SPI Write 0x72, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x00 (write data to register 1)
The timing document for the display indicates how each register should be initialized based on display size. Once the initialization is complete, we can commence writing data to the display.
Writing data to the display is not in itself difficult; however, there are a few steps to go from old data to new data and what is written depends on what is already there. This display technology uses a FET-based a-SI (amorphous silicon) active pixel matrix in a row/column, top/bottom electrode planes. A pixel’s charge is updated when its top and bottom elements are both driven to opposing potentials. White positively charged particles are attracted to the negative potential electrode and vice versa. To be happy a pixel likes some nominal charge. Too little and some particles are not fully attracted, too much and the particles may not want to leave this state without an increased opposing charge. You can see that while applying a reversed state will allow a charge to be neutralized and reversed, reapplying the present polarity not only strengthens the charge but also makes it harder for a polarity reversal to have the desired effect. Over charging a pixel can also have an effect on its neighbors by attracting some of its particles to a (potentially) opposite state.
To keep a DC balance, the recommended display update procedure includes canceling the last charged state before applying a new state. This is accomplished by applying an inverse image to retain the DC balance prior to a new image. The latest timing document suggests this be done in four stages. Stage 1 is the inverse previous image. Stage 2 is all white. Stage 3 is the inverse of the new image. Stage 4 is the new image.
So we are actually writing the complete display multiple times. Since two of the stages include inverse images, every pixel will change states, giving the display update a flash (all pixels) instead of the normal update of only pixels that require changes. This isn’t a big concern when the display is rarely updated; however, when used in an e-book (for instance), this can be distracting on every page turn.
The format for each stage or frame of a display update is the same. The data for each of the 176 rows (264 columns/row for the 2.71” display) is sent in three parts, the odd column bits from right to left, the row enable, and the even column bits from left to right. This begins with an SPI command of 0x70, 0x0A (selecting register 10) and 0x72, 0x00 + 1 row of frame data of 110 bytes (33 + 44 + 33). First, the 132 odd column bits are taken four at a time, encoded into 2-bit pairs, and sent to the display as a byte (for a total of 132/4 = 33 bytes). Second, the row is indicated by sending 44 bytes of data. Row data is also 2 bits of data per row, with a 11 enabling the row of choice and all other rows set to 00 data (i.e., row 1 = ‘11000000’,’00000000’, and so on). Finally, the 132 even columns bits are taken four at a time, encoded into 2-bit pairs, and sent to the display as a byte (for a total of 132/4 = 33 bytes). An SPI command of 0x70, 0x07, selects register 7, which processes the row’s data to the display. Row data happens 176 times for each frame. One complete frame is written for each stage of an image update.
Even though the choice for the display colors is limited to black and white, we must be concerned with the display’s state. The display itself is dumb and doesn’t know what state it is in, so it’s up to you to remember what you displayed last. Note in the listed stages (above) that stage 1 and 4 are inverse stages. There is no worry about accumulating charge as these stages inverse the present charge, so if previous image data is white 0, the encoded data for an inverse is black 11; and if the previous image data was black 1, the encoded data for an inverse is white 10. However, in stages 2 and 3 the data may remain the same for a given pixel. When a pixel is not going to be inverted, the encoded data used is a nothing 00, preventing over charging the pixel. So, while image data is 1 bit per pixel, encoded data is 2 bits per pixel. The display can be updated with a new image as often as necessary as long as it remains powered.
Besides the wide viewing angle and high contrast of this type of display, the technology is most known for its ability to continue displaying while powered off. This requires using the prescribed procedure of shutting down the display to ensure things remain unchanged. This begins with writing a frame consisting of “nothing” data “00”, followed by an extra line of “nothing” data “00” with the scan line data set to all “00”. This last line of data will clear the display border when used with the border control input.
With the display data set, the driver supplies are discharged making it impossible to further alter pixel charges. The internal registers are reset and all input signals are disabled, which places the display and the driving circuitry in complete power down. At this point, the only power being used is by your interface circuitry. It is quite unnerving to completely detach the display at this point and have the image remain on the screen.
We’ve discussed a few functions of the demo code written for this project, selecting an image within the mass storage device, dumping image data, and transferring the image data to the display (including initializing the display). Next time in Part 2, we will look at preparing new image data, see how temperature affects writing to the display, and the potential of partial screen updates.
ePaper Information, repaper.org.
Pervasive Displays, “E-Paper Display COG Driver Interface Timing for 1.44”, 1.9”, 2”, 2.6”, and 2.7” EPD with G2 COG and Aurora Mb Film,” Doc.No.4P015-00, 2015.
Arduino MEGA 2560 Microcontroller
Arduino | www.arduino.cc
EM027BS013 Display module interface
Embedded Artists AB | www.embeddedartists.com
LM75B I2C Temperature sensor
NXP Semiconductors | www.nxp.com
E1271CS021 2.7” TFT EPD Panel
Pervasive Displays | www.pervasivedisplays.com
W25Q80BVSS SpiFlash Memory
Winbond | www.winbond.com
PUBLISHED IN CIRCUIT CELLAR MAGAZINE • OCTOBER 2016 #315 – Get a PDF of the issueSponsor this Article