diff --git a/configs/sam4l-xplained/src/sam_ug2832hsweg04.c b/configs/sam4l-xplained/src/sam_ug2832hsweg04.c index a99aacc987..ccdc29842c 100644 --- a/configs/sam4l-xplained/src/sam_ug2832hsweg04.c +++ b/configs/sam4l-xplained/src/sam_ug2832hsweg04.c @@ -153,7 +153,7 @@ FAR struct lcd_dev_s *board_graphics_setup(unsigned int devno) { /* Bind the SPI port to the OLED */ - dev = ssd1306_initialize(spi, devno); + dev = ssd1306_initialize(spi, NULL, devno); if (!dev) { lcderr("ERROR: Failed to bind SPI port 1 to OLED %d: %d\n", devno); diff --git a/configs/samd20-xplained/src/sam_ug2832hsweg04.c b/configs/samd20-xplained/src/sam_ug2832hsweg04.c index 33755c18ad..982b4ca213 100644 --- a/configs/samd20-xplained/src/sam_ug2832hsweg04.c +++ b/configs/samd20-xplained/src/sam_ug2832hsweg04.c @@ -183,7 +183,7 @@ FAR struct lcd_dev_s *board_graphics_setup(unsigned int devno) { /* Bind the SPI port to the OLED */ - dev = ssd1306_initialize(spi, devno); + dev = ssd1306_initialize(spi, NULL, devno); if (!dev) { lcderr("ERROR: Failed to bind SPI port 1 to OLED %d: %d\n", devno); diff --git a/configs/samd21-xplained/src/sam_ug2832hsweg04.c b/configs/samd21-xplained/src/sam_ug2832hsweg04.c index 3414df2c28..2b49b5e4a9 100644 --- a/configs/samd21-xplained/src/sam_ug2832hsweg04.c +++ b/configs/samd21-xplained/src/sam_ug2832hsweg04.c @@ -183,7 +183,7 @@ FAR struct lcd_dev_s *board_graphics_setup(unsigned int devno) { /* Bind the SPI port to the OLED */ - dev = ssd1306_initialize(spi, devno); + dev = ssd1306_initialize(spi, NULL, devno); if (!dev) { lcderr("ERROR: Failed to bind SPI port 1 to OLED %d: %d\n", devno); diff --git a/configs/saml21-xplained/src/sam_ug2832hsweg04.c b/configs/saml21-xplained/src/sam_ug2832hsweg04.c index 0cbdb6f795..acc901afd1 100644 --- a/configs/saml21-xplained/src/sam_ug2832hsweg04.c +++ b/configs/saml21-xplained/src/sam_ug2832hsweg04.c @@ -183,7 +183,7 @@ FAR struct lcd_dev_s *board_graphics_setup(unsigned int devno) { /* Bind the SPI port to the OLED */ - dev = ssd1306_initialize(spi, devno); + dev = ssd1306_initialize(spi, NULL, devno); if (!dev) { lcderr("ERROR: Failed to bind SPI port 1 to OLED %d: %d\n", devno); diff --git a/configs/stm32f4discovery/src/stm32_ug2864hsweg01.c b/configs/stm32f4discovery/src/stm32_ug2864hsweg01.c index 3723f3ecbc..024c909418 100644 --- a/configs/stm32f4discovery/src/stm32_ug2864hsweg01.c +++ b/configs/stm32f4discovery/src/stm32_ug2864hsweg01.c @@ -132,7 +132,7 @@ FAR struct lcd_dev_s *board_graphics_setup(unsigned int devno) { /* Bind the SPI port to the OLED */ - dev = ssd1306_initialize(spi, devno); + dev = ssd1306_initialize(spi, NULL, devno); if (!dev) { lcderr("ERROR: Failed to bind SPI port 1 to OLED %d: %d\n", devno); diff --git a/drivers/lcd/ssd1306.h b/drivers/lcd/ssd1306.h index a873bf2e0a..415f0cf949 100644 --- a/drivers/lcd/ssd1306.h +++ b/drivers/lcd/ssd1306.h @@ -280,6 +280,9 @@ struct ssd1306_dev_s #endif uint8_t contrast; /* Current contrast setting */ bool on; /* true: display is on */ + bool is_conf; /* true: display had been configured */ + + FAR const struct ssd1306_priv_s *board_priv; /* Board specific structure */ /* The SSD1306 does not support reading from the display memory in SPI mode. * Since there is 1 BPP and access is byte-by-byte, it is necessary to keep diff --git a/drivers/lcd/ssd1306_base.c b/drivers/lcd/ssd1306_base.c index 0062347bb7..0c4a0a0cd4 100644 --- a/drivers/lcd/ssd1306_base.c +++ b/drivers/lcd/ssd1306_base.c @@ -180,6 +180,10 @@ static int ssd1306_setpower(struct lcd_dev_s *dev, int power); static int ssd1306_getcontrast(struct lcd_dev_s *dev); static int ssd1306_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); +static void ssd1306_do_disponoff(struct ssd1306_dev_s *priv, bool on); +static void ssd1306_configuredisplay(struct ssd1306_dev_s *priv); +static void ssd1306_redrawfb(struct ssd1306_dev_s *priv); + /************************************************************************************** * Private Data **************************************************************************************/ @@ -669,6 +673,34 @@ static int ssd1306_getpower(FAR struct lcd_dev_s *dev) return priv->on ? CONFIG_LCD_MAXPOWER : 0; } + /************************************************************************************** + * Name: ssd1306_do_disponoff + * + * Description: + * Enable/disable LCD panel power + * + **************************************************************************************/ + +static void ssd1306_do_disponoff(struct ssd1306_dev_s *priv, bool on) +{ + /* Lock and select device */ + + ssd1306_select(priv, true); + + /* Select command transfer */ + + ssd1306_cmddata(priv, true); + + /* Turn the display on/off */ + + (void)ssd1306_sendbyte(priv, (on ? SSD1306_DISPON : SSD1306_DISPOFF)); + + /* De-select and unlock the device */ + + ssd1306_cmddata(priv, false); + ssd1306_select(priv, false); +} + /************************************************************************************** * Name: ssd1306_setpower * @@ -685,28 +717,56 @@ static int ssd1306_setpower(FAR struct lcd_dev_s *dev, int power) lcdinfo("power: %d [%d]\n", power, priv->on ? CONFIG_LCD_MAXPOWER : 0); - /* Lock and select device */ - - ssd1306_select(priv, true); - if (power <= 0) { /* Turn the display off */ - (void)ssd1306_sendbyte(priv, SSD1306_DISPOFF); + ssd1306_do_disponoff(priv, false); priv->on = false; + + /* Try turn off power completely */ + + if (priv->board_priv && priv->board_priv->set_vcc) + { + /* Do power off. */ + + if (priv->board_priv->set_vcc(false)) + { + /* Display is completely powered off, not configured anymore. */ + + priv->is_conf = false; + } + } } else { - /* Turn the display on */ + if (priv->board_priv && priv->board_priv->set_vcc) + { + /* Do power on. */ + + (void)priv->board_priv->set_vcc(true); + } + + if (!priv->is_conf) + { + /* Configure display and turn the display on */ + + ssd1306_configuredisplay(priv); + + /* Draw the framebuffer */ + + ssd1306_redrawfb(priv); + } + else + { + /* Turn the display on */ + + ssd1306_do_disponoff(priv, true); + } - (void)ssd1306_sendbyte(priv, SSD1306_DISPON); priv->on = true; } - /* De-select and unlock the device */ - - ssd1306_select(priv, false); return OK; } @@ -783,55 +843,15 @@ static int ssd1306_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) } /************************************************************************************** - * Public Functions - **************************************************************************************/ - -/************************************************************************************** - * Name: ssd1306_initialize + * Name: ssd1306_configuredisplay * * Description: - * Initialize the UG-2864HSWEG01 video hardware. The initial state of the - * OLED is fully initialized, display memory cleared, and the OLED 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_SSD1306_NINTERFACES-1. - * This allows support for multiple OLED devices. - * - * Returned Value: - * - * On success, this function returns a reference to the LCD object for - * the specified OLED. NULL is returned on any failure. + * Setup LCD display. * **************************************************************************************/ -#ifdef CONFIG_LCD_SSD1306_SPI -FAR struct lcd_dev_s *ssd1306_initialize(FAR struct spi_dev_s *dev, unsigned int devno) -#else -FAR struct lcd_dev_s *ssd1306_initialize(FAR struct i2c_master_s *dev, unsigned int devno) -#endif +static void ssd1306_configuredisplay(struct ssd1306_dev_s *priv) { - FAR struct ssd1306_dev_s *priv = &g_oleddev; - - lcdinfo("Initializing\n"); - DEBUGASSERT(dev && devno == 0); - -#ifdef CONFIG_LCD_SSD1306_SPI - priv->spi = dev; - - /* Configure the SPI */ - - ssd1306_configspi(priv->spi); - -#else - /* Remember the I2C configuration */ - - priv->i2c = dev; - priv->addr = CONFIG_SSD1306_I2CADDR; -#endif - /* Lock and select device */ ssd1306_select(priv, true); @@ -921,19 +941,16 @@ FAR struct lcd_dev_s *ssd1306_initialize(FAR struct i2c_master_s *dev, unsigned ssd1306_select(priv, false); - /* Clear the display */ - up_mdelay(100); - ssd1306_fill(&priv->dev, CONFIG_NX_BGCOLOR); - return &priv->dev; + + priv->is_conf = true; } /************************************************************************************** - * Name: ssd1306_fill + * Name: ssd1306_redrawfb * * Description: - * This non-standard method can be used to clear the entire display by writing one - * color to the display. This is much faster than writing a series of runs. + * Redraw full framebuffer to display * * Input Parameters: * priv - Reference to private driver structure @@ -943,26 +960,10 @@ FAR struct lcd_dev_s *ssd1306_initialize(FAR struct i2c_master_s *dev, unsigned * **************************************************************************************/ -void ssd1306_fill(FAR struct lcd_dev_s *dev, uint8_t color) +static void ssd1306_redrawfb(struct ssd1306_dev_s *priv) { - FAR struct ssd1306_dev_s *priv = &g_oleddev; unsigned int page; - /* Make an 8-bit version of the selected color */ - - if (color & 1) - { - color = 0xff; - } - else - { - color = 0; - } - - /* Initialize the framebuffer */ - - memset(priv->fb, color, SSD1306_DEV_FBSIZE); - /* Lock and select device */ ssd1306_select(priv, true); @@ -999,4 +1000,114 @@ void ssd1306_fill(FAR struct lcd_dev_s *dev, uint8_t color) ssd1306_select(priv, false); } +/************************************************************************************** + * Public Functions + **************************************************************************************/ + +/************************************************************************************** + * Name: ssd1306_initialize + * + * Description: + * Initialize the UG-2864HSWEG01 video hardware. The initial state of the + * OLED is fully initialized, display memory cleared, and the OLED 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_SSD1306_NINTERFACES-1. + * This allows support for multiple OLED devices. + * + * Returned Value: + * + * On success, this function returns a reference to the LCD object for + * the specified OLED. NULL is returned on any failure. + * + **************************************************************************************/ + +#ifdef CONFIG_LCD_SSD1306_SPI +FAR struct lcd_dev_s *ssd1306_initialize(FAR struct spi_dev_s *dev, + FAR const struct ssd1306_priv_s *board_priv, + unsigned int devno) +#else +FAR struct lcd_dev_s *ssd1306_initialize(FAR struct i2c_master_s *dev, + FAR const struct ssd1306_priv_s *board_priv, + unsigned int devno) +#endif +{ + FAR struct ssd1306_dev_s *priv = &g_oleddev; + + DEBUGASSERT(dev && devno == 0); + + priv->on = false; + priv->is_conf = false; + + /* Register board specific functions */ + + priv->board_priv = board_priv; + +#ifdef CONFIG_LCD_SSD1306_SPI + priv->spi = dev; + + /* Configure the SPI */ + + ssd1306_configspi(priv->spi); + +#else + /* Remember the I2C configuration */ + + priv->i2c = dev; + priv->addr = CONFIG_SSD1306_I2CADDR; +#endif + + /* Initialize the framebuffer */ + + memset(priv->fb, SSD1306_Y1_BLACK & 1 ? 0xff : 0x00, SSD1306_DEV_FBSIZE); + + /* Power on and configure display */ + + ssd1306_setpower(&priv->dev, true); + + return &priv->dev; +} + +/************************************************************************************** + * Name: ssd1306_fill + * + * Description: + * This non-standard method can be used to clear the entire display by writing one + * color to the display. This is much faster than writing a series of runs. + * + * Input Parameters: + * priv - Reference to private driver structure + * + * Assumptions: + * Caller has selected the OLED section. + * + **************************************************************************************/ + +void ssd1306_fill(FAR struct lcd_dev_s *dev, uint8_t color) +{ + FAR struct ssd1306_dev_s *priv = (struct ssd1306_dev_s *)dev; + + /* Make an 8-bit version of the selected color */ + + if (color & 1) + { + color = 0xff; + } + else + { + color = 0; + } + + /* Initialize the framebuffer */ + + memset(priv->fb, color, SSD1306_DEV_FBSIZE); + + /* Draw the framebuffer */ + + ssd1306_redrawfb(priv); +} + #endif /* CONFIG_LCD_SSD1306 */ diff --git a/include/nuttx/lcd/ssd1306.h b/include/nuttx/lcd/ssd1306.h index ed4195e78b..fa1117828d 100644 --- a/include/nuttx/lcd/ssd1306.h +++ b/include/nuttx/lcd/ssd1306.h @@ -1,8 +1,9 @@ /************************************************************************************** - * include/nuttx/lcd/ug-2864hsweg01.h + * include/nuttx/lcd/ssd1306.h * * Driver for Univision UG-2864HSWEG01 OLED display or UG-2832HSWEG04 both with the - * Univision SSD1306 controller in SPI mode + * Univision SSD1306 controller in SPI mode and Densitron DD-12864WO-4A with SSD1309 + * in SPI mode. * * Copyright (C) 2012-2013, 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -14,6 +15,8 @@ * Doc No.: SAS1-B020-B, Univision Technology Inc. * 3. SSD1306, 128 X 64 Dot Matrix OLED/PLED, Preliminary Segment/Common Driver with * Controller, Solomon Systech + * 4. SSD1309, 128 x 64 Dot Matrix OLED/PLED Segment/Common Driver with Controller, + * Solomon Systech * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -200,6 +203,12 @@ * Public Types **************************************************************************************/ +struct ssd1306_priv_s +{ + bool (*set_vcc) (bool on); /* Allow board to control display power. Return true if + request state set successfully. */ +}; + /************************************************************************************** * Public Data **************************************************************************************/ @@ -224,6 +233,7 @@ extern "C" * Input Parameters: * * dev - A reference to the SPI/I2C driver instance. + * board_priv - Board specific structure. * devno - A value in the range of 0 through CONFIG_UG2864HSWEG01_NINTERFACES-1. * This allows support for multiple OLED devices. * @@ -237,9 +247,13 @@ extern "C" struct lcd_dev_s; /* See include/nuttx/lcd/lcd.h */ struct spi_dev_s; /* See include/nuttx/spi/spi.h */ #ifdef CONFIG_LCD_SSD1306_SPI -FAR struct lcd_dev_s *ssd1306_initialize(FAR struct spi_dev_s *dev, unsigned int devno); +FAR struct lcd_dev_s *ssd1306_initialize(FAR struct spi_dev_s *dev, + FAR const struct ssd1306_priv_s *board_priv, + unsigned int devno); #else -FAR struct lcd_dev_s *ssd1306_initialize(FAR struct i2c_master_s *dev, unsigned int devno); +FAR struct lcd_dev_s *ssd1306_initialize(FAR struct i2c_master_s *dev, + FAR const struct ssd1306_priv_s *board_priv, + unsigned int devno); #endif /************************************************************************************************