From e16f97ce2600a3bc7b1ae5bd66a1186bb1217010 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 19 Jul 2017 12:43:17 +1000 Subject: [PATCH] Added UC1610 driver. Thanks to aeroman --- changelog.txt | 1 + drivers/gdisp/UC1610/UC1610.h | 65 ++++ drivers/gdisp/UC1610/board_UC1610_template.h | 45 +++ drivers/gdisp/UC1610/driver.mk | 2 + drivers/gdisp/UC1610/gdisp_lld_UC1610.c | 322 +++++++++++++++++++ drivers/gdisp/UC1610/gdisp_lld_config.h | 29 ++ drivers/gdisp/readme.txt | 1 + 7 files changed, 465 insertions(+) create mode 100644 drivers/gdisp/UC1610/UC1610.h create mode 100644 drivers/gdisp/UC1610/board_UC1610_template.h create mode 100644 drivers/gdisp/UC1610/driver.mk create mode 100644 drivers/gdisp/UC1610/gdisp_lld_UC1610.c create mode 100644 drivers/gdisp/UC1610/gdisp_lld_config.h diff --git a/changelog.txt b/changelog.txt index eec3cc1d..c08f1178 100644 --- a/changelog.txt +++ b/changelog.txt @@ -39,6 +39,7 @@ FEATURE: Added KS0108 driver FEATURE: Added RA6963 driver FIX: Fixed clipping issue in gdispGDrawString() CHANGE: Upgrade GFILE FATFS support from V0.10b to V0.13 +FEATURE: Added UC1610 driver *** Release 2.7 *** diff --git a/drivers/gdisp/UC1610/UC1610.h b/drivers/gdisp/UC1610/UC1610.h new file mode 100644 index 00000000..f6d3d23d --- /dev/null +++ b/drivers/gdisp/UC1610/UC1610.h @@ -0,0 +1,65 @@ +/* + * 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://chibios-gfx.com/license.html + */ + +#ifndef _UC1610_H +#define _UC1610_H + + // screen dimensions + #define UC1610_SCREEN_WIDTH 160 + #define UC1610_SCREEN_HEIGHT 104 + #define UC1610_PAGE_HEIGHT 4 + + // i2c header addresses + #define UC1610_ADDRESS_WC 0x78 // write commands + #define UC1610_ADDRESS_RS 0x79 // read satus + #define UC1610_ADDRESS_WD 0x7A // write data + #define UC1610_ADDRESS_RD 0x7B // read data + + // hardware control commands + #define UC1610_SYSTEM_RESET 0xE2 + #define UC1610_NOP 0xE3 // no operation + #define UC1610_SET_TEMP_COMP 0x24 // set temperature compensation, default -0.05%/°C + #define UC1610_SET_PANEL_LOADING 0x29 // set panel loading, default 16~21 nF + #define UC1610_SET_PUMP_CONTROL 0x2F // default internal Vlcd (8x pump) + #define UC1610_SET_LCD_BIAS_RATIO 0xEB // default 11 + #define UC1610_SET_VBIAS_POT 0x81 // 1 byte (0~255) to follow setting the contrast, default 0x81 + #define UC1610_SET_LINE_RATE 0xA0 // default 12,1 Klps + #define UC1610_SET_DISPLAY_ENABLE 0xAE // + 1 mask / 0 : exit sleep mode / entering sleep mode + #define UC1610_SET_LCD_GRAY_SHADE 0xD0 // default 24% between the two gray shade levels + #define UC1610_SET_COM_END 0xF1 // set the number of used com electrodes (lines number -1) + + // ram address control + #define UC1610_SET_AC 0x88 // set ram addres control + #define UC1610_AC_WA_MASK 1 // automatic column/page increment wrap arroud (1 : cycle increment) + #define UC1610_AC_AIO_MASK (1 << 1) // auto increment order (0/1 : column/page increment first) + #define UC1610_AC_PID_MASK (1 << 2) // page addres auto increment order (0/1 : +1/-1) + + // set cursor ram address + #define UC1610_SET_CA_LSB 0x00 // + 4 LSB bits + #define UC1610_SET_CA_MSB 0x10 // + 4 MSB bits // MSB + LSB values range : 0~159 + #define UC1610_SET_PA 0x60 // + 5 bits // values range : 0~26 + + // display control commands + #define UC1610_SET_FIXED_LINES 0x90 // + 4 bits = 2xFL + #define UC1610_SET_SCROLL_LINES_LSB 0x40 // + 4 LSB bits scroll up display by N (7 bits) lines + #define UC1610_SET_SCROLL_LINES_MSB 0x50 // + 3 MSB bits + #define UC1610_SET_ALL_PIXEL_ON 0xA4 // + 1 mask / 0 : set all pixel on, reverse + #define UC1610_SET_INVERSE_DISPLAY 0xA6 // + 1 mask / 0 : inverse all data stored in ram, reverse + #define UC1610_SET_MAPPING_CONTROL 0xC0 // control mirorring + #define UC1610_SET_MAPPING_CONTROL_LC_MASK 1 // + #define UC1610_SET_MAPPING_CONTROL_MX_MASK (1 << 1) // + #define UC1610_SET_MAPPING_CONTROL_MY_MASK (1 << 2) // + + // window program mode + #define UC1610_SET_WINDOW_PROGRAM_ENABLE 0xF8 // + 1 mask / 0 : enable / disable window programming mode, + // reset before changing boundaries + #define UC1610_SET_WP_STARTING_CA 0xF4 // 1 byte to follow for column number + #define UC1610_SET_WP_ENDING_CA 0xF6 // 1 byte to follow for column number + #define UC1610_SET_WP_STARTING_PA 0xF5 // 1 byte to follow for page number + #define UC1610_SET_WP_ENDING_PA 0xF7 // 1 byte to follow for page number + +#endif /* _SSD1306_H */ diff --git a/drivers/gdisp/UC1610/board_UC1610_template.h b/drivers/gdisp/UC1610/board_UC1610_template.h new file mode 100644 index 00000000..206e7c88 --- /dev/null +++ b/drivers/gdisp/UC1610/board_UC1610_template.h @@ -0,0 +1,45 @@ +/* + * 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 + + +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_cmd(GDisplay *g, uint8_t * cmd, uint8_t length) { + (void) g; + (void) cmd; + (void) length; +} + +static GFXINLINE void write_data(GDisplay *g, uint8_t* data, uint16_t length) { + (void) g; + (void) data; + (void) length; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/UC1610/driver.mk b/drivers/gdisp/UC1610/driver.mk new file mode 100644 index 00000000..b12bc6a5 --- /dev/null +++ b/drivers/gdisp/UC1610/driver.mk @@ -0,0 +1,2 @@ +GFXINC += $(GFXLIB)/drivers/gdisp/UC1610 +GFXSRC += $(GFXLIB)/drivers/gdisp/UC1610/gdisp_lld_UC1610.c diff --git a/drivers/gdisp/UC1610/gdisp_lld_UC1610.c b/drivers/gdisp/UC1610/gdisp_lld_UC1610.c new file mode 100644 index 00000000..b602c991 --- /dev/null +++ b/drivers/gdisp/UC1610/gdisp_lld_UC1610.c @@ -0,0 +1,322 @@ +/* + * 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_UC1610 +#include "gdisp_lld_config.h" +#include "../../../src/gdisp/gdisp_driver.h" + +#include "board_UC1610.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#include "UC1610.h" + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT UC1610_SCREEN_HEIGHT +#endif + +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH UC1610_SCREEN_WIDTH +#endif + +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 40 +#endif + +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif + +// Some common routines and macros +#define PRIV(g) ((UC1610_Window *)g->priv) +#define RAM(g) ((uint8_t *)(PRIV(g) + 1)) +#define xyaddr(x, y) ((x) + GDISP_SCREEN_WIDTH * ((y) >> 2)) +#define xybit(y, c) ((c) << (((y) & 3) << 1)) +#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER << 0) + +typedef struct UC1610_Window { + coord_t x1; + coord_t y1; + coord_t x2; + coord_t y2; +} UC1610_Window; + +/*===========================================================================*/ +/* Driver local varriables. */ +/*===========================================================================*/ + +static uint8_t cmdBuffer[11]; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static void GFXINLINE power_on_sequence(GDisplay* g) { + cmdBuffer[0] = UC1610_SYSTEM_RESET; // software reset + write_cmd(g, cmdBuffer, 1); + gfxSleepMilliseconds(2); + cmdBuffer[0] = UC1610_SET_COM_END; // set com end value + cmdBuffer[1] = GDISP_SCREEN_HEIGHT - 1; + cmdBuffer[2] = UC1610_SET_PANEL_LOADING; + cmdBuffer[3] = UC1610_SET_LCD_BIAS_RATIO; + cmdBuffer[4] = UC1610_SET_VBIAS_POT; // set contrast + cmdBuffer[5] = (uint8_t) (GDISP_INITIAL_CONTRAST * 254 / 100); + cmdBuffer[6] = UC1610_SET_MAPPING_CONTROL; // bottom view + cmdBuffer[7] = UC1610_SET_SCROLL_LINES_LSB | 0; + cmdBuffer[8] = UC1610_SET_SCROLL_LINES_MSB | 0; // set scroll line on line 0 + cmdBuffer[9] = UC1610_SET_AC | UC1610_AC_WA_MASK; // set auto increment wrap arround + cmdBuffer[10] = UC1610_SET_DISPLAY_ENABLE | 1; // turn display on + write_cmd(g, cmdBuffer, 11); +} + +static void GFXINLINE flush_screen(GDisplay* g) { + PRIV(g)->x1 = 0; + PRIV(g)->y1 = 0; + PRIV(g)->x2 = GDISP_SCREEN_WIDTH-1; + PRIV(g)->y2 = GDISP_SCREEN_HEIGHT-1; + g->flags |= GDISP_FLG_NEEDFLUSH; + gdisp_lld_flush(g); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // The private area is the display surface + flush window structure. + g->priv = gfxAlloc(sizeof(UC1610_Window) + GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT / UC1610_PAGE_HEIGHT); + + // Initialise the board interface + init_board(g); + + // Hardware reset + // not needed : reset pin set to ON by init_board(g), software reset by power_on_sequence(g) + gfxSleepMilliseconds(12); + + // Acquire the bus + acquire_bus(g); + + // Init commands sequence + power_on_sequence(g); + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(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; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + return TRUE; +} + +#if GDISP_HARDWARE_DRAWPIXEL + LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + coord_t x, y; + uint8_t *c; + + // handle orientation + switch (g->g.Orientation) { + default : + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90 : + y = g->p.x; + x = g->p.y; + break; + case GDISP_ROTATE_270 : + y = g->p.x; + x = g->p.y; + break; + } + + + // update pixel color + c = RAM(g) + xyaddr(x, y); + *c &= ~xybit(y, LLDCOLOR_MASK()); + *c |= xybit(y, gdispColor2Native(g->p.color)); + + // update flush window boundaries + if (x < PRIV(g)->x1) { PRIV(g)->x1 = x; } + if (x > PRIV(g)->x2) { PRIV(g)->x2 = x; } + if (y < PRIV(g)->y1) { PRIV(g)->y1 = y; } + if (y > PRIV(g)->y2) { PRIV(g)->y2 = y; } + g->flags |= GDISP_FLG_NEEDFLUSH; + } +#endif + +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay* g) + { + coord_t x1, y1, x2, y2, cx; + uint8_t *c; + + // Don't flush unless we really need to + if (!(g->flags & GDISP_FLG_NEEDFLUSH)) + return; + + x1 = PRIV(g)->x1; + y1 = PRIV(g)->y1; + x2 = PRIV(g)->x2; + y2 = PRIV(g)->y2; + cx = x2 - x1 + 1; + + // Clear the 'need-flushing' flag and reset the window + g->flags &= ~GDISP_FLG_NEEDFLUSH; + PRIV(g)->x1 = GDISP_SCREEN_WIDTH; + PRIV(g)->y1 = GDISP_SCREEN_HEIGHT; + PRIV(g)->x2 = -1; + PRIV(g)->y2 = -1; + + // set window to fill + cmdBuffer[0] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 0; // before changing boundaries + cmdBuffer[1] = UC1610_SET_WP_STARTING_CA; + cmdBuffer[2] = x1; + cmdBuffer[3] = UC1610_SET_WP_ENDING_CA; + cmdBuffer[4] = x2; + cmdBuffer[5] = UC1610_SET_WP_STARTING_PA; + cmdBuffer[6] = y1 >> 2; + cmdBuffer[7] = UC1610_SET_WP_ENDING_PA; + cmdBuffer[8] = y2 >> 2; + cmdBuffer[9] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 1; // entering window programming + + acquire_bus(g); + write_cmd (g, cmdBuffer, 10); + + // write each page segment from RAM(g) to display RAM + for (c = RAM(g) + xyaddr(x1, y1) ; y1 <= y2 ; c += GDISP_SCREEN_WIDTH, y1 += UC1610_PAGE_HEIGHT) { + write_data(g, c, cx); + } + 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: + cmdBuffer[0] = UC1610_SYSTEM_RESET; + acquire_bus(g); + write_cmd(g, cmdBuffer, 1); + release_bus(g); + gfxSleepMilliseconds(2); + break; + case powerSleep: + cmdBuffer[0] = UC1610_SET_DISPLAY_ENABLE | 0; + acquire_bus(g); + write_cmd(g, cmdBuffer, 1); + release_bus(g); + gfxSleepMilliseconds(2); + break; + case powerOn: + if (g->g.Powermode == powerSleep) { + cmdBuffer[0] = UC1610_SET_DISPLAY_ENABLE | 1; + acquire_bus(g); + write_cmd(g, cmdBuffer, 1); + release_bus(g); + flush_screen(g); + } else { + gfxSleepMilliseconds(12); + acquire_bus(g); + power_on_sequence(g); + 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.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + cmdBuffer[0] = UC1610_SET_MAPPING_CONTROL; + acquire_bus(g); + write_cmd(g, cmdBuffer, 1); + release_bus(g); + flush_screen(g); + break; + case GDISP_ROTATE_180: // we can rotate 180° without modify screen buffer RAM(g) + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + cmdBuffer[0] = UC1610_SET_MAPPING_CONTROL | UC1610_SET_MAPPING_CONTROL_MY_MASK | UC1610_SET_MAPPING_CONTROL_MX_MASK; + acquire_bus(g); + write_cmd(g, cmdBuffer, 1); + release_bus(g); + flush_screen(g); + break; + case GDISP_ROTATE_90: // needs clearing screen and updating RAM(g) + g->g.Width = GDISP_SCREEN_HEIGHT; + g->g.Height = GDISP_SCREEN_WIDTH; + cmdBuffer[0] = UC1610_SET_MAPPING_CONTROL | UC1610_SET_MAPPING_CONTROL_MX_MASK; + acquire_bus(g); + write_cmd(g, cmdBuffer, 1); + release_bus(g); + break; + case GDISP_ROTATE_270: // needs clearing screen and updating RAM(g) + g->g.Width = GDISP_SCREEN_HEIGHT; + g->g.Height = GDISP_SCREEN_WIDTH; + cmdBuffer[0] = UC1610_SET_MAPPING_CONTROL | UC1610_SET_MAPPING_CONTROL_MY_MASK; + acquire_bus(g); + write_cmd(g, cmdBuffer, 1); + release_bus(g); + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + // TODO: backlight support at board level + /*if ((unsigned)g->p.ptr > 100) { g->p.ptr = (void *)100; } + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr;*/ + return; + + case GDISP_CONTROL_CONTRAST: + if ((unsigned)g->p.ptr > 100) { g->p.ptr = (void *)100; } + acquire_bus(g); + cmdBuffer[0] = UC1610_SET_VBIAS_POT; + cmdBuffer[1] = (uint8_t)((unsigned)g->p.ptr * 254 / 100); + write_cmd(g, cmdBuffer, 2); + release_bus(g); + g->g.Contrast = (unsigned)g->p.ptr; + flush_screen(g); + return; + + case GDISP_CONTROL_INVERSE: + cmdBuffer[0] = g->p.ptr ? (UC1610_SET_INVERSE_DISPLAY | 1) : (UC1610_SET_INVERSE_DISPLAY | 0); + acquire_bus(g); + write_cmd(g, cmdBuffer, 1); + release_bus(g); + //flush_screen(g); + return; + } + } +#endif + +#endif // GFX_USE_GDISP diff --git a/drivers/gdisp/UC1610/gdisp_lld_config.h b/drivers/gdisp/UC1610/gdisp_lld_config.h new file mode 100644 index 00000000..36e37ad5 --- /dev/null +++ b/drivers/gdisp/UC1610/gdisp_lld_config.h @@ -0,0 +1,29 @@ +/* + * 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 + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +#define GDISP_HARDWARE_FLUSH TRUE +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_CONTROL TRUE + +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_GRAY4 + +// This controller supports a special gdispControl() to inverse the display. +// Pass a parameter of 1 for inverse and 0 for normal. +#define GDISP_CONTROL_INVERSE (GDISP_CONTROL_LLD+0) + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */ diff --git a/drivers/gdisp/readme.txt b/drivers/gdisp/readme.txt index cc0fd724..f91922a6 100644 --- a/drivers/gdisp/readme.txt +++ b/drivers/gdisp/readme.txt @@ -35,6 +35,7 @@ TestStub - NULL driver just to test compile TLS8204 - Small monochrome LCD UC8173 - E-Ink display driver UC1601s - Small (64x132) monochrome LCD +UC1610 - Small (78x64 or 160x104) 4 level grayscale LCD 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)