quad color eInk demos

This commit is contained in:
Liz 2025-08-05 19:56:35 -04:00
parent 5e539a6626
commit 53dce06f35
8 changed files with 404 additions and 0 deletions

View file

@ -0,0 +1,117 @@
// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
//
// SPDX-License-Identifier: MIT
// Adafruit_ImageReader test for Adafruit E-Ink Breakouts.
// Demonstrates loading images from SD card or flash memory to the screen,
// to RAM, and how to query image file dimensions.
// Requires BMP file in root directory of QSPI Flash:
// blinka.bmp.
#include <Adafruit_GFX.h> // Core graphics library
#include "Adafruit_ThinkInk.h"
#include <SdFat_Adafruit_Fork.h> // SD card & FAT filesystem library
#include <Adafruit_SPIFlash.h> // SPI / QSPI flash library
#include <Adafruit_ImageReader_EPD.h> // Image-reading functions
// Comment out the next line to load from SPI/QSPI flash instead of SD card:
#define USE_SD_CARD
#define EPD_DC 10
#define EPD_CS 9
#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay)
#define SRAM_CS 6
#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset!
#define EPD_SPI &SPI // primary SPI
#define SD_CS 5 // SD card chip select
// 2.13" Quadcolor EPD with JD79661 chipset
ThinkInk_213_Quadcolor_AJHE5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY,
EPD_SPI);
#if defined(USE_SD_CARD)
SdFat SD; // SD card filesystem
Adafruit_ImageReader_EPD reader(SD); // Image-reader object, pass in SD filesys
#else
// SPI or QSPI flash filesystem (i.e. CIRCUITPY drive)
#if defined(__SAMD51__) || defined(NRF52840_XXAA)
Adafruit_FlashTransport_QSPI flashTransport(PIN_QSPI_SCK, PIN_QSPI_CS,
PIN_QSPI_IO0, PIN_QSPI_IO1, PIN_QSPI_IO2, PIN_QSPI_IO3);
#else
#if (SPI_INTERFACES_COUNT == 1 || defined(ADAFRUIT_CIRCUITPLAYGROUND_M0))
Adafruit_FlashTransport_SPI flashTransport(SS, &SPI);
#else
Adafruit_FlashTransport_SPI flashTransport(SS1, &SPI1);
#endif
#endif
Adafruit_SPIFlash flash(&flashTransport);
FatVolume filesys;
Adafruit_ImageReader_EPD reader(filesys); // Image-reader, pass in flash filesys
#endif
Adafruit_Image_EPD img; // An image loaded into RAM
int32_t width = 0, // BMP image dimensions
height = 0;
void setup(void) {
ImageReturnCode stat; // Status from image-reading functions
Serial.begin(115200);
while(!Serial); // Wait for Serial Monitor before continuing
display.begin();
display.setRotation(3);
// The Adafruit_ImageReader constructor call (above, before setup())
// accepts an uninitialized SdFat or FatVolume object. This MUST
// BE INITIALIZED before using any of the image reader functions!
Serial.print(F("Initializing filesystem..."));
// SPI or QSPI flash requires two steps, one to access the bare flash
// memory itself, then the second to access the filesystem within...
#if defined(USE_SD_CARD)
// SD card is pretty straightforward, a single call...
if(!SD.begin(SD_CS, SD_SCK_MHZ(10))) { // Breakouts require 10 MHz limit due to longer wires
Serial.println(F("SD begin() failed"));
for(;;); // Fatal error, do not continue
}
#else
// SPI or QSPI flash requires two steps, one to access the bare flash
// memory itself, then the second to access the filesystem within...
if(!flash.begin()) {
Serial.println(F("flash begin() failed"));
for(;;);
}
if(!filesys.begin(&flash)) {
Serial.println(F("filesys begin() failed"));
for(;;);
}
#endif
Serial.println(F("OK!"));
// Load full-screen BMP file 'blinka.bmp' at position (0,0) (top left).
// Notice the 'reader' object performs this, with 'epd' as an argument.
Serial.print(F("Loading blinka.bmp to canvas..."));
stat = reader.drawBMP((char *)"/blinka.bmp", display, 0, 0);
reader.printStatus(stat); // How'd we do?
display.display();
// Query the dimensions of image 'blinka.bmp' WITHOUT loading to screen:
Serial.print(F("Querying blinka.bmp image size..."));
stat = reader.bmpDimensions("blinka.bmp", &width, &height);
reader.printStatus(stat); // How'd we do?
if(stat == IMAGE_SUCCESS) { // If it worked, print image size...
Serial.print(F("Image dimensions: "));
Serial.print(width);
Serial.write('x');
Serial.println(height);
}
delay(30 * 1000); // Pause 30 seconds before continuing because it's eInk
}
void loop() {
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View file

@ -0,0 +1,116 @@
// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/***************************************************
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include "Adafruit_ThinkInk.h"
#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for
// Feather RP2040 ThinkInk
#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC
#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS
#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy
#define SRAM_CS -1 // use onboard RAM
#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset
#define EPD_SPI &SPI1 // secondary SPI for ThinkInk
#else
#define EPD_DC 10
#define EPD_CS 9
#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay)
#define SRAM_CS 6
#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset!
#define EPD_SPI &SPI // primary SPI
#endif
// 2.13" Quadcolor EPD with JD79661 chipset
ThinkInk_213_Quadcolor_AJHE5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY,
EPD_SPI);
void setup() {
Serial.begin(115200);
while (!Serial) {
delay(10);
}
Serial.println("Adafruit EPD full update test in red/yellow/black/white");
display.begin(THINKINK_QUADCOLOR);
}
void loop() {
Serial.println("Banner demo");
display.clearBuffer();
display.setTextSize(3);
display.setCursor((display.width() - 144) / 2, (display.height() - 24) / 2);
String text = "QuadColor";
uint16_t colors[] = {EPD_BLACK, EPD_RED, EPD_YELLOW};
for (int i = 0; i < text.length(); i++) {
// Change color for every character (0: BLACK, 1: RED, 2: YELLOW, 3: BLACK, etc.)
display.setTextColor(colors[i % 3]);
display.print(text.charAt(i));
}
display.display();
delay(15000);
Serial.println("Color quadrant demo");
display.clearBuffer();
// Top-left quadrant - EPD_BLACK
display.fillRect(0, 0, display.width() / 2, display.height() / 2, EPD_BLACK);
// Top-right quadrant - EPD_RED
display.fillRect(display.width() / 2, 0, display.width() / 2, display.height() / 2, EPD_RED);
// Bottom-left quadrant - EPD_YELLOW
display.fillRect(0, display.height() / 2, display.width() / 2, display.height() / 2, EPD_YELLOW);
// Bottom-right quadrant - assume you have a 4th color like EPD_WHITE or another color
display.fillRect(display.width() / 2, display.height() / 2, display.width() / 2, display.height() / 2, EPD_WHITE);
display.display();
delay(15000);
Serial.println("Text demo");
// large block of text
display.clearBuffer();
display.setTextSize(1);
testdrawtext(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur "
"adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, "
"fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor "
"neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet "
"ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a "
"tortor imperdiet posuere. ",
EPD_BLACK);
display.display();
delay(15000);
display.clearBuffer();
for (int16_t i = 0; i < display.width(); i += 4) {
display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK);
}
for (int16_t i = 0; i < display.height(); i += 4) {
display.drawLine(display.width() - 1, 0, 0, i, EPD_RED);
}
for (int16_t i = 0; i < display.width(); i += 4) {
display.drawLine(display.width()/2, display.height()-1, i, 0,
EPD_YELLOW);
}
display.display();
delay(15000);
}
void testdrawtext(const char *text, uint16_t color) {
display.setCursor(0, 0);
display.setTextColor(color);
display.setTextWrap(true);
display.print(text);
}

