Compare commits

...

2 commits

Author SHA1 Message Date
ladyada
01008abbb5 add demo for 2.7" v2 shield 2023-12-16 20:31:54 -05:00
ladyada
512bbbc23c adding expander support via function pointers 2023-12-16 20:25:15 -05:00
6 changed files with 382 additions and 2 deletions

View file

@ -0,0 +1,137 @@
/***************************************************
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"
#define EPD_CS 10
#define EPD_DC 9
#define SRAM_CS 8
#define EPD_BUSY -1
#define EPD_RESET -1
#define EPD_SPI &SPI // primary SPI
// 2.7" Tricolor Featherwing or Breakout with EK79686 chipset (v2 Black Shield)
ThinkInk_270_Tricolor_Z70 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS,
EPD_BUSY, EPD_SPI);
#include <Adafruit_XCA9554.h>
Adafruit_XCA9554 expander;
#define XCA_EPD_RESET 5
#define XCA_EPD_CARDDET 6
#define XCA_EPD_BUSY 7
void expanderEPDReset(void) {
expander.pinMode(XCA_EPD_RESET, OUTPUT);
expander.digitalWrite(XCA_EPD_RESET, HIGH); // start high for sure
delay(10);
expander.digitalWrite(XCA_EPD_RESET, LOW); // enter reset
delay(10);
expander.digitalWrite(XCA_EPD_RESET, HIGH); // bring out of reset
delay(10);
}
bool expanderEPDBusy(void) {
expander.pinMode(XCA_EPD_BUSY, INPUT);
return expander.digitalRead(XCA_EPD_BUSY);
}
void setup() {
Serial.begin(115200);
while (!Serial) {
delay(10);
}
Serial.println("Adafruit ThinkInk Shield test in red/black/white");
// Begin communication with the expander
if (!expander.begin(0x20)) { // Replace with actual I2C address if different
Serial.println("Failed to find XCA9554 chip");
while (1);
}
display.setCustomBusyFunction(expanderEPDBusy);
display.setCustomResetFunction(expanderEPDReset);
display.begin(THINKINK_TRICOLOR);
display.clearBuffer();
display.setTextSize(2);
display.setCursor(10, (display.height() - 24) / 2);
display.setTextColor(EPD_BLACK);
display.print("Press the ");
display.setTextColor(EPD_RED);
display.print("Buttons!");
display.display();
// set the 4 buttons to inputs via the expander
expander.pinMode(0, INPUT);
expander.pinMode(1, INPUT);
expander.pinMode(2, INPUT);
expander.pinMode(3, INPUT);
}
void loop() {
if (! expander.digitalRead(0)) {
Serial.println("Button A pressed");
Serial.println("Banner demo");
display.clearBuffer();
display.setTextSize(3);
display.setCursor((display.width() - 144) / 2, (display.height() - 24) / 2);
display.setTextColor(EPD_BLACK);
display.print("Tri");
display.setTextColor(EPD_RED);
display.print("Color");
display.display();
}
if (! expander.digitalRead(1)) {
Serial.println("Button B pressed");
Serial.println("Color rectangle demo");
display.clearBuffer();
display.fillRect(display.width() / 3, 0, display.width() / 3,
display.height(), EPD_BLACK);
display.fillRect((display.width() * 2) / 3, 0, display.width() / 3,
display.height(), EPD_RED);
display.display();
}
if (! expander.digitalRead(2)) {
Serial.println("Button C pressed");
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();
}
if (! expander.digitalRead(3)) {
Serial.println("Button D pressed");
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);
}
display.display();
}
}
void testdrawtext(const char *text, uint16_t color) {
display.setCursor(0, 0);
display.setTextColor(color);
display.setTextWrap(true);
display.print(text);
}

View file

@ -196,6 +196,10 @@ void Adafruit_EPD::begin(bool reset) {
*/
/**************************************************************************/
void Adafruit_EPD::hardwareReset(void) {
if ( _customResetFunction != NULL) {
_customResetFunction();
return;
}
if (_reset_pin >= 0) {
// Setup reset pin direction
pinMode(_reset_pin, OUTPUT);
@ -212,6 +216,37 @@ void Adafruit_EPD::hardwareReset(void) {
}
}
/**
* @brief Sets a custom reset function.
*
* @param resetFunction The function to be called for custom hardware reset.
*/
void Adafruit_EPD::setCustomResetFunction(customResetFunction resetFunction) {
_customResetFunction = resetFunction;
}
bool Adafruit_EPD::readBusyPin(void) {
if (_customBusyFunction) {
return _customBusyFunction();
}
if (_busy_pin >= 0) {
return digitalRead(_busy_pin);
}
return false;
}
/**
* @brief Sets a custom busy function.
*
* @param resetFunction The function to be called for custom business check.
*/
void Adafruit_EPD::setCustomBusyFunction(customBusyFunction busyFunction) {
_customBusyFunction = busyFunction;
}
/**************************************************************************/
/*!
@brief draw a single pixel on the screen

View file

@ -81,6 +81,11 @@ public:
thinkinkmode_t getMode(void) { return inkmode; }
typedef void (*customResetFunction)();
void setCustomResetFunction(customResetFunction resetFunction);
typedef bool (*customBusyFunction)();
void setCustomBusyFunction(customBusyFunction busyFunction);
protected:
void writeRAMFramebufferToEPD(uint8_t *buffer, uint32_t buffer_size,
uint8_t EPDlocation, bool invertdata = false);
@ -108,6 +113,7 @@ protected:
/**************************************************************************/
virtual void setRAMAddress(uint16_t x, uint16_t y) = 0;
bool readBusyPin(void);
virtual void busy_wait(void) = 0;
/**************************************************************************/
@ -131,6 +137,8 @@ protected:
/**************************************************************************/
virtual void powerDown(void) = 0;
void hardwareReset(void);
customResetFunction _customResetFunction = NULL;
customBusyFunction _customBusyFunction = NULL;
int16_t _dc_pin, ///< data/command pin
_reset_pin, ///< reset pin

View file

@ -21,6 +21,7 @@
#include "panels/ThinkInk_213_Grayscale4_T5.h"
#include "panels/ThinkInk_270_Grayscale4_W3.h"
#include "panels/ThinkInk_290_Grayscale4_T5.h"
#include "panels/ThinkInk_290_Grayscale4_T94.h"
#include "panels/ThinkInk_420_Grayscale4_T2.h"
#include "panels/ThinkInk_154_Mono_D27.h"

View file

@ -106,11 +106,11 @@ Adafruit_EK79686::Adafruit_EK79686(int width, int height, int16_t DC,
*/
/**************************************************************************/
void Adafruit_EK79686::busy_wait(void) {
if (_busy_pin >= 0) {
if (_busy_pin >= 0 || _customBusyFunction != NULL) {
do {
EPD_command(EK79686_FLG);
delay(10);
} while (!digitalRead(_busy_pin));
} while (!readBusyPin());
} else {
delay(BUSY_WAIT);
}

View file

@ -0,0 +1,199 @@
#ifndef _THINKINK_290_GRAYSCALE4_T94_H
#define _THINKINK_290_GRAYSCALE4_T94_H
// This file is #included by Adafruit_ThinkInk.h and does not need to
// #include anything else to pick up the EPD header or ink mode enum.
// clang-format off
/*
static const uint8_t ti_290t5_gray4_init_code[] {
IL0373_POWER_SETTING, 5, 0x03, 0x00, 0x2b, 0x2b, 0x13,
IL0373_BOOSTER_SOFT_START, 3, 0x17, 0x17, 0x17,
IL0373_POWER_ON, 0,
0xFF, 200,
IL0373_PANEL_SETTING, 1, 0x3F,
IL0373_PLL, 1, 0x3C,
IL0373_VCM_DC_SETTING, 1, 0x12,
IL0373_CDI, 1, 0x97,
0xFE // EOM
};
static const uint8_t ti_290t5_monopart_init_code[] {
IL0373_POWER_SETTING, 5, 0x03, 0x00, 0x2b, 0x2b, 0x03,
IL0373_BOOSTER_SOFT_START, 3, 0x17, 0x17, 0x17,
IL0373_POWER_ON, 0,
0xFF, 200,
IL0373_PANEL_SETTING, 2, 0xbF, 0x0d,
IL0373_PLL, 1, 0x3C,
IL0373_VCM_DC_SETTING, 1, 0x12,
IL0373_CDI, 1, 0x47,
0xFE // EOM
};
static const uint8_t ti_290t5_monofull_init_code[] {
IL0373_BOOSTER_SOFT_START, 3, 0x17, 0x17, 0x17,
IL0373_POWER_ON, 0,
0xFF, 200,
IL0373_PANEL_SETTING, 2, 0x1f, 0x0d,
IL0373_CDI, 1, 0x97,
0xFE // EOM
};
static const uint8_t ti_290t5_monopart_lut_code[] = {
// const unsigned char lut_vcom1[]
0x20, 44,
0x00, 0x01, 0x0E, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
// const unsigned char lut_ww1[]
0x21, 42,
0x00, 0x01, 0x0E, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// const unsigned char lut_bw1[]
0x22, 42,
0x20, 0x01, 0x0E, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// const unsigned char lut_wb1[]
0x23, 42,
0x10, 0x01, 0x0E, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// const unsigned char lut_bb1[]
0x24, 42,
0x00, 0x01, 0x0E, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE // EOM
};
const uint8_t ti_290t5_gray4_lut_code[] = {
//const unsigned char lut_vcom[] =
0x20, 42,
0x00, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x60, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
0x00, 0x13, 0x0A, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//const unsigned char lut_ww[] ={
0x21, 42,
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x10, 0x14, 0x0A, 0x00, 0x00, 0x01,
0xA0, 0x13, 0x01, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//const unsigned char lut_bw[] ={
0x22, 42,
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x99, 0x0C, 0x01, 0x03, 0x04, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//const unsigned char lut_wb[] ={
0x23, 42,
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x99, 0x0B, 0x04, 0x04, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//const unsigned char lut_bb[] ={
0x24, 42,
0x80, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x20, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x50, 0x13, 0x01, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE // EOM
};
*/
// clang-format on
class ThinkInk_290_Grayscale4_T94 : public Adafruit_SSD1680 {
public:
ThinkInk_290_Grayscale4_T94(int16_t SID, int16_t SCLK, int16_t DC, int16_t RST,
int16_t CS, int16_t SRCS, int16_t MISO,
int16_t BUSY = -1)
: Adafruit_SSD1680(296, 128, SID, SCLK, DC, RST, CS, SRCS, MISO, BUSY){};
ThinkInk_290_Grayscale4_T94(int16_t DC, int16_t RST, int16_t CS, int16_t SRCS,
int16_t BUSY = -1, SPIClass *spi = &SPI)
: Adafruit_SSD1680(296, 128, DC, RST, CS, SRCS, BUSY, spi){};
void begin(thinkinkmode_t mode = THINKINK_GRAYSCALE4) {
Adafruit_SSD1680::begin(true);
setColorBuffer(0, true); // layer 0 uninverted
setBlackBuffer(1, true); // layer 1 uninverted
inkmode = mode; // Preserve ink mode for ImageReader or others
/*
if (mode == THINKINK_GRAYSCALE4) {
_epd_init_code = ti_290t5_gray4_init_code;
_epd_lut_code = ti_290t5_gray4_lut_code;
layer_colors[EPD_WHITE] = 0b00;
layer_colors[EPD_BLACK] = 0b11;
layer_colors[EPD_RED] = 0b01;
layer_colors[EPD_GRAY] = 0b10;
layer_colors[EPD_LIGHT] = 0b01;
layer_colors[EPD_DARK] = 0b10;
} else if (mode == THINKINK_MONO) {
_epd_init_code = ti_290t5_monofull_init_code;
_epd_partial_init_code = ti_290t5_monopart_init_code;
_epd_partial_lut_code = ti_290t5_monopart_lut_code;
layer_colors[EPD_WHITE] = 0b11;
layer_colors[EPD_BLACK] = 0b01;
layer_colors[EPD_RED] = 0b01;
layer_colors[EPD_GRAY] = 0b01;
layer_colors[EPD_LIGHT] = 0b10;
layer_colors[EPD_DARK] = 0b01;
}
*/
default_refresh_delay = 800;
powerDown();
}
};
#endif // _THINKINK_290_GRAYSCALE4_T94_H