From 50c89877c36b5f588d33f1098c2ea000a88e8407 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 2 Feb 2017 17:07:59 +0100 Subject: [PATCH] Adding UC8173 driver --- .../gdisp/board_UC8173_nordic_nrf52_sdk11.h | 121 +++++ changelog.txt | 1 + drivers/gdisp/UC8173/UC8173.h | 224 ++++++++++ drivers/gdisp/UC8173/board_UC8173_template.h | 56 +++ drivers/gdisp/UC8173/driver.mk | 2 + drivers/gdisp/UC8173/gdisp_lld_UC8173.c | 419 ++++++++++++++++++ drivers/gdisp/UC8173/gdisp_lld_config.h | 29 ++ 7 files changed, 852 insertions(+) create mode 100644 boards/addons/gdisp/board_UC8173_nordic_nrf52_sdk11.h create mode 100644 drivers/gdisp/UC8173/UC8173.h create mode 100644 drivers/gdisp/UC8173/board_UC8173_template.h create mode 100644 drivers/gdisp/UC8173/driver.mk create mode 100644 drivers/gdisp/UC8173/gdisp_lld_UC8173.c create mode 100644 drivers/gdisp/UC8173/gdisp_lld_config.h diff --git a/boards/addons/gdisp/board_UC8173_nordic_nrf52_sdk11.h b/boards/addons/gdisp/board_UC8173_nordic_nrf52_sdk11.h new file mode 100644 index 00000000..a487ef20 --- /dev/null +++ b/boards/addons/gdisp/board_UC8173_nordic_nrf52_sdk11.h @@ -0,0 +1,121 @@ +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +#include "nrf_gpio.h" +#include "nrf_drv_spi.h" +#include "app_util_platform.h" + +#define PIN_CS 29 +#define PIN_SCK 3 +#define PIN_MOSI 4 +#define PIN_DC 12 +#define PIN_RESET 11 +#define PIN_BUSY 27 + +#define SPI_INSTANCE 0 + +static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); + +static GFXINLINE bool_t init_board(GDisplay* g) +{ + nrf_drv_spi_config_t spi_config; + ret_code_t err = NRF_SUCCESS; + + (void)g; + + // Initialize RESET pin + nrf_gpio_cfg_output(PIN_RESET); + + // Initialize RESET pin + nrf_gpio_cfg_output(PIN_DC); + + // Initialize BUSY pin + nrf_gpio_cfg_input(PIN_BUSY, NRF_GPIO_PIN_NOPULL); + + // Initialize RESET pin + nrf_gpio_cfg_output(PIN_CS); + + // Initialize SPI + spi_config.sck_pin = PIN_SCK; + spi_config.mosi_pin = PIN_MOSI; + spi_config.miso_pin = NRF_DRV_SPI_PIN_NOT_USED; + spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED; // We have to control the CS line ourself for burst writes > 255 bytes + spi_config.irq_priority = APP_IRQ_PRIORITY_LOW; + spi_config.orc = 0xFF; + spi_config.frequency = NRF_DRV_SPI_FREQ_4M; + spi_config.mode = NRF_DRV_SPI_MODE_0; + spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST; + err = nrf_drv_spi_init(&spi, &spi_config, 0); + if (err != NRF_SUCCESS) { + return FALSE; + } + + return TRUE; +} + +static GFXINLINE void post_init_board(GDisplay* g) +{ + (void)g; +} + +static GFXINLINE void setpin_reset(GDisplay* g, bool_t state) +{ + (void)g; + + if (state) { + nrf_gpio_pin_set(PIN_RESET); + } else { + nrf_gpio_pin_clear(PIN_RESET); + } +} + +static GFXINLINE bool_t getpin_busy(GDisplay* g) +{ + (void)g; + + if (nrf_gpio_pin_read(PIN_BUSY) == 1) { + return TRUE; + } else { + return FALSE; + } +} + +static GFXINLINE void acquire_bus(GDisplay* g) +{ + (void)g; + + nrf_gpio_pin_clear(PIN_CS); +} + +static GFXINLINE void release_bus(GDisplay* g) +{ + (void)g; + + nrf_gpio_pin_set(PIN_CS); +} + +static GFXINLINE void write_cmd(GDisplay* g, uint8_t cmd) +{ + (void)g; + + nrf_gpio_pin_clear(PIN_DC); + nrf_drv_spi_transfer(&spi, &cmd, 1, 0, 0); +} + +static GFXINLINE void write_data(GDisplay* g, uint8_t data) +{ + (void)g; + + nrf_gpio_pin_set(PIN_DC); + nrf_drv_spi_transfer(&spi, &data, 1, 0, 0); +} + +static GFXINLINE void write_data_burst(GDisplay* g, uint8_t* data, uint8_t length) +{ + (void)g; + + nrf_gpio_pin_set(PIN_DC); + nrf_drv_spi_transfer(&spi, data, length, 0, 0); +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/changelog.txt b/changelog.txt index ec655b0f..eb4b402d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -17,6 +17,7 @@ FEATURE: Added GDISP_IMAGE_GIF_BLIT_BUFFER_SIZE configuration option FIX: Fixed extra dots when drawing anti-aliased fonts with wordwrap FEATURE: Increase non-UTF8 font support to 0 to 255 rather than just the true ascii set FEATURE: Added Fb24bpp driver for RGB888 and BGR888 packed framebuffer displays +FEATURE: Added UC8173 driver *** Release 2.7 *** diff --git a/drivers/gdisp/UC8173/UC8173.h b/drivers/gdisp/UC8173/UC8173.h new file mode 100644 index 00000000..04063d5d --- /dev/null +++ b/drivers/gdisp/UC8173/UC8173.h @@ -0,0 +1,224 @@ +#ifndef _UC8173_H +#define _UC8173_H + +#include "gfx.h" + +#define DATA_MASK 0x0100 +#define DCX_CMD 0x0000 +#define DCX_DATA 0x0001 +#define MASTER 0x00 +#define SLAVE 0x01 +#define MAS_SLA 0x02 +#define BLACK 0x00 +#define WHITE 0x01 +#define RED 0x02 + +#define PSR 0x0000 +#define PWR 0x0001 +#define POF 0x0002 +#define PFS 0x0003 +#define PON 0x0004 +#define PMES 0x0005 +#define BTST 0x0006 +#define DSLP 0x0007 +#define SLP 0x0008 +#define DTM1 0x0010 +#define DRF 0x0012 +#define DTM2 0x0013 +#define DTMW 0x0014 +#define DTM3 0x0015 +#define DTM4 0x0016 +#define LUT_KWVCOM 0x0020 +#define LUT_RVCOM 0x0021 +#define LUT_KW 0x0022 +#define LUT_RR 0x0023 +#define LUT_RK 0x0024 +#define LUT_RW 0x0025 +#define LUT_FT 0x0026 +#define LPRD 0x0030 +#define TSC 0x0040 +#define TSE 0x0041 +#define TSW 0x0042 +#define TSR 0x0043 +#define PBC 0x0044 +#define CDI 0x0050 +#define LPD 0x0051 +#define TRES 0x0061 +#define GDS 0x0062 +#define GBS 0x0063 +#define GSS 0x0064 +#define REV 0x0070 +#define FLG 0x0071 +#define AMV 0x0080 +#define VV 0x0081 +#define VDCS 0x0082 +#define EDS 0x0083 +#define VBDS 0x0084 + +#define PGM 0x00A0 +#define APG 0x00A1 +#define ROTP 0x00A2 +#define CCSET 0x00E0 +#define PWS 0x00E3 +#define LVSEL 0x00E4 +#define TSSET 0x00E5 + +#define DF 0x00DF + +#define Initial_23_16 0x00 +#define Initial_15_0 0x0000 // 1K +#define Temperature 0x001000 +#define Temperature0_23_16 0x00 +#define Temperature0_15_0 0x0400 // 1K +#define Temperature1_23_16 0x00 +#define Temperature1_15_0 0x0800 +#define Temperature2_23_16 0x00 +#define Temperature2_15_0 0x0C00 +#define Temperature3_23_16 0x00 +#define Temperature3_15_0 0x1000 +#define Temperature4_23_16 0x00 +#define Temperature4_15_0 0x1400 +#define Temperature5_23_16 0x00 +#define Temperature5_15_0 0x1800 +#define Temperature6_23_16 0x00 +#define Temperature6_15_0 0x1C00 +#define Temperature7_23_16 0x00 +#define Temperature7_15_0 0x2000 +#define Temperature8_23_16 0x00 +#define Temperature8_15_0 0x2400 +#define Temperature9_23_16 0x00 +#define Temperature9_15_0 0x2800 +#define Temperature10_23_16 0x00 +#define Temperature10_15_0 0x2C00 + +#define Image_Start 0x003000 + +#define Initial_Counter 64 +#define Temperature_LUT_Counter 672 + +static uint8_t _lut_none[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static uint8_t _lut_temperature[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x29, 0xa9, 0xa9, 0xa8, + 0x29, 0xa9, 0xa9, 0xa8, 0x29, 0xa9, + 0xa9, 0xa8, 0x29, 0xa9, 0xa9, 0xa8, + 0x29, 0xa9, 0xa9, 0xa8, 0x29, 0xa9, + 0xa9, 0xa8, 0x29, 0xa9, 0xa9, 0xa0, + 0x29, 0xa9, 0x29, 0xa0, 0x28, 0xa9, + 0x21, 0x80, 0x28, 0xa9, 0x05, 0x80, + 0x28, 0xa1, 0x05, 0x04, 0x28, 0x80, + 0x05, 0x14, 0x08, 0x00, 0x15, 0x54, + 0x00, 0x04, 0x04, 0x54, 0x02, 0x54, + 0x14, 0x54, 0x02, 0x56, 0x14, 0x54, + 0x06, 0x56, 0x56, 0x54, 0x06, 0x56, + 0x56, 0x54, 0x16, 0x56, 0x56, 0x54, + 0x16, 0x56, 0x56, 0x54, 0x16, 0x56, + 0x52, 0x50, 0x16, 0x56, 0x52, 0x50, + 0x16, 0x56, 0x52, 0x50, 0x16, 0x52, + 0x52, 0x50, 0x16, 0x52, 0x52, 0x50, + 0x12, 0x52, 0x52, 0x40, 0x12, 0x52, + 0x52, 0x40, 0x1a, 0x4a, 0x4a, 0x48, + 0x2a, 0x6a, 0x6a, 0x68, 0x2a, 0x6a, + 0x6a, 0x68, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, + 0x5a, 0x55, 0x5a, 0x5a, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#endif // _UC8173_H diff --git a/drivers/gdisp/UC8173/board_UC8173_template.h b/drivers/gdisp/UC8173/board_UC8173_template.h new file mode 100644 index 00000000..f16205f4 --- /dev/null +++ b/drivers/gdisp/UC8173/board_UC8173_template.h @@ -0,0 +1,56 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +static GFXINLINE void init_board(GDisplay* g) +{ + (void) g; +} + +static GFXINLINE void post_init_board(GDisplay* g) +{ + (void) g; +} + +static GFXINLINE void setpin_reset(GDisplay* g, bool_t state) +{ + (void) g; + (void) state; +} + +static GFXINLINE void acquire_bus(GDisplay* g) +{ + (void) g; +} + +static GFXINLINE void release_bus(GDisplay* g) +{ + (void) g; +} + +static GFXINLINE void write_cmd(GDisplay* g, uint8_t cmd) +{ + (void) g; + (void) cmd; +} + +static GFXINLINE void write_data(GDisplay* g, uint8_t data) +{ + (void) g; + (void) data; +} + +static GFXINLINE void write_data_burst(GDisplay* g, uint8_t* data, uint16_t length) +{ + (void) g; + (void) data; + (void) length; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/UC8173/driver.mk b/drivers/gdisp/UC8173/driver.mk new file mode 100644 index 00000000..eebcd0b9 --- /dev/null +++ b/drivers/gdisp/UC8173/driver.mk @@ -0,0 +1,2 @@ +GFXINC += $(GFXLIB)/drivers/gdisp/UC8173 +GFXSRC += $(GFXLIB)/drivers/gdisp/UC8173/gdisp_lld_UC8173.c diff --git a/drivers/gdisp/UC8173/gdisp_lld_UC8173.c b/drivers/gdisp/UC8173/gdisp_lld_UC8173.c new file mode 100644 index 00000000..75a4a237 --- /dev/null +++ b/drivers/gdisp/UC8173/gdisp_lld_UC8173.c @@ -0,0 +1,419 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GDISP + +#define GDISP_DRIVER_VMT GDISPVMT_UC8173 +#include "gdisp_lld_config.h" +#include "../../../src/gdisp/gdisp_driver.h" +#include "UC8173.h" +#include "board_UC8173.h" + +#if defined(GDISP_SCREEN_WIDTH) + #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." + #define GDISP_SCREEN_WIDTH 240 +#endif +#if defined(GDISP_SCREEN_HEIGHT) + #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." + #define GDISP_SCREEN_HEIGHT 240 +#endif + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 240 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif + +#define PRIV(g) ((UC8173_Private*)((g)->priv)) +#define FRAMEBUFFER(g) (PRIV(g)->framebuffer) +#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER << 0) + +#if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_MONO + #define LINE_BYTES (GDISP_SCREEN_WIDTH/8) + #define WRITEBUFCMD DTM4 + #define xyaddr(x, y) (((x)>>3) + ((y) * LINE_BYTES)) + //#define xybit(x, c) ((c) << ((x) & 7)) // This one has the wrong order of the pixels inside the byte + #define xybit(x, c) ((c) << (7-((x) & 7))) +#elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_GRAY4 + #define LINE_BYTES (GDISP_SCREEN_WIDTH/4) + #define WRITEBUFCMD DTM2 // NOT SURE THIS IS RIGHT - MAY NEED TO USE DTM0 and then send a refresh??? + #define xyaddr(x, y) (((x)>>2) + ((y) * LINE_BYTES)) + //#define xybit(x, c) ((c) << (((x) & 3)<<1)) // This one has the wrong order of the pixels inside the byte + #define xybit(x, c) ((c) << (6-((x) & 3)<<1)) +#else + #error "UC8173: Unsupported driver color format" +#endif + +typedef struct UC8173_Private { + coord_t flushWindowX; + coord_t flushWindowY; + coord_t flushWindowWidth; + coord_t flushWindowHeight; + uint8_t* framebuffer; +} UC8173_Private; + +// This function rounds a given integer up to a specified multiple. Note, multiple must be a power of 2! +static GFXINLINE void _roundUp(coord_t* numToRound, uint8_t multiple) +{ + *numToRound = (*numToRound + multiple - 1) & ~(multiple - 1); +} + +static GFXINLINE void _wait_for_busy_high(GDisplay* g) +{ + while (!getpin_busy(g)); +} + +static GFXINLINE void _wait_for_busy_low(GDisplay* g) +{ + while (getpin_busy(g)); +} + +static void _load_lut(GDisplay* g, uint32_t LUT, uint8_t* LUT_Value) +{ + int i,counter; + int MODE = 2; + + if(MODE == 0) + counter = 512; //512 + else + counter = 42; + if(LUT == 0x26) + counter = 128; + + write_cmd(g, LUT); + for(i = 0; i < counter; i++) { + write_data(g, *LUT_Value); + LUT_Value++; + } +} + +void _load_lut2(GDisplay* g, uint32_t LUT, uint8_t* LUT_Value, uint32_t LUT_Counter) +{ + uint32_t i; + + write_cmd(g, LUT); + for (i = 0; i < LUT_Counter; i++) { + write_data(g, *LUT_Value); + LUT_Value++; + } +} + +static void _upload_Temperature_LUT(GDisplay* g) +{ + _load_lut2(g, LUT_KWVCOM, &_lut_temperature[0], 32); + _load_lut2(g, LUT_KW, &_lut_temperature[32], 512); + _load_lut2(g, LUT_FT, &_lut_temperature[544], 128); +} + +static void _clear_lut(GDisplay* g) +{ + write_cmd(g, PON); + _wait_for_busy_high(g); + + _load_lut(g, LUT_KW, _lut_none); + _load_lut(g, LUT_KWVCOM, _lut_none); + + write_cmd(g, POF); + _wait_for_busy_low(g); +} + +static void _invertFramebuffer(GDisplay* g) +{ + uint32_t i; + + for (i = 0; i < LINE_BYTES*GDISP_SCREEN_HEIGHT; i++) { + FRAMEBUFFER(g)[i] = ~(FRAMEBUFFER(g)[i]); + } + + // We should flush these changes to the display controller framebuffer at some point + g->flags |= GDISP_FLG_NEEDFLUSH; +} + +LLDSPEC bool_t gdisp_lld_init(GDisplay* g) +{ + // Allocate the private area plus the framebuffer + g->priv = gfxAlloc(sizeof(UC8173_Private) + LINE_BYTES*GDISP_SCREEN_HEIGHT); + if (!g->priv) { + return FALSE; + } + + // Initialize the private area + PRIV(g)->flushWindowX = 0; + PRIV(g)->flushWindowY = 0; + PRIV(g)->flushWindowWidth = GDISP_SCREEN_WIDTH; + PRIV(g)->flushWindowHeight = GDISP_SCREEN_HEIGHT; + PRIV(g)->framebuffer = (uint8_t*)(PRIV(g) + offsetof(UC8173_Private, framebuffer)); + + // Initialise the board interface + if (!init_board(g)) { + return FALSE; + } + + // Hardware reset + setpin_reset(g, FALSE); + gfxSleepMilliseconds(100); + setpin_reset(g, TRUE); + gfxSleepMilliseconds(1000); + + // Acquire the bus + acquire_bus(g); + + // Booster soft-start + write_cmd(g, BTST); + write_data(g, 0x17); //0x17 + write_data(g, 0x97); //0x97 + write_data(g, 0x20); //0x20 + + // Power settings + write_cmd(g, PWR); + write_data(g, 0x03); + write_data(g, 0x00); + write_data(g, 0x2B); //1C 2B + write_data(g, 0x2B); //1C 2B + write_data(g, 0x00); + + // Power-on + write_cmd(g, PON); + _wait_for_busy_high(g); + + // Panel setting register + write_cmd(g, PSR); + write_data(g, 0x0F); //0x0B + write_data(g, 0x86); //0x86 + + // Power-off sequence + write_cmd(g, PFS); + write_data(g, 0x00); + + // PLL control + write_cmd(g, LPRD); + write_data(g, 0x25); + + // Internal temperature sensor enable + write_cmd(g, TSE); + write_data(g, 0x00); // Use internal temperature sensor + + // VCOM and data interval settings + write_cmd(g, CDI); + write_data(g, 0xE1); + write_data(g, 0x20); + write_data(g, 0x10); + + // Set display panel resolution + write_cmd(g, TRES); + write_data(g, 0xEF); + write_data(g, 0x00); + write_data(g, 0xEF); + + // Undocumented register, taken from sample code + write_cmd(g, GDS); + write_data(g, 0xA9); + write_data(g, 0xA9); + write_data(g, 0xEB); + write_data(g, 0xEB); + write_data(g, 0x02); + + // Auto measure VCOM + write_cmd(g, AMV); + write_data(g, 0x11); // 5 seconds, enabled + + _wait_for_busy_high(g); + + // Get current VCOM value + // write_cmd(g, VV); + // unsigned char vcom_temp = spi_9b_get(); + // vcom_temp = vcom_temp + 4; + // Auto_VCOM = vcom_temp; + + // VCM_DC setting + write_cmd(g, VDCS); + write_data(g, 0x12); // Write vcom_temp here + + // Undocumented register, taken from sample code + write_cmd(g, VBDS); + write_data(g, 0x22); + + // Undocumented register, taken from sample code + write_cmd(g, LVSEL); + write_data(g, 0x02); + + // Undocumented register, taken from sample code + write_cmd(g, GBS); + write_data(g, 0x02); + write_data(g, 0x02); + + // Undocumented register, taken from sample code + write_cmd(g, GSS); + write_data(g, 0x02); + write_data(g, 0x02); + + // Undocumented register, taken from sample code + write_cmd(g, DF); // For REGAL (???) + write_data(g, 0x1F); + + // Clear the look-up table + _clear_lut(g); + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + + // Initialise the GDISP structure + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = 0; + g->g.Contrast = 0; + + return TRUE; +} + +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay* g) + { + coord_t y; + + // Don't flush unless we really need to + if (!(g->flags & GDISP_FLG_NEEDFLUSH)) { + return; + } + + // Round the flushing window width and height up to the next multiple of four + _roundUp(&(PRIV(g)->flushWindowWidth), 4); + _roundUp(&(PRIV(g)->flushWindowWidth), 4); + + // Acquire the bus to communicate with the display controller + acquire_bus(g); + + // Upload the new temperature LUT + _upload_Temperature_LUT(g); + + // Setup the window + write_cmd(g, DTMW); + write_data(g, (uint8_t)((PRIV(g)->flushWindowX >> 0) & 0xFF)); + write_data(g, (uint8_t)((PRIV(g)->flushWindowY >> 8) & 0x03)); + write_data(g, (uint8_t)((PRIV(g)->flushWindowY >> 0) & 0xFF)); + write_data(g, (uint8_t)((((PRIV(g)->flushWindowWidth)-1) >> 0) & 0xFF)); + write_data(g, (uint8_t)((((PRIV(g)->flushWindowHeight)-1) >> 8) & 0x03)); + write_data(g, (uint8_t)((((PRIV(g)->flushWindowHeight)-1) >> 0) & 0xFF)); + + // Dump our framebuffer + // Note: The display controller doesn't allow changing the vertical scanning direction + // so we have to manually send the lines "the other way around" here. + write_cmd(g, WRITEBUFCMD); + for (y = GDISP_SCREEN_HEIGHT-1; y >= 0; y--) { + write_data_burst(g, FRAMEBUFFER(g)+y*LINE_BYTES, LINE_BYTES); + } + + // Power-up the DC/DC converter to update the display panel + write_cmd(g, PON); + _wait_for_busy_high(g); + + // Refresh the panel contents + write_cmd(g, DRF); + write_data(g, 0x08); // Enable REGAL function + write_data(g, 0x00); + write_data(g, 0x00); + write_data(g, 0x00); + write_data(g, 0xEF); + write_data(g, 0x00); + write_data(g, 0xEF); + _wait_for_busy_high(g); + + // Power-down the DC/DC converter to make all the low-power pussys happy + write_cmd(g, POF); + _wait_for_busy_low(g); + + // Release the bus again + release_bus(g); + + // Clear the 'need-flushing' flag + g->flags &=~ GDISP_FLG_NEEDFLUSH; + } +#endif + +#if GDISP_HARDWARE_DRAWPIXEL + LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g) + { + coord_t x, y; + LLDCOLOR_TYPE *p; + + // Handle the different possible orientations + switch(g->g.Orientation) { + default: + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90: + x = g->p.y; + y = GDISP_SCREEN_HEIGHT-1 - g->p.x; + break; + case GDISP_ROTATE_180: + x = GDISP_SCREEN_WIDTH-1 - g->p.x; + y = GDISP_SCREEN_HEIGHT-1 - g->p.y; + break; + case GDISP_ROTATE_270: + x = GDISP_SCREEN_WIDTH-1 - g->p.y; + y = g->p.x; + break; + } + + // Modify the framebuffer content + p = &FRAMEBUFFER(g)[xyaddr(x,y)]; + *p &=~ xybit(x, LLDCOLOR_MASK()); + *p |= xybit(x, gdispColor2Native(g->p.color)); + +//#warning ToDo +// There appears to be an issue in the silicone, still talking to the manufacturer about this one. Update will follow! +#if 0 + // Update the flush window region + if (g->flags & GDISP_FLG_NEEDFLUSH) { + if (x < PRIV(g)->flushWindowX) + PRIV(g)->flushWindowX = x; + if (y < PRIV(g)->flushWindowY) + PRIV(g)->flushWindowY = y; + if (x > PRIV(g)->flushWindowX + PRIV(g)->flushWindowWidth) + PRIV(g)->flushWindowWidth = + } else { + PRIV(g)->flushWindowX = x; + PRIV(g)->flushWindowY = y; + PRIV(g)->flushWindowWidth = 1; + PRIV(g)->flushWindowHeight = 1; + } +#else + PRIV(g)->flushWindowX = 0; + PRIV(g)->flushWindowY = 0; + PRIV(g)->flushWindowWidth = GDISP_SCREEN_WIDTH; + PRIV(g)->flushWindowHeight = GDISP_SCREEN_HEIGHT; +#endif + + // We should flush these changes to the display controller framebuffer at some point + g->flags |= GDISP_FLG_NEEDFLUSH; + } +#endif + +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay* g) { + switch(g->p.x) { + case GDISP_CONTROL_INVERT: + _invertFramebuffer(g); + break; + + default: + break; + } + } +#endif + +#endif // GFX_USE_GDISP diff --git a/drivers/gdisp/UC8173/gdisp_lld_config.h b/drivers/gdisp/UC8173/gdisp_lld_config.h new file mode 100644 index 00000000..e10928eb --- /dev/null +++ b/drivers/gdisp/UC8173/gdisp_lld_config.h @@ -0,0 +1,29 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GDISP_LLD_CONFIG_H +#define _GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +#define GDISP_HARDWARE_FLUSH TRUE +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_PIXELREAD FALSE +#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_HARDWARE_FILLS FALSE + +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO + +#define GDISP_CONTROL_INVERT (GDISP_CONTROL_LLD+0) + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */