4
0
mirror of https://github.com/RT-Thread/rt-thread.git synced 2025-01-15 20:59:22 +08:00
onelife.real ea6d73f140 *** EFM32 branch ***
1. Upgrade Cortex driver library (CMSIS -> CMSIS & Device): version 2.3.2 -> 3.0.1 & 3.0.0
 - Remove "bsp/efm32/Libraries/CMSIS/Lib/ARM", "bsp/efm32/Libraries/CMSIS/Lib/G++" and "bsp/efm32/Libraries/CMSIS/SVD" to save space
2. Upgrade EFM32 driver libraries (efm32lib -> emlib): version 2.3.2 -> 3.0.0
 - Remove "bsp/efm32/Libraries/Device/EnergyMicro/EFM32LG" and "bsp/efm32/Libraries/Device/EnergyMicro/EFM32TG" to save space
3. Upgrade EFM32GG_DK3750 development kit driver library: version 1.2.2 -> 2.0.1
4. Upgrade EFM32_Gxxx_DK development kit driver library: version 1.7.3 -> 2.0.1
5. Add energy management unit driver and test code
6. Modify linker script and related code to compatible with new version of libraries
7. Change EFM32 branch version number to 1.0
8. Add photo frame demo application

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2122 bbd45198-f89e-11dd-88c7-29a3b14d5316
2012-05-18 04:40:40 +00:00

689 lines
20 KiB
C

