diff options
Diffstat (limited to 'drivers/gdisp/UC1610/gdisp_lld_UC1610.c')
-rw-r--r-- | drivers/gdisp/UC1610/gdisp_lld_UC1610.c | 322 |
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 |