Driving an e ink display arduino setup reliably requires more than just copying a sketch. Electrophoretic displays demand precise SPI timing, strict 3.3V logic adherence, and specific initialization sequences to avoid permanently ghosting the screen. This guide targets the Arduino Uno R3 (ATmega328P) paired with the Waveshare 2.13-inch V4 E-Paper Module (GDEH0213B72 controller). We will cover the exact hardware specs, safe 5V-to-3.3V SPI wiring, complete GxEPD2 code with hardware verification, and a decision tree for the most common failure modes.

Board Variant Note: This guide assumes the Waveshare V4 hardware revision. The V4 module includes an onboard LVC125A level-shifting IC, making it safe to connect directly to the Uno R3's 5V SPI pins. Older V2/V3 revisions lack this IC and will suffer immediate gate oxide breakdown if fed 5V logic.

Hardware Specifications and E Ink Display Arduino Pin Mapping

Before wiring, verify your module's specifications. The GDEH0213B72 is a 2.13-inch black-and-white display with partial refresh capabilities. Below is the data-dense specification sheet and the exact SPI pin mapping required for the Arduino Uno R3.

Table 1: GDEH0213B72 E Ink Module Specifications
ParameterValueEngineering Notes
Controller ICSSD1675B / GDEH0213B72Determines GxEPD2 class instantiation
Resolution250 x 122 pixelsEffective drawing area is 250x122; buffer is 4096 bytes
ColorsBlack, White1-bit per pixel (no grayscale native support)
Full Refresh Time~2.0 secondsIncludes screen flash sequence to clear ghosting
Partial Refresh Time~0.3 secondsNo screen flash; accumulates ghosting over 20-30 cycles
VCC Voltage3.3V to 5VModule has onboard 3.3V LDO regulator
SPI Logic Level3.3V (Tolerates 5V on V4)V4 uses LVC125A; V3 requires CD4050B level shifter
Active Current~25 mA (peak)During full refresh and charge pump operation

The Arduino Uno R3 uses a hardware SPI bus shared with the ICSP header. You must map the chip select, data/command, reset, and busy pins to standard digital I/O.

Table 2: Arduino Uno R3 to Waveshare 2.13" V4 Pinout
E Ink Module PinArduino Uno R3 PinFunction & Protocol
VCC5VPower (Module regulates down to 3.3V internally)
GNDGNDCommon ground reference
DIN (MOSI)Pin 11SPI Master Out Slave In (Hardware SPI)
CLK (SCK)Pin 13SPI Clock (Hardware SPI)
CSPin 10SPI Chip Select (Active LOW)
DCPin 9Data/Command selection (HIGH=Data, LOW=Command)
RSTPin 8Hardware Reset (Active LOW)
BUSYPin 7State indicator (HIGH=Busy, LOW=Ready)

Step-by-Step Wiring and Assembly

Follow this sequence to avoid floating logic states that can trigger erratic charge pump behavior during power-on.

  1. Set the Physical Switch: Locate the tiny slide switch on the Waveshare SPI HAT board. Slide it to the 'B' position. Position 'A' is for older display revisions and will send incorrect initialization commands to the GDEH0213B72.
  2. Seat the FPC Ribbon: If your display came detached, flip up the black FPC connector latch on the module, insert the ribbon cable with the blue stiffener facing up, and press the latch down firmly. A partially seated cable is the #1 cause of white-screen failures.
  3. Connect Power and Ground: Route 5V and GND from the Uno to the module. Do not power the display from the Arduino's 3.3V pin; the Uno's onboard 3.3V regulator is only rated for 150mA and may brownout during the display's 25mA refresh spikes combined with the ATmega328P's own draw.
  4. Wire the SPI Bus: Connect DIN to Pin 11, CLK to Pin 13, and CS to Pin 10.
  5. Wire the Control Pins: Connect DC to Pin 9, RST to Pin 8, and BUSY to Pin 7.

Complete GxEPD2 Arduino Code

This sketch uses the GxEPD2 library by Jean-Marc Zingg, the industry standard for driving e-paper displays on embedded systems. It includes a pre-flight hardware check to verify the BUSY pin is not floating before attempting the blocking display.init() sequence.


#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>

// --- Pin Definitions for Arduino Uno R3 ---
#define EPD_CS   10
#define EPD_DC   9
#define EPD_RST  8
#define EPD_BUSY 7
#define SPI_MOSI 11
#define SPI_SCK  13

// Instantiate display class for Waveshare 2.13" V4 (GDEH0213B72)
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display(GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));

