summaryrefslogtreecommitdiff
path: root/bsp/efm32/dev_lcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsp/efm32/dev_lcd.c')
-rw-r--r--bsp/efm32/dev_lcd.c625
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) */
+/***************************************************************************//**
+ * @}
+ ******************************************************************************/