Added WS29EPD driver by cpu20 for the WaveShare E-Paper display
This commit is contained in:
parent
e2fb6820d0
commit
853863254f
@ -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 ***
|
||||
|
39
drivers/gdisp/WS29EPD/WS29EPD.h
Normal file
39
drivers/gdisp/WS29EPD/WS29EPD.h
Normal file
@ -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
|
57
drivers/gdisp/WS29EPD/board_WS29EPD_template.h
Normal file
57
drivers/gdisp/WS29EPD/board_WS29EPD_template.h
Normal file
@ -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 */
|
2
drivers/gdisp/WS29EPD/driver.mk
Normal file
2
drivers/gdisp/WS29EPD/driver.mk
Normal file
@ -0,0 +1,2 @@
|
||||
GFXINC += $(GFXLIB)/drivers/gdisp/WS29EPD
|
||||
GFXSRC += $(GFXLIB)/drivers/gdisp/WS29EPD/gdisp_lld_WS29EPD.c
|
272
drivers/gdisp/WS29EPD/gdisp_lld_WS29EPD.c
Normal file
272
drivers/gdisp/WS29EPD/gdisp_lld_WS29EPD.c
Normal file
@ -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
|
22
drivers/gdisp/WS29EPD/gdisp_lld_config.h
Normal file
22
drivers/gdisp/WS29EPD/gdisp_lld_config.h
Normal file
@ -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
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user