Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#35 gdew075HD new epaper #36

Merged
merged 1 commit into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/CalEPD/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Add only the display srcs you are going to use if you want to keep compiled srcs to a minimum:
set(srcs
"models/wave12i48.cpp"
"models/gdew075HD.cpp"
"models/gdew075T7.cpp"
"models/gdew075T8.cpp"
"models/gdew0583t7.cpp"
Expand Down
72 changes: 72 additions & 0 deletions components/CalEPD/include/gdew075HD.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 7.5 HD 880*528 b/w Controller: ??
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "esp_system.h"
#include <stdint.h>
#include <math.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include <string>
#include <epd.h>
#include <Adafruit_GFX.h>
#include <epdspi.h>
#include "soc/rtc_wdt.h"
#include <gdew_colors.h>

#define GDEW075HD_WIDTH 880
#define GDEW075HD_HEIGHT 528

// EPD comment: Pixel number expressed in bytes; this is neither the buffer size nor the size of the buffer in the controller
// We are not adding page support so here this is our Buffer size
#define GDEW075HD_BUFFER_SIZE (uint32_t(GDEW075HD_WIDTH) * uint32_t(GDEW075HD_HEIGHT) / 8)
// 8 pix of this color in a buffer byte:
#define GDEW075HD_8PIX_BLACK 0x00
#define GDEW075HD_8PIX_WHITE 0xFF

class Gdew075HD : public Epd
{
public:

Gdew075HD(EpdSpi& IO);
uint8_t colors_supported = 1;

void drawPixel(int16_t x, int16_t y, uint16_t color); // Override GFX own drawPixel method

// EPD tests
void init(bool debug = false);

// Partial update of rectangle from buffer to screen, does not power off
void updateWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool using_rotation);
void fillScreen(uint16_t color);
void update();

private:
EpdSpi& IO;

uint8_t _buffer[GDEW075HD_BUFFER_SIZE];
bool _using_partial_mode = false;
bool _initial = true;

uint16_t _setPartialRamArea(uint16_t x, uint16_t y, uint16_t xe, uint16_t ye);
void _wakeUp();
void _sleep();
void _waitBusy(const char* message);
void _rotate(uint16_t& x, uint16_t& y, uint16_t& w, uint16_t& h);

// Command & data structs
// LUT tables for this display are filled with zeroes at the end with writeLuts()
static const epd_init_42 lut_20_LUTC_partial;
static const epd_init_42 lut_21_LUTWW_partial;
static const epd_init_42 lut_22_LUTKW_partial;
static const epd_init_42 lut_23_LUTWK_partial;
static const epd_init_42 lut_24_LUTKK_partial;
static const epd_init_42 lut_25_LUTBD_partial;

static const epd_power_4 epd_wakeup_power;
static const epd_init_1 epd_panel_setting_full;
static const epd_init_1 epd_panel_setting_partial;
static const epd_init_1 epd_pll;
static const epd_init_4 epd_resolution;
};
268 changes: 268 additions & 0 deletions components/CalEPD/models/gdew075HD.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
#include "gdew075HD.h"
#include <stdio.h>
#include <stdlib.h>
#include "esp_log.h"
#include "freertos/task.h"

// Partial Update Delay, may have an influence on degradation
#define GDEW075HD_PU_DELAY 100

//Place data into DRAM. Constant data gets placed into DROM by default, which is not accessible by DMA.

// 0x07 (2nd) VGH=20V,VGL=-20V
// 0x3f (1st) VDH= 15V
// 0x3f (2nd) VDH=-15V
DRAM_ATTR const epd_power_4 Gdew075HD::epd_wakeup_power = {
0x01, {0x07, 0x07, 0x3f, 0x3f}, 4};

DRAM_ATTR const epd_init_1 Gdew075HD::epd_panel_setting_full = {
0x00, {0x1f}, 1};

DRAM_ATTR const epd_init_1 Gdew075HD::epd_panel_setting_partial = {
0x00, {0x3f}, 1};

DRAM_ATTR const epd_init_4 Gdew075HD::epd_resolution = {
0x61, {GDEW075HD_WIDTH / 256, //source 800
GDEW075HD_WIDTH % 256,
GDEW075HD_HEIGHT / 256, //gate 480
GDEW075HD_HEIGHT % 256},
4};

// Constructor
Gdew075HD::Gdew075HD(EpdSpi &dio) : Adafruit_GFX(GDEW075HD_WIDTH, GDEW075HD_HEIGHT),
Epd(GDEW075HD_WIDTH, GDEW075HD_HEIGHT), IO(dio)
{
printf("Gdew075HD() constructor injects IO and extends Adafruit_GFX(%d,%d) Pix Buffer[%d]\n",
GDEW075HD_WIDTH, GDEW075HD_HEIGHT, GDEW075HD_BUFFER_SIZE);
printf("\nAvailable heap after Epd bootstrap:%d\n", xPortGetFreeHeapSize());
}

//Initialize the display
void Gdew075HD::init(bool debug)
{
debug_enabled = debug;
if (debug_enabled)
printf("Gdew075HD::init(debug:%d)\n", debug);
//Initialize SPI at 4MHz frequency. true for debug
IO.init(4, false);
fillScreen(EPD_WHITE);
}

void Gdew075HD::fillScreen(uint16_t color)
{
uint8_t data = (color == EPD_BLACK) ? GDEW075HD_8PIX_BLACK : GDEW075HD_8PIX_WHITE;
for (uint16_t x = 0; x < sizeof(_buffer); x++)
{
_buffer[x] = data;
}
}