View file

@ -0,0 +1,79 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
"""Blinka EPD Demo for the Quad Color eInk"""
import board
import digitalio
from PIL import Image, ImageDraw, ImageFont
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.jd79661 import Adafruit_JD79661
# create the spi device and pins we will need
spi = board.SPI()
ecs = digitalio.DigitalInOut(board.CE0)
dc = digitalio.DigitalInOut(board.D25)
srcs = None
rst = digitalio.DigitalInOut(board.D27) # can be None to not use this pin
busy = digitalio.DigitalInOut(board.D17) # can be None to not use this pin
display = Adafruit_JD79661(122, 250, spi,
cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs,
rst_pin=rst, busy_pin=busy)
display.rotation = 3
width = display.width
height = display.height
image = Image.new("RGB", (width, height))
WHITE = (0xFF, 0xFF, 0xFF)
YELLOW = (0xFF, 0xFF, 0x00)
RED = (0xFF, 0x00, 0x00)
BLACK = (0x00, 0x00, 0x00)
# clear the buffer
display.fill(Adafruit_EPD.WHITE)
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# empty it
draw.rectangle((0, 0, width, height), fill=WHITE)
# Draw an outline box
draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE)
# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = 5
shape_width = 30
top = padding
bottom = height - padding
# Move left to right keeping track of the current x position for drawing shapes.
x = padding
# Draw an ellipse.
draw.ellipse((x, top, x + shape_width, bottom), outline=YELLOW, fill=WHITE)
x += shape_width + padding
# Draw a rectangle.
draw.rectangle((x, top, x + shape_width, bottom), outline=RED, fill=BLACK)
x += shape_width + padding
# Draw a triangle.
draw.polygon(
[(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)],
outline=BLACK,
fill=RED,
)
x += shape_width + padding
# Draw an X.
draw.line((x, bottom, x + shape_width, top), fill=YELLOW)
draw.line((x, top, x + shape_width, bottom), fill=YELLOW)
x += shape_width + padding
# Load default font.
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
draw.text((x, top), "Hello", font=font, fill=YELLOW)
draw.text((x, top + 20), "World!", font=font, fill=YELLOW)
# Display image.
display.image(image)
display.display()

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View file

