300 lines
11 KiB
C++
300 lines
11 KiB
C++
|
|
#include "Waveshare.h"
|
|
|
|
// www.waveshare.com/wiki/4.2inch_e-Paper_Module_(B)
|
|
// https://www.waveshare.com/wiki/4.2inch_e-Paper_Module_(B)_Manual#Overview
|
|
|
|
template <int PIN_CS, int PIN_BUSY, int PIN_RST, int PIN_DC, typename SPI> class Waveshare_4_2 : public Waveshare<PIN_CS, PIN_BUSY, PIN_RST, PIN_DC, SPI> {
|
|
|
|
static constexpr const char* NAME = "E-Ink 4.2\"";
|
|
|
|
static constexpr const uint8_t PANEL_SETTING = 0x00;
|
|
static constexpr const uint8_t POWER_SETTING = 0x01;
|
|
static constexpr const uint8_t POWER_OFF = 0x02;
|
|
static constexpr const uint8_t POWER_OFF_SEQUENCE_SETTING = 0x03;
|
|
static constexpr const uint8_t POWER_ON = 0x04;
|
|
static constexpr const uint8_t POWER_ON_MEASURE = 0x05;
|
|
static constexpr const uint8_t BOOSTER_SOFT_START = 0x06;
|
|
static constexpr const uint8_t DEEP_SLEEP = 0x07;
|
|
static constexpr const uint8_t DATA_START_TRANSMISSION_1 = 0x10;
|
|
static constexpr const uint8_t DATA_STOP = 0x11;
|
|
static constexpr const uint8_t DISPLAY_REFRESH = 0x12;
|
|
static constexpr const uint8_t DATA_START_TRANSMISSION_2 = 0x13;
|
|
static constexpr const uint8_t LUT_FOR_VCOM = 0x20;
|
|
static constexpr const uint8_t LUT_WHITE_TO_WHITE = 0x21;
|
|
static constexpr const uint8_t LUT_BLACK_TO_WHITE = 0x22;
|
|
static constexpr const uint8_t LUT_WHITE_TO_BLACK = 0x23;
|
|
static constexpr const uint8_t LUT_BLACK_TO_BLACK = 0x24;
|
|
static constexpr const uint8_t PLL_CONTROL = 0x30;
|
|
static constexpr const uint8_t TEMPERATURE_SENSOR_COMMAND = 0x40;
|
|
static constexpr const uint8_t TEMPERATURE_SENSOR_SELECTION = 0x41;
|
|
static constexpr const uint8_t TEMPERATURE_SENSOR_WRITE = 0x42;
|
|
static constexpr const uint8_t TEMPERATURE_SENSOR_READ = 0x43;
|
|
static constexpr const uint8_t VCOM_AND_DATA_INTERVAL_SETTING = 0x50;
|
|
static constexpr const uint8_t LOW_POWER_DETECTION = 0x51;
|
|
static constexpr const uint8_t TCON_SETTING = 0x60;
|
|
static constexpr const uint8_t RESOLUTION_SETTING = 0x61;
|
|
static constexpr const uint8_t GSST_SETTING = 0x65;
|
|
static constexpr const uint8_t GET_STATUS = 0x71;
|
|
static constexpr const uint8_t AUTO_MEASUREMENT_VCOM = 0x80;
|
|
static constexpr const uint8_t READ_VCOM_VALUE = 0x81;
|
|
static constexpr const uint8_t VCM_DC_SETTING = 0x82;
|
|
static constexpr const uint8_t PARTIAL_WINDOW = 0x90;
|
|
static constexpr const uint8_t PARTIAL_IN = 0x91;
|
|
static constexpr const uint8_t PARTIAL_OUT = 0x92;
|
|
static constexpr const uint8_t PROGRAM_MODE = 0xA0;
|
|
static constexpr const uint8_t ACTIVE_PROGRAMMING = 0xA1;
|
|
static constexpr const uint8_t READ_OTP = 0xA2;
|
|
static constexpr const uint8_t POWER_SAVING = 0xE3;
|
|
|
|
public:
|
|
|
|
enum class Mode {
|
|
BLACK_WHITE,
|
|
BLACK_WHITE_RED,
|
|
};
|
|
|
|
public:
|
|
|
|
Waveshare_4_2(SPI& spi) : Waveshare<PIN_CS, PIN_BUSY, PIN_RST, PIN_DC, SPI>(spi) {
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
struct Window {
|
|
uint16_t x1; // must be multiple of 8
|
|
uint16_t y1;
|
|
uint16_t w; // must be multiple of 8
|
|
uint16_t h;
|
|
Window(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) : x1(x1), y1(y1), w(w), h(h) {}
|
|
};
|
|
|
|
void setWindow(Window& win) {
|
|
this->sendCommand(0x90);
|
|
this->sendData((win.x1) >> 8);
|
|
this->sendData((win.x1) >> 0);
|
|
this->sendData((win.x1+win.w-1) >> 8);
|
|
this->sendData((win.x1+win.w-1) >> 0);
|
|
this->sendData(win.y1 >> 8);
|
|
this->sendData(win.y1 >> 0);
|
|
this->sendData((win.y1+win.h-1) >> 8);
|
|
this->sendData((win.y1+win.h-1) >> 0);
|
|
this->sendData(0x0); // 0 = refresh only the window, 1 = refresh everything??
|
|
}
|
|
|
|
void enableWindow() {
|
|
this->sendCommand(PARTIAL_IN);
|
|
}
|
|
|
|
void disableWindow() {
|
|
this->sendCommand(PARTIAL_OUT);
|
|
}
|
|
|
|
void init(Mode mode) {
|
|
|
|
Log::addInfo(NAME, "init()");
|
|
|
|
this->reset();
|
|
|
|
this->send3(BOOSTER_SOFT_START, 0x17, 0x17, 0x17);
|
|
this->sendCommand(POWER_ON);
|
|
this->waitUntilIdle();
|
|
|
|
uint8_t cfg = 0x0F;
|
|
if (mode == Mode::BLACK_WHITE) {cfg |= (1<<4);}
|
|
this->send1(PANEL_SETTING, cfg);
|
|
this->send1(VCOM_AND_DATA_INTERVAL_SETTING, 0xF7);
|
|
|
|
//this->sendCommand(0x10);//DATA_START_TRANSMISSION_1
|
|
//usleep(10*1000);
|
|
|
|
Log::addInfo(NAME, "init() complete");
|
|
|
|
}
|
|
|
|
/** load black data, bit-set = black pixel, nullptr input = clear all */
|
|
void loadBlack(const uint8_t* black) {
|
|
this->sendCommand(DATA_START_TRANSMISSION_1);
|
|
if (black) {
|
|
for (int i = 0; i < 400*300/8; ++i) {this->sendData(~reverse(black[i]));}
|
|
} else {
|
|
for (int i = 0; i < 400*300/8; ++i) {this->sendData(0);} // 0 = pixel not set (blank)
|
|
}
|
|
this->sendCommand(DATA_STOP);
|
|
}
|
|
|
|
/** load black data, bit-set = red pixel, nullptr input = clear all */
|
|
void loadRed(const uint8_t* red) {
|
|
this->sendCommand(DATA_START_TRANSMISSION_2);
|
|
if (red) {
|
|
for (int i = 0; i < 400*300/8; ++i) {this->sendData(~reverse(red[i]));}
|
|
} else {
|
|
for (int i = 0; i < 400*300/8; ++i) {this->sendData(0);} // 0 = pixel not set (blank)
|
|
}
|
|
this->sendCommand(DATA_STOP);
|
|
}
|
|
|
|
static uint8_t reverse(uint8_t a) {
|
|
return
|
|
((a & 0x1) << 7) | ((a & 0x2) << 5) |
|
|
((a & 0x4) << 3) | ((a & 0x8) << 1) |
|
|
((a & 0x10) >> 1) | ((a & 0x20) >> 3) |
|
|
((a & 0x40) >> 5) | ((a & 0x80) >> 7);
|
|
}
|
|
|
|
void show() {
|
|
|
|
Log::addInfo(NAME, "refresh");
|
|
this->sendCommand(DISPLAY_REFRESH);
|
|
usleep(100*1000);
|
|
this->waitUntilIdle();
|
|
Log::addInfo(NAME, "refresh done");
|
|
|
|
Log::addInfo(NAME, "sleep");
|
|
this->send1(VCOM_AND_DATA_INTERVAL_SETTING, 0x17);
|
|
this->send1(VCM_DC_SETTING, 0x00); //to solve Vcom drop
|
|
this->send4(POWER_SETTING, 0x02, 0x00, 0x00, 0x00);
|
|
this->waitUntilIdle();
|
|
this->sendCommand(POWER_OFF);
|
|
Log::addInfo(NAME, "sleep done");
|
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
unsigned char lut_dc_4in2[44] = {
|
|
0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x17, 0x00, 0x00,
|
|
0x02, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x01, 0x00, 0x0E, 0x0E, 0x00,
|
|
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
//R21H
|
|
unsigned char lut_ww_4in2[42] = {
|
|
0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
//R22H r
|
|
unsigned char lut_bw_4in2[42] = {
|
|
0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
//R24H b
|
|
unsigned char lut_bb_4in2[42] = {
|
|
0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
//R23H w
|
|
unsigned char lut_wb_4in2[42] = {
|
|
0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
int EPD_Init_4in2()
|
|
{
|
|
EPD_Reset();
|
|
|
|
EPD_SendCommand(0x01);//POWER_SETTING
|
|
EPD_SendData(0x03); // VDS_EN, VDG_EN
|
|
EPD_SendData(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0]
|
|
EPD_SendData(0x2F); // VDH
|
|
EPD_SendData(0x2F); // VDL
|
|
EPD_SendData(0xFF); // VDHR
|
|
|
|
EPD_Send_3(0x06, 0x17, 0x17, 0x17);//BOOSTER_SOFT_START
|
|
EPD_SendCommand(0x04);//POWER_ON
|
|
EPD_WaitUntilIdle();
|
|
|
|
EPD_Send_2(0x00, 0xBF, 0x0B);//PANEL_SETTING: // KW-BF KWR-AF BWROTP 0f
|
|
EPD_Send_1(0x30, 0x3C);//PLL_CONTROL: 3A 100HZ, 29 150Hz, 39 200HZ, 31 171HZ
|
|
|
|
EPD_Send_4(0x61, 1, 144, 1, 44);// RESOLUTION_SETTING: HI(W), LO(W), HI(H), LO(H)
|
|
EPD_Send_1(0x82, 0x12);// VCM_DC_SETTING
|
|
EPD_Send_1(0x50, 0x97);// VCOM_AND_DATA_INTERVAL_SETTING: VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7
|
|
|
|
EPD_lut(0x20,44,&lut_dc_4in2[0]);// LUT_FOR_VCOM
|
|
EPD_lut(0x21,42,&lut_ww_4in2[0]);// LUT_WHITE_TO_WHITE
|
|
EPD_lut(0x22,42,&lut_bw_4in2[0]);// LUT_BLACK_TO_WHITE
|
|
EPD_lut(0x23,42,&lut_wb_4in2[0]);// LUT_WHITE_TO_BLACK
|
|
EPD_lut(0x24,42,&lut_bb_4in2[0]);// LUT_BLACK_TO_BLACK
|
|
|
|
EPD_SendCommand(0x10);//DATA_START_TRANSMISSION_1
|
|
delay(2);
|
|
for(int i = 0; i < 400*300; i++)EPD_SendData(0xFF);//Red channel
|
|
|
|
EPD_SendCommand(0x13);//DATA_START_TRANSMISSION_2
|
|
delay(2);
|
|
return 0;
|
|
|
|
}
|
|
|
|
unsigned char lut_dc_4in2b[] =
|
|
{
|
|
0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x17, 0x00, 0x00,
|
|
0x02, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x01, 0x00, 0x0E, 0x0E, 0x00,
|
|
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
//R21H
|
|
unsigned char lut_ww_4in2b[] =
|
|
{
|
|
0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
//R22H r
|
|
unsigned char lut_bw_4in2b[] =
|
|
{
|
|
0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
//R24H b
|
|
unsigned char lut_bb_4in2b[] =
|
|
{
|
|
0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
//R23H w
|
|
unsigned char lut_wb_4in2b[] =
|
|
{
|
|
0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
int EPD_Init_4in2b()
|
|
{
|
|
EPD_Reset();
|
|
EPD_Send_3(0x06,0x17,0x17,0x17);//BOOSTER_SOFT_START
|
|
EPD_SendCommand(0x04);//POWER_ON
|
|
EPD_WaitUntilIdle();
|
|
EPD_Send_1(0x00, 0x0F);//PANEL_SETTING
|
|
EPD_Send_1(0x50,0xF7);// VCOM_AND_DATA_INTERVAL_SETTING
|
|
|
|
EPD_SendCommand(0x10);//DATA_START_TRANSMISSION_1
|
|
delay(2);
|
|
return 0;
|
|
}
|
|
*/
|