522 lines
16 KiB
C
522 lines
16 KiB
C
|
/***************************************************************************//**
|
||
|
* @file
|
||
|
* @brief Dot matrix display Direct Driver for TFT SSD2119 "Generic" mode
|
||
|
* @author Energy Micro AS
|
||
|
* @version 1.2.2
|
||
|
*******************************************************************************
|
||
|
* @section License
|
||
|
* <b>(C) Copyright 2010 Energy Micro AS, http://www.energymicro.com</b>
|
||
|
*******************************************************************************
|
||
|
*
|
||
|
* This source code is the property of Energy Micro AS. The source and compiled
|
||
|
* code may only be used on Energy Micro "EFM32" microcontrollers.
|
||
|
*
|
||
|
* This copyright notice may not be removed from the source code nor changed.
|
||
|
*
|
||
|
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||
|
* obligation to support this Software. Energy Micro AS is providing the
|
||
|
* Software "AS IS", with no express or implied warranties of any kind,
|
||
|
* including, but not limited to, any implied warranties of merchantability
|
||
|
* or fitness for any particular purpose or warranties against infringement
|
||
|
* of any proprietary rights of a third party.
|
||
|
*
|
||
|
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||
|
* special damages, or any other relief, or for any claim by any third party,
|
||
|
* arising from your use of this Software.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
#include <stdint.h>
|
||
|
#include "graphics/em_types.h"
|
||
|
#include "dmd_ssd2119_registers.h"
|
||
|
#include "dmd_ssd2119.h"
|
||
|
#include "efm32.h"
|
||
|
#include "efm32_usart.h"
|
||
|
#include "efm32_cmu.h"
|
||
|
#include "efm32_gpio.h"
|
||
|
#include "tftspi.h"
|
||
|
|
||
|
/** Dimensions of the display */
|
||
|
DMD_DisplayGeometry dimensions =
|
||
|
{
|
||
|
.xSize = 320,
|
||
|
.ySize = 240,
|
||
|
.xClipStart = 0,
|
||
|
.yClipStart = 0,
|
||
|
.clipWidth = 320,
|
||
|
.clipHeight = 240,
|
||
|
};
|
||
|
|
||
|
/** FramePointer base address */
|
||
|
static volatile uint16_t *frameBuffer;
|
||
|
|
||
|
/* Local variables */
|
||
|
static uint32_t initialized = 0;
|
||
|
static uint16_t rcDriverOutputControl = 0;
|
||
|
|
||
|
/* Local function prototypes */
|
||
|
static uint16_t colorTransform24ToRGB565(uint8_t red, uint8_t green, uint8_t blue);
|
||
|
|
||
|
#if 0
|
||
|
static void colorTransformRGB565To24bpp(uint16_t color, uint8_t *red, uint8_t *green, uint8_t *blue);
|
||
|
#endif
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Transforms a 24bpp pixel data into an RGB565 pixel
|
||
|
*
|
||
|
* @param red
|
||
|
* 8-bit red component of the pixel
|
||
|
* @param green
|
||
|
* 8-bit green component of the pixel
|
||
|
* @param blue
|
||
|
* 8-bit blue component of the pixel
|
||
|
* @return
|
||
|
* 16-bit RGB565 value of pixel
|
||
|
******************************************************************************/
|
||
|
static uint16_t colorTransform24ToRGB565(uint8_t red, uint8_t green, uint8_t blue)
|
||
|
{
|
||
|
/* Transform each color into 6 bits by dropping the 2 LSB */
|
||
|
red = red >> 3;
|
||
|
green = green >> 2;
|
||
|
blue = blue >> 3;
|
||
|
|
||
|
/* Put it together to one 18bpp color number */
|
||
|
return (red << 11) | (green << 5) | blue;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Transforms an 16-bit RGB565 pixel into a 24bpp pixel
|
||
|
*
|
||
|
* @param[in] color
|
||
|
* RGB565 16-bit color pixel
|
||
|
* @param red
|
||
|
* return value for red component of 24bpp pixel
|
||
|
* @param green
|
||
|
* return value for green component of 24bpp pixel
|
||
|
* @param blue
|
||
|
* return value for blue component of 24bpp pixel
|
||
|
******************************************************************************/
|
||
|
#if 0
|
||
|
static void colorTransformRGB565To24bpp(uint16_t color, uint8_t *red,
|
||
|
uint8_t *green, uint8_t *blue)
|
||
|
{
|
||
|
/* Get the individual colors out of the 18bpp number */
|
||
|
uint8_t redValue = (color & 0x0003F000) >> 12;
|
||
|
uint8_t greenValue = (color & 0x00000FC0) >> 6;
|
||
|
uint8_t blueValue = (color & 0x0000003F);
|
||
|
|
||
|
/* Convert each color to 8-bit */
|
||
|
redValue <<= 2;
|
||
|
greenValue <<= 2;
|
||
|
blueValue <<= 2;
|
||
|
|
||
|
*red = redValue;
|
||
|
*green = greenValue;
|
||
|
*blue = blueValue;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Writes a value to a control register in the LCD controller
|
||
|
*
|
||
|
* @param reg
|
||
|
* The register that will be written to
|
||
|
* @param data
|
||
|
* The value to write to the register
|
||
|
*
|
||
|
* @return
|
||
|
* DMD_OK on success, otherwise error code
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMDIF_writeReg(uint8_t reg, uint16_t data)
|
||
|
{
|
||
|
SPI_TFT_WriteRegister(reg, data);
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Initializes the LCD display
|
||
|
*
|
||
|
* @param cmdRegAddr
|
||
|
* If set to 0, initialize SSD2119 for direct drive, if set to 1 update
|
||
|
* frame buffer base pointer (offset to EBI bank) only
|
||
|
* @param dataRegAddr
|
||
|
* Address in memory for frame buffer base pointer
|
||
|
*
|
||
|
* @return
|
||
|
* DMD_OK on success, otherwise error code
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMD_init(uint32_t cmdRegAddr, uint32_t dataRegAddr)
|
||
|
{
|
||
|
uint16_t data;
|
||
|
volatile uint32_t i;
|
||
|
(void) cmdRegAddr;
|
||
|
(void) dataRegAddr;
|
||
|
|
||
|
/* Use data reg addr as pointer to frame buffer */
|
||
|
frameBuffer = (uint16_t *) dataRegAddr;
|
||
|
|
||
|
if(cmdRegAddr==1) return DMD_OK;
|
||
|
|
||
|
SPI_TFT_Init();
|
||
|
|
||
|
DMDIF_writeReg(DMD_SSD2119_VCOM_OTP_1, 0x0006);
|
||
|
|
||
|
/* Oscillation driven DCLK */
|
||
|
#if 0
|
||
|
data = DMD_SSD2119_OSCILLATION_START_OSCEN;
|
||
|
DMDIF_writeReg(DMD_SSD2119_OSCILLATION_START, data);
|
||
|
#endif
|
||
|
|
||
|
/* Display control */
|
||
|
data = 0;
|
||
|
// data |= DMD_SSD2119_DISPLAY_CONTROL_DTE;
|
||
|
data |= DMD_SSD2119_DISPLAY_CONTROL_GON;
|
||
|
data |= DMD_SSD2119_DISPLAY_CONTROL_D1;
|
||
|
data |= DMD_SSD2119_DISPLAY_CONTROL_D0;
|
||
|
DMDIF_writeReg(DMD_SSD2119_DISPLAY_CONTROL, data);
|
||
|
|
||
|
/* Exit sleep mode */
|
||
|
data = 0;
|
||
|
DMDIF_writeReg(DMD_SSD2119_SLEEP_MODE_1, data);
|
||
|
|
||
|
/* Wait */
|
||
|
for (i = 0; i < 100000; i++);
|
||
|
|
||
|
/* Display control */
|
||
|
DMDIF_writeReg(DMD_SSD2119_DISPLAY_CONTROL, 0x33);
|
||
|
|
||
|
/* Entry mode */
|
||
|
|
||
|
data = DMD_SSD2119_ENTRY_MODE_DFM_65K << DMD_SSD2119_ENTRY_MODE_DFM_SHIFT;
|
||
|
data |= DMD_SSD2119_ENTRY_MODE_WMODE;
|
||
|
data |= DMD_SSD2119_ENTRY_MODE_NOSYNC;
|
||
|
data |= DMD_SSD2119_ENTRY_MODE_DMODE;
|
||
|
data |= DMD_SSD2119_ENTRY_MODE_ID1;
|
||
|
data |= DMD_SSD2119_ENTRY_MODE_ID0;
|
||
|
|
||
|
DMDIF_writeReg(DMD_SSD2119_ENTRY_MODE, data);
|
||
|
|
||
|
// DMDIF_writeReg(DMD_SSD2119_DRIVER_OUTPUT_CONTROL, 0x3aef);
|
||
|
|
||
|
/* Generic Interface Control */
|
||
|
// data = DMD_SSD2119_GENERIC_INTERFACE_CONTROL_INVDEN;
|
||
|
// DMDIF_writeReg(DMD_SSD2119_GENERIC_INTERFACE_CONTROL, data);
|
||
|
|
||
|
/* Driver output control */
|
||
|
data = 0;
|
||
|
data |= DMD_SSD2119_DRIVER_OUTPUT_CONTROL_REV;
|
||
|
data |= DMD_SSD2119_DRIVER_OUTPUT_CONTROL_GD;
|
||
|
// data |= DMD_SSD2119_DRIVER_OUTPUT_CONTROL_TB;
|
||
|
// data |= DMD_SSD2119_DRIVER_OUTPUT_CONTROL_SM;
|
||
|
// data |= DMD_SSD2119_DRIVER_OUTPUT_CONTROL_RL;
|
||
|
data |= ((DMD_VERTICAL_SIZE - 1) << DMD_SSD2119_DRIVER_OUTPUT_CONTROL_MUX_SHIFT);
|
||
|
DMDIF_writeReg(DMD_SSD2119_DRIVER_OUTPUT_CONTROL, data);
|
||
|
|
||
|
/* LCD AC control */
|
||
|
data = DMD_SSD2119_LCD_AC_CONTROL_BC;
|
||
|
data |= DMD_SSD2119_LCD_AC_CONTROL_EOR;
|
||
|
/* data |= DMD_SSD2119_LCD_AC_CONTROL_FLC; */
|
||
|
DMDIF_writeReg(DMD_SSD2119_LCD_AC_CONTROL, data);
|
||
|
|
||
|
/* RAM data write */
|
||
|
data = 0xff;
|
||
|
DMDIF_writeReg(DMD_SSD2119_ACCESS_DATA, data);
|
||
|
|
||
|
/* Mark graphics as initialized */
|
||
|
initialized = 1;
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Get the dimensions of the display and of the current clipping area
|
||
|
*
|
||
|
* @return
|
||
|
* DMD_Dimensions structure containing the size of the display and the
|
||
|
* clipping area
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMD_getDisplayGeometry(DMD_DisplayGeometry **geometry)
|
||
|
{
|
||
|
if (!initialized)
|
||
|
{
|
||
|
return DMD_ERROR_DRIVER_NOT_INITIALIZED;
|
||
|
}
|
||
|
*geometry = &dimensions;
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Sets the clipping area. All coordinates given to writeData/writeColor/readData
|
||
|
* are relative to this clipping area.
|
||
|
*
|
||
|
* @param xStart
|
||
|
* X coordinate of the upper left corner of the clipping area
|
||
|
* @param yStart
|
||
|
* Y coordinate of the upper left corner of the clipping area
|
||
|
* @param width
|
||
|
* Width of the clipping area
|
||
|
* @param height
|
||
|
* Height of the clipping area
|
||
|
*
|
||
|
* @return
|
||
|
* DMD_OK on success, otherwise error code
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMD_setClippingArea(uint16_t xStart, uint16_t yStart,
|
||
|
uint16_t width, uint16_t height)
|
||
|
{
|
||
|
if (!initialized)
|
||
|
{
|
||
|
return DMD_ERROR_DRIVER_NOT_INITIALIZED;
|
||
|
}
|
||
|
|
||
|
/* Check parameters */
|
||
|
if (xStart + width > dimensions.xSize ||
|
||
|
yStart + height > dimensions.ySize)
|
||
|
{
|
||
|
return DMD_ERROR_PIXEL_OUT_OF_BOUNDS;
|
||
|
}
|
||
|
|
||
|
if (width == 0 || height == 0)
|
||
|
{
|
||
|
return DMD_ERROR_EMPTY_CLIPPING_AREA;
|
||
|
}
|
||
|
|
||
|
/* Update the dimensions structure */
|
||
|
dimensions.xClipStart = xStart;
|
||
|
dimensions.yClipStart = yStart;
|
||
|
dimensions.clipWidth = width;
|
||
|
dimensions.clipHeight = height;
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Draws pixels to the display
|
||
|
*
|
||
|
* @param x
|
||
|
* X coordinate of the first pixel to be written, relative to the clipping area
|
||
|
* @param y
|
||
|
* Y coordinate of the first pixel to be written, relative to the clipping area
|
||
|
* @param data
|
||
|
* Array containing the pixel data. Each 8-bit element in the array are one color
|
||
|
* component of the pixel, so that 3 bytes represent one pixel. The pixels are
|
||
|
* ordered by increasing x coordinate, after the last pixel of a row, the next
|
||
|
* pixel will be the first pixel on the next row.
|
||
|
* @param numPixels
|
||
|
* Number of pixels to be written
|
||
|
*
|
||
|
* @return
|
||
|
* DMD_OK on success, otherwise error code
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMD_writeData(uint16_t x, uint16_t y, const uint8_t data[],
|
||
|
uint32_t numPixels)
|
||
|
{
|
||
|
uint8_t *dest = (uint8_t *)((uint32_t) frameBuffer +
|
||
|
(uint32_t) (y*dimensions.xSize*sizeof(uint16_t)) +
|
||
|
(uint32_t) (x*sizeof(uint16_t)));
|
||
|
|
||
|
while(numPixels--)
|
||
|
{
|
||
|
*dest++ = *data++;
|
||
|
}
|
||
|
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Reads data from display memory
|
||
|
* DOESN'T WORK yet - TIMING ISSUE?
|
||
|
*
|
||
|
* @param x
|
||
|
* X coordinate of the first pixel to be read, relative to the clipping area
|
||
|
* @param y
|
||
|
* Y coordinate of the first pixel to be read, relative to the clipping area
|
||
|
* @param data
|
||
|
* Pointer to where the pixel data will be stored
|
||
|
* @param numPixels
|
||
|
* Number of pixels to be read
|
||
|
*
|
||
|
* @return
|
||
|
* DMD_OK on success, otherwise error code
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMD_readData(uint16_t x, uint16_t y,
|
||
|
uint8_t data[], uint32_t numPixels)
|
||
|
{
|
||
|
uint8_t *source = (uint8_t *)((uint32_t) frameBuffer +
|
||
|
(uint32_t) (y*dimensions.xSize*sizeof(uint16_t)) +
|
||
|
(uint32_t) (x*sizeof(uint16_t)));
|
||
|
if (y > dimensions.ySize) return DMD_ERROR_PIXEL_OUT_OF_BOUNDS;
|
||
|
|
||
|
while(numPixels--)
|
||
|
{
|
||
|
*data++ = *source++;
|
||
|
}
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* \brief
|
||
|
* Draws a number of pixels of the same color to the display
|
||
|
*
|
||
|
* @param x
|
||
|
* X coordinate of the first pixel to be written, relative to the clipping area
|
||
|
* @param y
|
||
|
* Y coordinate of the first pixel to be written, relative to the clipping area
|
||
|
* @param red
|
||
|
* Red component of the color
|
||
|
* @param green
|
||
|
* Green component of the color
|
||
|
* @param blue
|
||
|
* Blue component of the color
|
||
|
* @param numPixels
|
||
|
* Number of pixels to be written
|
||
|
*
|
||
|
* @return
|
||
|
* DMD_OK on success, otherwise error code
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMD_writeColor(uint16_t x, uint16_t y,
|
||
|
uint8_t red, uint8_t green, uint8_t blue, uint32_t numPixels)
|
||
|
{
|
||
|
uint16_t color;
|
||
|
uint16_t xStart = x;
|
||
|
uint16_t *pixelPointer = (uint16_t *)
|
||
|
((uint32_t) frameBuffer +
|
||
|
(uint32_t) ((y+dimensions.yClipStart)*dimensions.xSize*sizeof(uint16_t)) +
|
||
|
(uint32_t) ((x+dimensions.xClipStart)*sizeof(uint16_t)));
|
||
|
color = colorTransform24ToRGB565(red,green,blue);
|
||
|
|
||
|
/* Draw the requied number of pixels */
|
||
|
while(numPixels--)
|
||
|
{
|
||
|
x++;
|
||
|
*pixelPointer++ = color;
|
||
|
/* Increment line, start at the right x position inside clipping region */
|
||
|
if (x>=dimensions.clipWidth)
|
||
|
{
|
||
|
x = xStart;
|
||
|
pixelPointer = (uint16_t *)
|
||
|
((uint32_t) frameBuffer +
|
||
|
(uint32_t) (((++y)+dimensions.yClipStart)*dimensions.xSize*sizeof(uint16_t)) +
|
||
|
(uint32_t) ((xStart+dimensions.xClipStart)*sizeof(uint16_t)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Turns off the display and puts it into sleep mode
|
||
|
* Does not turn off backlight
|
||
|
*
|
||
|
* @return
|
||
|
* DMD_OK on success, otherwise error code
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMD_sleep(void)
|
||
|
{
|
||
|
uint16_t data;
|
||
|
|
||
|
if (!initialized)
|
||
|
{
|
||
|
return DMD_ERROR_DRIVER_NOT_INITIALIZED;
|
||
|
}
|
||
|
|
||
|
/* Put into sleep mode */
|
||
|
data = DMD_SSD2119_SLEEP_MODE_1_SLP;
|
||
|
DMDIF_writeReg(DMD_SSD2119_SLEEP_MODE_1, data);
|
||
|
|
||
|
/* Turn off display */
|
||
|
data = 0;
|
||
|
DMDIF_writeReg(DMD_SSD2119_DISPLAY_CONTROL, 0x0000);
|
||
|
|
||
|
/* Delay 1.5 frame */
|
||
|
/*DMDIF_delay((1000 / DMD_FRAME_FREQUENCY) * 3 / 2);*/
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Wakes up the display from sleep mode
|
||
|
*
|
||
|
* @return
|
||
|
* DMD_OK on success, otherwise error code
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMD_wakeUp(void)
|
||
|
{
|
||
|
uint16_t data;
|
||
|
|
||
|
if (!initialized)
|
||
|
{
|
||
|
return DMD_ERROR_DRIVER_NOT_INITIALIZED;
|
||
|
}
|
||
|
|
||
|
/* Get out of sleep mode */
|
||
|
data = 0;
|
||
|
DMDIF_writeReg(DMD_SSD2119_SLEEP_MODE_1, data);
|
||
|
|
||
|
/* Turn on display */
|
||
|
data = DMD_SSD2119_DISPLAY_CONTROL_DTE;
|
||
|
data |= DMD_SSD2119_DISPLAY_CONTROL_GON;
|
||
|
data |= DMD_SSD2119_DISPLAY_CONTROL_D1;
|
||
|
data |= DMD_SSD2119_DISPLAY_CONTROL_D0;
|
||
|
DMDIF_writeReg(DMD_SSD2119_DISPLAY_CONTROL, data);
|
||
|
|
||
|
/* Delay 10 frames */
|
||
|
/*DMDIF_delay((1000 / DMD_FRAME_FREQUENCY) * 10);*/
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************//**
|
||
|
* @brief
|
||
|
* Set horizontal and vertical flip mode of display controller
|
||
|
*
|
||
|
* @param hor
|
||
|
* Set to flip display horizontally
|
||
|
*
|
||
|
* @param ver
|
||
|
* Set to flip display vertically
|
||
|
*
|
||
|
* @return
|
||
|
* Returns DMD_OK is successful, error otherwise.
|
||
|
******************************************************************************/
|
||
|
EMSTATUS DMD_flipDisplay(int horizontal, int vertical)
|
||
|
{
|
||
|
uint16_t reg;
|
||
|
|
||
|
reg = rcDriverOutputControl;
|
||
|
|
||
|
if (horizontal) reg &= ~DMD_SSD2119_DRIVER_OUTPUT_CONTROL_RL;
|
||
|
else reg |= DMD_SSD2119_DRIVER_OUTPUT_CONTROL_RL;
|
||
|
|
||
|
if (vertical) reg &= ~DMD_SSD2119_DRIVER_OUTPUT_CONTROL_TB;
|
||
|
else reg |= DMD_SSD2119_DRIVER_OUTPUT_CONTROL_TB;
|
||
|
|
||
|
rcDriverOutputControl = reg;
|
||
|
DMDIF_writeReg(DMD_SSD2119_DRIVER_OUTPUT_CONTROL, rcDriverOutputControl);
|
||
|
|
||
|
return DMD_OK;
|
||
|
}
|