From 01b68e90d0ef9c39297f2c81876ed67d130c9a78 Mon Sep 17 00:00:00 2001 From: "Paul A. Patience" Date: Mon, 24 Aug 2015 13:12:52 -0400 Subject: [PATCH 1/2] Add SSD1351 OLED controller support --- drivers/lcd/Kconfig | 171 +++++ drivers/lcd/Make.defs | 4 + drivers/lcd/ssd1351.c | 1256 +++++++++++++++++++++++++++++++++++ include/nuttx/lcd/ssd1351.h | 139 ++++ 4 files changed, 1570 insertions(+) create mode 100644 drivers/lcd/ssd1351.c create mode 100644 include/nuttx/lcd/ssd1351.h diff --git a/drivers/lcd/Kconfig b/drivers/lcd/Kconfig index ceceaad84d..d996b67a74 100644 --- a/drivers/lcd/Kconfig +++ b/drivers/lcd/Kconfig @@ -366,6 +366,177 @@ config SSD1306_I2CFREQ endif # LCD_SSD1306_I2C +config LCD_SSD1351 + bool "SSD1351 OLED Display Module" + default n + ---help--- + OLED Display Module, SSD1351, Solomon Systech. + +if LCD_SSD1351 + +choice + prompt "Interface" + default SSD1351_SPI4WIRE + +config SSD1351_SPI3WIRE + bool "3-wire SPI Interface" + select SPI + ---help--- + Enables support for the 3-wire SPI interface. + +config SSD1351_SPI4WIRE + bool "4-wire SPI Interface" + select SPI + select SPI_CMDDATA + ---help--- + Enables support for the 4-wire SPI interface. + +endchoice + +config SSD1351_SPIMODE + int "SPI Mode" + default 0 + range 0 3 + ---help--- + Specifies the SPI mode. + +config SSD1351_SPIFREQ + int "SPI Frequency" + default 1000000 + ---help--- + Specifies the SPI frequency. + +config SSD1351_NINTERFACES + int "Number of SSD1351 Devices" + default 1 + range 1 1 + ---help--- + Specifies the number of physical SSD1351 devices that will + be supported. + +config SSD1351_XRES + int "X Resolution" + default 128 + range 1 128 + ---help--- + Specifies the X resolution of the display. + +config SSD1351_YRES + int "Y Resolution" + default 128 + range 1 128 + ---help--- + Specifies the Y resolution of the display. + +config SSD1351_MIRRORX + bool "Mirror X" + default n + ---help--- + Mirrors the display along the X axis. + +config SSD1351_MIRRORY + bool "Mirror Y" + default n + ---help--- + Mirrors the display along the Y axis. + +config SSD1351_INVERT + bool "Invert Display" + default n + ---help--- + Inverts the display. + +config SSD1351_VDDEXT + bool "External VDD" + default n + ---help--- + Specifies that VDD is external. + +config SSD1351_TRST + int "Reset Period" + default 5 + range 5 31 + ---help--- + Specifies the reset period in DCLKs. + +config SSD1351_TPRECHG1 + int "First Pre-charge Period" + default 8 + range 3 15 + ---help--- + Specifies the first pre-charge period in DCLKs. + +config SSD1351_PERFENHANCE + bool "Enhance Display Performance" + default n + ---help--- + Enhances the display performance. + +config SSD1351_CLKDIV + int "Clock Divider" + default 0 + range 0 10 + ---help--- + Specifies the clock divider. + +config SSD1351_OSCFREQ + int "Oscillator Frequency" + default 15 + range 0 15 + ---help--- + Specifies the oscillator frequency. + +config SSD1351_TPRECHG2 + int "Second Pre-charge Period" + default 8 + range 1 15 + ---help--- + Specifies the second pre-charge period in DCLKs. + +config SSD1351_VPRECHG + int "Voltage Pre-charge Level" + default 50 + range 20 60 + ---help--- + Specifies the pre-charge voltage level as a percentage of VCC. + +config SSD1351_VCOMH + int "COM Deselect Voltage Level" + default 82 + range 72 86 + ---help--- + Specifies the COM deselect voltage level as a percentage of VCC. + +config SSD1351_CONTRASTA + int "Color A Contrast" + default 138 + range 0 255 + ---help--- + Specifies the contrast of color A. + +config SSD1351_CONTRASTB + int "Color B Contrast" + default 81 + range 0 255 + ---help--- + Specifies the contrast of color B. + +config SSD1351_CONTRASTC + int "Color C Contrast" + default 138 + range 0 255 + ---help--- + Specifies the contrast of color C. + +config SSD1351_MSTRCONTRAST + int "Master Contrast Ratio" + default 16 + range 1 16 + ---help--- + Specifies the master contrast ratio in sixteenths. + +endif + config LCD_ST7565 bool "ST7565 LCD Display Module" default n diff --git a/drivers/lcd/Make.defs b/drivers/lcd/Make.defs index 6c46771f09..1becc0fa97 100644 --- a/drivers/lcd/Make.defs +++ b/drivers/lcd/Make.defs @@ -71,6 +71,10 @@ ifeq ($(CONFIG_LCD_SSD1289),y) CSRCS += ssd1289.c endif +ifeq ($(CONFIG_LCD_SSD1351),y) + CSRCS += ssd1351.c +endif + ifeq ($(CONFIG_LCD_MIO283QT2),y) CSRCS += mio283qt2.c endif diff --git a/drivers/lcd/ssd1351.c b/drivers/lcd/ssd1351.c new file mode 100644 index 0000000000..e11e6b1fb1 --- /dev/null +++ b/drivers/lcd/ssd1351.c @@ -0,0 +1,1256 @@ +/**************************************************************************** + * drivers/lcd/ssd1351.c + * LCD driver for the Solomon Systech SSD1351 LCD controller + * + * Copyright (C) 2015 Omni Hoverboards Inc. All rights reserved. + * Author: Paul Alexander Patience + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_LCD_SSD1351 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* SSD1351 configuration settings: + * CONFIG_SSD1351_SPI3WIRE - 3-wire SPI interface + * CONFIG_SSD1351_SPI4WIRE - 4-wire SPI interface + * CONFIG_SSD1351_SPIMODE - SPI mode + * CONFIG_SSD1351_SPIFREQ - SPI frequency + * CONFIG_SSD1351_NINTERFACES - number of physical devices supported + * CONFIG_SSD1351_XRES - X resolution + * CONFIG_SSD1351_YRES - Y resolution + * CONFIG_SSD1351_MIRRORX - mirror along the X axis + * CONFIG_SSD1351_MIRRORY - mirror along the Y axis + * CONFIG_SSD1351_INVERT - invert the display + * CONFIG_SSD1351_VDDEXT - external VDD + * CONFIG_SSD1351_TRST - reset period + * CONFIG_SSD1351_TPRECHG1 - first pre-charge period + * CONFIG_SSD1351_PERFENHANCE - enhace display performance + * CONFIG_SSD1351_CLKDIV - clock divider + * CONFIG_SSD1351_OSCFREQ - oscillator frequency + * CONFIG_SSD1351_TPRECHG2 - second pre-charge period + * CONFIG_SSD1351_VPRECHG - pre-charge voltage level + * CONFIG_SSD1351_VCOMH - COM deselect voltage level + * CONFIG_SSD1351_CONTRASTA - color A contrast + * CONFIG_SSD1351_CONTRASTB - color B contrast + * CONFIG_SSD1351_CONTRASTC - color C contrast + * CONFIG_SSD1351_MSTRCONTRAST - master contrast ratio + * + * Required LCD driver settings: + * CONFIG_LCD_SSD1351 - enables SSD1351 support + * CONFIG_LCD_MAXPOWER - maximum power, must be 1 + * + * Additional LCD driver settings: + * CONFIG_LCD_LANDSCAPE - landscape + * CONFIG_LCD_RLANDSCAPE - reverse landscape + * CONFIG_LCD_PORTRAIT - portrait + * CONFIG_LCD_RPORTRAIT - reverse portrait + * + * Required SPI driver settings: + * CONFIG_SPI - enables support for SPI + * CONFIG_SPI_CMDDATA - enables support for cmd/data selection + * (if using 4-wire SPI) + * + * NX settings that must be undefined: + * CONFIG_NX_DISABLE_16BPP - disables 16 bpp support + */ + +/* Verify that all configuration requirements have been met */ + +/* Interface to use */ + +#if !defined(CONFIG_SSD1351_SPI3WIRE) && !defined(CONFIG_SSD1351_SPI4WIRE) +# error "Choose an interface to use" +#endif + +#if defined(CONFIG_SSD1351_SPI3WIRE) && defined(CONFIG_SSD1351_SPI4WIRE) +# error "Cannot choose more than one interface" +#endif + +/* SPI */ + +#ifndef CONFIG_SPI +# error "Requires support for SPI" +#endif + +/* Cmd/data selection */ + +#if defined(CONFIG_SSD1351_SPI4WIRE) && !defined(CONFIG_SPI_CMDDATA) +# error "4-wire SPI interface requires support for SPI_CMDDATA" +#endif + +/* Number of bits per pixel */ + +#ifdef CONFIG_NX_DISABLE_16BPP +# error "Requires support for 16 bits per pixel" +#endif + +/* Max power */ + +#ifndef CONFIG_LCD_MAXPOWER +# define CONFIG_LCD_MAXPOWER 1 +#endif + +#if CONFIG_LCD_MAXPOWER != 1 +# error "CONFIG_LCD_MAXPOWER should be 1" +#endif + +/* SPI mode */ + +#ifndef CONFIG_SSD1351_SPIMODE +# define CONFIG_SSD1351_SPIMODE SPIDEV_MODE0 +#endif + +/* SPI frequency */ + +#ifndef CONFIG_SSD1351_SPIFREQ +# define CONFIG_SSD1351_SPIFREQ 1000000 +#endif + +/* The number of physical interfaces that will be supported */ + +#ifndef CONFIG_SSD1351_NINTERFACES +# define CONFIG_SSD1351_NINTERFACES 1 +#endif + +#if CONFIG_SSD1351_NINTERFACES != 1 +# error "This implementation supports only a single LCD device" +#endif + +/* X resolution */ + +#ifndef CONFIG_SSD1351_XRES +# define CONFIG_SSD1351_XRES 128 +#endif + +#if CONFIG_SSD1351_XRES < 0 || CONFIG_SSD1351_XRES > 128 +# error "Invalid X resolution" +#endif + +/* Y resolution */ + +#ifndef CONFIG_SSD1351_YRES +# define CONFIG_SSD1351_YRES 128 +#endif + +#if CONFIG_SSD1351_YRES < 0 || CONFIG_SSD1351_YRES > 128 +# error "Invalid Y resolution" +#endif + +/* Reset period */ + +#ifndef CONFIG_SSD1351_TRST +# define CONFIG_SSD1351_TRST 5 +#endif + +/* First pre-charge period */ + +#ifndef CONFIG_SSD1351_TPRECHG1 +# define CONFIG_SSD1351_TPRECHG1 8 +#endif + +/* Clock divider */ + +#ifndef CONFIG_SSD1351_CLKDIV +# define CONFIG_SSD1351_CLKDIV 0 +#endif + +/* Oscillator frequency */ + +#ifndef CONFIG_SSD1351_OSCFREQ +# define CONFIG_SSD1351_OSCFREQ 15 +#endif + +/* Second pre-charge period */ + +#ifndef CONFIG_SSD1351_TPRECHG2 +# define CONFIG_SSD1351_TPRECHG2 8 +#endif + +/* Pre-charge voltage level */ + +#ifndef CONFIG_SSD1351_VPRECHG +# define CONFIG_SSD1351_VPRECHG 50 +#endif + +/* COM deselect voltage level */ + +#ifndef CONFIG_SSD1351_VCOMH +# define CONFIG_SSD1351_VCOMH 82 +#endif + +/* Color A contrast */ + +#ifndef CONFIG_SSD1351_CONTRASTA +# define CONFIG_SSD1351_CONTRASTA 138 +#endif + +/* Color B contrast */ + +#ifndef CONFIG_SSD1351_CONTRASTB +# define CONFIG_SSD1351_CONTRASTB 81 +#endif + +/* Color C contrast */ + +#ifndef CONFIG_SSD1351_CONTRASTC +# define CONFIG_SSD1351_CONTRASTC 138 +#endif + +/* Master contrast ratio */ + +#ifndef CONFIG_SSD1351_MSTRCONTRAST +# define CONFIG_SSD1351_MSTRCONTRAST 16 +#endif + +/* 9-bit SPI */ + +#ifdef CONFIG_SSD1351_SPI3WIRE +# define SSD1351_SPICMD 0 +# define SSD1351_SPIDATA (1 << 8) +#endif + +/* Macro Helpers ************************************************************/ + +#define SSD1351_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define SSD1351_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define SSD1351_CLAMP(n, a, b) SSD1351_MIN(SSD1351_MAX(n, a), b) + +/* Fundamental Commands *****************************************************/ + +/* Set column address. Two data bytes. + * Data 1: start address (0-127) + * Data 2: end address (0-127) + */ + +#define SSD1351_CMD_COLADDR 0x15 + +/* Set row address. Two data bytes. + * Data 1: start address (0-127) + * Data 2: end address (0-127) + */ + +#define SSD1351_CMD_ROWADDR 0x75 + +/* Write data bytes to RAM. */ + +#define SSD1351_CMD_RAMWRITE 0x5c + +/* Read data bytes from RAM. */ + +#define SSD1351_CMD_RAMREAD 0x5d + +/* Set address increment, column address mapping, color sequence, + * scan direction, COM split, and color depth. + * One data byte. + */ + +#define SSD1351_CMD_ORIENTATION 0xa0 +#define SSD1351_ADDRINCHORIZ 0x00 /* Horizontal address increment */ +#define SSD1351_ADDRINCVERT 0x01 /* Vertical address increment */ +#define SSD1351_REMAPCOL0 0x00 /* Column address 0 mapped to SEG0 */ +#define SSD1351_REMAPCOL127 0x02 /* Column address 127 mapped to SEG0 */ +#define SSD1351_COLORABC 0x00 /* Color sequence ABC */ +#define SSD1351_COLORCBA 0x04 /* Color sequence CBA */ +#define SSD1351_SCANFROMCOM0 0x00 /* Scan from COM0 */ +#define SSD1351_SCANTOCOM0 0x10 /* Scan to COM0 */ +#define SSD1351_SPLITDIS 0x00 /* Disable COM split odd even */ +#define SSD1351_SPLITEN 0x20 /* Enable COM split odd even */ +#define SSD1351_DEPTH65K 0x00 /* 65k color depth */ +#define SSD1351_DEPTH262K1 0x80 /* 262k color depth format 1 */ +#define SSD1351_DEPTH262K2 0xc0 /* 262k color depth format 2 */ + +/* Set vertical scroll by RAM (0-128). One data byte. */ + +#define SSD1351_CMD_STARTLINE 0xa1 +#define SSD1351_STARTLINE(n) SSD1351_CLAMP(n, 0, 128) + +/* Set vertical scroll by row (0-128). One data byte. */ + +#define SSD1351_CMD_OFFSET 0xa2 +#define SSD1351_OFFSET(n) SSD1351_CLAMP(n, 0, 128) + +/* Set all pixels off. No data bytes. */ + +#define SSD1351_CMD_ALLOFF 0xa4 + +/* Set all pixels on. No data bytes. */ + +#define SSD1351_CMD_ALLON 0xa5 + +/* Set normal display. No data bytes. */ + +#define SSD1351_CMD_NORMAL 0xa6 + +/* Set inverse display. No data bytes. */ + +#define SSD1351_CMD_INVERSE 0xa7 + +/* Set VDD and interface. One data byte. */ + +#define SSD1351_CMD_VDDIFACE 0xab +#define SSD1351_VDDEXT 0x00 /* external VDD */ +#define SSD1351_VDDINT 0x01 /* internal VDD */ +#define SSD1351_IFACE8BIT 0x00 /* 8-bit parallel */ +#define SSD1351_IFACE16BIT 0x40 /* 16-bit parallel */ +#define SSD1351_IFACE18BIT 0xc0 /* 18-bit parallel */ + +/* Set display off (sleep mode on). No data bytes. */ + +#define SSD1351_CMD_DISPOFF 0xae + +/* Set display on (sleep mode off). No data bytes. */ + +#define SSD1351_CMD_DISPON 0xaf + +/* Set reset period in DCLKs (5-31) and first pre-charge period + * in DCLKs (3-15). One data byte. + */ + +#define SSD1351_CMD_TRSTTPRECHG1 0xb1 +#define SSD1351_TRST(n) (SSD1351_CLAMP(n, 5, 31) / 2) +#define SSD1351_TPRECHG1(n) (SSD1351_CLAMP(n, 3, 15) << 4) + +/* Set display performance. Three data bytes. */ + +#define SSD1351_CMD_PERF 0xb2 +#define SSD1351_PERFNORMAL 0x00 /* Data 1: normal performance */ +#define SSD1351_PERFENHANCED 0xa4 /* Data 1: enhanced performance */ +#define SSD1351_PERFDATA2 0x00 +#define SSD1351_PERFDATA3 0x00 + +/* Set clock divider (0-10) and oscillator frequency (0-15). + * One data byte. + */ + +#define SSD1351_CMD_DIVFREQ 0xb3 +#define SSD1351_CLKDIV(r) (SSD1351_CLAMP(r, 0, 10) << 0) +#define SSD1351_OSCFREQ(r) (SSD1351_CLAMP(r, 0, 15) << 4) + +/* Set segment low voltage. Three data bytes. */ + +#define SSD1351_CMD_VSL 0xb4 +#define SSD1351_VSLEXT 0xa0 /* Data 1: external VSL */ +#define SSD1351_VSLDATA2 0xb5 +#define SSD1351_VSLDATA3 0x55 + +/* Set GPIO pins. One data byte. */ + +#define SSD1351_CMD_GPIO 0xb5 +#define SSD1351_GPIODIS 0x00 /* High impedance, disabled */ +#define SSD1351_GPIOEN 0x01 /* High impedance, enabled */ +#define SSD1351_GPIOLOW 0x02 /* Output low */ +#define SSD1351_GPIOHIGH 0x03 /* Output high */ +#define SSD1351_GPIO0(n) (((n) & 3) << 0) +#define SSD1351_GPIO1(n) (((n) & 3) << 2) + +/* Set second pre-charge period in DCLKs (1-15). One data byte. */ + +#define SSD1351_CMD_TPRECHG2 0xb6 +#define SSD1351_TPRECHG2(n) SSD1351_CLAMP(n, 1, 15) + +/* Set lookup table for grayscale pulse width. 63 data bytes. */ + +#define SSD1351_CMD_LUT 0xb8 + +/* Use built-in linear lookup table. No data bytes. */ + +#define SSD1351_CMD_LINEARLUT 0xb9 + +/* Set pre-charge voltage level as a percentage of VCC (20-60). + * One data byte. + */ + +#define SSD1351_CMD_VPRECHG 0xbb +#define SSD1351_VPRECHG(n) (100 * (SSD1351_CLAMP(n, 20, 60) - 20) / \ + (100 * (60 - 20) / 31)) + +/* Set COM deselect voltage level as a percentage of VCC (72-86). + * One data byte. + */ + +#define SSD1351_CMD_VCOMH 0xbe +#define SSD1351_VCOMH(n) ((SSD1351_CLAMP(n, 72, 86) - 72) / 2) + +/* Set contrast for colors A (0-255), B (0-255), and C (0-255). + * Three data bytes. + * Data 1: color A + * Data 2: color B + * Data 3: color C + */ + +#define SSD1351_CMD_CONTRAST 0xc1 +#define SSD1351_CONTRAST(n) SSD1351_CLAMP(n, 0, 255) + +/* Set master contrast ratio in sixteenths (1-16). One data byte. */ + +#define SSD1351_CMD_MSTRCONTRAST 0xc7 +#define SSD1351_MSTRCONTRAST(n) (SSD1351_CLAMP(n, 1, 16) - 1) + +/* Set multiplex ratio (16-128). One data byte. */ + +#define SSD1351_CMD_MUXRATIO 0xca +#define SSD1351_MUXRATIO(n) (SSD1351_CLAMP(n, 16, 128) - 1) + +/* Set command lock. One data byte. */ + +#define SSD1351_CMD_LOCK 0xfd +#define SSD1351_UNLOCK 0x12 /* Unlock commands */ +#define SSD1351_LOCK 0x16 /* Lock commands */ +#define SSD1351_INACCESSIBLE 0xb0 /* Make some commands inaccessible */ +#define SSD1351_ACCESSIBLE 0xb1 /* Make some commands accessible */ + +/* Graphic Acceleration Commands ********************************************/ + +/* Set horizontal scroll. Five data bytes. + * Data 1: 0x00: no scrolling + * 0x01-0x3f: scroll towards SEG127 with 1 column offset + * 0x40-0xff: scroll towards SEG0 with 1 column offset + * Data 2: start row address + * Data 3: number of rows to scroll + */ + +#define SSD1351_CMD_HSCROLL 0x96 +#define SSD1351_HSCROLLDATA4 0x00 /* Data 4 */ +#define SSD1351_HSCROLLTEST 0x00 /* Data 5: test mode */ +#define SSD1351_HSCROLLNORMAL 0x01 /* Data 5: normal */ +#define SSD1351_HSCROLLSLOW 0x02 /* Data 5: slow */ +#define SSD1351_HSCROLLSLOWEST 0x03 /* Data 5: slowest */ + +/* Start horizontal scroll. No data bytes. */ + +#define SSD1351_CMD_STARTHSCROLL 0x9e + +/* Stop horizontal scroll. No data bytes. */ + +#define SSD1351_CMD_STOPHSCROLL 0x9f + +/* Color Properties *********************************************************/ + +/* Display resolution */ + +#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) +#define SSD1351_XRES CONFIG_SSD1351_XRES +#define SSD1351_YRES CONFIG_SSD1351_YRES +#else +#define SSD1351_XRES CONFIG_SSD1351_YRES +#define SSD1351_YRES CONFIG_SSD1351_XRES +#endif + +/* Color depth and format */ + +#define SSD1351_BPP 16 +#define SSD1351_COLORFMT FB_FMT_RGB16_565 +#define SSD1351_STRIDE (2 * SSD1351_XRES) +#define SSD1351_PIX2BYTES(p) (2 * (p)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes the state of this driver */ + +struct ssd1351_dev_s +{ + /* Publically visible device structure */ + + struct lcd_dev_s dev; + + /* Private LCD-specific information follows */ + + FAR struct spi_dev_s *spi; /* Contained SPI driver instance */ + uint8_t power; /* Current power (backlight) setting */ + + /* This is working memory allocated by the LCD driver for each LCD device + * and for each color plane. This memory will hold one raster line of + * data. The size of the allocated run buffer must therefore be at least + * (bpp * xres / 8). Actual alignment of the buffer must conform to the + * bitwidth of the underlying pixel type. + * + * If there are multiple planes, they may share the same working buffer + * because different planes will not be operate on concurrently. However, + * if there are multiple LCD devices, they must each have unique run + * buffers. + */ + + uint16_t runbuffer[SSD1351_XRES]; + + /* This is another buffer, but used internally by the LCD driver in order + * to expand the pixel data into 9-bit data needed by the LCD. There are + * some customizations that would eliminate the need for this extra buffer + * and for the extra expansion/copy, but those customizations would require + * a special, non-standard SPI driver that could expand 8- to 9-bit data on + * the fly. + */ + +#ifdef CONFIG_SSD1351_SPI3WIRE + uint16_t rowbuffer[SSD1351_STRIDE+1]; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* SPI Helpers */ + +static inline void ssd1351_configspi(FAR struct spi_dev_s *spi); +#ifdef CONFIG_SPI_OWNBUS +static inline void ssd1351_select(FAR struct spi_dev_s *spi); +static inline void ssd1351_deselect(FAR struct spi_dev_s *spi); +#else +static void ssd1351_select(FAR struct spi_dev_s *spi); +static void ssd1351_deselect(FAR struct spi_dev_s *spi); +#endif +static void ssd1351_cmddata(FAR struct ssd1351_dev_s *priv, uint8_t cmd, + FAR const uint8_t *data, size_t datlen); + +/* LCD Data Transfer Methods */ + +static int ssd1351_putrun(fb_coord_t row, fb_coord_t col, + FAR const uint8_t *buffer, size_t npixels); +static int ssd1351_getrun(fb_coord_t row, fb_coord_t col, + FAR uint8_t *buffer, size_t npixels); + +/* LCD Configuration */ + +static int ssd1351_getvideoinfo(FAR struct lcd_dev_s *dev, + FAR struct fb_videoinfo_s *vinfo); +static int ssd1351_getplaneinfo(FAR struct lcd_dev_s *dev, + unsigned int planeno, + FAR struct lcd_planeinfo_s *pinfo); + +/* LCD RGB Mapping */ + +#ifdef CONFIG_FB_CMAP +# error "RGB color mapping not supported by this driver" +#endif + +/* Cursor Controls */ + +#ifdef CONFIG_FB_HWCURSOR +# error "Cursor control not supported by this driver" +#endif + +/* LCD Specific Controls */ + +static int ssd1351_getpower(struct lcd_dev_s *dev); +static int ssd1351_setpower(struct lcd_dev_s *dev, int power); +static int ssd1351_getcontrast(struct lcd_dev_s *dev); +static int ssd1351_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); + +/* Initialization */ + +static inline void ssd1351_hwinitialize(FAR struct ssd1351_dev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is the standard, NuttX LCD driver object */ + +static struct ssd1351_dev_s g_lcddev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ssd1351_configspi + * + * Description: + * Configure the SPI. + * + ****************************************************************************/ + +static inline void ssd1351_configspi(FAR struct spi_dev_s *spi) +{ + SPI_SETMODE(spi, CONFIG_SSD1351_SPIMODE); +#ifdef CONFIG_SSD1351_SPI3WIRE + SPI_SETBITS(spi, 9); +#else + SPI_SETBITS(spi, 8); +#endif + SPI_SETFREQUENCY(spi, CONFIG_SSD1351_SPIFREQ); +} + +/**************************************************************************** + * Name: ssd1351_select + * + * Description: + * Select the SPI, locking and re-configuring if necessary. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_OWNBUS +static inline void ssd1351_select(FAR struct spi_dev_s *spi) +{ + /* We own the SPI bus, so just select the chip */ + + gdbg("SELECTED\n"); + SPI_SELECT(spi, SPIDEV_DISPLAY, true); +} +#else +static void ssd1351_select(FAR struct spi_dev_s *spi) +{ + /* Select the chip, locking the SPI bus in case there are multiple devices + * competing for the SPI bus + */ + + gdbg("SELECTED\n"); + SPI_LOCK(spi, true); + SPI_SELECT(spi, SPIDEV_DISPLAY, true); + + /* Now make sure that the SPI bus is configured for this device (it might + * have gotten configured for a different device while unlocked) + */ + + ssd1351_configspi(spi); +} +#endif + +/**************************************************************************** + * Name: ssd1351_deselect + * + * Description: + * De-select the SPI. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_OWNBUS +static inline void ssd1351_deselect(FAR struct spi_dev_s *spi) +{ + /* We own the SPI bus, so just de-select the chip */ + + gdbg("DE-SELECTED\n"); + SPI_SELECT(spi, SPIDEV_DISPLAY, false); +} +#else +static void ssd1351_deselect(FAR struct spi_dev_s *spi) +{ + /* De-select the chip and relinquish the SPI bus */ + + gdbg("DE-SELECTED\n"); + SPI_SELECT(spi, SPIDEV_DISPLAY, false); + SPI_LOCK(spi, false); +} +#endif + +/**************************************************************************** + * Name: ssd1351_cmddata + * + * Description: + * Send a 1-byte command followed by datlen data bytes. + * + ****************************************************************************/ + +#ifdef CONFIG_SSD1351_SPI3WIRE +static void ssd1351_cmddata(FAR struct ssd1351_dev_s *priv, uint8_t cmd, + FAR const uint8_t *data, size_t datlen) +{ + size_t i; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + DEBUGASSERT((data == NULL && datlen == 0) || (data != NULL && datlen > 0)); + DEBUGASSERT(datlen <= SSD1351_STRIDE); + + /* Copy the command into the line buffer */ + + priv->rowbuffer[0] = (uint16_t)cmd | SSD1351_SPICMD; + + /* Copy any data after the command into the line buffer */ + + for (i = 0; i < datlen; i++) + { + priv->rowbuffer[i+1] = (uint16_t)data[i] | SSD1351_SPIDATA; + } + + /* Send the line buffer */ + + (void)SPI_SNDBLOCK(priv->spi, priv->rowbuffer, datlen+1); +} +#else +static void ssd1351_cmddata(FAR struct ssd1351_dev_s *priv, uint8_t cmd, + FAR const uint8_t *data, size_t datlen) +{ + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + DEBUGASSERT((data == NULL && datlen == 0) || (data != NULL && datlen > 0)); + + /* Select command transfer */ + + (void)SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true); + + /* Send the command */ + + (void)SPI_SEND(priv->spi, cmd); + + /* Do we have any data to send? */ + + if (datlen > 0) + { + /* Yes, select data transfer */ + + (void)SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, false); + + /* Transfer all of the data */ + + (void)SPI_SNDBLOCK(priv->spi, data, datlen); + } +} +#endif + +/**************************************************************************** + * Name: ssd1351_setcursor + * + * Description: + * Set the cursor position. + * + ****************************************************************************/ + +static void ssd1351_setcursor(FAR struct ssd1351_dev_s *priv, uint8_t col, + uint8_t row) +{ + uint8_t buf[2]; + +#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) + /* Set the column address to the column */ + + buf[0] = col; + buf[1] = SSD1351_XRES - 1; + ssd1351_cmddata(priv, SSD1351_CMD_COLADDR, buf, 2); + + /* Set the row address to the row */ + + buf[0] = row; + buf[1] = SSD1351_YRES - 1; + ssd1351_cmddata(priv, SSD1351_CMD_ROWADDR, buf, 2); +#else + /* Set the column address to the row */ + + buf[0] = row; + buf[1] = SSD1351_YRES - 1; + ssd1351_cmddata(priv, SSD1351_CMD_COLADDR, buf, 2); + + /* Set the row address to the column */ + + buf[0] = col; + buf[1] = SSD1351_XRES - 1; + ssd1351_cmddata(priv, SSD1351_CMD_ROWADDR, buf, 2); +#endif +} + +/**************************************************************************** + * Name: ssd1351_putrun + * + * Description: + * This method can be used to write a partial raster line to the LCD: + * + * Input Parameters: + * row - Starting row to write to (range: 0 <= row < yres) + * col - Starting column to write to (range: 0 <= col <= xres-npixels + * buffer - The buffer containing the run to be written to the LCD + * npixels - The number of pixels to write to the LCD + * (range: 0 < npixels <= xres-col) + * + ****************************************************************************/ + +static int ssd1351_putrun(fb_coord_t row, fb_coord_t col, + FAR const uint8_t *buffer, size_t npixels) +{ + FAR struct ssd1351_dev_s *priv = &g_lcddev; + + /* Sanity check */ + + DEBUGASSERT(buffer != NULL && ((uintptr_t)buffer & 1) == 0 && + col >= 0 && col+npixels <= SSD1351_XRES && + row >= 0 && row < SSD1351_YRES); + + /* Select and lock the device */ + + ssd1351_select(priv->spi); + + /* Set the starting position for the run */ + + ssd1351_setcursor(priv, col, row); + + /* Transfer all of the data */ + + ssd1351_cmddata(priv, SSD1351_CMD_RAMWRITE, buffer, + SSD1351_PIX2BYTES(npixels)); + + /* Unlock and de-select the device */ + + ssd1351_deselect(priv->spi); + + return OK; +} + +/**************************************************************************** + * Name: ssd1351_getrun + * + * Description: + * This method can be used to read a partial raster line from the LCD. + * + * Input Parameters: + * row - Starting row to read from (range: 0 <= row < yres) + * col - Starting column to read from (range: 0 <= col <= xres-npixels) + * buffer - The buffer in which to return the run read from the LCD + * npixels - The number of pixels to read from the LCD + * (range: 0 < npixels <= xres-col) + * + ****************************************************************************/ + +static int ssd1351_getrun(fb_coord_t row, fb_coord_t col, + FAR uint8_t *buffer, size_t npixels) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: ssd1351_getvideoinfo + * + * Description: + * Get information about the LCD video controller configuration. + * + ****************************************************************************/ + +static int ssd1351_getvideoinfo(FAR struct lcd_dev_s *dev, + FAR struct fb_videoinfo_s *vinfo) +{ + DEBUGASSERT(dev != NULL && vinfo != NULL); + + vinfo->fmt = SSD1351_COLORFMT; + vinfo->xres = SSD1351_XRES; + vinfo->yres = SSD1351_YRES; + vinfo->nplanes = 1; + + gvdbg("fmt: %u xres: %u yres: %u nplanes: %u\n", + vinfo->fmt, vinfo->xres, vinfo->yres, vinfo->nplanes); + return OK; +} + +/**************************************************************************** + * Name: ssd1351_getplaneinfo + * + * Description: + * Get information about the configuration of each LCD color plane. + * + ****************************************************************************/ + +static int ssd1351_getplaneinfo(FAR struct lcd_dev_s *dev, + unsigned int planeno, + FAR struct lcd_planeinfo_s *pinfo) +{ + FAR struct ssd1351_dev_s *priv = (FAR struct ssd1351_dev_s *)dev; + + DEBUGASSERT(dev != NULL && pinfo != NULL && planeno == 0); + + pinfo->putrun = ssd1351_putrun; + pinfo->getrun = ssd1351_getrun; + pinfo->buffer = (uint8_t *)priv->runbuffer; + pinfo->bpp = SSD1351_BPP; + + gvdbg("planeno: %u bpp: %u\n", planeno, pinfo->bpp); + return OK; +} + +/**************************************************************************** + * Name: ssd1351_getpower + * + * Description: + * Get the LCD panel power status + * (0: full off - CONFIG_LCD_MAXPOWER: full on). + * On backlit LCDs, this setting may correspond to the backlight setting. + * + ****************************************************************************/ + +static int ssd1351_getpower(FAR struct lcd_dev_s *dev) +{ + FAR struct ssd1351_dev_s *priv = (FAR struct ssd1351_dev_s *)dev; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL); + gvdbg("power: %d\n", priv->power); + + return priv->power; +} + +/**************************************************************************** + * Name: ssd1351_setpower + * + * Description: + * Enable/disable LCD panel power + * (0: full off - CONFIG_LCD_MAXPOWER: full on). + * On backlit LCDs, this setting may correspond to the backlight setting. + * + ****************************************************************************/ + +static int ssd1351_setpower(FAR struct lcd_dev_s *dev, int power) +{ + FAR struct ssd1351_dev_s *priv = (FAR struct ssd1351_dev_s *)dev; + + /* Sanity check */ + + DEBUGASSERT(priv != NULL && (unsigned int)power <= CONFIG_LCD_MAXPOWER); + gvdbg("power: %d\n", power); + + /* Select and lock the device */ + + ssd1351_select(priv->spi); + + if (power > 0) + { + /* Turn the display on */ + + ssd1351_cmddata(priv, SSD1351_CMD_DISPON, NULL, 0); + priv->power = CONFIG_LCD_MAXPOWER; + } + else + { + /* Turn the display off */ + + ssd1351_cmddata(priv, SSD1351_CMD_DISPOFF, NULL, 0); + priv->power = 0; + } + + /* Unlock and de-select the device */ + + ssd1351_deselect(priv->spi); + + return OK; +} + +/**************************************************************************** + * Name: ssd1351_getcontrast + * + * Description: + * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). + * + ****************************************************************************/ + +static int ssd1351_getcontrast(FAR struct lcd_dev_s *dev) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: ssd1351_setcontrast + * + * Description: + * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). + * + ****************************************************************************/ + +static int ssd1351_setcontrast(FAR struct lcd_dev_s *dev, + unsigned int contrast) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: ssd1351_hwinitialize + * + * Description: + * Initialize the video hardware. + * + ****************************************************************************/ + +static inline void ssd1351_hwinitialize(FAR struct ssd1351_dev_s *priv) +{ + size_t i; + uint8_t buf[3]; + + /* Select and lock the device */ + + ssd1351_select(priv->spi); + + /* Unlock most commands */ + + buf[0] = SSD1351_UNLOCK; + ssd1351_cmddata(priv, SSD1351_CMD_LOCK, buf, 1); + + /* Unlock the rest of the commands */ + + buf[0] = SSD1351_ACCESSIBLE; + ssd1351_cmddata(priv, SSD1351_CMD_LOCK, buf, 1); + + /* Turn the display off */ + + ssd1351_cmddata(priv, SSD1351_CMD_DISPOFF, NULL, 0); + + /* Set the address increment, the column address mapping, the color + * sequence, the scan direction, the COM split, and the color depth + */ + + buf[0] = SSD1351_COLORABC | SSD1351_SPLITEN | SSD1351_DEPTH65K; +#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) + buf[0] |= SSD1351_ADDRINCHORIZ; +#else + buf[0] |= SSD1351_ADDRINCVERT; +#endif +#if (defined(CONFIG_LCD_LANDSCAPE) && !defined(CONFIG_SSD1351_MIRRORX)) || \ + (defined(CONFIG_LCD_RLANDSCAPE) && defined(CONFIG_SSD1351_MIRRORX)) || \ + (defined(CONFIG_LCD_PORTRAIT) && !defined(CONFIG_SSD1351_MIRRORY)) || \ + (defined(CONFIG_LCD_RPORTRAIT) && defined(CONFIG_SSD1351_MIRRORY)) + buf[0] |= SSD1351_REMAPCOL0; +#else + buf[0] |= SSD1351_REMAPCOL127; +#endif +#if (defined(CONFIG_LCD_LANDSCAPE) && !defined(CONFIG_SSD1351_MIRRORY)) || \ + (defined(CONFIG_LCD_RLANDSCAPE) && defined(CONFIG_SSD1351_MIRRORY)) || \ + (defined(CONFIG_LCD_PORTRAIT) && defined(CONFIG_SSD1351_MIRRORX)) || \ + (defined(CONFIG_LCD_RPORTRAIT) && !defined(CONFIG_SSD1351_MIRRORX)) + buf[0] |= SSD1351_SCANTOCOM0; +#else + buf[0] |= SSD1351_SCANFROMCOM0; +#endif + ssd1351_cmddata(priv, SSD1351_CMD_ORIENTATION, buf, 1); + + /* Set the vertical scroll by RAM */ + +#if (defined(CONFIG_LCD_LANDSCAPE) && !defined(CONFIG_SSD1351_MIRRORY)) || \ + (defined(CONFIG_LCD_RLANDSCAPE) && defined(CONFIG_SSD1351_MIRRORY)) || \ + (defined(CONFIG_LCD_PORTRAIT) && defined(CONFIG_SSD1351_MIRRORX)) || \ + (defined(CONFIG_LCD_RPORTRAIT) && !defined(CONFIG_SSD1351_MIRRORX)) + buf[0] = SSD1351_STARTLINE(CONFIG_SSD1351_YRES); +#else + buf[0] = SSD1351_STARTLINE(0); +#endif + ssd1351_cmddata(priv, SSD1351_CMD_STARTLINE, buf, 1); + + /* Set the vertical scroll by row */ + + buf[0] = SSD1351_OFFSET(0); + ssd1351_cmddata(priv, SSD1351_CMD_OFFSET, buf, 1); + + /* Set the display to normal or inverse */ + +#ifdef CONFIG_SSD1351_INVERT + ssd1351_cmddata(priv, SSD1351_CMD_INVERSE, NULL, 0); +#else + ssd1351_cmddata(priv, SSD1351_CMD_NORMAL, NULL, 0); +#endif + + /* Set the VDD and the interface */ + +#ifdef CONFIG_SSD1351_VDDEXT + buf[0] = SSD1351_VDDEXT; +#else + buf[0] = SSD1351_VDDINT; +#endif + buf[0] |= SSD1351_IFACE8BIT; + ssd1351_cmddata(priv, SSD1351_CMD_VDDIFACE, buf, 1); + + /* Set the reset period and the first pre-charge period */ + + buf[0] = SSD1351_TRST(CONFIG_SSD1351_TRST) | + SSD1351_TPRECHG1(CONFIG_SSD1351_TPRECHG1); + ssd1351_cmddata(priv, SSD1351_CMD_TRSTTPRECHG1, buf, 1); + + /* Set the display performance */ + +#ifdef CONFIG_SSD1351_PERFENHANCE + buf[0] = SSD1351_PERFENHANCE; +#else + buf[0] = SSD1351_PERFNORMAL; +#endif + buf[1] = SSD1351_PERFDATA2; + buf[2] = SSD1351_PERFDATA3; + ssd1351_cmddata(priv, SSD1351_CMD_PERF, buf, 3); + + /* Set the clock divider and the oscillator frequency */ + + buf[0] = SSD1351_CLKDIV(CONFIG_SSD1351_CLKDIV) | + SSD1351_OSCFREQ(CONFIG_SSD1351_OSCFREQ); + ssd1351_cmddata(priv, SSD1351_CMD_DIVFREQ, buf, 1); + + /* Set the segment low voltage */ + + buf[0] = SSD1351_VSLEXT; + buf[1] = SSD1351_VSLDATA2; + buf[2] = SSD1351_VSLDATA3; + ssd1351_cmddata(priv, SSD1351_CMD_VSL, buf, 3); + + /* Set the GPIO pins */ + + buf[0] = SSD1351_GPIO0(SSD1351_GPIOLOW) | SSD1351_GPIO1(SSD1351_GPIOLOW); + ssd1351_cmddata(priv, SSD1351_CMD_GPIO, buf, 1); + + /* Set the second pre-charge period */ + + buf[0] = SSD1351_TPRECHG2(CONFIG_SSD1351_TPRECHG2); + ssd1351_cmddata(priv, SSD1351_CMD_TPRECHG2, buf, 1); + + /* Use the built-in linear lookup table */ + + ssd1351_cmddata(priv, SSD1351_CMD_LINEARLUT, NULL, 0); + + /* Set the pre-charge voltage level */ + + buf[0] = SSD1351_VPRECHG(CONFIG_SSD1351_VPRECHG); + ssd1351_cmddata(priv, SSD1351_CMD_VPRECHG, buf, 1); + + /* Set the COM deselect voltage level */ + + buf[0] = SSD1351_VCOMH(CONFIG_SSD1351_VCOMH); + ssd1351_cmddata(priv, SSD1351_CMD_VCOMH, buf, 1); + + /* Set the contrast */ + + buf[0] = SSD1351_CONTRAST(CONFIG_SSD1351_CONTRASTA); + buf[1] = SSD1351_CONTRAST(CONFIG_SSD1351_CONTRASTB); + buf[2] = SSD1351_CONTRAST(CONFIG_SSD1351_CONTRASTC); + ssd1351_cmddata(priv, SSD1351_CMD_CONTRAST, buf, 3); + + /* Set the master contrast ratio */ + + buf[0] = SSD1351_MSTRCONTRAST(CONFIG_SSD1351_MSTRCONTRAST); + ssd1351_cmddata(priv, SSD1351_CMD_MSTRCONTRAST, buf, 1); + + /* Set the multiplex ratio */ + + buf[0] = SSD1351_MUXRATIO(128); + ssd1351_cmddata(priv, SSD1351_CMD_MUXRATIO, buf, 1); + + /* Lock some of the commands */ + + buf[0] = SSD1351_INACCESSIBLE; + ssd1351_cmddata(priv, SSD1351_CMD_LOCK, buf, 1); + + /* Set the cursor position */ + + ssd1351_setcursor(priv, 0, 0); + + /* Clear the display memory */ + + buf[0] = 0; + buf[1] = 0; + for (i = 0; i < SSD1351_XRES * SSD1351_YRES; i++) + { + ssd1351_cmddata(priv, SSD1351_CMD_RAMWRITE, buf, 2); + } + + /* Unlock and de-select the device */ + + ssd1351_deselect(priv->spi); +} + +/**************************************************************************** + * Name: ssd1351_initialize + * + * Description: + * Initialize the video hardware. The initial state of the device + * is fully initialized, display memory cleared, and ready to use, + * but with the power setting at 0 (full off == sleep mode). + * + * Input Parameters: + * spi - A reference to the SPI driver instance. + * devno - A value in the range of 0 through CONFIG_SSD1351_NINTERFACES-1. + * This allows support for multiple devices. + * + * Returned Value: + * On success, this function returns a reference to the LCD object for the + * specified device. NULL is returned on failure. + * + ****************************************************************************/ + +FAR struct lcd_dev_s *ssd1351_initialize(FAR struct spi_dev_s *spi, + unsigned int devno) +{ + FAR struct ssd1351_dev_s *priv = &g_lcddev; + size_t i; + uint16_t buf[SSD1351_XRES/2]; + + /* Sanity check */ + + DEBUGASSERT(spi != NULL && devno == 0); + + /* Initialize the driver data structure */ + + priv->dev.getvideoinfo = ssd1351_getvideoinfo; + priv->dev.getplaneinfo = ssd1351_getplaneinfo; + priv->dev.getpower = ssd1351_getpower; + priv->dev.setpower = ssd1351_setpower; + priv->dev.getcontrast = ssd1351_getcontrast; + priv->dev.setcontrast = ssd1351_setcontrast; + priv->spi = spi; + priv->power = 0; + + /* Configure the SPI bus if we own it. Otherwise, don't bother because + * it might change. + */ + +#ifdef CONFIG_SPI_OWNBUS + ssd1351_configspi(spi); +#endif + + /* Configure the device */ + + ssd1351_hwinitialize(priv); + + ssd1351_setpower(&priv->dev, 1); + + memset(buf, 0xff, sizeof(buf)); + for (i = 0; i < SSD1351_YRES / 4; i++) + { + ssd1351_putrun(i, 0, (const uint8_t *)buf, SSD1351_XRES/2); + } + + return &priv->dev; +} + +#endif /* CONFIG_LCD_SSD1351 */ diff --git a/include/nuttx/lcd/ssd1351.h b/include/nuttx/lcd/ssd1351.h new file mode 100644 index 0000000000..37b0483a92 --- /dev/null +++ b/include/nuttx/lcd/ssd1351.h @@ -0,0 +1,139 @@ +/**************************************************************************** + * include/nuttx/lcd/ssd1351.h + * + * Copyright (C) 2015 Omni Hoverboards Inc. All rights reserved. + * Author: Paul Alexander Patience + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_LCD_SSD1351_H +#define __INCLUDE_NUTTX_LCD_SSD1351_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_LCD_SSD1351 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* SSD1351 configuration settings: + * CONFIG_SSD1351_SPI3WIRE - 3-wire SPI interface + * CONFIG_SSD1351_SPI4WIRE - 4-wire SPI interface + * CONFIG_SSD1351_SPIMODE - SPI mode + * CONFIG_SSD1351_SPIFREQ - SPI frequency + * CONFIG_SSD1351_NINTERFACES - number of physical devices supported + * CONFIG_SSD1351_XRES - X resolution + * CONFIG_SSD1351_YRES - Y resolution + * CONFIG_SSD1351_MIRRORX - mirror along the X axis + * CONFIG_SSD1351_MIRRORY - mirror along the Y axis + * CONFIG_SSD1351_INVERT - invert the display + * CONFIG_SSD1351_VDDEXT - external VDD + * CONFIG_SSD1351_TRST - reset period + * CONFIG_SSD1351_TPRECHG1 - first pre-charge period + * CONFIG_SSD1351_PERFENHANCE - enhace display performance + * CONFIG_SSD1351_CLKDIV - clock divider + * CONFIG_SSD1351_OSCFREQ - oscillator frequency + * CONFIG_SSD1351_TPRECHG2 - second pre-charge period + * CONFIG_SSD1351_VPRECHG - pre-charge voltage level + * CONFIG_SSD1351_VCOMH - COM deselect voltage level + * CONFIG_SSD1351_CONTRASTA - color A contrast + * CONFIG_SSD1351_CONTRASTB - color B contrast + * CONFIG_SSD1351_CONTRASTC - color C contrast + * CONFIG_SSD1351_MSTRCONTRAST - master contrast ratio + * + * Required LCD driver settings: + * CONFIG_LCD_SSD1351 - enables SSD1351 support + * CONFIG_LCD_MAXPOWER - maximum power, must be 1 + * + * Additional LCD driver settings: + * CONFIG_LCD_LANDSCAPE - landscape + * CONFIG_LCD_RLANDSCAPE - reverse landscape + * CONFIG_LCD_PORTRAIT - portrait + * CONFIG_LCD_RPORTRAIT - reverse portrait + * + * Required SPI driver settings: + * CONFIG_SPI - enables support for SPI + * CONFIG_SPI_CMDDATA - enables support for cmd/data selection + * (if using 4-wire SPI) + * + * NX settings that must be undefined: + * CONFIG_NX_DISABLE_16BPP - disables 16 bpp support + */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct spi_dev_s; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Name: ssd1351_initialize + * + * Description: + * Initialize the video hardware. The initial state of the device + * is fully initialized, display memory cleared, and ready to use, + * but with the power setting at 0 (full off == sleep mode). + * + * Input Parameters: + * spi - A reference to the SPI driver instance. + * devno - A value in the range of 0 through CONFIG_SSD1351_NINTERFACES-1. + * This allows support for multiple devices. + * + * Returned Value: + * On success, this function returns a reference to the LCD object for the + * specified device. NULL is returned on failure. + * + ****************************************************************************/ + +FAR struct lcd_dev_s *ssd1351_initialize(FAR struct spi_dev_s *spi, + unsigned int devno); + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_LCD_SSD1351 */ +#endif /* __INCLUDE_NUTTX_LCD_SSD1351_H */ From 726adbeb3f6703eae28dbdad2f91dfc7a3854632 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 28 Aug 2015 17:05:02 -0600 Subject: [PATCH 2/2] Update ChangeLog --- ChangeLog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index cc6e9cd57a..d848da89b0 100755 --- a/ChangeLog +++ b/ChangeLog @@ -10892,4 +10892,6 @@ and, as a result, incorrect data transfers can cause crashes. The fix is to lock into a single device once the MSS is locked locked down (2015-08-27). - + * drivers/lcd and include/nuttx/lcd: Add SSD1351 OLED controller + support. Contributed by Paul Alexander Patience (2015-08-28). + \ No newline at end of file