aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gdisp/ED060SC4
diff options
context:
space:
mode:
authorJoel Bodenmann <joel@unormal.org>2013-11-10 21:07:16 +0100
committerJoel Bodenmann <joel@unormal.org>2013-11-10 21:07:16 +0100
commitda2740b706d720292113445ee1db30f8a9873dc4 (patch)
tree8f8b1902d4af6a23b3daf26990f580b76ea31ea4 /drivers/gdisp/ED060SC4
parent6ca3537a696e7ace8098771a9a7105380604253d (diff)
parenta8ce005e2621b0108863297948cea0fa52c8bf2a (diff)
downloaduGFX-da2740b706d720292113445ee1db30f8a9873dc4.tar.gz
uGFX-da2740b706d720292113445ee1db30f8a9873dc4.tar.bz2
uGFX-da2740b706d720292113445ee1db30f8a9873dc4.zip
merging GDISPStreaming
Diffstat (limited to 'drivers/gdisp/ED060SC4')
-rw-r--r--drivers/gdisp/ED060SC4/board_ED060SC4_template.h202
-rw-r--r--drivers/gdisp/ED060SC4/gdisp_lld.mk2
-rw-r--r--drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c625
-rw-r--r--drivers/gdisp/ED060SC4/gdisp_lld_config.h9
-rw-r--r--drivers/gdisp/ED060SC4/readme.txt3
5 files changed, 832 insertions, 9 deletions
diff --git a/drivers/gdisp/ED060SC4/board_ED060SC4_template.h b/drivers/gdisp/ED060SC4/board_ED060SC4_template.h
new file mode 100644
index 00000000..6d71a986
--- /dev/null
+++ b/drivers/gdisp/ED060SC4/board_ED060SC4_template.h
@@ -0,0 +1,202 @@
+/*
+ * 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/ST7565/board_ST7565_template.h
+ * @brief GDISP Graphic Driver subsystem board interface for the ST7565 display.
+ *
+ * @addtogroup GDISP
+ * @{
+ */
+
+#ifndef _GDISP_LLD_BOARD_H
+#define _GDISP_LLD_BOARD_H
+
+/**
+ * @brief Optional parameters that can be put in this file.
+ * @note The values listed below are the defaults.
+ *
+ * @note #define GDISP_SCREEN_HEIGHT 600
+ * @note #define GDISP_SCREEN_WIDTH 800
+ *
+ * @note Number of pixels per byte<br>
+ * #define EINK_PPB 4
+ *
+ * @note Delay for generating clock pulses.
+ * Unit is approximate clock cycles of the CPU (0 to 15).
+ * This should be atleast 50 ns.<br>
+ * #define EINK_CLOCKDELAY 0
+ *
+ * @note Width of one framebuffer block.
+ * Must be divisible by EINK_PPB and evenly divide GDISP_SCREEN_WIDTH.<br>
+ * #define EINK_BLOCKWIDTH 20
+ *
+ * @note
+ * @note Height of one framebuffer block.
+ * Must evenly divide GDISP_SCREEN_WIDTH.<br>
+ * #define EINK_BLOCKHEIGHT 20
+ *
+ * @note Number of block buffers to use for framebuffer emulation.<br>
+ * #define EINK_NUMBUFFERS 40
+ *
+ * @note Do a "blinking" clear, i.e. clear to opposite polarity first.
+ * This reduces the image persistence.<br>
+ * #define EINK_BLINKCLEAR TRUE
+ *
+ * @note Number of passes to use when clearing the display<br>
+ * #define EINK_CLEARCOUNT 10
+ *
+ * @note Number of passes to use when writing to the display<br>
+ * #define EINK_WRITECOUNT 4
+ */
+
+/**
+ * @brief Initialise the board for the display.
+ *
+ * @param[in] g The GDisplay structure
+ *
+ * @note Set the g->board member to whatever is appropriate. For multiple
+ * displays this might be a pointer to the appropriate register set.
+ *
+ * @notapi
+ */
+static inline void init_board(GDisplay *g) {
+ (void) g;
+}
+
+/**
+ * @brief Delay for display waveforms. Should be an accurate microsecond delay.
+ *
+ * @param[in] us The number of microseconds
+ */
+static void eink_delay(int us) {
+ (void) us;
+}
+
+/**
+ * @brief Turn the E-ink panel Vdd supply (+3.3V) on or off.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpower_vdd(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+/**
+ * @brief Turn the E-ink panel negative supplies (-15V, -20V) on or off.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpower_vneg(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+/**
+ * @brief Turn the E-ink panel positive supplies (-15V, -20V) on or off.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpower_vpos(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+/**
+ * @brief Set the state of the LE (source driver Latch Enable) pin.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpin_le(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+/**
+ * @brief Set the state of the OE (source driver Output Enable) pin.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpin_oe(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+/**
+ * @brief Set the state of the CL (source driver Clock) pin.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpin_cl(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+/**
+ * @brief Set the state of the SPH (source driver Start Pulse Horizontal) pin.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpin_sph(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+/**
+ * @brief Set the state of the D0-D7 (source driver Data) pins.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] value The byte to write
+ */
+static inline void setpins_data(GDisplay *g, uint8_t value) {
+ (void) g;
+ (void) value;
+}
+
+/**
+ * @brief Set the state of the CKV (gate driver Clock Vertical) pin.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpin_ckv(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+/**
+ * @brief Set the state of the GMODE (gate driver Gate Mode) pin.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpin_gmode(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+/**
+ * @brief Set the state of the SPV (gate driver Start Pulse Vertical) pin.
+ *
+ * @param[in] g The GDisplay structure
+ * @param[in] on On or off
+ */
+static inline void setpin_spv(GDisplay *g, bool_t on) {
+ (void) g;
+ (void) on;
+}
+
+#endif /* _GDISP_LLD_BOARD_H */
+/** @} */
diff --git a/drivers/gdisp/ED060SC4/gdisp_lld.mk b/drivers/gdisp/ED060SC4/gdisp_lld.mk
index d5c1492f..0c78e1a7 100644
--- a/drivers/gdisp/ED060SC4/gdisp_lld.mk
+++ b/drivers/gdisp/ED060SC4/gdisp_lld.mk
@@ -1,2 +1,2 @@
-GFXSRC += $(GFXLIB)/drivers/gdisp/ED060SC4/gdisp_lld.c
GFXINC += $(GFXLIB)/drivers/gdisp/ED060SC4
+GFXSRC += $(GFXLIB)/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c
diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c b/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c
new file mode 100644
index 00000000..3ab1de79
--- /dev/null
+++ b/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c
@@ -0,0 +1,625 @@
+/*
+ * 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/ED060SC4/gdisp_lld.c
+ * @brief GDISP Graphics Driver for the E-ink panel ED060SC4.
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GDISP
+
+#define GDISP_DRIVER_VMT GDISPVMT_ED060SC4
+#include "../drivers/gdisp/ED060SC4/gdisp_lld_config.h"
+#include "gdisp/lld/gdisp_lld.h"
+
+#include "board_ED060SC4.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#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
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+#define PRIV(g) ((drvPriv *)g->priv)
+
+/** Delay between signal changes, to give time for IO pins to change state. */
+static inline void clockdelay(void)
+{
+ #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(GDisplay *g)
+{
+ setpin_ckv(g, TRUE);
+ eink_delay(1);
+ setpin_ckv(g, FALSE);
+ eink_delay(4);
+}
+
+/** Horizontal clock pulse for clocking data into source driver */
+static void hclock(GDisplay *g)
+{
+ clockdelay();
+ setpin_cl(g, TRUE);
+ clockdelay();
+ setpin_cl(g, 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(GDisplay *g)
+{
+ setpin_gmode(g, TRUE);
+ vclock_quick(g);
+ setpin_spv(g, FALSE);
+ vclock_quick(g);
+ setpin_spv(g, TRUE);
+ vclock_quick(g);
+}
+
+/** 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(GDisplay *g)
+{
+ setpin_ckv(g, TRUE);
+ setpin_oe(g, TRUE);
+ eink_delay(5);
+ setpin_oe(g, FALSE);
+ setpin_ckv(g, 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(GDisplay *g)
+{
+ setpin_ckv(g, TRUE);
+ eink_delay(20);
+ setpin_ckv(g, 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(GDisplay *g)
+{
+ setpin_ckv(g, TRUE);
+ eink_delay(1);
+ setpin_ckv(g, 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(GDisplay *g)
+{
+ setpin_gmode(g, FALSE);
+ vclock_quick(g);
+ vclock_quick(g);
+ vclock_quick(g);
+ vclock_quick(g);
+ vclock_quick(g);
+}
+
+/** Start updating the source driver data (from left to right). */
+static void hscan_start(GDisplay *g)
+{
+ /* Disable latching and output enable while we are modifying the row. */
+ setpin_le(g, FALSE);
+ setpin_oe(g, FALSE);
+
+ /* The start pulse should remain low for the duration of the row. */
+ setpin_sph(g, FALSE);
+}
+
+/** Write data to the horizontal row. */
+static void hscan_write(GDisplay *g, const uint8_t *data, int count)
+{
+ while (count--)
+ {
+ /* Set the next byte on the data pins */
+ setpins_data(g, *data++);
+
+ /* Give a clock pulse to the shift register */
+ hclock(g);
+ }
+}
+
+/** 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(GDisplay *g)
+{
+ /* End the scan */
+ setpin_sph(g, TRUE);
+ hclock(g);
+
+ /* Latch the new data */
+ setpin_le(g, TRUE);
+ clockdelay();
+ setpin_le(g, FALSE);
+}
+
+/** Turn on the power to the E-Ink panel, observing proper power sequencing. */
+static void power_on(GDisplay *g)
+{
+ unsigned i;
+
+ /* First the digital power supply and signal levels. */
+ setpower_vdd(g, TRUE);
+ setpin_le(g, FALSE);
+ setpin_oe(g, FALSE);
+ setpin_cl(g, FALSE);
+ setpin_sph(g, TRUE);
+ setpins_data(g, 0);
+ setpin_ckv(g, FALSE);
+ setpin_gmode(g, FALSE);
+ setpin_spv(g, TRUE);
+
+ /* Min. 100 microsecond delay after digital supply */
+ gfxSleepMicroseconds(100);
+
+ /* Then negative voltages and min. 1000 microsecond delay. */
+ setpower_vneg(g, TRUE);
+ gfxSleepMicroseconds(1000);
+
+ /* Finally the positive voltages. */
+ setpower_vpos(g, TRUE);
+
+ /* Clear the vscan shift register */
+ vscan_start(g);
+ for (i = 0; i < GDISP_SCREEN_HEIGHT; i++)
+ vclock_quick(g);
+ vscan_stop(g);
+}
+
+/** Turn off the power, observing proper power sequencing. */
+static void power_off(GDisplay *g)
+{
+ /* First the high voltages */
+ setpower_vpos(g, FALSE);
+ setpower_vneg(g, FALSE);
+
+ /* Wait for any capacitors to drain */
+ gfxSleepMilliseconds(100);
+
+ /* Then put all signals and digital supply to ground. */
+ setpin_le(g, FALSE);
+ setpin_oe(g, FALSE);
+ setpin_cl(g, FALSE);
+ setpin_sph(g, FALSE);
+ setpins_data(g, 0);
+ setpin_ckv(g, FALSE);
+ setpin_gmode(g, FALSE);
+ setpin_spv(g, FALSE);
+ setpower_vdd(g, 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;
+
+typedef struct drvPriv {
+ uint8_t g_next_block; /* Index of the next free block buffer. */
+ 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.
+ */
+ uint8_t g_blockmap[BLOCKS_Y][BLOCKS_X];
+} drvPriv;
+
+/** Check if the row contains any allocated blocks. */
+static bool_t blocks_on_row(GDisplay *g, unsigned by)
+{
+ unsigned bx;
+ for (bx = 0; bx < BLOCKS_X; bx++)
+ {
+ if (PRIV(g)->g_blockmap[by][bx] != 0)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/** Write out a block row. */
+static void write_block_row(GDisplay *g, unsigned by)
+{
+ unsigned bx, dy, dx;
+ for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++)
+ {
+ hscan_start(g);
+ for (bx = 0; bx < BLOCKS_X; bx++)
+ {
+ if (PRIV(g)->g_blockmap[by][bx] == 0)
+ {
+ for (dx = 0; dx < WIDTH_BYTES; dx++)
+ {
+ const uint8_t dummy = 0;
+ hscan_write(g, &dummy, 1);
+ }
+ }
+ else
+ {
+ block_t *block = &PRIV(g)->g_blocks[PRIV(g)->g_blockmap[by][bx] - 1];
+ hscan_write(g, &block->data[dy][0], WIDTH_BYTES);
+ }
+ }
+ hscan_stop(g);
+
+ vscan_write(g);
+ }
+}
+
+/** Clear the block map, i.e. deallocate all blocks */
+static void clear_block_map(GDisplay *g)
+{
+ unsigned bx, by;
+ for (by = 0; by < BLOCKS_Y; by++)
+ {
+ for (bx = 0; bx < BLOCKS_X; bx++)
+ {
+ PRIV(g)->g_blockmap[by][bx] = 0;
+ }
+ }
+
+ PRIV(g)->g_next_block = 0;
+}
+
+/** 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(GDisplay *g, unsigned bx, unsigned by)
+{
+ block_t *result;
+ drvPriv *priv;
+
+ priv = PRIV(g);
+ if (priv->g_blockmap[by][bx] == 0)
+ {
+ if (priv->g_next_block >= EINK_NUMBUFFERS)
+ gdisp_lld_flush(g);
+
+ result = &priv->g_blocks[priv->g_next_block];
+ priv->g_blockmap[by][bx] = priv->g_next_block + 1;
+ priv->g_next_block++;
+ zero_block(result);
+ return result;
+ }
+ else
+ {
+ result = &priv->g_blocks[priv->g_blockmap[by][bx] - 1];
+ return result;
+ }
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
+ g->priv = gfxAlloc(sizeof(drvPriv));
+
+ init_board(g);
+
+ /* 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(g);
+
+ clear_block_map(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 = 100;
+ g->g.Contrast = 100;
+ return TRUE;
+}
+
+#if GDISP_HARDWARE_FLUSH
+ LLDSPEC void gdisp_lld_flush(GDisplay *g) {
+ unsigned by, dy, i;
+
+ for (i = 0; i < EINK_WRITECOUNT; i++) {
+ vscan_start(g);
+
+ for (by = 0; by < BLOCKS_Y; by++) {
+ if (!blocks_on_row(g, by)) {
+ /* Skip the whole row of blocks. */
+ for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++)
+ vscan_skip(g);
+ } else {
+ /* Write out the blocks. */
+ write_block_row(g, by);
+ }
+ }
+
+ vscan_stop(g);
+ }
+
+ clear_block_map(g);
+ }
+#endif
+
+#if GDISP_HARDWARE_DRAWPIXEL
+ void gdisp_lld_draw_pixel(GDisplay *g) {
+ block_t *block;
+ uint8_t byte;
+ unsigned bx, by, dx, dy;
+ uint8_t bitpos;
+
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ bx = g->p.x / EINK_BLOCKWIDTH;
+ dx = g->p.x % EINK_BLOCKWIDTH;
+ by = g->p.y / EINK_BLOCKHEIGHT;
+ dy = g->p.y % EINK_BLOCKHEIGHT;
+ break;
+ case GDISP_ROTATE_90:
+ bx = g->p.y / EINK_BLOCKWIDTH;
+ dx = g->p.y % EINK_BLOCKWIDTH;
+ by = (GDISP_SCREEN_HEIGHT-1 - g->p.x) / EINK_BLOCKHEIGHT;
+ dy = (GDISP_SCREEN_HEIGHT-1 - g->p.x) % EINK_BLOCKHEIGHT;
+ break;
+ case GDISP_ROTATE_180:
+ bx = (GDISP_SCREEN_WIDTH-1 - g->p.x) / EINK_BLOCKWIDTH;
+ dx = (GDISP_SCREEN_WIDTH-1 - g->p.x) % EINK_BLOCKWIDTH;
+ by = (GDISP_SCREEN_HEIGHT-1 - g->p.y) / EINK_BLOCKHEIGHT;
+ dy = (GDISP_SCREEN_HEIGHT-1 - g->p.y) % EINK_BLOCKHEIGHT;
+ break;
+ case GDISP_ROTATE_270:
+ bx = (GDISP_SCREEN_WIDTH-1 - g->p.y) / EINK_BLOCKWIDTH;
+ dx = (GDISP_SCREEN_WIDTH-1 - g->p.y) % EINK_BLOCKWIDTH;
+ by = g->p.x / EINK_BLOCKHEIGHT;
+ dy = g->p.x % EINK_BLOCKHEIGHT;
+ break;
+ }
+
+ block = alloc_buffer(g, bx, by);
+
+ bitpos = (6 - 2 * (dx % EINK_PPB));
+ byte = block->data[dy][dx / EINK_PPB];
+ byte &= ~(PIXELMASK << bitpos);
+ if (COLOR2NATIVE(g->p.color) != Black)
+ byte |= PIXEL_WHITE << bitpos;
+ else
+ byte |= PIXEL_BLACK << bitpos;
+ block->data[dy][dx / EINK_PPB] = byte;
+ }
+#endif
+
+#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
+ LLDSPEC void gdisp_lld_control(GDisplay *g) {
+ switch(g->p.x) {
+ case GDISP_CONTROL_POWER:
+ if (g->g.Powermode == (powermode_t)g->p.ptr)
+ return;
+ switch((powermode_t)g->p.ptr) {
+ case powerOff:
+ case powerSleep:
+ case powerDeepSleep:
+ gdisp_lld_flush(g);
+ power_off(g);
+ break;
+ case powerOn:
+ power_on(g);
+ break;
+ default:
+ return;
+ }
+ g->g.Powermode = (powermode_t)g->p.ptr;
+ return;
+
+ case GDISP_CONTROL_ORIENTATION:
+ if (g->g.Orientation == (orientation_t)g->p.ptr)
+ return;
+ switch((orientation_t)g->p.ptr) {
+ case GDISP_ROTATE_0:
+ case GDISP_ROTATE_180:
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ break;
+ case GDISP_ROTATE_90:
+ case GDISP_ROTATE_270:
+ g->g.Height = GDISP_SCREEN_WIDTH;
+ g->g.Width = GDISP_SCREEN_HEIGHT;
+ break;
+ default:
+ return;
+ }
+ g->g.Orientation = (orientation_t)g->p.ptr;
+ return;
+
+ default:
+ return;
+ }
+ }
+#endif
+
+/* ===============================
+ * Accelerated routines
+ * =============================== */
+
+#if GDISP_HARDWARE_CLEARS
+ static void subclear(GDisplay *g, color_t color) {
+ unsigned x, y;
+ uint8_t byte;
+
+ hscan_start(g);
+ byte = color ? BYTE_WHITE : BYTE_BLACK;
+ for (x = 0; x < GDISP_SCREEN_WIDTH; x++)
+ {
+ hscan_write(g, &byte, 1);
+ }
+ hscan_stop(g);
+
+ setpin_oe(g, TRUE);
+ vscan_start(g);
+ for (y = 0; y < GDISP_SCREEN_HEIGHT; y++)
+ vscan_bulkwrite(g);
+ vscan_stop(g);
+ setpin_oe(g, FALSE);
+ }
+
+ void gdisp_lld_clear(GDisplay *g) {
+ unsigned i;
+
+ clear_block_map(g);
+
+ if (EINK_BLINKCLEAR) {
+ subclear(g, !g->p.color);
+ gfxSleepMilliseconds(50);
+ }
+
+ for (i = 0; i < EINK_CLEARCOUNT; i++) {
+ subclear(g, g->p.color);
+ gfxSleepMilliseconds(10);
+ }
+ }
+#endif
+
+#endif // GFX_USE_GDISP
diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_config.h b/drivers/gdisp/ED060SC4/gdisp_lld_config.h
index befd997c..47e84779 100644
--- a/drivers/gdisp/ED060SC4/gdisp_lld_config.h
+++ b/drivers/gdisp/ED060SC4/gdisp_lld_config.h
@@ -12,15 +12,12 @@
#if GFX_USE_GDISP
-#define GDISP_DRIVER_NAME "ED060SC4"
+#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing
+#define GDISP_HARDWARE_DRAWPIXEL TRUE
#define GDISP_HARDWARE_CLEARS TRUE
-#define GDISP_HARDWARE_FILLS FALSE
-#define GDISP_HARDWARE_BITFILLS FALSE
-#define GDISP_HARDWARE_SCROLL FALSE
-#define GDISP_HARDWARE_PIXELREAD FALSE
#define GDISP_HARDWARE_CONTROL TRUE
-#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_MONO
+#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO
#endif
diff --git a/drivers/gdisp/ED060SC4/readme.txt b/drivers/gdisp/ED060SC4/readme.txt
index 5409d810..852a0010 100644
--- a/drivers/gdisp/ED060SC4/readme.txt
+++ b/drivers/gdisp/ED060SC4/readme.txt
@@ -38,8 +38,7 @@ result in faster drawing, but also use more RAM on the processor:
After drawing your images, you should flush the buffers using the following
command:
- #include <ed060sc4.h>
- gdispControl(GDISP_CONTROL_FLUSH, 0);
+ gdispFlush();
The buffers are also flushed whenever you turn the display off using: