IT8951 E-Paper Display
The it8951 display platform provides a driver for e-paper displays using the
ITE IT8951 controller.
The IT8951 controller supports 16-level grayscale and multiple refresh modes including fast partial updates. It is found in larger e-paper displays (4.7" and above) and integrated boards such as the M5Paper.
The communication method uses SPI, so you need to have an
spi: section in your configuration. Both MOSI and MISO are required (the
driver reads device info and register values from the controller).
For integrated boards with predefined configurations, only the model name needs to be specified. Other options can be overridden if needed.
display: - platform: it8951 model: m5stack-m5paper lambda: |- it.filled_circle(it.get_width() / 2, it.get_height() / 2, 50, Color::BLACK);Supported models
Section titled “Supported models”Generic controller
Section titled “Generic controller”Using the generic IT8951 model requires full configuration with pins and
dimensions specified.
| Model name | Description |
|---|---|
| IT8951 | Generic IT8951 controller. Datasheet |
Integrated display boards
Section titled “Integrated display boards”These models have predefined pin assignments and dimensions. At minimum only the model name needs to be configured.
| Model name | Manufacturer | Dimensions | Description |
|---|---|---|---|
| m5stack-m5paper | M5Stack | 960×540 | M5Paper 4.7" e-ink, 16-level grayscale. Doc |
| Seeed-reTerminal-E1003 | Seeed Studio | 1872×1404 | Product page |
| Seeed-EE03 | Seeed Studio | 1872×1404 | Seeed EE03 board with 10.3" e-paper. |
IMPORTANT
m5stack-m5paper model work with the SKU K049 model and variants (K049-B, K049-C)
Newer (but EOL) M5PaperS3 does not use the IT8951 nor any driver, but rather a direct connection to the ESP32S3 which is not supported by this component.
Configuration variables
Section titled “Configuration variables”When using an integrated display board model, most configuration (pins, dimensions, VCOM) is preset but can be overridden.
-
model (Required): The model of the IT8951 display. See the table above for options (case is not significant). One of
IT8951,m5stack-m5paper,Seeed-reTerminal-E1003,Seeed-EE03. -
cs_pin (Required for generic, Optional for integrated boards, Pin Schema): The SPI chip select pin.
-
busy_pin (Required for generic, Optional for integrated boards, Pin Schema): The HRDY (host ready) pin. The IT8951 uses active-high ready signaling (HIGH = ready, LOW = busy).
-
reset_pin (Required for generic, Optional for integrated boards, Pin Schema): The hardware reset pin. Make sure you pull this pin high (by connecting it to 3.3V with a resistor) if not connected to a GPIO pin.
-
enable_pin (Optional, Pin Schema or list): One or more GPIOs driven high during setup to power on the panel, before reset and initialization. Useful for boards with one or more power-enable rails for the display.
-
dimensions (Required for generic, Optional for integrated boards): Dimensions of the screen, specified either as width x height (e.g.
960x540) or with separate config keys. The dimensions are in pixels and represent the native panel orientation (before rotation).- width (Required, int): Specifies width of display in pixels.
- height (Required, int): Specifies height of display in pixels.
-
rotation (Optional, int): Set the rotation of the display. Everything drawn in
lambda:will be rotated. One of0°(default),90°,180°,270°. -
transform (Optional, dict): Additional transform applied on top of rotation.
- mirror_x (Required, boolean): If true, mirror the x axis.
- mirror_y (Required, boolean): If true, mirror the y axis.
- swap_xy (Required, boolean): If true, swap x and y axis.
-
update_mode (Optional, enum): Default waveform mode for display updates. If not set, defaults to
GC16(full grayscale). Can be overridden per-update via theit8951.updateaction. One of:Mode Description INITFull erase to white. Use after power-on or when display state is unknown. DUDirect update. Fast, non-flash. Black/white transitions only. Also available as fast.GC16Grayscale clearing. Full 16-level grayscale, highest quality. Also available as full.GL16Grayscale light. 16 levels with reduced flash, good for anti-aliased text on white. GLR16Like GL16 with reduced artifacts (requires image preprocessing). GLD16Like GL16 with further reduced artifacts (full display update recommended). DU44-level grayscale, fast update. Good for anti-aliased text in menus. A2Fastest mode. Black/white only, minimal ghosting. Good for animations/page turns. NOTE
Not every waveform is present in every panel's waveform LUT. On the supported Seeed panels only
GC16(grayscale) andDU(monochrome) have been verified to render correctly; the reduced-grayscale modes (GL16,GLR16,GLD16,DU4) andA2can leave a white background rendered as grey. The driver's automatic mode selection therefore only ever usesGC16andDU; setupdate_modeto another value only if you have confirmed it works on your panel. -
full_update_every (Optional, int): Number of updates between forced full
GC16refreshes, which clear accumulated ghosting. Defaults to30; range1–255. The first update after boot is always a full refresh. In monochrome mode (grayscale: false) the intervening updates use the fastDUwaveform; in grayscale mode they remainGC16(see the note under update_mode). -
auto_clear_enabled (Optional, boolean): When
true(the default when alambdaorpagesis configured), the framebuffer is cleared before every render, so each update redraws and refreshes the whole screen. Set tofalseto enable partial area updates, where only the changed region is transferred and refreshed — see Area updates. -
vcom (Optional, int): VCOM voltage in millivolts. Each e-paper panel has a specific VCOM value printed on its flex cable. Defaults to
2300(2.3V) for m5stack-m5paper. Incorrect VCOM can cause image quality issues. -
invert_colors (Optional, boolean): Invert the color mapping (swap black and white). Defaults to
false. -
sleep_when_done (Optional, boolean): Put the IT8951 controller into deep sleep after each display update completes. Reduces power consumption but adds wake-up latency for the next update. Defaults to
truefor m5stack-m5paper,falsefor Seeed boards. -
grayscale (Optional, boolean): Selects the framebuffer pixel format. When
true(default), the framebuffer stores 16-level grayscale (4 bits per pixel) and updates use theGC16waveform. Whenfalse, the framebuffer is packed monochrome (1 bit per pixel): this halves RAM use, roughly halves the transfer time, and enables fastDUpartial refreshes between full cleans. Choosefalsefor pure black/white content (text, QR codes, line art) where speed and memory matter more than gray levels. -
dithering (Optional, boolean): Monochrome only (no effect when
grayscaleistrue). Whentrue(default), colors are reproduced with ordered (Bayer) dithering, so pale shades — button fills, spinner arcs, light grays — render as a visible black/white stipple instead of vanishing to white. Pure black and pure white stay solid. Set tofalsefor a hard 50% black/white threshold (crisper, stipple-free text at the cost of pale fills disappearing). -
reset_duration (Optional, Time): Duration of the hardware reset pulse. Defaults to
10ms. Maximum500ms. -
lambda (Optional, lambda): The lambda to use for rendering content on the display. See Display Rendering Engine for more information.
-
pages (Optional, list): Show pages instead of a single lambda. See Display Pages.
-
update_interval (Optional, Time): The interval to re-draw the screen. Defaults to
1min. Useneverto only manually update the screen viacomponent.update. -
spi_id (Optional, ID): Required to specify the ID of the SPI Component if your configuration defines multiple SPI buses.
-
id (Optional, ID): Manually specify the ID used for code generation.
Actions
Section titled “Actions”it8951.update Action
Section titled “it8951.update Action”Trigger a display update with an optional waveform mode override:
on_...: then: - it8951.update: id: my_display mode: DU- id (Required, ID): The display to update.
- mode (Optional, string): The waveform mode for this update. If omitted,
uses the configured
update_modeor defaults toGC16. Supports templating.
Full configuration examples
Section titled “Full configuration examples”M5Paper (integrated board)
Section titled “M5Paper (integrated board)”Minimal configuration — pins and dimensions are preset:
spi: clk_pin: GPIO18 mosi_pin: GPIO23 miso_pin: GPIO34
display: - platform: it8951 model: m5stack-m5paper update_interval: 30s update_mode: DU full_update_every: 20 rotation: 270 lambda: |- it.print(10, 10, id(my_font), "Hello, M5Paper!");Generic IT8951 controller
Section titled “Generic IT8951 controller”Full configuration with explicit pins and dimensions:
spi: clk_pin: GPIO18 mosi_pin: GPIO23 miso_pin: GPIO19
display: - platform: it8951 model: IT8951 dimensions: width: 1024 height: 758 cs_pin: GPIO15 reset_pin: GPIO22 busy_pin: GPIO27 vcom: 2100 update_interval: 1min full_update_every: 10 rotation: 0 lambda: |- it.fill(Color::WHITE); it.print(10, 10, id(my_font), Color::BLACK, "Hello!");Using with LVGL
Section titled “Using with LVGL”When using with LVGL, set update_interval: never and let LVGL manage updates:
display: - platform: it8951 model: m5stack-m5paper id: my_display update_interval: never rotation: 270Partial updates with different modes
Section titled “Partial updates with different modes”Use fast mode for interactive elements and full mode for periodic cleanup:
display: - platform: it8951 model: m5stack-m5paper id: my_display update_mode: DU full_update_every: 30 update_interval: 5s rotation: 270 lambda: |- it.fill(Color::WHITE); it.strftime(10, 10, id(my_font), "%H:%M:%S", id(my_time).now());Area updates (partial regions)
Section titled “Area updates (partial regions)”By default every update redraws and refreshes the whole screen, because
auto_clear_enabled defaults to true and clears the framebuffer before each
render. Setting auto_clear_enabled: false enables area updates: the
framebuffer persists between updates, and only the bounding box of whatever your
lambda draws is transferred to the controller and refreshed on the panel. This
is much faster and flashes only the changed region.
Because the buffer persists, your lambda must erase the area it is about to redraw (drawing over the old pixels), otherwise remnants of the previous content remain. Erasing counts as drawing, so it is included in the changed region:
display: - platform: it8951 model: m5stack-m5paper id: my_display auto_clear_enabled: false update_mode: DU full_update_every: 30 update_interval: 1s rotation: 270 lambda: |- // Erase just the clock area, then redraw it. Only this rectangle is // transferred and refreshed; the rest of the panel is untouched. it.filled_rectangle(0, 0, 360, 90, Color::WHITE); it.strftime(0, 0, id(my_font), Color::BLACK, "%H:%M:%S", id(my_time).now());Notes:
- The changed region's horizontal extent is rounded out to a multiple of 32 pixels (a hardware alignment requirement); vertical extent is exact.
- A full
GC16refresh is still forced everyfull_update_everyupdates, and on the first update after boot, to clear accumulated ghosting. - If a lambda draws nothing, the update is skipped entirely.
Technical notes
Section titled “Technical notes”- The IT8951 controller supports up to 16 levels of grayscale (4 bits per
pixel). Set
grayscale: falseto store the framebuffer as packed 1-bit monochrome instead, which uses a quarter of the RAM and transfers far less data per update for pure black/white content. - The driver is fully non-blocking. SPI operations are queued and executed one per main loop iteration, gated on the HRDY pin. Row data transfer is time-sliced to stay within the loop tick budget.
- The framebuffer is stored in PSRAM on ESP32 devices. For a 960×540 display at 4bpp, this requires approximately 260 KB.
- The display rendering lambda runs synchronously and may take 200-300ms for complex UIs due to PSRAM access latency. This is normal for e-paper displays with large framebuffers.