2018-07-07 13:14:28 +00:00
/*
* 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 :
*
2018-10-01 15:32:39 +00:00
* http : //ugfx.io/license.html
2018-07-07 13:14:28 +00:00
*/
# 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. */
2018-11-03 00:51:23 +00:00
gU8 GDOControl [ ] = { ( GDISP_SCREEN_HEIGHT - 1 ) % 256 , ( GDISP_SCREEN_HEIGHT - 1 ) / 256 , 0x00 } ;
gU8 softstart [ ] = { 0xd7 , 0xd6 , 0x9d } ;
gU8 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
2018-07-07 13:14:28 +00:00
/*===========================================================================*/
/* 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 ] . . .
*
*/
2018-11-03 00:51:23 +00:00
g - > priv = gfxAlloc ( ( GDISP_SCREEN_WIDTH / WS29EPD_PPB ) * GDISP_SCREEN_HEIGHT * sizeof ( gU8 ) ) ;
2018-07-07 13:14:28 +00:00
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 ) ;
2018-11-03 00:51:23 +00:00
gU8 zeros [ 2 ] = { 0 , 0 } ;
2018-07-07 13:14:28 +00:00
write_reg ( g , SET_RAM_X_CNT , 0x00 ) ; // Set cursor at origin
write_reg_data ( g , SET_RAM_Y_CNT , zeros , 2 ) ;
2018-11-03 00:51:23 +00:00
gU8 dataX [ 2 ] = { 0 , ( GDISP_SCREEN_WIDTH - 1 ) / 8 } ;
gU8 dataY [ 4 ] = { 0 , 0 , ( GDISP_SCREEN_HEIGHT - 1 ) % 256 , ( GDISP_SCREEN_HEIGHT - 1 ) / 256 } ;
2018-07-07 13:14:28 +00:00
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 ;
2018-07-08 03:51:20 +00:00
g - > g . Orientation = gOrientation0 ;
2018-07-08 01:47:36 +00:00
g - > g . Powermode = gPowerOn ;
2018-07-07 13:14:28 +00:00
return gTrue ;
}
#if 0 // Not needed yet
static void set_cursor ( GDisplay * g ) {
2018-11-03 00:51:23 +00:00
gU8 dataY [ 2 ] ;
2018-07-07 13:14:28 +00:00
dataY [ 0 ] = g - > p . y % 256 ; // Y-data is send in two bytes
dataY [ 1 ] = g - > p . y / 256 ;
switch ( g - > g . Orientation ) {
default :
2018-07-08 03:51:20 +00:00
case gOrientation0 :
case gOrientation180 :
2018-07-07 13:14:28 +00:00
write_reg ( g , SET_RAM_X_CNT , g - > p . x / WS29EPD_PPB ) ;
write_reg_data ( g , SET_RAM_Y_CNT , dataY , 2 ) ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
case gOrientation270 :
2018-07-07 13:14:28 +00:00
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 ) {
2018-11-03 00:51:23 +00:00
gU8 dataX [ 2 ] ;
gU8 dataY [ 4 ] ;
2018-07-07 13:14:28 +00:00
// 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 :
2018-07-08 03:51:20 +00:00
case gOrientation0 :
case gOrientation180 :
2018-07-07 13:14:28 +00:00
write_reg_data ( g , SET_RAM_X_ADR , dataX , 2 ) ;
write_reg_data ( g , SET_RAM_Y_ADR , dataY , 4 ) ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
case gOrientation270 :
2018-07-07 13:14:28 +00:00
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 ) {
2018-07-08 00:54:19 +00:00
gCoord x , y ;
2018-07-07 13:14:28 +00:00
switch ( g - > g . Orientation ) {
default :
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2018-07-07 13:14:28 +00:00
x = g - > p . x ;
y = g - > p . y ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2018-07-07 13:14:28 +00:00
x = g - > p . y ;
y = GDISP_SCREEN_HEIGHT - 1 - g - > p . x ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2018-07-07 13:14:28 +00:00
x = GDISP_SCREEN_WIDTH - 1 - g - > p . x ;
y = GDISP_SCREEN_HEIGHT - 1 - g - > p . y ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2018-07-07 13:14:28 +00:00
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
2018-11-03 00:51:23 +00:00
( ( gU8 * ) g - > priv ) [ ( GDISP_SCREEN_HEIGHT * ( x / WS29EPD_PPB ) ) + y ] | = ( 1 < < ( WS29EPD_PPB - 1 - ( x % WS29EPD_PPB ) ) ) ;
2018-07-07 13:14:28 +00:00
else
2018-11-03 00:51:23 +00:00
( ( gU8 * ) g - > priv ) [ ( GDISP_SCREEN_HEIGHT * ( x / WS29EPD_PPB ) ) + y ] & = ~ ( 1 < < ( WS29EPD_PPB - 1 - ( x % WS29EPD_PPB ) ) ) ;
2018-07-07 13:14:28 +00:00
}
# 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 + + )
2018-11-03 00:51:23 +00:00
write_data ( g , ( ( gU8 * ) g - > priv ) [ ( GDISP_SCREEN_HEIGHT * j ) + i ] ) ;
2018-07-07 13:14:28 +00:00
/* 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 :
2018-07-08 01:47:36 +00:00
if ( g - > g . Powermode = = ( gPowermode ) g - > p . ptr )
2018-07-07 13:14:28 +00:00
return ;
2018-07-08 01:47:36 +00:00
switch ( ( gPowermode ) g - > p . ptr ) {
case gPowerOff :
case gPowerSleep :
case gPowerDeepSleep :
2018-07-07 13:14:28 +00:00
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 ;
2018-07-08 01:47:36 +00:00
case gPowerOn :
2018-07-07 13:14:28 +00:00
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 ;
}
2018-07-08 01:47:36 +00:00
g - > g . Powermode = ( gPowermode ) g - > p . ptr ;
2018-07-07 13:14:28 +00:00
return ;
case GDISP_CONTROL_ORIENTATION :
2018-07-08 03:51:20 +00:00
if ( g - > g . Orientation = = ( gOrientation ) g - > p . ptr )
2018-07-07 13:14:28 +00:00
return ;
2018-07-08 03:51:20 +00:00
switch ( ( gOrientation ) g - > p . ptr ) {
case gOrientation0 :
2018-07-07 13:14:28 +00:00
g - > g . Height = GDISP_SCREEN_HEIGHT ;
g - > g . Width = GDISP_SCREEN_WIDTH ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2018-07-07 13:14:28 +00:00
g - > g . Height = GDISP_SCREEN_WIDTH ;
g - > g . Width = GDISP_SCREEN_HEIGHT ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2018-07-07 13:14:28 +00:00
g - > g . Height = GDISP_SCREEN_HEIGHT ;
g - > g . Width = GDISP_SCREEN_WIDTH ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2018-07-07 13:14:28 +00:00
g - > g . Height = GDISP_SCREEN_WIDTH ;
g - > g . Width = GDISP_SCREEN_HEIGHT ;
break ;
default :
return ;
}
2018-07-08 03:51:20 +00:00
g - > g . Orientation = ( gOrientation ) g - > p . ptr ;
2018-07-07 13:14:28 +00:00
return ;
default :
return ;
}
}
# endif
# endif // GFX_USE_GDISP