void checkHardware() {
  // Pre-flight check: Verify BUSY pin is not floating
  pinMode(EPD_BUSY, INPUT);
  int busyState = digitalRead(EPD_BUSY);
  if (busyState == HIGH) {
    Serial.println("WARNING: BUSY pin reads HIGH before init. Check wiring or FPC cable.");
  } else {
    Serial.println("Hardware check passed: BUSY pin is LOW (Ready).");
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial) { delay(10); } // Wait for serial port on native USB boards
  Serial.println("Starting E Ink Display Arduino Setup...");

  checkHardware();

  // Initialize display. The true parameter enables serial debug output.
  // If the BUSY pin is wired incorrectly, this will hang and print '_Update_Full : Busy Timeout!'
  display.init(115200, true, 2000, false); 

  display.setRotation(1); // Landscape mode
  display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);

  // --- Draw Content ---
  display.firstPage();
  do {
    display.fillScreen(GxEPD_WHITE);
    display.setCursor(10, 30);
    display.print("ElectricalFlux");
    display.setCursor(10, 55);
    display.print("E-Ink Test OK");
    display.drawRect(5, 5, 240, 112, GxEPD_BLACK);
  } while (display.nextPage());

  Serial.println("Full refresh complete. Entering loop.");
}

void loop() {
  // E Ink displays should not be refreshed continuously in the main loop.
  // Use deep sleep or a long delay to prevent screen degradation.
  delay(60000); 
}

Debugging: Fixing the 'Busy Timeout!' Error

The most common point of failure in e ink display arduino projects is a blank screen accompanied by a serial monitor error. If your wiring or FPC connection is flawed, the GxEPD2 library will block execution and eventually output the following exact error string to the serial monitor:

_Update_Full : Busy Timeout!

This means the SSD1675B controller never pulled the BUSY pin LOW to signal that the internal charge pump and refresh sequence finished. If you encounter this, execute these first three things to check in order:

  1. Reseat the FPC Cable: Open the latch, pull the ribbon out, inspect the gold contacts for oxidation or tears, and reinsert it perfectly straight. A 1mm misalignment shorts the SPI clock to VCC.
  2. Verify the BUSY Pin Logic: Use a multimeter to measure DC voltage between the BUSY pin on the module and GND. During a refresh attempt, it should spike to 3.3V, then drop to 0V. If it stays at 0V or floats at ~1.2V, the controller IC is dead or the ribbon trace is broken.
  3. Check the Physical Switch: Ensure the slide switch on the SPI HAT is physically set to 'B'. If it is on 'A', the library sends initialization commands for a different controller, causing the IC to lock up and hold the BUSY line HIGH indefinitely.
Table 3: Ranked Causes for Blank Screen / Timeout Failures
ProbabilityRoot CauseDiagnostic Measurement / Fix
45%FPC Ribbon Cable MisalignedVisual inspection. Re-seat cable. Check for 0 ohms between pin 1 and pin 2.
25%Incorrect HAT Switch PositionVerify switch is on 'B' for V4 GDEH0213B72 modules.
15%Wiring to Wrong SPI PinsVerify DIN is on Uno Pin 11, not Pin 12 (MISO). E-Ink is write-only.
10%Insufficient 5V Current SupplyMeasure VCC during refresh. If it drops below 2.8V, upgrade USB power supply.
5%Dead Controller IC (ESD Damage)Measure current draw. If >50mA constantly, the IC is shorted internally.

For deeper protocol analysis, consult the Waveshare E-Paper Hardware Manual, which contains the raw SPI command sequences if you need to bypass the library and write directly to the SSD1675B registers.

Extending and Simplifying Your E Ink Build

Once the baseline full-refresh is working, you will likely want to optimize the project for either battery life or visual smoothness.

How to Extend: ESP32 Migration and Deep Sleep

The Arduino Uno R3 draws roughly 45mA continuously, making it useless for battery-powered e-ink dashboards. To extend this build, migrate the code to an ESP32-DevKitC V4. The ESP32 allows you to use the esp_sleep_enable_timer_wakeup() API. Between refreshes, the ESP32 can enter deep sleep, dropping system current to ~10 µA. When paired with a 2000mAh 18650 Li-ion cell and a 5µA quiescent current LDO, a weather station updating once an hour will run for over two years.

How to Simplify: Partial Refresh for UI Elements

Full refreshes cause the screen to flash black and white, which is visually jarring for dynamic data like clocks or stock tickers. You can simplify the visual experience by enabling partial refresh. This restricts the display to updating only a specific bounding box without flashing the entire screen.


// Enable partial refresh mode
// Note: Partial refresh accumulates ghosting. Run a full refresh every 20 cycles.
display.setPartialWindow(100, 50, 80, 30); 
display.firstPage();
do {
  display.fillScreen(GxEPD_WHITE);
  display.setCursor(105, 70);
  display.print("23.4 C");
} while (display.nextPage());

When designing your e ink display arduino project, remember that electrophoretic physics limits how fast you can push data. Rely on the Arduino SPI Reference to ensure your bus speed doesn't exceed the display's 4MHz maximum clock rating, and always design your UI around the display's high-latency, high-contrast strengths rather than treating it like an LCD.