quad color eInk demos
This commit is contained in:
parent
5e539a6626
commit
53dce06f35
8 changed files with 404 additions and 0 deletions
|
|
@ -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() {
|
||||
|
||||
}
|
||||
BIN
Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/blinka.bmp
Normal file
BIN
Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/blinka.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
|
|
@ -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);
|
||||
}
|
||||
79
Quad_Color_eInk_Demos/Blinka_EPD_Demo/code.py
Normal file
79
Quad_Color_eInk_Demos/Blinka_EPD_Demo/code.py
Normal 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()
|
||||
BIN
Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/blinka.png
Normal file
BIN
Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/blinka.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.9 KiB |
92
Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/code.py
Normal file
92
Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/code.py
Normal 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()
|
||||
Loading…
Reference in a new issue