diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gdisp/ED060SC4/ed060sc4.h | 16 | ||||
-rw-r--r-- | drivers/gdisp/ED060SC4/gdisp_lld.c | 606 | ||||
-rw-r--r-- | drivers/gdisp/ED060SC4/gdisp_lld_board_example.h | 127 | ||||
-rw-r--r-- | drivers/gdisp/ED060SC4/gdisp_lld_board_template.h | 83 | ||||
-rw-r--r-- | drivers/gdisp/SSD1289/gdisp_lld.c | 637 |
5 files changed, 1469 insertions, 0 deletions
diff --git a/drivers/gdisp/ED060SC4/ed060sc4.h b/drivers/gdisp/ED060SC4/ed060sc4.h new file mode 100644 index 00000000..8a38f135 --- /dev/null +++ b/drivers/gdisp/ED060SC4/ed060sc4.h @@ -0,0 +1,16 @@ +/* + * 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 _ED060SC4_H_ +#define _ED060SC4_H_ + +#include "gfx.h" + +/* Control command for flushing all data to display. */ +#define GDISP_CONTROL_FLUSH (GDISP_CONTROL_LLD + 0) + +#endif diff --git a/drivers/gdisp/ED060SC4/gdisp_lld.c b/drivers/gdisp/ED060SC4/gdisp_lld.c new file mode 100644 index 00000000..fcc03944 --- /dev/null +++ b/drivers/gdisp/ED060SC4/gdisp_lld.c @@ -0,0 +1,606 @@ +/* + * 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 + */ + +/* Low-level E-ink panel driver routines for ED060SC4. */ + +#include "gfx.h" +#include "ed060sc4.h" + +#if GFX_USE_GDISP + +#include "gdisp/lld/emulation.c" + +/* ================================= + * Default configuration + * ================================= */ + +#ifndef GDISP_SCREEN_HEIGHT +# define GDISP_SCREEN_HEIGHT 600 +#endif + +#ifndef GDISP_SCREEN_WIDTH +# define GDISP_SCREEN_WIDTH 800 +#endif + +/* Number of pixels per byte */ +#ifndef EINK_PPB +# define EINK_PPB 4 +#endif + +/* Delay for generating clock pulses. + * Unit is approximate clock cycles of the CPU (0 to 15). + * This should be atleast 50 ns. + */ +#ifndef EINK_CLOCKDELAY +# define EINK_CLOCKDELAY 0 +#endif + +/* Width of one framebuffer block. + * Must be divisible by EINK_PPB and evenly divide GDISP_SCREEN_WIDTH. */ +#ifndef EINK_BLOCKWIDTH +# define EINK_BLOCKWIDTH 20 +#endif + +/* Height of one framebuffer block. + * Must evenly divide GDISP_SCREEN_WIDTH. */ +#ifndef EINK_BLOCKHEIGHT +# define EINK_BLOCKHEIGHT 20 +#endif + +/* Number of block buffers to use for framebuffer emulation. */ +#ifndef EINK_NUMBUFFERS +# define EINK_NUMBUFFERS 40 +#endif + +/* Do a "blinking" clear, i.e. clear to opposite polarity first. + * This reduces the image persistence. */ +#ifndef EINK_BLINKCLEAR +# define EINK_BLINKCLEAR TRUE +#endif + +/* Number of passes to use when clearing the display */ +#ifndef EINK_CLEARCOUNT +# define EINK_CLEARCOUNT 10 +#endif + +/* Number of passes to use when writing to the display */ +#ifndef EINK_WRITECOUNT +# define EINK_WRITECOUNT 4 +#endif + +/* ==================================== + * Lower level driver functions + * ==================================== */ + +#include "gdisp_lld_board.h" + +/** Delay between signal changes, to give time for IO pins to change state. */ +static inline void clockdelay() +{ + #if EINK_CLOCKDELAY & 1 + asm("nop"); + #endif + #if EINK_CLOCKDELAY & 2 + asm("nop"); + asm("nop"); + #endif + #if EINK_CLOCKDELAY & 4 + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + #endif + #if EINK_CLOCKDELAY & 8 + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + #endif +} + +/** Fast vertical clock pulse for gate driver, used during initializations */ +static void vclock_quick() +{ + setpin_ckv(TRUE); + eink_delay(1); + setpin_ckv(FALSE); + eink_delay(4); +} + +/** Horizontal clock pulse for clocking data into source driver */ +static void hclock() +{ + clockdelay(); + setpin_cl(TRUE); + clockdelay(); + setpin_cl(FALSE); +} + +/** Start a new vertical gate driver scan from top. + * Note: Does not clear any previous bits in the shift register, + * so you should always scan through the whole display before + * starting a new scan. + */ +static void vscan_start() +{ + setpin_gmode(TRUE); + vclock_quick(); + setpin_spv(FALSE); + vclock_quick(); + setpin_spv(TRUE); + vclock_quick(); +} + +/** Waveform for strobing a row of data onto the display. + * Attempts to minimize the leaking of color to other rows by having + * a long idle period after a medium-length strobe period. + */ +static void vscan_write() +{ + setpin_ckv(TRUE); + setpin_oe(TRUE); + eink_delay(5); + setpin_oe(FALSE); + setpin_ckv(FALSE); + eink_delay(200); +} + +/** Waveform used when clearing the display. Strobes a row of data to the + * screen, but does not mind some of it leaking to other rows. + */ +static void vscan_bulkwrite() +{ + setpin_ckv(TRUE); + eink_delay(20); + setpin_ckv(FALSE); + eink_delay(200); +} + +/** Waveform for skipping a vertical row without writing anything. + * Attempts to minimize the amount of change in any row. + */ +static void vscan_skip() +{ + setpin_ckv(TRUE); + eink_delay(1); + setpin_ckv(FALSE); + eink_delay(100); +} + +/** Stop the vertical scan. The significance of this escapes me, but it seems + * necessary or the next vertical scan may be corrupted. + */ +static void vscan_stop() +{ + setpin_gmode(FALSE); + vclock_quick(); + vclock_quick(); + vclock_quick(); + vclock_quick(); + vclock_quick(); +} + +/** Start updating the source driver data (from left to right). */ +static void hscan_start() +{ + /* Disable latching and output enable while we are modifying the row. */ + setpin_le(FALSE); + setpin_oe(FALSE); + + /* The start pulse should remain low for the duration of the row. */ + setpin_sph(FALSE); +} + +/** Write data to the horizontal row. */ +static void hscan_write(const uint8_t *data, int count) +{ + while (count--) + { + /* Set the next byte on the data pins */ + setpins_data(*data++); + + /* Give a clock pulse to the shift register */ + hclock(); + } +} + +/** Finish and transfer the row to the source drivers. + * Does not set the output enable, so the drivers are not yet active. */ +static void hscan_stop() +{ + /* End the scan */ + setpin_sph(TRUE); + hclock(); + + /* Latch the new data */ + setpin_le(TRUE); + clockdelay(); + setpin_le(FALSE); +} + +/** Turn on the power to the E-Ink panel, observing proper power sequencing. */ +static void power_on() +{ + unsigned i; + + /* First the digital power supply and signal levels. */ + setpower_vdd(TRUE); + setpin_le(FALSE); + setpin_oe(FALSE); + setpin_cl(FALSE); + setpin_sph(TRUE); + setpins_data(0); + setpin_ckv(FALSE); + setpin_gmode(FALSE); + setpin_spv(TRUE); + + /* Min. 100 microsecond delay after digital supply */ + gfxSleepMicroseconds(100); + + /* Then negative voltages and min. 1000 microsecond delay. */ + setpower_vneg(TRUE); + gfxSleepMicroseconds(1000); + + /* Finally the positive voltages. */ + setpower_vpos(TRUE); + + /* Clear the vscan shift register */ + vscan_start(); + for (i = 0; i < GDISP_SCREEN_HEIGHT; i++) + vclock_quick(); + vscan_stop(); +} + +/** Turn off the power, observing proper power sequencing. */ +static void power_off() +{ + /* First the high voltages */ + setpower_vpos(FALSE); + setpower_vneg(FALSE); + + /* Wait for any capacitors to drain */ + gfxSleepMilliseconds(100); + + /* Then put all signals and digital supply to ground. */ + setpin_le(FALSE); + setpin_oe(FALSE); + setpin_cl(FALSE); + setpin_sph(FALSE); + setpins_data(0); + setpin_ckv(FALSE); + setpin_gmode(FALSE); + setpin_spv(FALSE); + setpower_vdd(FALSE); +} + +/* ==================================== + * Framebuffer emulation layer + * ==================================== */ + +#if EINK_PPB == 4 +#define PIXELMASK 3 +#define PIXEL_WHITE 2 +#define PIXEL_BLACK 1 +#define BYTE_WHITE 0xAA +#define BYTE_BLACK 0x55 +#else +#error Unsupported EINK_PPB value. +#endif + +#if GDISP_SCREEN_HEIGHT % EINK_BLOCKHEIGHT != 0 +#error GDISP_SCREEN_HEIGHT must be evenly divisible by EINK_BLOCKHEIGHT +#endif + +#if GDISP_SCREEN_WIDTH % EINK_BLOCKWIDTH != 0 +#error GDISP_SCREEN_WIDTH must be evenly divisible by EINK_BLOCKWIDTH +#endif + +#if EINK_BLOCKWIDTH % EINK_PPB != 0 +#error EINK_BLOCKWIDTH must be evenly divisible by EINK_PPB +#endif + +#if EINK_NUMBUFFERS > 254 +#error EINK_NUMBUFFERS must be at most 254. +#endif + +#define BLOCKS_Y (GDISP_SCREEN_HEIGHT / EINK_BLOCKHEIGHT) +#define BLOCKS_X (GDISP_SCREEN_WIDTH / EINK_BLOCKWIDTH) +#define WIDTH_BYTES (EINK_BLOCKWIDTH / EINK_PPB) + +/* Buffers that store the data for a small area of the display. */ +typedef struct { + uint8_t data[EINK_BLOCKHEIGHT][WIDTH_BYTES]; +} block_t; + +static uint8_t g_next_block; /* Index of the next free block buffer. */ +static block_t g_blocks[EINK_NUMBUFFERS]; + +/* Map that stores the buffers associated to each area of the display. + * Value of 0 means that the block is not allocated. + * Other values are the index in g_blocks + 1. + */ +static uint8_t g_blockmap[BLOCKS_Y][BLOCKS_X]; + +/** Check if the row contains any allocated blocks. */ +static bool_t blocks_on_row(unsigned by) +{ + unsigned bx; + for (bx = 0; bx < BLOCKS_X; bx++) + { + if (g_blockmap[by][bx] != 0) + { + return TRUE; + } + } + return FALSE; +} + +/** Write out a block row. */ +static void write_block_row(unsigned by) +{ + unsigned bx, dy, dx; + for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) + { + hscan_start(); + for (bx = 0; bx < BLOCKS_X; bx++) + { + if (g_blockmap[by][bx] == 0) + { + for (dx = 0; dx < WIDTH_BYTES; dx++) + { + const uint8_t dummy = 0; + hscan_write(&dummy, 1); + } + } + else + { + block_t *block = &g_blocks[g_blockmap[by][bx] - 1]; + hscan_write(&block->data[dy][0], WIDTH_BYTES); + } + } + hscan_stop(); + + vscan_write(); + } +} + +/** Clear the block map, i.e. deallocate all blocks */ +static void clear_block_map() +{ + unsigned bx, by; + for (by = 0; by < BLOCKS_Y; by++) + { + for (bx = 0; bx < BLOCKS_X; bx++) + { + g_blockmap[by][bx] = 0; + } + } + + g_next_block = 0; +} + +/** Flush all the buffered rows to display. */ +static void flush_buffers() +{ + unsigned by, dy, i; + + for (i = 0; i < EINK_WRITECOUNT; i++) + { + vscan_start(); + + for (by = 0; by < BLOCKS_Y; by++) + { + if (!blocks_on_row(by)) + { + /* Skip the whole row of blocks. */ + for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) + { + vscan_skip(); + } + } + else + { + /* Write out the blocks. */ + write_block_row(by); + } + } + + vscan_stop(); + } + + clear_block_map(); +} + +/** Initialize a newly allocated block. */ +static void zero_block(block_t *block) +{ + unsigned dx, dy; + for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) + { + for (dx = 0; dx < WIDTH_BYTES; dx++) + { + block->data[dy][dx] = 0; + } + } +} + +/** Allocate a buffer + * Automatically flushes if all buffers are full. */ +static block_t *alloc_buffer(unsigned bx, unsigned by) +{ + block_t *result; + if (g_blockmap[by][bx] == 0) + { + if (g_next_block >= EINK_NUMBUFFERS) + { + flush_buffers(); + } + + result = &g_blocks[g_next_block]; + g_blockmap[by][bx] = g_next_block + 1; + g_next_block++; + zero_block(result); + return result; + } + else + { + result = &g_blocks[g_blockmap[by][bx] - 1]; + return result; + } +} + +/* =============================== + * Public functions + * =============================== */ + +bool_t gdisp_lld_init(void) +{ + init_board(); + + /* Make sure that all the pins are in "off" state. + * Having any pin high could cause voltage leaking to the + * display, which in turn causes the image to leak slowly away. + */ + power_off(); + + clear_block_map(); + + /* Initialize the global GDISP structure */ + GDISP.Width = GDISP_SCREEN_WIDTH; + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Orientation = GDISP_ROTATE_0; + GDISP.Powermode = powerOff; + GDISP.Backlight = 0; + GDISP.Contrast = 0; + #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + GDISP.clipx0 = 0; + GDISP.clipy0 = 0; + GDISP.clipx1 = GDISP.Width; + GDISP.clipy1 = GDISP.Height; + #endif + + return TRUE; +} + +void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) +{ + block_t *block; + uint8_t byte; + unsigned bx, by, dx, dy; + uint8_t bitpos; + + bx = x / EINK_BLOCKWIDTH; + by = y / EINK_BLOCKHEIGHT; + dx = x % EINK_BLOCKWIDTH; + dy = y % EINK_BLOCKHEIGHT; + + if (bx < 0 || bx >= BLOCKS_X || by < 0 || by >= BLOCKS_Y) + return; + + block = alloc_buffer(bx, by); + + bitpos = (6 - 2 * (dx % EINK_PPB)); + byte = block->data[dy][dx / EINK_PPB]; + byte &= ~(PIXELMASK << bitpos); + if (color) + { + byte |= PIXEL_WHITE << bitpos; + } + else + { + byte |= PIXEL_BLACK << bitpos; + } + block->data[dy][dx / EINK_PPB] = byte; +} + +#if !GDISP_NEED_CONTROL +#error You must enable GDISP_NEED_CONTROL for the E-Ink driver. +#endif + +void gdisp_lld_control(unsigned what, void *value) { + gdisp_powermode_t newmode; + + switch(what) + { + case GDISP_CONTROL_POWER: + newmode = (gdisp_powermode_t)value; + + if (GDISP.Powermode == newmode) + return; + + if (newmode == powerOn) + { + power_on(); + } + else + { + flush_buffers(); + power_off(); + } + GDISP.Powermode = newmode; + break; + + case GDISP_CONTROL_FLUSH: + flush_buffers(); + break; + } +} + +/* =============================== + * Accelerated routines + * =============================== */ + +#if GDISP_HARDWARE_CLEARS + +static void subclear(color_t color) +{ + unsigned x, y; + uint8_t byte; + + hscan_start(); + byte = color ? BYTE_WHITE : BYTE_BLACK; + for (x = 0; x < GDISP_SCREEN_WIDTH; x++) + { + hscan_write(&byte, 1); + } + hscan_stop(); + + setpin_oe(TRUE); + vscan_start(); + for (y = 0; y < GDISP_SCREEN_HEIGHT; y++) + { + vscan_bulkwrite(); + } + vscan_stop(); + setpin_oe(FALSE); +} + +void gdisp_lld_clear(color_t color) +{ + unsigned i; + clear_block_map(); + + if (EINK_BLINKCLEAR) + { + subclear(!color); + gfxSleepMilliseconds(50); + } + + for (i = 0; i < EINK_CLEARCOUNT; i++) + { + subclear(color); + gfxSleepMilliseconds(10); + } + +} +#endif + +#endif diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h b/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h new file mode 100644 index 00000000..98f05ee8 --- /dev/null +++ b/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h @@ -0,0 +1,127 @@ +/* + * 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 + */ + +/* Board interface definitions for ED060SC4 PrimeView E-ink panel. + * + * This file corresponds to the connections shown in example_schematics.png, + * and is designed to interface with ChibiOS/RT. + * + * Please note that this file has never been tested in exactly this pin + * configuration, because the actual boards I have are slightly different. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +#include <hal.h> + +/* + * IO pins assignments. + */ +#define GPIOB_EINK_VDD 0 +#define GPIOB_EINK_GMODE 1 +#define GPIOB_EINK_SPV 2 +#define GPIOB_EINK_CKV 3 +#define GPIOB_EINK_CL 4 +#define GPIOB_EINK_LE 5 +#define GPIOB_EINK_OE 6 +#define GPIOB_EINK_SPH 7 +#define GPIOB_EINK_D0 8 +#define GPIOB_EINK_D1 9 +#define GPIOB_EINK_D2 10 +#define GPIOB_EINK_D3 11 +#define GPIOB_EINK_D4 12 +#define GPIOB_EINK_D5 13 +#define GPIOB_EINK_D6 14 +#define GPIOB_EINK_D7 15 + +#define GPIOC_SMPS_CTRL 13 +#define GPIOC_VPOS_CTRL 14 +#define GPIOC_VNEG_CTRL 15 + + +/* Set up IO pins for the panel connection. */ +static inline void init_board(void) { + /* Main SMPS power control, active low + * (open collector so that MOSFET gate can be pulled up to Vbat) */ + palWritePad(GPIOC, GPIOC_SMPS_CTRL, true); + palSetPadMode(GPIOC, GPIOC_SMPS_CTRL, PAL_MODE_OUTPUT_OPENDRAIN); + + /* Power control for the positive & negative side */ + palWritePad(GPIOC, GPIOC_VPOS_CTRL, false); + palSetPadMode(GPIOC, GPIOC_VPOS_CTRL, PAL_MODE_OUTPUT_PUSHPULL); + palWritePad(GPIOC, GPIOC_VNEG_CTRL, false); + palSetPadMode(GPIOC, GPIOC_VNEG_CTRL, PAL_MODE_OUTPUT_PUSHPULL); + + /* Main data bus */ + palWritePort(GPIOB, 0); + palSetGroupMode(GPIOB, 0xFFFF, 0, PAL_MODE_OUTPUT_PUSHPULL); +} + +/* Delay for display waveforms. Should be an accurate microsecond delay. */ +static void eink_delay(int us) +{ + halPolledDelay(US2RTT(us)); +} + +/* Turn the E-ink panel Vdd supply (+3.3V) on or off. */ +static inline void setpower_vdd(bool_t on) { + palWritePad(GPIOB, GPIOB_SMPS_CTRL, !on); + palWritePad(GPIOA, GPIOA_EINK_VDD, on); +} + +/* Turn the E-ink panel negative supplies (-15V, -20V) on or off. */ +static inline void setpower_vneg(bool_t on) { + palWritePad(GPIOA, GPIOA_VNEG_CTRL, on); +} + +/* Turn the E-ink panel positive supplies (-15V, -20V) on or off. */ +static inline void setpower_vpos(bool_t on) { + palWritePad(GPIOA, GPIOA_VPOS_CTRL, on); +} + +/* Set the state of the LE (source driver Latch Enable) pin. */ +static inline void setpin_le(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_LE, on); +} + +/* Set the state of the OE (source driver Output Enable) pin. */ +static inline void setpin_oe(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_OE, on); +} + +/* Set the state of the CL (source driver Clock) pin. */ +static inline void setpin_cl(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_CL, on); +} + +/* Set the state of the SPH (source driver Start Pulse Horizontal) pin. */ +static inline void setpin_sph(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_SPH, on); +} + +/* Set the state of the D0-D7 (source driver Data) pins. */ +static inline void setpins_data(uint8_t value) { + palWriteGroup(GPIOB, 0xFF, GPIOB_EINK_D0, value); +} + +/* Set the state of the CKV (gate driver Clock Vertical) pin. */ +static inline void setpin_ckv(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_CKV, on); +} + +/* Set the state of the GMODE (gate driver Gate Mode) pin. */ +static inline void setpin_gmode(bool_t on) { + palWritePad(GPIOC, GPIOC_EINK_GMODE, on); +} + +/* Set the state of the SPV (gate driver Start Pulse Vertical) pin. */ +static inline void setpin_spv(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_SPV, on); +} + +#endif diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h b/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h new file mode 100644 index 00000000..68129bf8 --- /dev/null +++ b/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h @@ -0,0 +1,83 @@ +/* + * 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 + */ + +/* Board interface definitions for ED060SC4 PrimeView E-ink panel. + * + * You should implement the following functions to define the interface to + * the panel on your board. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/* Set up IO pins for the panel connection. */ +static inline void init_board(void) { + #error Unimplemented +} + +/* Delay for display waveforms. Should be an accurate microsecond delay. */ +static void eink_delay(int us) +{ + #error Unimplemented +} + +/* Turn the E-ink panel Vdd supply (+3.3V) on or off. */ +static inline void setpower_vdd(bool_t on) { + #error Unimplemented +} + +/* Turn the E-ink panel negative supplies (-15V, -20V) on or off. */ +static inline void setpower_vneg(bool_t on) { + #error Unimplemented +} + +/* Turn the E-ink panel positive supplies (-15V, -20V) on or off. */ +static inline void setpower_vpos(bool_t on) { + #error Unimplemented +} + +/* Set the state of the LE (source driver Latch Enable) pin. */ +static inline void setpin_le(bool_t on) { + #error Unimplemented +} + +/* Set the state of the OE (source driver Output Enable) pin. */ +static inline void setpin_oe(bool_t on) { + #error Unimplemented +} + +/* Set the state of the CL (source driver Clock) pin. */ +static inline void setpin_cl(bool_t on) { + #error Unimplemented +} + +/* Set the state of the SPH (source driver Start Pulse Horizontal) pin. */ +static inline void setpin_sph(bool_t on) { + #error Unimplemented +} + +/* Set the state of the D0-D7 (source driver Data) pins. */ +static inline void setpins_data(uint8_t value) { + #error Unimplemented +} + +/* Set the state of the CKV (gate driver Clock Vertical) pin. */ +static inline void setpin_ckv(bool_t on) { + #error Unimplemented +} + +/* Set the state of the GMODE (gate driver Gate Mode) pin. */ +static inline void setpin_gmode(bool_t on) { + #error Unimplemented +} + +/* Set the state of the SPV (gate driver Start Pulse Vertical) pin. */ +static inline void setpin_spv(bool_t on) { + #error Unimplemented +} + +#endif diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c new file mode 100644 index 00000000..a55dd467 --- /dev/null +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -0,0 +1,637 @@ +/*
+ * 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
+ */
+
+/**
+ * @file drivers/gdisp/SSD1289/gdisp_lld.c
+ * @brief GDISP Graphics Driver subsystem low level driver source for the SSD1289 display.
+ *
+ * @addtogroup GDISP
+ * @{
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/
+
+/* Include the emulation code for things we don't support */
+#include "gdisp/lld/emulation.c"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#ifndef GDISP_SCREEN_HEIGHT
+ #define GDISP_SCREEN_HEIGHT 320
+#endif
+#ifndef GDISP_SCREEN_WIDTH
+ #define GDISP_SCREEN_WIDTH 240
+#endif
+
+#define GDISP_INITIAL_CONTRAST 50
+#define GDISP_INITIAL_BACKLIGHT 100
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+#include "gdisp_lld_board.h"
+
+// Some common routines and macros
+#define write_reg(reg, data) { write_index(reg); write_data(data); }
+#define stream_start() write_index(0x0022);
+#define stream_stop()
+#define delay(us) gfxSleepMicroseconds(us)
+#define delayms(ms) gfxSleepMilliseconds(ms)
+
+static inline void set_cursor(coord_t x, coord_t y) {
+ /* Reg 0x004E is an 8 bit value
+ * Reg 0x004F is 9 bit
+ * Use a bit mask to make sure they are not set too high
+ */
+ switch(GDISP.Orientation) {
+ case GDISP_ROTATE_180:
+ write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-x) & 0x00FF);
+ write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-y) & 0x01FF);
+ break;
+ case GDISP_ROTATE_0:
+ write_reg(0x004e, x & 0x00FF);
+ write_reg(0x004f, y & 0x01FF);
+ break;
+ case GDISP_ROTATE_270:
+ write_reg(0x004e, y & 0x00FF);
+ write_reg(0x004f, x & 0x01FF);
+ break;
+ case GDISP_ROTATE_90:
+ write_reg(0x004e, (GDISP_SCREEN_WIDTH - y - 1) & 0x00FF);
+ write_reg(0x004f, (GDISP_SCREEN_HEIGHT - x - 1) & 0x01FF);
+ break;
+ }
+}
+
+static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) {
+
+ //set_cursor(x, y);
+
+ /* Reg 0x44 - Horizontal RAM address position
+ * Upper Byte - HEA
+ * Lower Byte - HSA
+ * 0 <= HSA <= HEA <= 0xEF
+ * Reg 0x45,0x46 - Vertical RAM address position
+ * Lower 9 bits gives 0-511 range in each value
+ * 0 <= Reg(0x45) <= Reg(0x46) <= 0x13F
+ */
+
+ switch(GDISP.Orientation) {
+ case GDISP_ROTATE_0:
+ write_reg(0x44, (((x+cx-1) << 8) & 0xFF00 ) | (x & 0x00FF));
+ write_reg(0x45, y & 0x01FF);
+ write_reg(0x46, (y+cy-1) & 0x01FF);
+ break;
+ case GDISP_ROTATE_270:
+ write_reg(0x44, (((y+cy-1) << 8) & 0xFF00 ) | (y & 0x00FF));
+ write_reg(0x45, x & 0x01FF);
+ write_reg(0x46, (x+cx-1) & 0x01FF);
+ break;
+ case GDISP_ROTATE_180:
+ write_reg(0x44, (((GDISP_SCREEN_WIDTH-x-1) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (x+cx)) & 0x00FF));
+ write_reg(0x45, (GDISP_SCREEN_HEIGHT-(y+cy)) & 0x01FF);
+ write_reg(0x46, (GDISP_SCREEN_HEIGHT-y-1) & 0x01FF);
+ break;
+ case GDISP_ROTATE_90:
+ write_reg(0x44, (((GDISP_SCREEN_WIDTH - y - 1) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (y+cy)) & 0x00FF));
+ write_reg(0x45, (GDISP_SCREEN_HEIGHT - (x+cx)) & 0x01FF);
+ write_reg(0x46, (GDISP_SCREEN_HEIGHT - x - 1) & 0x01FF);
+ break;
+ }
+
+ set_cursor(x, y);
+}
+
+static inline void reset_viewport(void) {
+ set_viewport(0, 0, GDISP.Width, GDISP.Height);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/* ---- Required Routines ---- */
+/*
+ The following 2 routines are required.
+ All other routines are optional.
+*/
+
+/**
+ * @brief Low level GDISP driver initialization.
+ *
+ * @notapi
+ */
+bool_t gdisp_lld_init(void) {
+ /* Initialise your display */
+ init_board();
+
+ // Hardware reset
+ setpin_reset(TRUE);
+ delayms(20);
+ setpin_reset(FALSE);
+ delayms(20);
+
+ // Get the bus for the following initialisation commands
+ acquire_bus();
+
+ write_reg(0x0000,0x0001); delay(5);
+ write_reg(0x0003,0xA8A4); delay(5);
+ write_reg(0x000C,0x0000); delay(5);
+ write_reg(0x000D,0x080C); delay(5);
+ write_reg(0x000E,0x2B00); delay(5);
+ write_reg(0x001E,0x00B0); delay(5);
+ write_reg(0x0001,0x2B3F); delay(5);
+ write_reg(0x0002,0x0600); delay(5);
+ write_reg(0x0010,0x0000); delay(5);
+ write_reg(0x0011,0x6070); delay(5);
+ write_reg(0x0005,0x0000); delay(5);
+ write_reg(0x0006,0x0000); delay(5);
+ write_reg(0x0016,0xEF1C); delay(5);
+ write_reg(0x0017,0x0003); delay(5);
+ write_reg(0x0007,0x0133); delay(5);
+ write_reg(0x000B,0x0000); delay(5);
+ write_reg(0x000F,0x0000); delay(5);
+ write_reg(0x0041,0x0000); delay(5);
+ write_reg(0x0042,0x0000); delay(5);
+ write_reg(0x0048,0x0000); delay(5);
+ write_reg(0x0049,0x013F); delay(5);
+ write_reg(0x004A,0x0000); delay(5);
+ write_reg(0x004B,0x0000); delay(5);
+ write_reg(0x0044,0xEF00); delay(5);
+ write_reg(0x0045,0x0000); delay(5);
+ write_reg(0x0046,0x013F); delay(5);
+ write_reg(0x0030,0x0707); delay(5);
+ write_reg(0x0031,0x0204); delay(5);
+ write_reg(0x0032,0x0204); delay(5);
+ write_reg(0x0033,0x0502); delay(5);
+ write_reg(0x0034,0x0507); delay(5);
+ write_reg(0x0035,0x0204); delay(5);
+ write_reg(0x0036,0x0204); delay(5);
+ write_reg(0x0037,0x0502); delay(5);
+ write_reg(0x003A,0x0302); delay(5);
+ write_reg(0x003B,0x0302); delay(5);
+ write_reg(0x0023,0x0000); delay(5);
+ write_reg(0x0024,0x0000); delay(5);
+ write_reg(0x0025,0x8000); delay(5);
+ write_reg(0x004f,0x0000); delay(5);
+ write_reg(0x004e,0x0000); delay(5);
+
+ // Release the bus
+ release_bus();
+
+ /* Turn on the back-light */
+ set_backlight(GDISP_INITIAL_BACKLIGHT);
+
+ /* Initialise the GDISP structure */
+ GDISP.Width = GDISP_SCREEN_WIDTH;
+ GDISP.Height = GDISP_SCREEN_HEIGHT;
+ GDISP.Orientation = GDISP_ROTATE_0;
+ GDISP.Powermode = powerOn;
+ GDISP.Backlight = GDISP_INITIAL_BACKLIGHT;
+ GDISP.Contrast = GDISP_INITIAL_CONTRAST;
+ #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
+ GDISP.clipx0 = 0;
+ GDISP.clipy0 = 0;
+ GDISP.clipx1 = GDISP.Width;
+ GDISP.clipy1 = GDISP.Height;
+ #endif
+ return TRUE;
+}
+
+/**
+ * @brief Draws a pixel on the display.
+ *
+ * @param[in] x X location of the pixel
+ * @param[in] y Y location of the pixel
+ * @param[in] color The color of the pixel
+ *
+ * @notapi
+ */
+void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
+ #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
+ if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return;
+ #endif
+
+ acquire_bus();
+ set_cursor(x, y);
+ write_reg(0x0022, color);
+ release_bus();
+}
+
+/* ---- Optional Routines ---- */
+/*
+ All the below routines are optional.
+ Defining them will increase speed but everything
+ will work if they are not defined.
+ If you are not using a routine - turn it off using
+ the appropriate GDISP_HARDWARE_XXXX macro.
+ Don't bother coding for obvious similar routines if
+ there is no performance penalty as the emulation software
+ makes a good job of using similar routines.
+ eg. If gfillarea() is defined there is little
+ point in defining clear() unless the
+ performance bonus is significant.
+ For good performance it is suggested to implement
+ fillarea() and blitarea().
+*/
+
+#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__)
+ /**
+ * @brief Clear the display.
+ * @note Optional - The high level driver can emulate using software.
+ *
+ * @param[in] color The color of the pixel
+ *
+ * @notapi
+ */
+ void gdisp_lld_clear(color_t color) {
+ unsigned area;
+
+ area = GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT;
+
+ acquire_bus();
+ reset_viewport();
+ set_cursor(0, 0);
+
+ stream_start();
+
+ #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM)
+ uint8_t i;
+ dmaStreamSetPeripheral(GDISP_DMA_STREAM, &color);
+ dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M);
+ for (i = area/65535; i; i--) {
+ dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535);
+ dmaStreamEnable(GDISP_DMA_STREAM);
+ dmaWaitCompletion(GDISP_DMA_STREAM);
+ }
+ dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535);
+ dmaStreamEnable(GDISP_DMA_STREAM);
+ dmaWaitCompletion(GDISP_DMA_STREAM);
+ #else
+ uint32_t index;
+ for(index = 0; index < area; index++)
+ write_data(color);
+ #endif //#ifdef GDISP_USE_DMA
+
+ stream_stop();
+ release_bus();
+ }
+#endif
+
+#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__)
+ /**
+ * @brief Fill an area with a color.
+ * @note Optional - The high level driver can emulate using software.
+ *
+ * @param[in] x, y The start filled area
+ * @param[in] cx, cy The width and height to be filled
+ * @param[in] color The color of the fill
+ *
+ * @notapi
+ */
+ void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
+ unsigned area;
+
+ #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
+ if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; }
+ if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; }
+ if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return;
+ if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x;
+ if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y;
+ #endif
+
+ area = cx*cy;
+
+ acquire_bus();
+ set_viewport(x, y, cx, cy);
+ stream_start();
+
+ #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM)
+ uint8_t i;
+ dmaStreamSetPeripheral(GDISP_DMA_STREAM, &color);
+ dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M);
+ for (i = area/65535; i; i--) {
+ dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535);
+ dmaStreamEnable(GDISP_DMA_STREAM);
+ dmaWaitCompletion(GDISP_DMA_STREAM);
+ }
+ dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535);
+ dmaStreamEnable(GDISP_DMA_STREAM);
+ dmaWaitCompletion(GDISP_DMA_STREAM);
+ #else
+ uint32_t index;
+ for(index = 0; index < area; index++)
+ write_data(color);
+ #endif //#ifdef GDISP_USE_DMA
+
+ stream_stop();
+ release_bus();
+ }
+#endif
+
+#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__)
+ /**
+ * @brief Fill an area with a bitmap.
+ * @note Optional - The high level driver can emulate using software.
+ *
+ * @param[in] x, y The start filled area
+ * @param[in] cx, cy The width and height to be filled
+ * @param[in] srcx, srcy The bitmap position to start the fill from
+ * @param[in] srccx The width of a line in the bitmap.
+ * @param[in] buffer The pixels to use to fill the area.
+ *
+ * @notapi
+ */
+ void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
+
+ #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
+ if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; }
+ if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; }
+ if (srcx+cx > srccx) cx = srccx - srcx;
+ if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return;
+ if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x;
+ if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y;
+ #endif
+
+ buffer += srcx + srcy * srccx;
+
+ acquire_bus();
+ set_viewport(x, y, cx, cy);
+ stream_start();
+
+ #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM)
+ uint32_t area = cx*cy;
+ uint8_t i;
+ dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer);
+ dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PINC | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M);
+ for (i = area/65535; i; i--) {
+ dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535);
+ dmaStreamEnable(GDISP_DMA_STREAM);
+ dmaWaitCompletion(GDISP_DMA_STREAM);
+ }
+ dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535);
+ dmaStreamEnable(GDISP_DMA_STREAM);
+ dmaWaitCompletion(GDISP_DMA_STREAM);
+ #else
+ coord_t endx, endy;
+ uint32_t lg;
+ endx = srcx + cx;
+ endy = y + cy;
+ lg = srccx - cx;
+ for(; y < endy; y++, buffer += lg)
+ for(x=srcx; x < endx; x++)
+ write_data(*buffer++);
+ #endif //#ifdef GDISP_USE_DMA
+
+ stream_stop();
+ release_bus();
+ }
+#endif
+
+#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__)
+ /**
+ * @brief Get the color of a particular pixel.
+ * @note Optional.
+ * @note If x,y is off the screen, the result is undefined.
+ *
+ * @param[in] x, y The pixel to be read
+ *
+ * @notapi
+ */
+ color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) {
+ color_t color;
+
+ #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
+ if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0;
+ #endif
+
+ acquire_bus();
+ set_cursor(x, y);
+ stream_start();
+
+ /* FSMC timing */
+ FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_3 | FSMC_BTR1_DATAST_3 | FSMC_BTR1_BUSTURN_0 ;
+
+ color = read_data(); // dummy read
+ color = read_data();
+
+ /* FSMC timing */
+ FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ;
+
+ stream_stop();
+ release_bus();
+
+ return color;
+ }
+#endif
+
+#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__)
+ /**
+ * @brief Scroll vertically a section of the screen.
+ * @note Optional.
+ * @note If x,y + cx,cy is off the screen, the result is undefined.
+ * @note If lines is >= cy, it is equivelent to a area fill with bgcolor.
+ *
+ * @param[in] x, y The start of the area to be scrolled
+ * @param[in] cx, cy The size of the area to be scrolled
+ * @param[in] lines The number of lines to scroll (Can be positive or negative)
+ * @param[in] bgcolor The color to fill the newly exposed area.
+ *
+ * @notapi
+ */
+ void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) {
+ static color_t buf[((GDISP_SCREEN_HEIGHT > GDISP_SCREEN_WIDTH ) ? GDISP_SCREEN_HEIGHT : GDISP_SCREEN_WIDTH)];
+ coord_t row0, row1;
+ unsigned i, gap, abslines, j;
+
+ #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
+ if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; }
+ if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; }
+ if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return;
+ if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x;
+ if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y;
+ #endif
+
+ abslines = lines < 0 ? -lines : lines;
+
+ acquire_bus();
+ if ((coord_t)abslines >= cy) {
+ abslines = cy;
+ gap = 0;
+ } else {
+ gap = cy - abslines;
+ for(i = 0; i < gap; i++) {
+ if(lines > 0) {
+ row0 = y + i + lines;
+ row1 = y + i;
+ } else {
+ row0 = (y - i - 1) + lines;
+ row1 = (y - i - 1);
+ }
+
+ /* read row0 into the buffer and then write at row1*/
+ set_viewport(x, row0, cx, 1);
+ stream_start();
+
+ /* FSMC timing */
+ FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_3 | FSMC_BTR1_DATAST_3 | FSMC_BTR1_BUSTURN_0 ;
+
+ j = read_data(); // dummy read
+ for (j = 0; (coord_t)j < cx; j++)
+ buf[j] = read_data();
+
+ /* FSMC timing */
+ FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ;
+
+ stream_stop();
+
+ set_viewport(x, row1, cx, 1);
+ stream_start();
+ for (j = 0; (coord_t)j < cx; j++)
+ write_data(buf[j]);
+ stream_stop();
+ }
+ }
+
+ /* fill the remaining gap */
+ set_viewport(x, lines > 0 ? (y+(coord_t)gap) : y, cx, abslines);
+ stream_start();
+ gap = cx*abslines;
+ for(i = 0; i < gap; i++) write_data(bgcolor);
+ stream_stop();
+ release_bus();
+ }
+#endif
+
+#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__)
+ /**
+ * @brief Driver Control
+ * @details Unsupported control codes are ignored.
+ * @note The value parameter should always be typecast to (void *).
+ * @note There are some predefined and some specific to the low level driver.
+ * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t
+ * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t
+ * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver
+ * that only supports off/on anything other
+ * than zero is on.
+ * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100.
+ * GDISP_CONTROL_LLD - Low level driver control constants start at
+ * this value.
+ *
+ * @param[in] what What to do.
+ * @param[in] value The value to use (always cast to a void *).
+ *
+ * @notapi
+ */
+ void gdisp_lld_control(unsigned what, void *value) {
+ switch(what) {
+ case GDISP_CONTROL_POWER:
+ if (GDISP.Powermode == (gdisp_powermode_t)value)
+ return;
+ switch((gdisp_powermode_t)value) {
+ case powerOff:
+ acquire_bus();
+ write_reg(0x0010, 0x0000); // leave sleep mode
+ write_reg(0x0007, 0x0000); // halt operation
+ write_reg(0x0000, 0x0000); // turn off oszillator
+ write_reg(0x0010, 0x0001); // enter sleepmode
+ release_bus();
+ break;
+ case powerOn:
+ acquire_bus();
+ write_reg(0x0010, 0x0000); // leave sleep mode
+ release_bus();
+ if (GDISP.Powermode != powerSleep)
+ gdisp_lld_init();
+ break;
+ case powerSleep:
+ acquire_bus();
+ write_reg(0x0010, 0x0001); // enter sleep mode
+ release_bus();
+ break;
+ default:
+ return;
+ }
+ GDISP.Powermode = (gdisp_powermode_t)value;
+ return;
+ case GDISP_CONTROL_ORIENTATION:
+ if (GDISP.Orientation == (gdisp_orientation_t)value)
+ return;
+ switch((gdisp_orientation_t)value) {
+ case GDISP_ROTATE_0:
+ acquire_bus();
+ write_reg(0x0001, 0x2B3F);
+ /* ID = 11 AM = 0 */
+ write_reg(0x0011, 0x6070);
+ release_bus();
+ GDISP.Height = GDISP_SCREEN_HEIGHT;
+ GDISP.Width = GDISP_SCREEN_WIDTH;
+ break;
+ case GDISP_ROTATE_90:
+ acquire_bus();
+ write_reg(0x0001, 0x293F);
+ /* ID = 11 AM = 1 */
+ write_reg(0x0011, 0x6078);
+ release_bus();
+ GDISP.Height = GDISP_SCREEN_WIDTH;
+ GDISP.Width = GDISP_SCREEN_HEIGHT;
+ break;
+ case GDISP_ROTATE_180:
+ acquire_bus();
+ write_reg(0x0001, 0x2B3F);
+ /* ID = 01 AM = 0 */
+ write_reg(0x0011, 0x6040);
+ release_bus();
+ GDISP.Height = GDISP_SCREEN_HEIGHT;
+ GDISP.Width = GDISP_SCREEN_WIDTH;
+ break;
+ case GDISP_ROTATE_270:
+ acquire_bus();
+ write_reg(0x0001, 0x293F);
+ /* ID = 01 AM = 1 */
+ write_reg(0x0011, 0x6048);
+ release_bus();
+ GDISP.Height = GDISP_SCREEN_WIDTH;
+ GDISP.Width = GDISP_SCREEN_HEIGHT;
+ break;
+ default:
+ return;
+ }
+ #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION
+ GDISP.clipx0 = 0;
+ GDISP.clipy0 = 0;
+ GDISP.clipx1 = GDISP.Width;
+ GDISP.clipy1 = GDISP.Height;
+ #endif
+ GDISP.Orientation = (gdisp_orientation_t)value;
+ return;
+ case GDISP_CONTROL_BACKLIGHT:
+ if ((unsigned)value > 100)
+ value = (void *)100;
+ set_backlight((unsigned)value);
+ GDISP.Backlight = (unsigned)value;
+ return;
+ default:
+ return;
+/*
+ case GDISP_CONTROL_CONTRAST:
+*/
+ }
+ }
+#endif
+
+#endif /* GFX_USE_GDISP */
+/** @} */
|