@ -0,0 +1,92 @@
# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
Image resizing and drawing using the Pillow Library for Quad Color eInk
"""
import board
import digitalio
from PIL import Image, ImageEnhance
from adafruit_epd.jd79661 import Adafruit_JD79661
# create the spi device and pins we will need
spi = board.SPI()
ecs = digitalio.DigitalInOut(board.CE0)
dc = digitalio.DigitalInOut(board.D25)
srcs = None
rst = digitalio.DigitalInOut(board.D27) # can be None to not use this pin
busy = digitalio.DigitalInOut(board.D17) # can be None to not use this pin
# give them all to our driver
display = Adafruit_JD79661(122, 250, # 2.13" Quad-color display
spi,
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=srcs,
rst_pin=rst,
busy_pin=busy,
)
display.rotation = 3
image = Image.open("blinka.png")
# Scale the image to the smaller screen dimension
image_ratio = image.width / image.height
screen_ratio = display.width / display.height
if screen_ratio < image_ratio:
scaled_width = image.width * display.height // image.height
scaled_height = display.height
else:
scaled_width = display.width
scaled_height = image.height * display.width // image.width
image = image.resize((scaled_width, scaled_height), Image.BICUBIC)
# Crop and center the image
x = scaled_width // 2 - display.width // 2
y = scaled_height // 2 - display.height // 2
image = image.crop((x, y, x + display.width, y + display.height)).convert("RGB")
quad_colors = [
(0, 0, 0), # Black
(255, 255, 255), # White
(255, 0, 0), # Red
(255, 255, 0), # Yellow
]
palette_image = Image.new('P', (1, 1))
# Create palette data - PIL expects 768 values (256 colors * 3 channels)
palette_data = []
for color in quad_colors:
palette_data.extend(color)
# Fill remaining palette entries with black
for i in range(4, 256):
palette_data.extend([0, 0, 0])
palette_image.putpalette(palette_data)
enhancer = ImageEnhance.Color(image)
image = enhancer.enhance(1.5)
temp_image = image.quantize(palette=palette_image, dither=Image.Dither.FLOYDSTEINBERG)
pixels = temp_image.load()
width, height = temp_image.size
final_palette = Image.new('P', (1, 1))
final_palette.putpalette(palette_data)
final_image = Image.new('P', (width, height))
final_pixels = final_image.load()
# Copy pixels, ensuring they use indices 0-3
for y in range(height):
for x in range(width):
# Clamp pixel values to 0-3 range
final_pixels[x, y] = min(pixels[x, y], 3)
final_image.putpalette(palette_data)
# Convert back to RGB for display
image = final_image.convert('RGB')
# Display image.
display.image(image)
display.display()