aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2018-07-07 23:14:28 +1000
committerinmarket <andrewh@inmarket.com.au>2018-07-07 23:14:28 +1000
commit853863254f1636ac7fa1fc03a26c8b3cb5c64718 (patch)
tree1213cc8ec025243ee4ad08560f8b56bc82d30d68
parente2fb6820d013420bf9a69ac5b8955f9ebb6af4f0 (diff)
downloaduGFX-853863254f1636ac7fa1fc03a26c8b3cb5c64718.tar.gz
uGFX-853863254f1636ac7fa1fc03a26c8b3cb5c64718.tar.bz2
uGFX-853863254f1636ac7fa1fc03a26c8b3cb5c64718.zip
Added WS29EPD driver by cpu20 for the WaveShare E-Paper display
-rw-r--r--changelog.txt1
-rw-r--r--drivers/gdisp/WS29EPD/WS29EPD.h39
-rw-r--r--drivers/gdisp/WS29EPD/board_WS29EPD_template.h57
-rw-r--r--drivers/gdisp/WS29EPD/driver.mk2
-rw-r--r--drivers/gdisp/WS29EPD/gdisp_lld_WS29EPD.c272
-rw-r--r--drivers/gdisp/WS29EPD/gdisp_lld_config.h22
-rw-r--r--drivers/gdisp/readme.txt2
7 files changed, 395 insertions, 0 deletions
diff --git a/changelog.txt b/changelog.txt
index e782b7c7..1e595752 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -26,6 +26,7 @@ FIX: Fixed ST7735 driver and added kapacuk changes
FEATURE: Added keyboard support to radio buttons (by Steffan)
FEATURE: Added internal use only GFX_COMPILESTAGE (used to control compilation)
FEATURE: Added support for ChibiOS Kernel V5
+FEATURE: Added WS29EPD WaveShare E-Paper display
*** Release 2.8 ***
diff --git a/drivers/gdisp/WS29EPD/WS29EPD.h b/drivers/gdisp/WS29EPD/WS29EPD.h
new file mode 100644
index 00000000..2233cc6a
--- /dev/null
+++ b/drivers/gdisp/WS29EPD/WS29EPD.h
@@ -0,0 +1,39 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#ifndef _WS29EPD_H_
+#define _WS29EPD_H_
+
+#include "gfx.h"
+
+/* Register definitions. */
+#define DRIVER_OUTPUT_CTRL 0x01
+#define BOOSTER_SOFT_START_CTRL 0x0C
+#define DEEP_SLEEP_MODE 0x10
+#define DATA_ENTRY_MODE_SETTING 0x11
+
+#define SWRESET 0x12
+#define TEMP_SENSOR_CTRL 0x1A
+#define MASTER_ACTIVATION 0x20
+#define DISPLAY_UPDATE_CTRL 0x21
+
+#define DISPLAY_UPDATE_CTRL2 0x22
+#define WRITE_RAM 0x24
+#define WRITE_VCOM_REG 0x2C
+#define WRITE_LUT_REG 0x32
+
+#define SET_DUMMY_LINE_PERIOD 0x3A
+#define SET_GATE_LINE_WIDTH 0x3B
+#define BORDER_WAVEFORM_CTRL 0x3C
+#define SET_RAM_X_ADR 0x44
+
+#define SET_RAM_Y_ADR 0x45
+#define SET_RAM_X_CNT 0x4E
+#define SET_RAM_Y_CNT 0x4F
+#define NOP 0xFF
+
+#endif
diff --git a/drivers/gdisp/WS29EPD/board_WS29EPD_template.h b/drivers/gdisp/WS29EPD/board_WS29EPD_template.h
new file mode 100644
index 00000000..4d966124
--- /dev/null
+++ b/drivers/gdisp/WS29EPD/board_WS29EPD_template.h
@@ -0,0 +1,57 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#ifndef GDISP_LLD_BOARD_H
+#define GDISP_LLD_BOARD_H
+
+#include "WS29EPD.h"
+
+static GFXINLINE void init_board(GDisplay *g) {
+ (void) g;
+}
+
+static GFXINLINE void post_init_board(GDisplay *g) {
+ (void) g;
+}
+
+static GFXINLINE void setpin_reset(GDisplay *g, bool_t state) {
+ (void) g;
+ (void) state;
+}
+
+static GFXINLINE void acquire_bus(GDisplay *g) {
+ (void) g;
+}
+
+static GFXINLINE void release_bus(GDisplay *g) {
+ (void) g;
+}
+
+static GFXINLINE void write_data(GDisplay *g, uint8_t data) {
+ (void) g;
+ (void) data;
+}
+
+static GFXINLINE void write_reg(GDisplay *g, uint8_t reg, uint8_t data){
+ (void) g;
+ (void) reg;
+ (void) data;
+}
+
+static GFXINLINE void write_cmd(GDisplay *g, uint8_t reg){
+ (void) g;
+ (void) reg;
+}
+
+static GFXINLINE void write_reg_data(GDisplay *g, uint8_t reg, uint8_t *data, uint8_t len) {
+ (void) g;
+ (void) reg;
+ (void) data;
+ (void) len;
+}
+
+#endif /* GDISP_LLD_BOARD_H */
diff --git a/drivers/gdisp/WS29EPD/driver.mk b/drivers/gdisp/WS29EPD/driver.mk
new file mode 100644
index 00000000..b611addc
--- /dev/null
+++ b/drivers/gdisp/WS29EPD/driver.mk
@@ -0,0 +1,2 @@
+GFXINC += $(GFXLIB)/drivers/gdisp/WS29EPD
+GFXSRC += $(GFXLIB)/drivers/gdisp/WS29EPD/gdisp_lld_WS29EPD.c
diff --git a/drivers/gdisp/WS29EPD/gdisp_lld_WS29EPD.c b/drivers/gdisp/WS29EPD/gdisp_lld_WS29EPD.c
new file mode 100644
index 00000000..ab700b0a
--- /dev/null
+++ b/drivers/gdisp/WS29EPD/gdisp_lld_WS29EPD.c
@@ -0,0 +1,272 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GDISP
+
+#define GDISP_DRIVER_VMT GDISPVMT_WS29EPD
+#include "gdisp_lld_config.h"
+#include "../../../src/gdisp/gdisp_driver.h"
+
+#include "board_WS29EPD.h"
+#include "WS29EPD.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#ifndef GDISP_SCREEN_HEIGHT
+ #define GDISP_SCREEN_HEIGHT 296
+#endif
+#ifndef GDISP_SCREEN_WIDTH
+ #define GDISP_SCREEN_WIDTH 128
+#endif
+
+/* Every data byte determines 8 pixels. */
+#ifndef WS29EPD_PPB
+ #define WS29EPD_PPB 8
+#endif
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/* initialization variables according to WaveShare. */
+uint8_t GDOControl[] = {(GDISP_SCREEN_HEIGHT-1)%256,(GDISP_SCREEN_HEIGHT-1)/256,0x00};
+uint8_t softstart[] = {0xd7,0xd6,0x9d};
+uint8_t LUTDefault_full[] = {0x02,0x02,0x01,0x11,0x12,0x12,0x22,0x22,0x66,0x69,0x69,0x59,0x58,0x99,0x99,0x88,0x00,0x00,0x00,0x00,0xF8,0xB4,0x13,0x51,0x35,0x51,0x51,0x19,0x01,0x00}; // Initialize the full display
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+LLDSPEC gBool gdisp_lld_init(GDisplay *g) {
+ /* Use the private area as a frame buffer.
+ *
+ * The frame buffer will be one big array of bytes storing all the pixels with WS29EPD_PPB pixel per byte.
+ * For the layout, the frame will be stored line by line in the x-direction.
+ * So: [Line x=0][Line x=1][Line x=2] ... [Line x=GDISP_SCREEN_WIDTH/WS29EPD_PPB]
+ * And every x-line contains GDISP_SCREEN_HEIGHT y-values:
+ * [y=0; y=1; y=2; y=3; ...; y=GDISP_SCREEN_HEIGHT][y=0; y=1; y=2; y=3; ...; y=GDISP_SCREEN_HEIGHT]...
+ *
+ */
+ g->priv = gfxAlloc((GDISP_SCREEN_WIDTH / WS29EPD_PPB) * GDISP_SCREEN_HEIGHT * sizeof(uint8_t));
+ if (!g->priv)
+ return gFalse;
+
+ /* Initialize the LL hardware. */
+ init_board(g);
+
+ /* Hardware reset. */
+ setpin_reset(g, gFalse);
+ gfxSleepMilliseconds(100);
+ setpin_reset(g, gTrue);
+ gfxSleepMilliseconds(100);
+
+ /* Acquire the bus for the whole initialization. */
+ acquire_bus(g);
+
+ /* Send the initialization commands. (according to WaveShare) */
+ write_reg_data(g, DRIVER_OUTPUT_CTRL, GDOControl, sizeof(GDOControl)/sizeof(GDOControl[0]));
+ write_reg_data(g, BOOSTER_SOFT_START_CTRL, softstart, sizeof(softstart)/sizeof(softstart[0]));
+ write_reg(g, WRITE_VCOM_REG, 0xA8); // VCOM 7c
+ write_reg(g, SET_DUMMY_LINE_PERIOD, 0x1A); // 4 dummy lines per gate
+ write_reg(g, SET_GATE_LINE_WIDTH, 0x08); // 2us per line -> Lower this value for faster screen refresh
+ write_reg(g, DATA_ENTRY_MODE_SETTING, 0x03); // Ram data entry mode -> X and Y increase
+
+ write_reg_data(g, WRITE_LUT_REG, LUTDefault_full, sizeof(LUTDefault_full)/sizeof(LUTDefault_full[0])); // Initialize the LUT full
+
+ write_reg(g, DISPLAY_UPDATE_CTRL2, 0xC0); // Power ON the display
+ write_cmd(g, MASTER_ACTIVATION);
+ write_reg(g, DEEP_SLEEP_MODE, 0x00);
+
+ uint8_t zeros[2] = { 0, 0 };
+ write_reg(g, SET_RAM_X_CNT, 0x00); // Set cursor at origin
+ write_reg_data(g, SET_RAM_Y_CNT, zeros, 2);
+
+ uint8_t dataX[2] = { 0, (GDISP_SCREEN_WIDTH-1)/8 };
+ uint8_t dataY[4] = { 0, 0, (GDISP_SCREEN_HEIGHT-1)%256, (GDISP_SCREEN_HEIGHT-1)/256 };
+ write_reg_data(g, SET_RAM_X_ADR, dataX, 2); // Set viewport for the whole screen
+ write_reg_data(g, SET_RAM_Y_ADR, dataY, 4);
+
+ release_bus(g);
+
+ gfxSleepMilliseconds(1500); // Wait for the display to initialize
+
+ /* Finish board initialization. */
+ post_init_board(g);
+
+ /* Initialise the GDISP structure */
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+ g->g.Orientation = GDISP_ROTATE_0;
+ g->g.Powermode = powerOn;
+ return gTrue;
+}
+
+#if 0 // Not needed yet
+ static void set_cursor(GDisplay *g) {
+ uint8_t dataY[2];
+
+ dataY[0] = g->p.y % 256; // Y-data is send in two bytes
+ dataY[1] = g->p.y / 256;
+
+ switch(g->g.Orientation) {
+ default:
+ case GDISP_ROTATE_0:
+ case GDISP_ROTATE_180:
+ write_reg(g, SET_RAM_X_CNT, g->p.x / WS29EPD_PPB);
+ write_reg_data(g, SET_RAM_Y_CNT, dataY, 2);
+ break;
+
+ case GDISP_ROTATE_90:
+ case GDISP_ROTATE_270:
+ write_reg(g, SET_RAM_Y_CNT, g->p.x / WS29EPD_PPB);
+ write_reg_data(g, SET_RAM_X_CNT, dataY, 2);
+ break;
+ }
+ }
+
+ static void set_viewport(GDisplay *g) {
+ uint8_t dataX[2];
+ uint8_t dataY[4];
+
+ // Fill up the X and Y position buffers.
+ dataX[0] = g->p.x / WS29EPD_PPB;
+ dataX[1] = (g->p.x + g->p.cx - 1) / WS29EPD_PPB;
+
+ dataY[0] = g->p.y % 256; // Y-data is 9-bits so send in two bytes
+ dataY[1] = g->p.y / 256;
+ dataY[2] = (g->p.y + g->p.cy - 1) % 256;
+ dataY[3] = (g->p.y + g->p.cy - 1) / 256;
+
+ switch(g->g.Orientation) {
+ default:
+ case GDISP_ROTATE_0:
+ case GDISP_ROTATE_180:
+ write_reg_data(g, SET_RAM_X_ADR, dataX, 2);
+ write_reg_data(g, SET_RAM_Y_ADR, dataY, 4);
+ break;
+ case GDISP_ROTATE_90:
+ case GDISP_ROTATE_270:
+ write_reg_data(g, SET_RAM_X_ADR, dataY, 4);
+ write_reg_data(g, SET_RAM_Y_ADR, dataX, 2);
+ break;
+ }
+ }
+#endif
+
+#if GDISP_HARDWARE_DRAWPIXEL
+LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
+ coord_t x, y;
+
+ switch(g->g.Orientation) {
+ default:
+ case GDISP_ROTATE_0:
+ x = g->p.x;
+ y = g->p.y;
+ break;
+ case GDISP_ROTATE_90:
+ x = g->p.y;
+ y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
+ break;
+ case GDISP_ROTATE_180:
+ x = GDISP_SCREEN_WIDTH-1 - g->p.x;
+ y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
+ break;
+ case GDISP_ROTATE_270:
+ x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
+ y = g->p.x;
+ break;
+ }
+ /* There is only black and no black (white). */
+ if (gdispColor2Native(g->p.color) != Black) // Indexing in the array is done as described in the init routine
+ ((uint8_t *)g->priv)[(GDISP_SCREEN_HEIGHT*(x/WS29EPD_PPB)) + y] |= (1 << (WS29EPD_PPB-1 - (x % WS29EPD_PPB)));
+ else
+ ((uint8_t *)g->priv)[(GDISP_SCREEN_HEIGHT*(x/WS29EPD_PPB)) + y] &= ~(1 << (WS29EPD_PPB-1 - (x % WS29EPD_PPB)));
+}
+#endif
+
+#if GDISP_HARDWARE_FLUSH
+LLDSPEC void gdisp_lld_flush(GDisplay *g) {
+ acquire_bus(g);
+
+ /* Start writing frame buffer to ram. */
+ write_cmd(g, WRITE_RAM);
+
+ for(int i=0; i<GDISP_SCREEN_HEIGHT; i++)
+ for(int j=0; j<=((GDISP_SCREEN_WIDTH-1)/8); j++)
+ write_data(g, ((uint8_t *)g->priv)[(GDISP_SCREEN_HEIGHT*j) + i]);
+
+ /* Update the screen. */
+ write_reg(g, DISPLAY_UPDATE_CTRL2, 0xc7); // Full update (partial hasn't been implemented yet)
+ write_cmd(g, MASTER_ACTIVATION);
+ write_cmd(g, NOP);
+ release_bus(g);
+}
+#endif
+
+#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
+LLDSPEC void gdisp_lld_control(GDisplay *g) {
+ switch(g->p.x) {
+ case GDISP_CONTROL_POWER:
+ if (g->g.Powermode == (powermode_t)g->p.ptr)
+ return;
+ switch((powermode_t)g->p.ptr) {
+ case powerOff:
+ case powerSleep:
+ case powerDeepSleep:
+ acquire_bus(g); // Put de display in deep sleep
+ write_reg(g, DISPLAY_UPDATE_CTRL2, 0x03);
+ write_reg(g, DEEP_SLEEP_MODE, 0x01);
+ release_bus(g);
+ break;
+ case powerOn:
+ acquire_bus(g); // Awake the display again
+ write_reg(g, DISPLAY_UPDATE_CTRL2, 0xC0);
+ write_reg(g, DEEP_SLEEP_MODE, 0x00);
+ release_bus(g);
+ break;
+ default:
+ return;
+ }
+ g->g.Powermode = (powermode_t)g->p.ptr;
+ return;
+
+ case GDISP_CONTROL_ORIENTATION:
+ if (g->g.Orientation == (orientation_t)g->p.ptr)
+ return;
+ switch((orientation_t)g->p.ptr) {
+ case GDISP_ROTATE_0:
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ break;
+ case GDISP_ROTATE_90:
+ g->g.Height = GDISP_SCREEN_WIDTH;
+ g->g.Width = GDISP_SCREEN_HEIGHT;
+ break;
+ case GDISP_ROTATE_180:
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ break;
+ case GDISP_ROTATE_270:
+ g->g.Height = GDISP_SCREEN_WIDTH;
+ g->g.Width = GDISP_SCREEN_HEIGHT;
+ break;
+ default:
+ return;
+ }
+ g->g.Orientation = (orientation_t)g->p.ptr;
+ return;
+ default:
+ return;
+ }
+}
+#endif
+
+#endif // GFX_USE_GDISP
diff --git a/drivers/gdisp/WS29EPD/gdisp_lld_config.h b/drivers/gdisp/WS29EPD/gdisp_lld_config.h
new file mode 100644
index 00000000..0892a53c
--- /dev/null
+++ b/drivers/gdisp/WS29EPD/gdisp_lld_config.h
@@ -0,0 +1,22 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#ifndef _GDISP_LLD_CONFIG_H
+#define _GDISP_LLD_CONFIG_H
+
+#if GFX_USE_GDISP
+
+#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing
+#define GDISP_HARDWARE_DRAWPIXEL TRUE
+#define GDISP_HARDWARE_STREAM_WRITE FALSE
+#define GDISP_HARDWARE_CONTROL TRUE
+
+#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO
+
+#endif
+
+#endif
diff --git a/drivers/gdisp/readme.txt b/drivers/gdisp/readme.txt
index 3860d282..ecc2ba85 100644
--- a/drivers/gdisp/readme.txt
+++ b/drivers/gdisp/readme.txt
@@ -37,6 +37,8 @@ TLS8204 - Small monochrome LCD
UC8173 - E-Ink display driver
UC1601s - Small (64x132) monochrome LCD
UC1610 - Small (78x64 or 160x104) 4 level grayscale LCD
+UC8175 - Small E-Ink display
+WS29EPD - Small E-Ink display by WaveShare
QImage - Driver that allows rendering into a QImage object (of the Qt framework)
uGFXnet - Remote Network display (in drivers/multiple/uGFXnet directory)
Win32 - Microsoft Windows (in drivers/multiple/Win32 directory)