Tasmota/lib/libesp32/JPEGDEC/examples/epd_demo/Grayscale_IL0398.cpp

370 lines
11 KiB
C++

// slimmed down version of the Open Book IL0398 driver.
// https://github.com/joeycastillo/The-Open-Book/blob/master/src/Grayscale_IL0398.cpp
#include "Grayscale_IL0398.h"
#define BUSY_WAIT 500
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef _swap_int16_t
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
#endif
/**************************************************************************/
/*!
@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
*/
/**************************************************************************/
Grayscale_IL0398::Grayscale_IL0398(int width, int height,
int8_t SID, int8_t SCLK, int8_t DC, int8_t RST,
int8_t CS, int8_t SRCS, int8_t MISO, int8_t BUSY) :
Adafruit_EPD(width, height, SID, SCLK, DC, RST, CS, SRCS, MISO, BUSY) {
buffer1_size = ((uint32_t)width * (uint32_t)height) / 8;
buffer2_size = buffer1_size;
if (SRCS >= 0) {
use_sram = true;
buffer1_addr = 0;
buffer2_addr = buffer1_size;
buffer1 = buffer2 = NULL;
} else {
buffer1 = (uint8_t *)malloc(buffer1_size);
buffer2 = (uint8_t *)malloc(buffer2_size);
}
}
// 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
*/
/**************************************************************************/
Grayscale_IL0398::Grayscale_IL0398(int width, int height,
int8_t DC, int8_t RST,
int8_t CS, int8_t SRCS, int8_t BUSY, SPIClass *spi) :
Adafruit_EPD(width, height, DC, RST, CS, SRCS, BUSY, spi) {
buffer1_size = ((uint32_t)width * (uint32_t)height) / 8;
buffer2_size = buffer1_size;
if (SRCS >= 0) {
use_sram = true;
buffer1_addr = 0;
buffer2_addr = 0;
buffer1 = buffer2 = NULL;
} else {
buffer1 = (uint8_t *)malloc(buffer1_size);
buffer2 = (uint8_t *)malloc(buffer1_size);
}
}
/**************************************************************************/
/*!
@brief wait for busy signal to end
*/
/**************************************************************************/
void Grayscale_IL0398::busy_wait(void)
{
if (_busy_pin > -1) {
do {
EPD_command(IL0398_GETSTATUS);
delay(10);
} while (!digitalRead(_busy_pin)); //wait for busy high
delay(200);
} else {
delay(BUSY_WAIT);
}
}
/**************************************************************************/
/*!
@brief begin communication with and set up the display.
@param reset if true the reset pin will be toggled.
*/
/**************************************************************************/
void Grayscale_IL0398::begin(bool reset)
{
Adafruit_EPD::begin(reset);
setBlackBuffer(0, true);
powerDown();
}
/**************************************************************************/
/*!
@brief signal the display to update
*/
/**************************************************************************/
void Grayscale_IL0398::update()
{
EPD_command(IL0398_DISPLAY_REFRESH);
delay(100);
busy_wait();
if (_busy_pin <= -1) {
delay(5000);
}
}
const unsigned char Grayscale_IL0398::LUT_VCOM_GRAYSCALE[] PROGMEM =
{
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,
0x00,
0x00
};
const unsigned char Grayscale_IL0398::LUT_WW_GRAYSCALE[] PROGMEM =
{
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 Grayscale_IL0398::LUT_WB_GRAYSCALE[] PROGMEM =
{
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 Grayscale_IL0398::LUT_BW_GRAYSCALE[] PROGMEM =
{
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 Grayscale_IL0398::LUT_BB_GRAYSCALE[] PROGMEM =
{
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,
};
/**************************************************************************/
/*!
@brief start up the display. Same as init, but here for compatibility with
Adafruit_EPD; you can call Grayscale_IL0398::init with more options.
*/
/**************************************************************************/
void Grayscale_IL0398::powerUp() {
uint8_t buf[5];
hardwareReset();
buf[0] = 0x03; // Panel will generate VDH and VDL (1<<0) and VGH and VGL (1<<1)
buf[1] = 0x00; // VCOMH=VDH+VCOMDC and VCOML=VDL+VCOMDC; VGH and VGL are 16v and -16v respectively
buf[2] = 0x2b; // VDH= 11V
buf[3] = 0x2b; // VDL=-11V
buf[4] = 0x13; // VDHR=6.2V
EPD_command(IL0398_POWER_SETTING, buf, 5);
buf[0] = 0x17; // phase A: soft start 10ms, driving strength 3, off time 6.58us
buf[1] = 0x17; // phase B: soft start 10ms, driving strength 3, off time 6.58us
buf[2] = 0x17; // phase C: driving strength 3, off time 6.58us
EPD_command(IL0398_BOOSTER_SOFT_START, buf, 3);
buf[0] = 0x3F; // (1<<4) sets display to monochrome and (1<<5) enables custom LUTs
EPD_command(IL0398_PANEL_SETTING, buf, 1);
buf[0] = 0x3C; // 50 Hz
EPD_command(IL0398_PLL, buf, 1);
buf[0] = (HEIGHT >> 8) & 0xFF;
buf[1] = HEIGHT & 0xFF;
buf[2] = (WIDTH >> 8) & 0xFF;
buf[3] = WIDTH & 0xFF;
EPD_command(IL0398_RESOLUTION, buf, 4);
buf[0] = 0x12; // VCOM_DC = -1.5v
EPD_command(IL0398_VCM_DC_SETTING, buf, 1);
buf[0] = 0xD7; // 0x57 for black border. 0x97 for white border. 0xD7 for floating border.
EPD_command(IL0398_VCOM, buf, 1);
EPD_command(IL0398_LUT1, LUT_VCOM_GRAYSCALE, sizeof(LUT_VCOM_GRAYSCALE));
EPD_command(IL0398_LUTWW, LUT_WW_GRAYSCALE, sizeof(LUT_WW_GRAYSCALE));
EPD_command(IL0398_LUTBW, LUT_BW_GRAYSCALE, sizeof(LUT_BW_GRAYSCALE));
EPD_command(IL0398_LUTWB, LUT_WB_GRAYSCALE, sizeof(LUT_WB_GRAYSCALE));
EPD_command(IL0398_LUTBB, LUT_BB_GRAYSCALE, sizeof(LUT_BB_GRAYSCALE));
EPD_command(IL0398_POWER_ON);
busy_wait();
delay(20);
}
/**************************************************************************/
/*!
@brief wind down the display
*/
/**************************************************************************/
void Grayscale_IL0398::powerDown()
{
uint8_t buf[4];
// power off
buf[0] = 0xF7; // border floating
EPD_command(IL0398_VCOM, buf, 1);
EPD_command(IL0398_POWER_OFF);
busy_wait();
buf[0] = 0xA5; // deep sleep
EPD_command(IL0398_DEEP_SLEEP, buf, 1);
delay(100);
}
/**************************************************************************/
/*!
@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 Grayscale_IL0398::drawPixel(int16_t x, int16_t y, uint16_t color) {
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
return;
uint8_t *pByte1;
uint8_t *pByte2;
// check rotation, move pixel around if necessary
switch (getRotation()) {
case 1:
EPD_swap(x, y);
x = WIDTH - x - 1;
break;
case 2:
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
break;
case 3:
EPD_swap(x, y);
y = HEIGHT - y - 1;
break;
}
uint16_t addr = ( (uint32_t)(WIDTH - 1 - x) * (uint32_t)HEIGHT + y)/8;
if (use_sram) {
uint8_t byte1 = sram.read8(blackbuffer_addr + addr);
uint8_t byte2 = sram.read8(colorbuffer_addr + addr);
pByte1 = &byte1;
pByte2 = &byte2;
} else {
pByte1 = black_buffer + addr;
pByte2 = color_buffer + addr;
}
switch (color) {
case EPD_BLACK:
*pByte1 &= ~(1 << (7 - (y%8)));
*pByte2 &= ~(1 << (7 - (y%8)));
break;
case EPD_DARK:
*pByte1 |= (1 << (7 - (y%8)));
*pByte2 &= ~(1 << (7 - (y%8)));
break;
case EPD_LIGHT:
*pByte1 &= ~(1 << (7 - (y%8)));
*pByte2 |= (1 << (7 - (y%8)));
break;
case EPD_WHITE:
*pByte1 |= (1 << (7 - (y%8)));
*pByte2 |= (1 << (7 - (y%8)));
break;
}
if (use_sram) {
sram.write8(addr, *pByte1);
sram.write8(addr + buffer1_size, *pByte2);
}
}
/**************************************************************************/
/*!
@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 Grayscale_IL0398::writeRAMCommand(uint8_t index) {
if (index == 0) {
return EPD_command(IL0398_DTM2, false);
}
if (index == 1) {
return EPD_command(IL0398_DTM1, false);
}
return 0;
}
/**************************************************************************/
/*!
@brief Some displays require setting the RAM address pointer
@param x X address counter value
@param y Y address counter value
*/
/**************************************************************************/
void Grayscale_IL0398::setRAMAddress(uint16_t x, uint16_t y) {
// on this chip we do nothing
}
/*!
* @file Adafruit_IL0398.cpp
*
* Forked from Adafruit_IL0398.cpp; copyright notce below.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Written by Dean Miller for Adafruit Industries.
* Open Book additions by Joey Castillo.
*
* BSD license, all text here must be included in any redistribution.
*
*/