From f1d75f32becd3583c1eab3baf32b0448b7100156 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 7 Apr 2015 23:23:01 +1000 Subject: [PATCH] SSD1331 OLED display controller driver - accelerated including scroll support. --- drivers/gdisp/SSD1331/SSD1331.h | 89 +++++ .../gdisp/SSD1331/board_SSD1331_template.h | 42 +++ drivers/gdisp/SSD1331/driver.mk | 2 + drivers/gdisp/SSD1331/gdisp_lld_SSD1331.c | 329 ++++++++++++++++++ drivers/gdisp/SSD1331/gdisp_lld_config.h | 31 ++ 5 files changed, 493 insertions(+) create mode 100644 drivers/gdisp/SSD1331/SSD1331.h create mode 100644 drivers/gdisp/SSD1331/board_SSD1331_template.h create mode 100644 drivers/gdisp/SSD1331/driver.mk create mode 100644 drivers/gdisp/SSD1331/gdisp_lld_SSD1331.c create mode 100644 drivers/gdisp/SSD1331/gdisp_lld_config.h diff --git a/drivers/gdisp/SSD1331/SSD1331.h b/drivers/gdisp/SSD1331/SSD1331.h new file mode 100644 index 00000000..a30dcdcf --- /dev/null +++ b/drivers/gdisp/SSD1331/SSD1331.h @@ -0,0 +1,89 @@ +#ifndef SSD1331_H +#define SSD1331_H + +#define SSD1331_COLUMN_ADDRESS 0x15 // 2 data: startx endx +#define SSD1331_ROW_ADDRESS 0x75 // 2 data: starty endy +#define SSD1331_CONTRAST_A 0x81 // 1 data: 0 - 255 default=128 +#define SSD1331_CONTRAST_B 0x82 // 1 data: 0 - 255 default=128 +#define SSD1331_CONTRAST_C 0x83 // 1 data: 0 - 255 default=128 +#define SSD1331_BRIGHTNESS 0x87 // 1 data: 0 - 15 default=15 +#define SSD1331_PRECHARGE_A 0x8A // 1 data: 0 - 255 default=128 +#define SSD1331_PRECHARGE_B 0x8B // 1 data: 0 - 255 default=128 +#define SSD1331_PRECHARGE_C 0x8C // 1 data: 0 - 255 default=128 +#define SSD1331_MODE 0xA0 // 1 data:- default=0x40 + #define SSD1331_MODE_VINC 0x01 + #define SSD1331_MODE_COLUMN_REVERSE 0x02 + #define SSD1331_MODE_BGR 0x04 // if 1 then A=Blue,B=Green,C=Red + #define SSD1331_MODE_COM_SWAPLR 0x08 + #define SSD1331_MODE_COM_REVERSE 0x10 + #define SSD1331_MODE_COM_SPLIT 0x20 + #define SSD1331_MODE_8_BIT 0x00 + #define SSD1331_MODE_16_BIT 0x40 + #define SSD1331_MODE_16_BIT2 0x80 +#define SSD1331_START_LINE 0xA1 // 1 data: liney default=0 +#define SSD1331_COM_OFFSET 0xA2 // 1 data: liney default=0 +#define SSD1331_PIXELS_NORMAL 0xA4 // 0 data - default +#define SSD1331_PIXELS_FILL 0xA5 // 0 data +#define SSD1331_PIXELS_OFF 0xA6 // 0 data +#define SSD1331_DISPLAY_INVERSE 0xA7 // 0 data +#define SSD1331_MULTIPLEX 0xA8 // 1 data: 15-63 default=63 +#define SSD1331_DIM 0xAB // 5 data: + // 0x00 - Reserved + // ContrastA 0 - 255 default=0? + // ContrastB 0 - 255 default=0? + // ContrastC 0 - 255 default=0? + // Precharge 0 - 31 default=0? +#define SSD1331_RESET 0xAD // 1 data: + #define SSD1331_RESET_ON 0x8F // Reset - default + #define SSD1331_RESET_OFF 0x8E // Normal +#define SSD1331_DISPLAY_OFF 0xAE // 0 data - default +#define SSD1331_DISPLAY_DIM 0xAC // 0 data +#define SSD1331_DISPLAY_ON 0xAF // 0 data +#define SSD1331_POWER 0xB0 // 1 data: + #define SSD1331_POWER_ON 0x0B // Normal Operation + #define SSD1331_POWER_OFF 0x1A // Power Save - default +#define SSD1331_PHASE_PERIOD 0xB1 // 1 data: Phase 1 bit0-3 1-15, Phase 2 bit4-7 1-15 default=0x74 +#define SSD1331_CLOCKS 0xB3 // 1 data: Divide bit0-3 + 1, Freq bits4-7 default=0xD0 +#define SSD1331_GRAYSCALE 0xB8 // 32 data: each 1-125 default=1,5,9...121,125 +#define SSD1331_GRAYSCALE_LINEAR 0xB9 // 0 data +#define SSD1331_PRECHARGE_VOLTAGE 0xBB // 1 data: 0 - 62 (even only) default=62 +#define SSD1331_NOP 0xBC // 0 data +#define SSD1331_NOP1 0xBD // 0 data +#define SSD1331_NOP2 0xE3 // 0 data +#define SSD1331_DESELECT_VOLTAGE 0xBE // 1 data: 0 - 62 (even only) default=62 +#define SSD1331_LOCK 0xFD // 1 data: + #define SSD1331_LOCK_ON 0x16 // Lock MCU + #define SSD1331_LOCK_OFF 0x12 // Unlock MCU - default + +#define SSD1331_DRAW_LINE 0x21 // 7 data: + // startx, starty, + // endx, endy, + // C, B, A - 6 bits each +#define SSD1331_DRAW_RECT 0x22 // 10 data: + // startx, starty, + // endx, endy, + // C, B, A - line color 6 bits each + // C, B, A - fill color 6 bits each +#define SSD1331_DRAW_COPY 0x23 // 6 data: + // startx, starty, + // endx, endy, + // newx, newy +#define SSD1331_DIM_AREA 0x24 // 4 data: + // startx, starty, + // endx, endy +#define SSD1331_DRAW_CLEAR 0x25 // 4 data: + // startx, starty, + // endx, endy +#define SSD1331_DRAW_MODE 0x26 // 1 data: + #define SSD1331_DRAW_FILLRECT 0x01 // Fill Rectangle Draws + #define SSD1331_COPY_REVERSE 0x10 // Reverse colors when copying +#define SSD1331_SCROLL 0x27 // 5 data: + // 0 - 95 columns horizontal scroll + // starty + // cy + // 0 - 63 rows vertical scroll + // time 0 = 6 frames, 1 = 10 frames, 2 = 100 frames, 3 = 200 frames +#define SSD1331_SCROLL_STOP 0x2E // 0 data +#define SSD1331_SCROLL_START 0x2F // 0 data + +#endif // SSD1331_H diff --git a/drivers/gdisp/SSD1331/board_SSD1331_template.h b/drivers/gdisp/SSD1331/board_SSD1331_template.h new file mode 100644 index 00000000..1f202936 --- /dev/null +++ b/drivers/gdisp/SSD1331/board_SSD1331_template.h @@ -0,0 +1,42 @@ +/* + * 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 inline void init_board(GDisplay *g) { + (void) g; +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_cmd(GDisplay *g, uint8_t index) { + (void) g; + (void) index; +} + +static inline void write_data(GDisplay *g, uint8_t data) { + (void) g; + (void) data; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/SSD1331/driver.mk b/drivers/gdisp/SSD1331/driver.mk new file mode 100644 index 00000000..b729431f --- /dev/null +++ b/drivers/gdisp/SSD1331/driver.mk @@ -0,0 +1,2 @@ +GFXINC += $(GFXLIB)/drivers/gdisp/SSD1331 +GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1331/gdisp_lld_SSD1331.c diff --git a/drivers/gdisp/SSD1331/gdisp_lld_SSD1331.c b/drivers/gdisp/SSD1331/gdisp_lld_SSD1331.c new file mode 100644 index 00000000..d53fa27e --- /dev/null +++ b/drivers/gdisp/SSD1331/gdisp_lld_SSD1331.c @@ -0,0 +1,329 @@ +/* + * 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 + +#if defined(GDISP_SCREEN_HEIGHT) + #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." + #undef GISP_SCREEN_HEIGHT +#endif +#if defined(GDISP_SCREEN_WIDTH) + #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." + #undef GDISP_SCREEN_WIDTH +#endif + +#define GDISP_DRIVER_VMT GDISPVMT_SSD1331 +#include "gdisp_lld_config.h" +#include "src/gdisp/gdisp_driver.h" + +#include "board_SSD1331.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 64 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 96 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 100 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 32 +#endif + +#include "SSD1331.h" + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +// Some common routines and macros +#define write_reg(g, reg, data) { write_cmd(g, reg); write_data(g, data); } + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +static const initdata[] = { + SSD1331_DISPLAY_OFF, + SSD1331_START_LINE, 0x00, + SSD1331_COM_OFFSET, 0x00, + SSD1331_PIXELS_NORMAL, + SSD1331_MULTIPLEX, 0x3F, + SSD1331_RESET, SSD1331_RESET_OFF, + SSD1331_POWER, SSD1331_POWER_ON, + SSD1331_PHASE_PERIOD, 0x31, + SSD1331_CLOCKS, 0xF0, + SSD1331_PRECHARGE_A, 0x64, + SSD1331_PRECHARGE_B, 0x78, + SSD1331_PRECHARGE_C, 0x64, + SSD1331_PRECHARGE_VOLTAGE, 0x3A, + SSD1331_DESELECT_VOLTAGE, 0x3E, + SSD1331_CONTRAST_A, 0x91, + SSD1331_CONTRAST_B, 0x50, + SSD1331_CONTRAST_C, 0x7D, + SSD1331_BRIGHTNESS, (GDISP_INITIAL_BACKLIGHT*10)/63, + #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565 + SSD1331_MODE, SSD1331_MODE_16_BIT|SSD1331_MODE_COM_SPLIT, + #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_BGR565 + SSD1331_MODE, SSD1331_MODE_16_BIT|SSD1331_MODE_COM_SPLIT|SSD1331_MODE_BGR, + #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB332 + SSD1331_MODE, SSD1331_MODE_8_BIT|SSD1331_MODE_COM_SPLIT, + #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_BGR332 + SSD1331_MODE, SSD1331_MODE_8_BIT|SSD1331_MODE_COM_SPLIT|SSD1331_MODE_BGR, + #else + #error "SSD1331: Invalid color format" + #endif + SSD1331_DRAW_MODE, SSD1331_DRAW_FILLRECT, +}; + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + int i; + + // No private area for this controller + g->priv = 0; + + // Initialise the board interface + init_board(g); + + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(20); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(20); + + // Get the bus for the following initialisation commands + acquire_bus(g); + + for(i=0;ig.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_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + write_cmd(g, SSD1331_COLUMN_ADDRESS); + write_cmd(g, g->p.x); + write_cmd(g, g->p.x + g->p.cx - 1); + write_cmd(g, SSD1331_ROW_ADDRESS); + write_cmd(g, g->p.y); + write_cmd(g, g->p.y + g->p.cy - 1); + } + #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565 || GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_BGR565 + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + LLDCOLOR_TYPE c; + + c = gdispColor2Native(g->p.color); + write_data(g, c >> 8); + write_data(g, c); + } + #else + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, gdispColor2Native(g->p.color)); + } + #endif + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); + } +#endif + +#if GDISP_HARDWARE_FILLS + LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { + uint8_t a6, b6, c6; + + acquire_bus(g); + + if (g->p.color == Black) { + // Use clear window command + write_cmd(g, SSD1331_DRAW_CLEAR); + write_cmd(g, g->p.x); + write_cmd(g, g->p.y); + write_cmd(g, g->p.x + g->p.cx - 1); + write_cmd(g, g->p.y + g->p.cy - 1); + release_bus(g); + return; + } + + #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565 || GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB322 + c6 = RED_OF(g->p.color) >> 2; + #if COLOR_BITS_R < 5 + if (c6 & 0x20) c6 |= (1<<(6-COLOR_BITS_R))-1; + #endif + b6 = GREEN_OF(g->p.color) >> 2; + #if COLOR_BITS_G < 6 + if (b6 & 0x20) b6 |= (1<<(6-COLOR_BITS_G))-1; + #endif + a6 = BLUE_OF(g->p.color) >> 2; + #if COLOR_BITS_B < 5 + if (a6 & 0x20) a6 |= (1<<(6-COLOR_BITS_B))-1; + #endif + #else + c6 = BLUE_OF(g->p.color) >> 2; + #if COLOR_BITS_B < 5 + if (c6 & 0x20) c6 |= (1<<(6-COLOR_BITS_B))-1; + #endif + b6 = GREEN_OF(g->p.color) >> 2; + #if COLOR_BITS_G < 6 + if (b6 & 0x20) b6 |= (1<<(6-COLOR_BITS_G))-1; + #endif + a6 = RED_OF(g->p.color) >> 2; + #if COLOR_BITS_R < 5 + if (a6 & 0x20) a6 |= (1<<(6-COLOR_BITS_R))-1; + #endif + #endif + if (g->p.cx == 1 || g->p.cy == 1) { + // Use Line command + write_cmd(g, SSD1331_DRAW_LINE); + write_cmd(g, g->p.x); + write_cmd(g, g->p.y); + write_cmd(g, g->p.x + g->p.cx - 1); + write_cmd(g, g->p.y + g->p.cy - 1); + } else { + // Use Rectangle command + + write_cmd(g, SSD1331_DRAW_RECT); + write_cmd(g, g->p.x); + write_cmd(g, g->p.y); + write_cmd(g, g->p.x + g->p.cx - 1); + write_cmd(g, g->p.y + g->p.cy - 1); + //outline + write_cmd(g, c6); + write_cmd(g, b6); + write_cmd(g, a6); + //fill + } + + write_cmd(g, c6); + write_cmd(g, b6); + write_cmd(g, a6); + release_bus(g); + } +#endif + +#if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL + LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g) { + acquire_bus(g); + write_cmd(g, SSD1331_DRAW_COPY); + write_cmd(g, g->p.x); + write_cmd(g, g->p.y); + write_cmd(g, g->p.x + g->p.cx - 1); + write_cmd(g, g->p.y + g->p.cy - 1); + write_cmd(g, g->p.x); + write_cmd(g, g->p.y - lines); + 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: + case powerSleep: + case powerDeepSleep: + acquire_bus(g); + write_cmd(g, SSD1331_DISPLAY_OFF); + release_bus(g); + break; + case powerOn: + acquire_bus(g); + write_cmd(g, SSD1331_DISPLAY_ON); + 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: + acquire_bus(g); + //TODO + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + acquire_bus(g); + //TODO + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + acquire_bus(g); + //TODO + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + acquire_bus(g); + //TODO + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + */ + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + acquire_bus(g); + write_cmd(g, SSD1331_BRIGHTNESS); + write_cmd(g, ((unsigned)g->p.ptr*10)/63); + release_bus(g); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + //case GDISP_CONTROL_CONTRAST: + default: + return; + } + } +#endif + +#endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/SSD1331/gdisp_lld_config.h b/drivers/gdisp/SSD1331/gdisp_lld_config.h new file mode 100644 index 00000000..d941f714 --- /dev/null +++ b/drivers/gdisp/SSD1331/gdisp_lld_config.h @@ -0,0 +1,31 @@ +/* + * 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. */ +/*===========================================================================*/ + +// This controller supports some optimized drawing routines - but no read (at least with SPI interfacing) +#define GDISP_HARDWARE_STREAM_WRITE TRUE +#define GDISP_HARDWARE_FILLS TRUE +#define GDISP_HARDWARE_SCROLL TRUE +#define GDISP_HARDWARE_CONTROL TRUE + +// This driver supports 4 pixel formats - pick the one you want. +//#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_BGR565 +//#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB332 +//#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_BGR332 + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */