Added UC1610 driver. Thanks to aeroman

This commit is contained in:
inmarket 2017-07-19 12:43:17 +10:00
parent 97511a9fc7
commit e16f97ce26
7 changed files with 465 additions and 0 deletions

View File

@ -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 ***

View File

@ -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 */

View File

@ -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 */

View File

@ -0,0 +1,2 @@
GFXINC += $(GFXLIB)/drivers/gdisp/UC1610
GFXSRC += $(GFXLIB)/drivers/gdisp/UC1610/gdisp_lld_UC1610.c

View File

@ -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

View File

@ -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 */

View File

@ -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)