void Gdew075HD::_wakeUp()
{
IO.reset(200);

IO.cmd(0x12);

_waitBusy("Reset_12");

IO.cmd(0x46); // Auto Write Red RAM
IO.data(0xf7);
_waitBusy("Write Red RAM");

IO.cmd(0x47); // Auto Write B/W RAM
IO.data(0xf7);
_waitBusy("Write B/W RAM");

IO.cmd(0x0C); // Soft start setting
IO.data(0xAE);
IO.data(0xC7);
IO.data(0xC3);
IO.data(0xC0);
IO.data(0x40);

IO.cmd(0x01); // Set MUX as 527
IO.data(0xAF);
IO.data(0x02);
IO.data(0x01); //0x01

IO.cmd(0x11); // Data entry mode
IO.data(0x01);

IO.cmd(0x44);
IO.data(0x00); // RAM x address start at 0
IO.data(0x00);
IO.data(0x6F);
IO.data(0x03);

IO.cmd(0x45);
IO.data(0xAF);
IO.data(0x02);
IO.data(0x00);
IO.data(0x00);

IO.cmd(0x3C); // VBD
IO.data(0x01); // LUT1, for white

IO.cmd(0x18); // Temperature Sensor Control
IO.data(0X80);

IO.cmd(0x22);
IO.data(0XB1); //Load Temperature and waveform setting.
IO.cmd(0x20);
_waitBusy("Load Temperature");

IO.cmd(0x4E); // set RAM x address count to 0;
IO.data(0x00);
IO.data(0x00);

IO.cmd(0x4F);
IO.data(0x00);
IO.data(0x00);

IO.cmd(0x4F);
IO.data(0x00);
IO.data(0x00);


IO.cmd(0x24);//BLOCK
}

void Gdew075HD::update()
{
uint64_t startTime = esp_timer_get_time();
_using_partial_mode = false;
_wakeUp();

IO.cmd(0x24); //Black RAM
printf("Sending a %d bytes buffer via SPI\n", sizeof(_buffer));

// v2 SPI optimizing. Check: https://github.com/martinberlin/cale-idf/wiki/About-SPI-optimization
uint16_t i = 0;
uint8_t xLineBytes = GDEW075HD_WIDTH / 8;
uint8_t x1buf[xLineBytes];
for (uint16_t y = 1; y <= GDEW075HD_HEIGHT; y++)
{
for (uint16_t x = 1; x <= xLineBytes; x++)
{
uint8_t data = i < sizeof(_buffer) ? _buffer[i] : 0x00;
x1buf[x - 1] = data;
if (x == xLineBytes)
{ // Flush the X line buffer to SPI
IO.data(x1buf, sizeof(x1buf));
}
++i;
}
}

/*
for (uint16_t i = 1; i <= GDEW075HD_BUFFER_SIZE; i++)
{
IO.data(_buffer[i]);
if (i<50) {
printf("%x ", _buffer[i]);
}
} */

uint64_t endTime = esp_timer_get_time();
IO.cmd(0x22); // Show
IO.data(0xF7); // 0xF7
IO.cmd(0x20);

vTaskDelay(200 / portTICK_PERIOD_MS);
_waitBusy("Update");

uint64_t updateTime = esp_timer_get_time();
printf("\n\nSTATS (ms)\n%llu _wakeUp settings+send Buffer\n%llu update \n%llu total time in millis\n",
(endTime - startTime) / 1000, (updateTime - endTime) / 1000, (updateTime - startTime) / 1000);

// Additional 2 seconds wait before sleeping since in low temperatures full update takes longer
vTaskDelay(2000 / portTICK_PERIOD_MS);

_sleep();
}

void Gdew075HD::updateWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool using_rotation)
{
printf("updateWindow: Not implemented\n");
}

void Gdew075HD::_waitBusy(const char *message)
{
if (debug_enabled)
{
ESP_LOGI(TAG, "_waitBusy for %s", message);
}
int64_t time_since_boot = esp_timer_get_time();

while (1)
{
if (gpio_get_level((gpio_num_t)CONFIG_EINK_BUSY) == 0) {
break;
}
vTaskDelay(1);
if (esp_timer_get_time() - time_since_boot > 2000000)
{
if (debug_enabled)
ESP_LOGI(TAG, "Busy Timeout");
break;
}
}
}

void Gdew075HD::_sleep()
{
IO.cmd(0x10);
IO.data(0x01);
}

void Gdew075HD::_rotate(uint16_t &x, uint16_t &y, uint16_t &w, uint16_t &h)
{
switch (getRotation())
{
case 1:
swap(x, y);
swap(w, h);
x = GDEW075HD_WIDTH - x - w - 1;
break;
case 2:
x = GDEW075HD_WIDTH - x - w - 1;
y = GDEW075HD_HEIGHT - y - h - 1;
break;
case 3:
swap(x, y);
swap(w, h);
y = GDEW075HD_HEIGHT - y - h - 1;
break;
}
}

void Gdew075HD::drawPixel(int16_t x, int16_t y, uint16_t color)
{
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
return;
switch (getRotation())
{
case 1:
swap(x, y);
x = GDEW075HD_WIDTH - x - 1;
break;
case 2:
x = GDEW075HD_WIDTH - x - 1;
y = GDEW075HD_HEIGHT - y - 1;
break;
case 3:
swap(x, y);
y = GDEW075HD_HEIGHT - y - 1;
break;
}
uint16_t i = x / 8 + y * GDEW075HD_WIDTH / 8;

if (color)
{
_buffer[i] = (_buffer[i] | (1 << (7 - x % 8)));
}
else
{
_buffer[i] = (_buffer[i] & (0xFF ^ (1 << (7 - x % 8))));
}
}