diff options
Diffstat (limited to 'bsp/efm32/dev_lcd.c')
| -rw-r--r-- | bsp/efm32/dev_lcd.c | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/bsp/efm32/dev_lcd.c b/bsp/efm32/dev_lcd.c new file mode 100644 index 0000000000..e678c9a617 --- /dev/null +++ b/bsp/efm32/dev_lcd.c @@ -0,0 +1,625 @@ +/***************************************************************************//** + * @file dev_lcd.c + * @brief LCD driver of RT-Thread RTOS for EFM32 + * COPYRIGHT (C) 2011, RT-Thread Development Team + * @author onelife + * @version 0.4 beta + ******************************************************************************* + * @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 for EFM32 + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup efm32 + * @{ + ******************************************************************************/ + +/* Includes ------------------------------------------------------------------*/ +#include "board.h" +#include "drv_usart.h" +#include "dev_lcd.h" + +#if defined(EFM32_USING_LCD) +#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 -----------------------------------------------*/ +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); + +/* Private variables ---------------------------------------------------------*/ +static rt_device_t lcd; +static struct rt_device lcd_device; +static struct rt_device_graphic_info lcd_info; +static const struct rtgui_graphic_driver_ops lcd_ops = + { + efm32_spiLcd_setPixel, + efm32_spiLcd_getPixel, + efm32_spiLcd_drawHLine, + efm32_spiLcd_drawVLine, + efm32_spiLcd_drawRawHLine + }; +static rt_bool_t lcdAutoCs = true; + +/* Private functions ---------------------------------------------------------*/ +/***************************************************************************//** + * @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 + * 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); +} + +/***************************************************************************//** +* @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 + * 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_spiLed_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); + + /* Reconfig speed */ + usart = (struct efm32_usart_device_t *)(lcd->user_data); + USART_BaudrateSyncSet(usart->usart_device, 0, EFM32_LCD_SPICLK); + + /* Config CS pin */ + if (!(usart->state & USART_STATE_AUTOCS)) + { + GPIO_PinModeSet(LCD_CS_PORT, LCD_CS_PIN, gpioModePushPull, 1); + lcdAutoCs = false; + } + + // TODO: add another method + /* TFT initialize or reinitialize to Address Mapped Mode + 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(); + } + /* Configure display for Direct Drive + 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; + } + } + + /* Get LCD geometry */ + ret = DMD_getDisplayGeometry(&geometry); + if (ret != DMD_OK) + { + lcd_debug("LCD err: get geometry failed!\n"); + break; + } + + /* Init LCD info */ + lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565P; + lcd_info.bits_per_pixel = 16; + lcd_info.width = geometry->xSize - 1; + lcd_info.height = geometry->ySize - 1; + lcd_info.framebuffer = RT_NULL; + + flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_DMA_TX; + efm32_spiLcd_register(&lcd_device, LCD_DEVICE_NAME, flag, (void *)&lcd_ops); + + /* 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; + code = DMDIF_readDeviceCode(); + + /* Set as rtgui graphic driver */ + rtgui_graphic_set_device(&lcd_device); + + lcd_debug("LCD: H/W (%x) init OK!\n", code); + return; + } while(0); + + lcd_debug("LCD err: H/W init failed!\n"); +} + + #endif /* defined(EFM32_USING_LCD) */ +/***************************************************************************//** + * @} + ******************************************************************************/ |