/***************************************************************************//**
* @file dev_lcd.c
* @brief LCD driver of RT-Thread RTOS for EFM32
* COPYRIGHT (C) 2012, RT-Thread Development Team
* @author onelife
* @version 1.0
*******************************************************************************
* @section License
* The license and distribution terms for this file may be found in the file
* LICENSE in this distribution or at http://www.rt-thread.org/license/LICENSE
*******************************************************************************
* @section Change Logs
* Date Author Notes
* 2011-12-16 onelife Initial creation of address mapped method (pixel
* drive) for EFM32GG_DK3750 board
* 2011-12-29 onelife Add direct drive method (frame buffer) support
******************************************************************************/
/***************************************************************************//**
* @addtogroup EFM32GG_DK3750
* @{
******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "board.h"
#include "drv_usart.h"
#include "dev_lcd.h"
#if defined(EFM32_USING_LCD)
#if (!defined(LCD_MAPPED) && !defined(LCD_DIRECT))
#error "Unknown LCD access mode"
#endif
#include <rtgui/rtgui.h>
#include <rtgui/driver.h>
#include <dmd_ssd2119.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
#ifdef EFM32_LCD_DEBUG
#define lcd_debug(format,args...) rt_kprintf(format, ##args)
#else
#define lcd_debug(format,args...)
#endif
/* Private function prototypes -----------------------------------------------*/
#if defined(LCD_MAPPED)
static void efm32_spiLcd_setPixel(rtgui_color_t *c, int x, int y);
static void efm32_spiLcd_getPixel(rtgui_color_t *c, int x, int y);
static void efm32_spiLcd_drawRawHLine(rt_uint8_t *pixels, int x1, int x2, int y);
static void efm32_spiLcd_drawHLine(rtgui_color_t *c, int x1, int x2, int y);
static void efm32_spiLcd_drawVLine(rtgui_color_t *c, int x1, int x2, int y);
#endif
/* Private variables ---------------------------------------------------------*/
static rt_device_t lcd;
static struct rt_device lcd_device;
static rt_bool_t lcdAutoCs = true;
static struct rt_device_graphic_info lcd_info;
#if defined(LCD_MAPPED)
static const struct rtgui_graphic_driver_ops lcd_ops =
{
efm32_spiLcd_setPixel,
efm32_spiLcd_getPixel,
efm32_spiLcd_drawHLine,
efm32_spiLcd_drawVLine,
efm32_spiLcd_drawRawHLine
};
/* Private functions ---------------------------------------------------------*/
/***************************************************************************//**
* @brief
* Draw a pixel with specified color
*
* @details
*
* @note
*
* @param[in] c
* Pointer to color
*
* @param[in] x
* Horizontal position
*
* @param[in] y
* Vertical position
******************************************************************************/
static void efm32_spiLcd_setPixel(rtgui_color_t *c, int x, int y)
{
rt_uint32_t ret = RT_EOK;
do
{
/* Check if pixel is outside clipping region */
if ((x < 0) || (x > lcd_info.width))
{
break;
}
if ((y < 0) || (y > lcd_info.height))
{
break;
}
/* Write color */
ret = DMD_writePixel((rt_uint16_t)x, (rt_uint16_t)y, (rt_uint16_t)*c, 1);
if (ret != 0)
{
break;
}
return;
} while(0);
// lcd_debug("LCD err: Set pixel at (%d,%d: %x) failed (%x)!\n", x, y, *c, ret);
}
/***************************************************************************//**
* @brief
* Get the color of a pixel
*
* @details
*
* @note
*
* @param[out] c
* Pointer to color
*
* @param[in] x
* Horizontal position
*
* @param[in] y
* Vertical position
******************************************************************************/
static void efm32_spiLcd_getPixel(rtgui_color_t *c, int x, int y)
{
rt_uint32_t ret = RT_EOK;
do
{
/* Check if pixel is outside clipping region */
if ((x < 0) || (x > lcd_info.width))
{
break;
}
if ((y < 0) || (y > lcd_info.height))
{
break;
}
/* Read color */
ret = DMD_readPixel((rt_uint16_t)x, (rt_uint16_t)y, (rt_uint16_t *)c);
if (ret != 0)
{
break;
}
return;
} while(0);
lcd_debug("LCD err: Get pixel at (%d,%d: %x) failed (%x)!\n",
x, y, *c, ret);
}
/***************************************************************************//**
* @brief
* Draw a horizontal line with raw color
*
* @details
*
* @note
*
* @param[in] pixels
* Pointer to raw color
*
* @param[in] x1
* Horizontal start position
*
* @param[in] x2
* Horizontal end position
*
* @param[in] y
* Vertical position
******************************************************************************/
static void efm32_spiLcd_drawRawHLine(rt_uint8_t *pixels, int x1, int x2, int y)
{
lcd_debug("LCD: RAW H LINE!\n");
}
/***************************************************************************//**
* @brief
* Draw a horizontal line with specified color
*
* @details
*
* @note
*
* @param[in] c
* Pointer to color
*
* @param[in] x1
* Horizontal start position
*
* @param[in] x2
* Horizontal end position
*
* @param[in] y
* Vertical position
******************************************************************************/
static void efm32_spiLcd_drawHLine(rtgui_color_t *c, int x1, int x2, int y)
{
rt_uint32_t ret = RT_EOK;
do
{
/* Check if line is outside of clipping region */
if ((y < 0) || (y > lcd_info.height))
{
break;
}
/* Swap the coordinates if x1 is larger than x2 */
if (x1 > x2)
{
int swap;
swap = x1;
x1 = x2;
x2 = swap;
}
/* Check if entire line is outside clipping region */
if ((x1 > lcd_info.width) || (x2 < 0))
{
/* Nothing to draw */
break;
}
/* Clip the line if necessary */
if (x1 < 0)
{
x1 = 0;
}
if (x2 > lcd_info.width)
{
x2 = lcd_info.width;
}
/* Write color */
rt_uint32_t length = x2 - x1 + 1;
ret = DMD_writePixel((rt_uint16_t)x1, (rt_uint16_t)y,
(rt_uint16_t)*c, length);
if (ret != 0)
{
break;
}
return;
} while(0);
// lcd_debug("LCD err: Draw hline at (%d-%d,%d: %x) failed (%x)!\n", x1, x2, y, *c, ret);
}
/***************************************************************************//**
* @brief
* Draw a vertical line with specified color
*
* @details
*
* @note
*
* @param[in] c
* Pointer to color
*
* @param[in] x
* Horizontal position
*
* @param[in] y1
* Vertical start position
*
* @param[in] y2
* Vertical end position
******************************************************************************/
static void efm32_spiLcd_drawVLine(rtgui_color_t *c, int x , int y1, int y2)
{
rt_uint32_t ret = RT_EOK;
do
{
/* Check if line is outside of clipping region */
if ((x < 0) || (x > lcd_info.width))
{
break;
}
/* Swap the coordinates if y1 is larger than y2 */
if (y1 > y2)
{
rt_uint16_t swap;
swap = y1;
y1 = y2;
y2 = swap;
}
/* Check if entire line is outside clipping region */
if ((y1 > lcd_info.height) || (y2 < 0))
{
/* Nothing to draw */
break;
}
/* Clip the line if necessary */
if (y1 < 0)
{
y1 = 0;
}
if (y2 > lcd_info.height)
{
y2 = lcd_info.height;
}
/* Set clipping area */
rt_uint16_t length = y2 - y1 + 1;
ret = DMD_setClippingArea((rt_uint16_t)x, (rt_uint16_t)y1, 1, length);
if (ret != DMD_OK)
{
break;
}
/* Write color */
ret= DMD_writePixel(0, 0, (rt_uint16_t)*c, length);
if (ret != DMD_OK)
{
break;
}
/* Reset clipping area */
ret = DMD_setClippingArea(0, 0, lcd_info.width, lcd_info.height);
if (ret != DMD_OK)
{
break;
}
return;
} while(0);
// lcd_debug("LCD err: Draw vline at (%d,%d-%d: %x) failed (%x)!\n", x, y1, y2, *c, ret);
}
#endif
/***************************************************************************//**
* @brief
* Configure LCD device
*
* @details
*
* @note
*
* @param[in] dev
* Pointer to device descriptor
*
* @param[in] cmd
* IIC control command
*
* @param[in] args
* Arguments
*
* @return
* Error code
******************************************************************************/
static rt_err_t efm32_spiLcd_control (rt_device_t dev, rt_uint8_t cmd, void *args)
{
switch (cmd)
{
case RTGRAPHIC_CTRL_RECT_UPDATE:
break;
case RTGRAPHIC_CTRL_POWERON:
break;
case RTGRAPHIC_CTRL_POWEROFF:
break;
case RTGRAPHIC_CTRL_GET_INFO:
rt_memcpy(args, &lcd_info, sizeof(struct rt_device_graphic_info));
break;
case RTGRAPHIC_CTRL_SET_MODE:
break;
}
return RT_EOK;
}
/***************************************************************************//**
* @brief
* Set/Clear chip select
*
* @details
*
* @note
*
* @param[in] enable
* Chip select pin setting
******************************************************************************/
static void efm32_spiLcd_cs(rt_uint8_t enable)
{
if (!lcdAutoCs)
{
if (enable)
{
GPIO_PinOutClear(LCD_CS_PORT, LCD_CS_PIN);
}
else
{
GPIO_PinOutSet(LCD_CS_PORT, LCD_CS_PIN);
}
}
}
/***************************************************************************//**
* @brief
* Write data to SSD2119 controller
*
* @param[in] reg
* Register to write to
*
* @param[in] data
* 16-bit data to write into register
*
* @note
* It's not possible to read back register value through SSD2119 SPI interface
******************************************************************************/
rt_err_t efm32_spiLcd_writeRegister(rt_uint8_t reg, rt_uint16_t data)
{
struct efm32_usart_device_t *usart;
rt_uint8_t buf_ins[3];
rt_uint8_t buf_res[3];
RT_ASSERT(lcd != RT_NULL);
usart = (struct efm32_usart_device_t *)(lcd->user_data);
/* Build instruction buffer */
buf_res[0] = (data & 0xff00) >> 8;
buf_res[1] = data & 0x00ff;
buf_ins[0] = 1; /* Instruction length */
buf_ins[1] = reg; /* Instruction */
*(rt_uint8_t **)(&buf_ins[2]) = buf_res; /* Data */
efm32_spiLcd_cs(1);
if (lcd->write(lcd, EFM32_NO_DATA, buf_ins, 2) == 0)
{
lcd_debug("LCD: Write data failed!\n");
return -RT_ERROR;
}
efm32_spiLcd_cs(0);
return RT_EOK;
}
/***************************************************************************//**
* @brief
* Register LCD device
*
* @details
*
* @note
*
* @param[in] device
* Pointer to device descriptor
*
* @param[in] name
* Device name
*
* @param[in] flag
* Configuration flags
*
* @param[in] iic
* Pointer to IIC device descriptor
*
* @return
* Error code
******************************************************************************/
rt_err_t efm32_spiLcd_register(
rt_device_t device,
const char *name,
rt_uint32_t flag,
void *data)
{
RT_ASSERT(device != RT_NULL);
device->type = RT_Device_Class_Graphic;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = RT_NULL;
device->write = RT_NULL;
device->control = efm32_spiLcd_control;
device->user_data = data;
/* register a character device */
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
}
/***************************************************************************//**
* @brief
* Initialize LCD device
*
* @details
*
* @note
*
******************************************************************************/
void efm32_spiLcd_init(void)
{
struct efm32_usart_device_t *usart;
rt_uint32_t flag;
DMD_DisplayGeometry *geometry;
rt_uint32_t ret;
do
{
USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT;
/* Find SPI device */
lcd = rt_device_find(LCD_USING_DEVICE_NAME);
if (lcd == RT_NULL)
{
lcd_debug("LCD err: Can't find %s!\n", LCD_USING_DEVICE_NAME);
break;
}
lcd_debug("LCD: Find device %s\n", LCD_USING_DEVICE_NAME);
/* Config CS pin */
usart = (struct efm32_usart_device_t *)(lcd->user_data);
if (!(usart->state & USART_STATE_AUTOCS))
{
GPIO_PinModeSet(LCD_CS_PORT, LCD_CS_PIN, gpioModePushPull, 1);
lcdAutoCs = false;
}
/* TFT initialize or reinitialize. Assumes EBI has been configured
correctly in DVK_init(DVK_Init_EBI) */
rt_uint32_t freq = SystemCoreClockGet();
rt_uint32_t i;
rt_bool_t warning = RT_FALSE;
/* If we are in BC_UIF_AEM_EFM state, we can redraw graphics */
while (DVK_readRegister(&BC_REGISTER->UIF_AEM) != BC_UIF_AEM_EFM)
{
if (!warning)
{
lcd_debug("LCD: Please press AEM button!!!\n");
warning = RT_TRUE;
}
}
lcd_debug("LCD: Got LCD control\n");
/* If we're not BC_ARB_CTRL_EBI state, we need to reconfigure display controller */
if (DVK_readRegister(&BC_REGISTER->ARB_CTRL) != BC_ARB_CTRL_EBI)
{
lcd_debug("LCD: Set to EBI mode\n");
/* Configure for EBI mode and reset display */
DVK_displayControl(DVK_Display_EBI);
DVK_displayControl(DVK_Display_ResetAssert);
DVK_displayControl(DVK_Display_PowerDisable);
/* Short delay */
freq = SystemCoreClockGet();
for(i = 0; i < (freq / 100); i++)
{
__NOP();
}
#if defined(LCD_MAPPED)
/* Configure display for address mapped method + 3-wire SPI mode */
DVK_displayControl(DVK_Display_Mode8080);
DVK_displayControl(DVK_Display_PowerEnable);
DVK_displayControl(DVK_Display_ResetRelease);
/* Initialize graphics - abort on failure */
ret = DMD_init(BC_SSD2119_BASE, BC_SSD2119_BASE + 2);
if (ret == DMD_OK)
{
/* Make sure display is configured with correct rotation */
DMD_flipDisplay(1, 1);
}
else if (ret != DMD_ERROR_DRIVER_ALREADY_INITIALIZED)
{
lcd_debug("LCD err: driver init failed %x\n", ret);
break;
}
#elif defined(LCD_DIRECT)
/* Configure TFT direct drive method from EBI BANK2 */
const EBI_TFTInit_TypeDef tftInit =
{
ebiTFTBank2, /* Select EBI Bank 2 */
ebiTFTWidthHalfWord, /* Select 2-byte (16-bit RGB565) increments */
ebiTFTColorSrcMem, /* Use memory as source for mask/blending */
ebiTFTInterleaveUnlimited, /* Unlimited interleaved accesses */
ebiTFTFrameBufTriggerVSync, /* VSYNC as frame buffer update trigger */
false, /* Drive DCLK from negative edge of internal clock */
ebiTFTMBDisabled, /* No masking and alpha blending enabled */
ebiTFTDDModeExternal, /* Drive from external memory */
ebiActiveLow, /* CS Active Low polarity */
ebiActiveHigh, /* DCLK Active High polarity */
ebiActiveLow, /* DATAEN Active Low polarity */
ebiActiveLow, /* HSYNC Active Low polarity */
ebiActiveLow, /* VSYNC Active Low polarity */
320, /* Horizontal size in pixels */
1, /* Horizontal Front Porch */
30, /* Horizontal Back Porch */
2, /* Horizontal Synchronization Pulse Width */
240, /* Vertical size in pixels */
1, /* Vertical Front Porch */
4, /* Vertical Back Porch */
2, /* Vertical Synchronization Pulse Width */
0x0000, /* Frame Address pointer offset to EBI memory base */
4, /* DCLK Period */
0, /* DCLK Start cycles */
0, /* DCLK Setup cycles */
0, /* DCLK Hold cycles */
};
DVK_enablePeripheral(DVK_TFT);
/* Configure display for Direct Drive + 3-wire SPI mode */
DVK_displayControl(DVK_Display_ModeGeneric);
DVK_displayControl(DVK_Display_PowerEnable);
DVK_displayControl(DVK_Display_ResetRelease);
/* Configure GPIO for EBI and TFT */
/* EBI TFT DCLK/Dot Clock */
GPIO_PinModeSet(gpioPortA, 8, gpioModePushPull, 0);
/* EBI TFT DATAEN */
GPIO_PinModeSet(gpioPortA, 9, gpioModePushPull, 0);
/* EBI TFT VSYNC */
GPIO_PinModeSet(gpioPortA, 10, gpioModePushPull, 0);
/* EBI TFT HSYNC */
GPIO_PinModeSet(gpioPortA, 11, gpioModePushPull, 0);
/* Initialize display */
DMD_init(0, (rt_uint32_t)EBI_BankAddress(EBI_BANK2));
/* Configure EBI TFT direct drive */
EBI_TFTInit(&tftInit);
#endif
}
/* Get LCD geometry */
ret = DMD_getDisplayGeometry(&geometry);
if (ret != DMD_OK)
{
lcd_debug("LCD err: get geometry failed!\n");
break;
}
/* Init LCD info */
flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_DMA_TX;
lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565P;
lcd_info.bits_per_pixel = 16;
lcd_info.width = geometry->xSize;
lcd_info.height = geometry->ySize;
#if defined(LCD_MAPPED)
lcd_info.framebuffer = RT_NULL;
efm32_spiLcd_register(&lcd_device, LCD_DEVICE_NAME, flag, (void *)&lcd_ops);
#elif defined(LCD_DIRECT)
lcd_info.framebuffer = (rt_uint8_t *)EBI_BankAddress(EBI_BANK2);
efm32_spiLcd_register(&lcd_device, LCD_DEVICE_NAME, flag, RT_NULL);
#endif
/* Set clipping area */
ret = DMD_setClippingArea(0, 0, geometry->xSize, geometry->ySize);
if (ret != DMD_OK)
{
lcd_debug("LCD err: set clipping area failed!\n");
break;
}
/* Read device code */
rt_uint16_t code = 0xFFFF;
#if defined(LCD_MAPPED)
code = DMDIF_readDeviceCode();
#endif
/* Set as rtgui graphic driver */
rtgui_graphic_set_device(&lcd_device);
lcd_debug("LCD: H/W init OK!\n");
return;
} while(0);
lcd_debug("LCD err: H/W init failed!\n");
}
#endif /* defined(EFM32_USING_LCD) */
/***************************************************************************//**
* @}
******************************************************************************/