From ce00990e52808c5f8e2ceefd38f9eeb44bb96eab Mon Sep 17 00:00:00 2001 From: Kevin Townsend Date: Tue, 17 Jan 2012 20:14:11 +0100 Subject: [PATCH] First draft --- drivers/lcd/tft/hw/ssd1331.c | 466 +++++++++++++++++++++++++++++++++++ drivers/lcd/tft/hw/ssd1331.h | 110 +++++++++ 2 files changed, 576 insertions(+) create mode 100644 drivers/lcd/tft/hw/ssd1331.c create mode 100644 drivers/lcd/tft/hw/ssd1331.h diff --git a/drivers/lcd/tft/hw/ssd1331.c b/drivers/lcd/tft/hw/ssd1331.c new file mode 100644 index 0000000..ddc8694 --- /dev/null +++ b/drivers/lcd/tft/hw/ssd1331.c @@ -0,0 +1,466 @@ +/**************************************************************************/ +/*! + @file SSD1331.c + @author K. Townsend (microBuilder.eu) + + @section DESCRIPTION + + Driver for SSD1331 96x64 pixel RGB OLED displays. + + This driver uses a bit-banged SPI interface and 16-bit RGB565 colours. + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2010, microBuilder SARL + All rights reserved. + + 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 of the copyright holders 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 ''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 HOLDER 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. +*/ +/**************************************************************************/ +#include "ssd1331.h" +#include "core/systick/systick.h" + +static volatile lcdOrientation_t lcdOrientation = LCD_ORIENTATION_PORTRAIT; +static lcdProperties_t ssd1331Properties = { 96, 64, false, false, false }; + +/*************************************************/ +/* Private Methods */ +/*************************************************/ + +// You can speed all of these slow GPIO calls up by using the SET/CLR macros! + +#define CMD(c) do { gpioSetValue( SSD1331_CS_PORT, SSD1331_CS_PIN, 1 ); \ + gpioSetValue( SSD1331_DC_PORT, SSD1331_DC_PIN, 0 ); \ + gpioSetValue( SSD1331_CS_PORT, SSD1331_CS_PIN, 0 ); \ + ssd1331SendByte( c ); \ + gpioSetValue( SSD1331_CS_PORT, SSD1331_CS_PIN, 1 ); \ + } while (0); +#define DATA(c) do { gpioSetValue( SSD1331_CS_PORT, SSD1331_CS_PIN, 1 ); \ + gpioSetValue( SSD1331_DC_PORT, SSD1331_DC_PIN, 1 ); \ + gpioSetValue( SSD1331_CS_PORT, SSD1331_CS_PIN, 0 ); \ + ssd1331SendByte( c ); \ + gpioSetValue( SSD1331_CS_PORT, SSD1331_CS_PIN, 1 ); \ + } while (0); +#define DELAY(mS) do { systickDelay( mS / CFG_SYSTICK_DELAY_IN_MS ); } while(0); + +/**************************************************************************/ +/*! + @brief Simulates an SPI write using GPIO + + @param[in] byte + The byte to send +*/ +/**************************************************************************/ +void ssd1331SendByte(uint8_t byte) +{ + int8_t i; + + // Make sure clock pin starts high + gpioSetValue(SSD1331_SCK_PORT, SSD1331_SCK_PIN, 1); + + // Write from MSB to LSB + for (i=7; i>=0; i--) + { + // Set clock pin low + gpioSetValue(SSD1331_SCK_PORT, SSD1331_SCK_PIN, 0); + // Set data pin high or low depending on the value of the current bit + gpioSetValue(SSD1331_SID_PORT, SSD1331_SID_PIN, byte & (1 << i) ? 1 : 0); + // Set clock pin high + gpioSetValue(SSD1331_SCK_PORT, SSD1331_SCK_PIN, 1); + } +} + +/**************************************************************************/ +/*! + @brief Reads a 16-bit value from the 8-bit data bus +*/ +/**************************************************************************/ +uint16_t ssd1331ReadData(void) +{ + // ToDo + return 0; +} + +/**************************************************************************/ +/*! + @brief Reads a 16-bit value +*/ +/**************************************************************************/ +uint16_t ssd1331Read(uint16_t addr) +{ + // ToDo + return 0; +} + +/**************************************************************************/ +/*! + @brief Returns the 16-bit (4-hexdigit) controller code +*/ +/**************************************************************************/ +uint16_t ssd1331Type(void) +{ + // ToDo + return 0; +} + +/**************************************************************************/ +/*! + @brief Sets the cursor to the specified X/Y position +*/ +/**************************************************************************/ +void ssd1331SetCursor(uint8_t x, uint8_t y) +{ + if ((x >= ssd1331Properties.width) || (y >= ssd1331Properties.height)) + return; + // set x and y coordinate + CMD(SSD1331_CMD_SETCOLUMN); + CMD(x); + CMD(ssd1331Properties.width-1); + + CMD(SSD1331_CMD_SETROW); + CMD(y); + CMD(ssd1331Properties.height-1); +} + +/**************************************************************************/ +/*! + @brief Draws a solid line using HW acceleration +*/ +/**************************************************************************/ +void ssd1331DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t color) +{ + if ((x1 >= ssd1331Properties.width) || (x2 >= ssd1331Properties.width) || + (y1 >= ssd1331Properties.height) || (y2 >= ssd1331Properties.height)) { + return; + } + + CMD(SSD1331_CMD_DRAWLINE); + CMD(x1); + CMD(y1); + CMD(x2); + CMD(y2); + CMD((color >> 11) << 1); + CMD((color >> 5) & 0x3F); + CMD((color << 1)& 0x3F); +} + +/**************************************************************************/ +/*! + @brief Draws a filled rectangle using HW acceleration +*/ +/**************************************************************************/ +void ssd1331FillRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t pencolor, uint16_t fillcolor) +{ + if ((x1 >= ssd1331Properties.width) || (x2 >= ssd1331Properties.width) || + (y1 >= ssd1331Properties.height) || (y2 >= ssd1331Properties.height)) { + return; + } + + // fill! + CMD(SSD1331_CMD_FILL); + CMD(0x01); + + CMD(SSD1331_CMD_DRAWRECT); + CMD(x1); + CMD(y1); + CMD(x2); + CMD(y2); + CMD((pencolor >> 11) << 1); + CMD((pencolor >> 5) & 0x3F); + CMD((pencolor << 1)& 0x3F); + + CMD((fillcolor >> 11) << 1); + CMD((fillcolor >> 5) & 0x3F); + CMD((fillcolor << 1)& 0x3F); +} + +/**************************************************************************/ +/*! + @brief Inverts the R and B in an RGB565 color +*/ +/**************************************************************************/ +uint16_t invert565Color(uint16_t color) +{ + uint16_t r, g, b; + + b = (color>>0) & 0x1f; + g = (color>>5) & 0x3f; + r = (color>>11) & 0x1f; + + return( (b<<11) + (g<<5) + (r<<0) ); +} + +/*************************************************/ +/* Public Methods */ +/*************************************************/ + +/**************************************************************************/ +/*! + @brief Configures any pins or HW and initialises the LCD controller +*/ +/**************************************************************************/ +void lcdInit(void) +{ + // Set all pins to output + gpioSetDir(SSD1331_SCK_PORT, SSD1331_SCK_PIN, gpioDirection_Output); + gpioSetDir(SSD1331_SID_PORT, SSD1331_SID_PIN, gpioDirection_Output); + gpioSetDir(SSD1331_DC_PORT, SSD1331_DC_PIN, gpioDirection_Output); + gpioSetDir(SSD1331_RST_PORT, SSD1331_RST_PIN, gpioDirection_Output); + gpioSetDir(SSD1331_CS_PORT, SSD1331_CS_PIN, gpioDirection_Output); + + // Reset the LCD + SET_RST; + DELAY(1); + CLR_RST; + DELAY(10); + SET_RST; + + // Disable pullups + SSD1331_DISABLEPULLUPS(); + + CMD(SSD1331_CMD_DISPLAYOFF); // 0xAE + CMD(SSD1331_CMD_SETREMAP); // 0xA0 + CMD(0x76); // 0x74 + CMD(SSD1331_CMD_STARTLINE); // 0xA1 + CMD(0x0); + CMD(SSD1331_CMD_DISPLAYOFFSET); // 0xA2 + CMD(0x0); + CMD(SSD1331_CMD_NORMALDISPLAY); // 0xA4 + CMD(SSD1331_CMD_SETMULTIPLEX); // 0xA8 + CMD(0x3F); // 0x3F 1/64 duty + CMD(SSD1331_CMD_SETMASTER); // 0xAD + CMD(0x8E); + CMD(SSD1331_CMD_POWERMODE); // 0xB0 + CMD(0x0B); + CMD(SSD1331_CMD_PRECHARGE); // 0xB1 + CMD(0x31); + CMD(SSD1331_CMD_CLOCKDIV); // 0xB3 + CMD(0xF0); // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16) + CMD(SSD1331_CMD_PRECHARGEA); // 0x8A + CMD(0x64); + CMD(SSD1331_CMD_PRECHARGEB); // 0x8B + CMD(0x78); + CMD(SSD1331_CMD_PRECHARGEA); // 0x8C + CMD(0x64); + CMD(SSD1331_CMD_PRECHARGELEVEL); // 0xBB + CMD(0x3A); + CMD(SSD1331_CMD_VCOMH); // 0xBE + CMD(0x3E); + CMD(SSD1331_CMD_MASTERCURRENT); // 0x87 + CMD(0x06); + CMD(SSD1331_CMD_CONTRASTA); // 0x81 + CMD(0x91); + CMD(SSD1331_CMD_CONTRASTB); // 0x82 + CMD(0x50); + CMD(SSD1331_CMD_CONTRASTC); // 0x83 + CMD(0x7D); + CMD(SSD1331_CMD_DISPLAYON);//--turn on oled panel + + // Fill black + lcdFillRGB(COLOR_BLACK); +} + +/**************************************************************************/ +/*! + @brief Enables or disables the LCD backlight +*/ +/**************************************************************************/ +void lcdBacklight(bool state) +{ + // No backlight ... do nothing +} + +/**************************************************************************/ +/*! + @brief Renders a simple test pattern on the LCD +*/ +/**************************************************************************/ +void lcdTest(void) +{ + uint32_t i,j; + ssd1331SetCursor(0, 0); + + for(i=0;i<64;i++) + { + for(j=0;j<96;j++) + { + if(i>55){DATA(invert565Color(COLOR_WHITE)>>8);DATA(invert565Color(COLOR_WHITE));} + else if(i>47){DATA(invert565Color(COLOR_BLUE)>>8);DATA(invert565Color(COLOR_BLUE));} + else if(i>39){DATA(invert565Color(COLOR_GREEN)>>8);DATA(invert565Color(COLOR_GREEN));} + else if(i>31){DATA(invert565Color(COLOR_CYAN)>>8);DATA(invert565Color(COLOR_CYAN));} + else if(i>23){DATA(invert565Color(COLOR_RED)>>8);DATA(invert565Color(COLOR_RED));} + else if(i>15){DATA(invert565Color(COLOR_MAGENTA)>>8);DATA(invert565Color(COLOR_MAGENTA));} + else if(i>7){DATA(invert565Color(COLOR_YELLOW)>>8);DATA(invert565Color(COLOR_YELLOW));} + else {DATA(invert565Color(COLOR_BLACK)>>8);DATA(invert565Color(COLOR_BLACK));} + } + } +} + +/**************************************************************************/ +/*! + @brief Fills the LCD with the specified 16-bit color +*/ +/**************************************************************************/ +void lcdFillRGB(uint16_t data) +{ + data = invert565Color(data); + ssd1331FillRect(0,0,ssd1331Properties.width-1,ssd1331Properties.height-1, data, data); +} + +/**************************************************************************/ +/*! + @brief Draws a single pixel at the specified X/Y location +*/ +/**************************************************************************/ +void lcdDrawPixel(uint16_t x, uint16_t y, uint16_t color) +{ + if ((x >= ssd1331Properties.width) || (y >= ssd1331Properties.height)) + return; + + ssd1331SetCursor((uint8_t)x, (uint8_t)y); + color = invert565Color(color); + DATA(color >> 8); + DATA(color); +} + +/**************************************************************************/ +/*! + @brief Draws an array of consecutive RGB565 pixels (much + faster than addressing each pixel individually) +*/ +/**************************************************************************/ +void lcdDrawPixels(uint16_t x, uint16_t y, uint16_t *data, uint32_t len) +{ + // ToDo +} + +/**************************************************************************/ +/*! + @brief Optimised routine to draw a horizontal line faster than + setting individual pixels +*/ +/**************************************************************************/ +void lcdDrawHLine(uint16_t x0, uint16_t x1, uint16_t y, uint16_t color) +{ + color = invert565Color(color); + ssd1331DrawLine((uint8_t)x0, (uint8_t)y, (uint8_t)x1, (uint8_t)y, color); +} + +/**************************************************************************/ +/*! + @brief Optimised routine to draw a vertical line faster than + setting individual pixels +*/ +/**************************************************************************/ +void lcdDrawVLine(uint16_t x, uint16_t y0, uint16_t y1, uint16_t color) +{ + color = invert565Color(color); + ssd1331DrawLine((uint8_t)x, (uint8_t)y0, (uint8_t)x, (uint8_t)y1, color); +} + +/**************************************************************************/ +/*! + @brief Gets the 16-bit color of the pixel at the specified location +*/ +/**************************************************************************/ +uint16_t lcdGetPixel(uint16_t x, uint16_t y) +{ + // ToDo + return 0; +} + +/**************************************************************************/ +/*! + @brief Sets the LCD orientation to horizontal and vertical +*/ +/**************************************************************************/ +void lcdSetOrientation(lcdOrientation_t orientation) +{ + // Not supported +} + +/**************************************************************************/ +/*! + @brief Gets the current screen orientation (horizontal or vertical) +*/ +/**************************************************************************/ +lcdOrientation_t lcdGetOrientation(void) +{ + return lcdOrientation; +} + +/**************************************************************************/ +/*! + @brief Gets the width in pixels of the LCD screen (varies depending + on the current screen orientation) +*/ +/**************************************************************************/ +uint16_t lcdGetWidth(void) +{ + return ssd1331Properties.width; +} + +/**************************************************************************/ +/*! + @brief Gets the height in pixels of the LCD screen (varies depending + on the current screen orientation) +*/ +/**************************************************************************/ +uint16_t lcdGetHeight(void) +{ + return ssd1331Properties.height; +} + +/**************************************************************************/ +/*! + @brief Scrolls the contents of the LCD screen vertically the + specified number of pixels using a HW optimised routine +*/ +/**************************************************************************/ +void lcdScroll(int16_t pixels, uint16_t fillColor) +{ + // ToDo +} + +/**************************************************************************/ +/*! + @brief Gets the controller's 16-bit (4 hexdigit) ID +*/ +/**************************************************************************/ +uint16_t lcdGetControllerID(void) +{ + return ssd1331Type(); +} + +/**************************************************************************/ +/*! + @brief Returns the LCDs 'lcdProperties_t' that describes the LCDs + generic capabilities and dimensions +*/ +/**************************************************************************/ +lcdProperties_t lcdGetProperties(void) +{ + return ssd1331Properties; +} diff --git a/drivers/lcd/tft/hw/ssd1331.h b/drivers/lcd/tft/hw/ssd1331.h new file mode 100644 index 0000000..ff0931a --- /dev/null +++ b/drivers/lcd/tft/hw/ssd1331.h @@ -0,0 +1,110 @@ +/**************************************************************************/ +/*! + @file ssd1331.h + @author K. Townsend (microBuilder.eu) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2010, microBuilder SARL + All rights reserved. + + 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 of the copyright holders 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 ''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 HOLDER 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 __SSD1331_H__ +#define __SSD1331_H__ + +#include "projectconfig.h" + +#include "drivers/lcd/tft/lcd.h" +#include "core/gpio/gpio.h" + +// Control pins +#define SSD1331_SID_PORT 2 // DAT +#define SSD1331_SID_PIN 1 +#define SSD1331_SCK_PORT 2 // SCK +#define SSD1331_SCK_PIN 2 +#define SSD1331_DC_PORT 2 // D/C +#define SSD1331_DC_PIN 3 +#define SSD1331_RST_PORT 2 // RST +#define SSD1331_RST_PIN 4 +#define SSD1331_CS_PORT 2 // OLEDCS +#define SSD1331_CS_PIN 5 + +// Placed here to try to keep all pin specific values in header file +#define SSD1331_DISABLEPULLUPS() do { gpioSetPullup(&IOCON_PIO2_1, gpioPullupMode_Inactive); \ + gpioSetPullup(&IOCON_PIO2_2, gpioPullupMode_Inactive); \ + gpioSetPullup(&IOCON_PIO2_3, gpioPullupMode_Inactive); \ + gpioSetPullup(&IOCON_PIO2_4, gpioPullupMode_Inactive); \ + gpioSetPullup(&IOCON_PIO2_5, gpioPullupMode_Inactive); } while (0) + +// These registers allow fast single operation clear+set of bits (see section 8.5.1 of LPC1343 UM) +#define SSD1331_GPIO2DATA_SID (*(pREG32 (GPIO_GPIO2_BASE + ((1 << SSD1331_SID_PIN) << 2)))) +#define SSD1331_GPIO2DATA_SCK (*(pREG32 (GPIO_GPIO2_BASE + ((1 << SSD1331_SCK_PIN) << 2)))) +#define SSD1331_GPIO2DATA_DC (*(pREG32 (GPIO_GPIO2_BASE + ((1 << SSD1331_DC_PIN) << 2)))) +#define SSD1331_GPIO2DATA_RST (*(pREG32 (GPIO_GPIO2_BASE + ((1 << SSD1331_RST_PIN) << 2)))) +#define SSD1331_GPIO2DATA_CS (*(pREG32 (GPIO_GPIO2_BASE + ((1 << SSD1331_CS_PIN) << 2)))) + +// Macros for control line state +#define CLR_DC SSD1331_GPIO2DATA_DC = (0) +#define SET_DC SSD1331_GPIO2DATA_DC = (1 << SSD1331_DC_PIN) +#define CLR_RST SSD1331_GPIO2DATA_RST = (0) +#define SET_RST SSD1331_GPIO2DATA_RST = (1 << SSD1331_RST_PIN) +#define CLR_CS SSD1331_GPIO2DATA_CS = (0) +#define SET_CS SSD1331_GPIO2DATA_CS = (1 << SSD1331_CS_PIN) + +enum +{ + SSD1331_CMD_DRAWLINE = 0x21, + SSD1331_CMD_DRAWRECT = 0x22, + SSD1331_CMD_FILL = 0x26, + SSD1331_CMD_SETCOLUMN = 0x15, + SSD1331_CMD_SETROW = 0x75, + SSD1331_CMD_CONTRASTA = 0x81, + SSD1331_CMD_CONTRASTB = 0x82, + SSD1331_CMD_CONTRASTC = 0x83, + SSD1331_CMD_MASTERCURRENT = 0x87, + SSD1331_CMD_SETREMAP = 0xA0, + SSD1331_CMD_STARTLINE = 0xA1, + SSD1331_CMD_DISPLAYOFFSET = 0xA2, + SSD1331_CMD_NORMALDISPLAY = 0xA4, + SSD1331_CMD_DISPLAYALLON = 0xA5, + SSD1331_CMD_DISPLAYALLOFF = 0xA6, + SSD1331_CMD_INVERTDISPLAY = 0xA7, + SSD1331_CMD_SETMULTIPLEX = 0xA8, + SSD1331_CMD_SETMASTER = 0xAD, + SSD1331_CMD_DISPLAYOFF = 0xAE, + SSD1331_CMD_DISPLAYON = 0xAF, + SSD1331_CMD_POWERMODE = 0xB0, + SSD1331_CMD_PRECHARGE = 0xB1, + SSD1331_CMD_CLOCKDIV = 0xB3, + SSD1331_CMD_PRECHARGEA = 0x8A, + SSD1331_CMD_PRECHARGEB = 0x8B, + SSD1331_CMD_PRECHARGEC = 0x8C, + SSD1331_CMD_PRECHARGELEVEL = 0xBB, + SSD1331_CMD_VCOMH = 0xBE +}; + +#endif -- 2.20.1