aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gdisp/UC1610/gdisp_lld_UC1610.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gdisp/UC1610/gdisp_lld_UC1610.c')
-rw-r--r--drivers/gdisp/UC1610/gdisp_lld_UC1610.c322
1 files changed, 322 insertions, 0 deletions
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