aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gdisp/UC1610/UC1610.h65
-rw-r--r--drivers/gdisp/UC1610/board_UC1610_template.h45
-rw-r--r--drivers/gdisp/UC1610/driver.mk2
-rw-r--r--drivers/gdisp/UC1610/gdisp_lld_UC1610.c322
-rw-r--r--drivers/gdisp/UC1610/gdisp_lld_config.h29
-rw-r--r--drivers/gdisp/readme.txt1
6 files changed, 464 insertions, 0 deletions
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)