7 changed files with 465 additions and 0 deletions
@ -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 */ |
@ -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 */ |
@ -0,0 +1,2 @@ |
|||
GFXINC += $(GFXLIB)/drivers/gdisp/UC1610 |
|||
GFXSRC += $(GFXLIB)/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
|
@ -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 */ |
Loading…
Reference in new issue