add 3.52" quad color (note upside-down connector!)

This commit is contained in:
ladyada 2025-07-27 10:14:13 -04:00
parent a44b60d8f4
commit 308619ed00
6 changed files with 406 additions and 3 deletions

View file

@ -30,6 +30,10 @@
ThinkInk_213_Quadcolor_AJHE5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, ThinkInk_213_Quadcolor_AJHE5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY,
EPD_SPI); EPD_SPI);
// 3.52" Quadcolor EPD with JD79667 chipset
ThinkInk_352_Quadcolor_AJHE5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY,
EPD_SPI);
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
while (!Serial) { while (!Serial) {

View file

@ -34,6 +34,7 @@
#include "panels/ThinkInk_290_Tricolor_Z10.h" #include "panels/ThinkInk_290_Tricolor_Z10.h"
#include "panels/ThinkInk_290_Tricolor_Z13.h" #include "panels/ThinkInk_290_Tricolor_Z13.h"
#include "panels/ThinkInk_290_Tricolor_Z94.h" #include "panels/ThinkInk_290_Tricolor_Z94.h"
#include "panels/ThinkInk_352_Quadcolor_AJHE5.h"
#include "panels/ThinkInk_370_Mono_BAAMFGN.h" #include "panels/ThinkInk_370_Mono_BAAMFGN.h"
#include "panels/ThinkInk_370_Tricolor_BABMFGNR.h" #include "panels/ThinkInk_370_Tricolor_BABMFGNR.h"
#include "panels/ThinkInk_420_Grayscale4_MFGN.h" #include "panels/ThinkInk_420_Grayscale4_MFGN.h"

View file

@ -131,10 +131,10 @@ void Adafruit_JD79661::drawPixel(int16_t x, int16_t y, uint16_t color) {
uint8_t* pBuf; uint8_t* pBuf;
// deal with non-8-bit heights // deal with non-4-bit heights
uint16_t _WIDTH = WIDTH; uint16_t _WIDTH = WIDTH;
if (_WIDTH % 8 != 0) { if (_WIDTH % 4 != 0) {
_WIDTH += 8 - (_WIDTH % 8); _WIDTH += 4 - (_WIDTH % 4);
} }
// check rotation, move pixel around if necessary // check rotation, move pixel around if necessary

View file

@ -0,0 +1,315 @@
#include "Adafruit_JD79667.h"
#include "Adafruit_EPD.h"
#define EPD_RAM_BW 0x10
#define EPD_RAM_RED 0x13
#define BUSY_WAIT 500
// clang-format off
const uint8_t jd79667_default_init_code[] {
0xFF, 10, // wait a lil bit
0x4D, 1, 0x78,
JD79667_PANEL_SETTING, 2, 0x0F, 0x29, // PSR, Display resolution is 180x384
JD79667_POWER_SETTING, 2, 0x07, 0x00, // PWR
0x03, 3, 0x10, 0x54, 0x44, // POFS
JD79667_BOOSTER_SOFTSTART, 7, 0x05, 0x00, 0x3F, 0x0A, 0x25, 0x12, 0x1A,
JD79667_CDI, 1, 0x37, // CDI
0x60, 2, 0x02, 0x02, // TCON
JD79667_RESOLUTION, 4, 0, 180, 1, 128, // TRES 180x384
0xE7, 1, 0x1C,
0xE3, 1, 0x22,
0xB4, 1, 0xD0,
0xB5, 1, 0x03,
0xE9, 1, 0x01,
JD79667_PLL_CONTROL, 1, 0x08,
JD79667_POWER_ON, 0,
0xFE};
// clang-format on
/**************************************************************************/
/*!
@brief constructor if using external SRAM chip and software SPI
@param width the width of the display in pixels
@param height the height of the display in pixels
@param SID the SID pin to use
@param SCLK the SCLK pin to use
@param DC the data/command pin to use
@param RST the reset pin to use
@param CS the chip select pin to use
@param SRCS the SRAM chip select pin to use
@param MISO the MISO pin to use
@param BUSY the busy pin to use
*/
/**************************************************************************/
Adafruit_JD79667::Adafruit_JD79667(int width, int height, int16_t SID,
int16_t SCLK, int16_t DC, int16_t RST,
int16_t CS, int16_t SRCS, int16_t MISO,
int16_t BUSY)
: Adafruit_EPD(width, height, SID, SCLK, DC, RST, CS, SRCS, MISO, BUSY) {
if ((width % 8) != 0) {
width += 8 - (width % 8);
}
buffer1_size = width * height / 4;
buffer2_size = 0;
if (SRCS >= 0) {
use_sram = true;
buffer1_addr = 0;
buffer2_addr = 0;
} else {
buffer1 = (uint8_t*)malloc(buffer1_size);
buffer2 = buffer1;
}
singleByteTxns = true;
}
// constructor for hardware SPI - we indicate DataCommand, ChipSelect, Reset
/**************************************************************************/
/*!
@brief constructor if using on-chip RAM and hardware SPI
@param width the width of the display in pixels
@param height the height of the display in pixels
@param DC the data/command pin to use
@param RST the reset pin to use
@param CS the chip select pin to use
@param SRCS the SRAM chip select pin to use
@param BUSY the busy pin to use
*/
/**************************************************************************/
Adafruit_JD79667::Adafruit_JD79667(int width, int height, int16_t DC,
int16_t RST, int16_t CS, int16_t SRCS,
int16_t BUSY, SPIClass* spi)
: Adafruit_EPD(width, height, DC, RST, CS, SRCS, BUSY, spi) {
if ((width % 8) != 0) {
width += 8 - (width % 8);
}
buffer1_size = width * height / 4;
buffer2_size = 0;
if (SRCS >= 0) {
use_sram = true;
buffer1_addr = 0;
buffer2_addr = 0;
} else {
buffer1 = (uint8_t*)malloc(buffer1_size);
buffer2 = buffer1;
}
singleByteTxns = true;
}
/**************************************************************************/
/*!
@brief clear all data buffers
*/
/**************************************************************************/
void Adafruit_JD79667::clearBuffer() {
if (use_sram) {
sram.erase(colorbuffer_addr, buffer1_size, 0x55);
} else {
memset(buffer1, 0x55, buffer1_size);
}
}
/**************************************************************************/
/*!
@brief draw a single pixel on the screen
@param x the x axis position
@param y the y axis position
@param color the color of the pixel
*/
/**************************************************************************/
void Adafruit_JD79667::drawPixel(int16_t x, int16_t y, uint16_t color) {
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
return;
uint8_t* pBuf;
// deal with non-4-bit heights
uint16_t _WIDTH = WIDTH;
if (_WIDTH % 4 != 0) {
_WIDTH += 4 - (_WIDTH % 4);
}
// check rotation, move pixel around if necessary
switch (getRotation()) {
case 1:
EPD_swap(x, y);
x = _WIDTH - x - 1;
// remove the offset
x -= _WIDTH - WIDTH;
break;
case 2:
x = _WIDTH - x - 1;
y = HEIGHT - y - 1;
// re-add the offset
x += _WIDTH - WIDTH;
break;
case 3:
EPD_swap(x, y);
y = HEIGHT - y - 1;
break;
}
uint32_t addr = ((uint32_t)x + (uint32_t)y * _WIDTH) / 4;
uint8_t color_c;
if (use_sram) {
color_c = sram.read8(colorbuffer_addr + addr);
pBuf = &color_c;
} else {
pBuf = color_buffer + addr;
}
if (color == EPD_BLACK) {
color = JD79667_BLACK;
} else if (color == EPD_RED) {
color = JD79667_RED;
} else if (color == EPD_YELLOW) {
color = JD79667_YELLOW;
} else if (color == EPD_WHITE) {
color = JD79667_WHITE;
}
uint8_t byte_offset_mask = 0x3 << (3 - (x % 4)) * 2;
uint8_t byte_offset_value = (color & 0x3) << (3 - (x % 4)) * 2;
*pBuf &= ~byte_offset_mask; // save reverse mask
*pBuf |= byte_offset_value; // now add in the new color
if (use_sram) {
sram.write8(colorbuffer_addr + addr, *pBuf);
}
}
/**************************************************************************/
/*!
@brief wait for busy signal to end
*/
/**************************************************************************/
void Adafruit_JD79667::busy_wait(void) {
if (_busy_pin >= 0) {
while (!digitalRead(_busy_pin)) { // wait for busy HIGH!
delay(10);
}
} else {
delay(BUSY_WAIT);
}
}
/**************************************************************************/
/*!
@brief begin communication with and set up the display.
@param reset if true the reset pin will be toggled.
*/
/**************************************************************************/
void Adafruit_JD79667::begin(bool reset) {
Adafruit_EPD::begin(reset);
delay(100);
}
/**************************************************************************/
/*!
@brief signal the display to update
*/
/**************************************************************************/
void Adafruit_JD79667::update() {
uint8_t buf[1];
// display update sequence
buf[0] = 0x00;
EPD_command(JD79667_DISPLAY_REFRESH, buf, 1);
busy_wait();
if (_busy_pin <= -1) {
delay(1000);
}
}
void Adafruit_JD79667::hardwareReset(void) {
if (_reset_pin >= 0) {
// Setup reset pin direction
pinMode(_reset_pin, OUTPUT);
// VDD (3.3V) goes high at start, lets just chill for a ms
digitalWrite(_reset_pin, HIGH);
delay(20);
// bring reset low
digitalWrite(_reset_pin, LOW);
// wait 40ms
delay(40);
// bring out of reset
digitalWrite(_reset_pin, HIGH);
delay(50);
}
}
/**************************************************************************/
/*!
@brief start up the display
*/
/**************************************************************************/
void Adafruit_JD79667::powerUp() {
hardwareReset();
busy_wait();
const uint8_t* init_code = jd79667_default_init_code;
if (_epd_init_code != NULL) {
init_code = _epd_init_code;
}
EPD_commandList(init_code);
busy_wait();
}
/**************************************************************************/
/*!
@brief wind down the display
*/
/**************************************************************************/
void Adafruit_JD79667::powerDown() {
uint8_t buf[1];
// Only deep sleep if we can get out of it
if (_reset_pin >= 0) {
// deep sleep
buf[0] = 0x00;
EPD_command(JD79667_POWER_OFF, buf, 1);
busy_wait();
delay(100);
buf[0] = 0xA5;
EPD_command(JD79667_DEEP_SLEEP, buf, 1);
}
}
/**************************************************************************/
/*!
@brief Send the specific command to start writing to EPD display RAM
@param index The index for which buffer to write (0 or 1 or tri-color
displays) Ignored for monochrome displays.
@returns The byte that is read from SPI at the same time as sending the
command
*/
/**************************************************************************/
uint8_t Adafruit_JD79667::writeRAMCommand(uint8_t index) {
(void)index;
EPD_command(JD79667_DATA_START_XMIT);
return true;
}
/**************************************************************************/
/*!
@brief Some displays require setting the RAM address pointer
@param x X address counter value
@param y Y address counter value
*/
/**************************************************************************/
void Adafruit_JD79667::setRAMAddress(uint16_t x, uint16_t y) {
(void)x;
(void)y;
}

View file

@ -0,0 +1,53 @@
#ifndef LIB_ADAFRUIT_JD79667
#define LIB_ADAFRUIT_JD79667
#include <Arduino.h>
#include "Adafruit_EPD.h"
#define JD79667_PANEL_SETTING 0x00
#define JD79667_POWER_SETTING 0x01
#define JD79667_POWER_OFF 0x02
#define JD79667_POWER_ON 0x04
#define JD79667_BOOSTER_SOFTSTART 0x06
#define JD79667_DATA_START_XMIT 0x10
#define JD79667_DISPLAY_REFRESH 0x12
#define JD79667_DEEP_SLEEP 0x07
#define JD79667_PLL_CONTROL 0x30
#define JD79667_CDI 0x50
#define JD79667_RESOLUTION 0x61
#define JD79667_BLACK 0b00
#define JD79667_WHITE 0b01
#define JD79667_YELLOW 0b10
#define JD79667_RED 0b11
/**************************************************************************/
/*!
@brief Class for interfacing with JD79667 EPD drivers
*/
/**************************************************************************/
class Adafruit_JD79667 : public Adafruit_EPD {
public:
Adafruit_JD79667(int width, int height, 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_JD79667(int width, int height, int16_t DC, int16_t RST, int16_t CS,
int16_t SRCS, int16_t BUSY = -1, SPIClass* spi = &SPI);
void begin(bool reset = true);
void powerUp();
void update(void);
void powerDown();
void clearBuffer();
void drawPixel(int16_t x, int16_t y, uint16_t color);
void hardwareReset(void);
protected:
void busy_wait();
void setRAMAddress(uint16_t x, uint16_t y);
uint8_t writeRAMCommand(uint8_t index);
};
#endif

View file

@ -0,0 +1,30 @@
#ifndef _THINKINK_352_QUADCOLOR_AJHE5_H
#define _THINKINK_352_QUADCOLOR_AJHE5_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.
class ThinkInk_352_Quadcolor_AJHE5 : public Adafruit_JD79667 {
public:
ThinkInk_352_Quadcolor_AJHE5(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_JD79667(180, 384, SID, SCLK, DC, RST, CS, SRCS, MISO, BUSY){};
ThinkInk_352_Quadcolor_AJHE5(int16_t DC, int16_t RST, int16_t CS,
int16_t SRCS, int16_t BUSY = -1,
SPIClass* spi = &SPI)
: Adafruit_JD79667(180, 384, DC, RST, CS, SRCS, BUSY, spi){};
void begin(thinkinkmode_t mode = THINKINK_QUADCOLOR) {
Adafruit_JD79667::begin(true);
inkmode = mode; // Preserve ink mode for ImageReader or others
default_refresh_delay = 13000;
setRotation(1);
powerDown();
}
};
#endif // _THINKINK_352_Quad