From 5f17570ebcba8998757cdcb2df0a92a6215b7448 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 23 Oct 2013 01:34:56 +1000 Subject: [PATCH] Convert ED060SC4 to new driver format --- ...ard_example.h => board_ED060SC4_example.h} | 74 ++- .../gdisp/ED060SC4/board_ED060SC4_template.h | 202 ++++++ drivers/gdisp/ED060SC4/ed060sc4.h | 16 - drivers/gdisp/ED060SC4/gdisp_lld.c | 587 +++++++++--------- drivers/gdisp/ED060SC4/gdisp_lld.mk | 2 +- .../gdisp/ED060SC4/gdisp_lld_board_template.h | 83 --- drivers/gdisp/ED060SC4/gdisp_lld_config.h | 7 +- drivers/gdisp/ED060SC4/readme.txt | 3 +- 8 files changed, 554 insertions(+), 420 deletions(-) rename drivers/gdisp/ED060SC4/{gdisp_lld_board_example.h => board_ED060SC4_example.h} (61%) create mode 100644 drivers/gdisp/ED060SC4/board_ED060SC4_template.h delete mode 100644 drivers/gdisp/ED060SC4/ed060sc4.h delete mode 100644 drivers/gdisp/ED060SC4/gdisp_lld_board_template.h diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h b/drivers/gdisp/ED060SC4/board_ED060SC4_example.h similarity index 61% rename from drivers/gdisp/ED060SC4/gdisp_lld_board_example.h rename to drivers/gdisp/ED060SC4/board_ED060SC4_example.h index 98f05ee8..cb5a92b8 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h +++ b/drivers/gdisp/ED060SC4/board_ED060SC4_example.h @@ -43,84 +43,100 @@ #define GPIOC_VPOS_CTRL 14 #define GPIOC_VNEG_CTRL 15 +static inline void init_board(GDisplay *g) { -/* 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); + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + /* 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); + break; + } } /* Delay for display waveforms. Should be an accurate microsecond delay. */ -static void eink_delay(int us) -{ +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) { +static inline void setpower_vdd(GDisplay *g, bool_t on) { + (void) g; 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) { +static inline void setpower_vneg(GDisplay *g, bool_t on) { + (void) g; 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) { +static inline void setpower_vpos(GDisplay *g, bool_t on) { + (void) g; 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) { +static inline void setpin_le(GDisplay *g, bool_t on) { + (void) g; 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) { +static inline void setpin_oe(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOB, GPIOB_EINK_OE, on); } /* Set the state of the CL (source driver Clock) pin. */ -static inline void setpin_cl(bool_t on) { +static inline void setpin_cl(GDisplay *g, bool_t on) { + (void) g; 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) { +static inline void setpin_sph(GDisplay *g, bool_t on) { + (void) g; 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) { +static inline void setpins_data(GDisplay *g, uint8_t value) { + (void) g; 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) { +static inline void setpin_ckv(GDisplay *g, bool_t on) { + (void) g; 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) { +static inline void setpin_gmode(GDisplay *g, bool_t on) { + (void) g; 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) { +static inline void setpin_spv(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOB, GPIOB_EINK_SPV, on); } 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
+ * #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.
+ * #define EINK_CLOCKDELAY 0 + * + * @note Width of one framebuffer block. + * Must be divisible by EINK_PPB and evenly divide GDISP_SCREEN_WIDTH.
+ * #define EINK_BLOCKWIDTH 20 + * + * @note + * @note Height of one framebuffer block. + * Must evenly divide GDISP_SCREEN_WIDTH.
+ * #define EINK_BLOCKHEIGHT 20 + * + * @note Number of block buffers to use for framebuffer emulation.
+ * #define EINK_NUMBUFFERS 40 + * + * @note Do a "blinking" clear, i.e. clear to opposite polarity first. + * This reduces the image persistence.
+ * #define EINK_BLINKCLEAR TRUE + * + * @note Number of passes to use when clearing the display
+ * #define EINK_CLEARCOUNT 10 + * + * @note Number of passes to use when writing to the display
+ * #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/ed060sc4.h b/drivers/gdisp/ED060SC4/ed060sc4.h deleted file mode 100644 index 8a38f135..00000000 --- a/drivers/gdisp/ED060SC4/ed060sc4.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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 index fcc03944..14e7f88a 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld.c +++ b/drivers/gdisp/ED060SC4/gdisp_lld.c @@ -5,30 +5,35 @@ * http://ugfx.org/license.html */ -/* Low-level E-ink panel driver routines for ED060SC4. */ +/** + * @file drivers/gdisp/ED060SC4/gdisp_lld.c + * @brief GDISP Graphics Driver for the E-ink panel ED060SC4. + */ #include "gfx.h" -#include "ed060sc4.h" #if GFX_USE_GDISP -#include "gdisp/lld/emulation.c" +#define GDISP_DRIVER_VMT GDISPVMT_ED060SC4 +#include "../drivers/gdisp/ED060SC4/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" -/* ================================= - * Default configuration - * ================================= */ +#include "board_ED060SC4.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ #ifndef GDISP_SCREEN_HEIGHT -# define GDISP_SCREEN_HEIGHT 600 + #define GDISP_SCREEN_HEIGHT 600 #endif - #ifndef GDISP_SCREEN_WIDTH -# define GDISP_SCREEN_WIDTH 800 + #define GDISP_SCREEN_WIDTH 800 #endif /* Number of pixels per byte */ #ifndef EINK_PPB -# define EINK_PPB 4 + #define EINK_PPB 4 #endif /* Delay for generating clock pulses. @@ -36,50 +41,50 @@ * This should be atleast 50 ns. */ #ifndef EINK_CLOCKDELAY -# define EINK_CLOCKDELAY 0 + #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 + #define EINK_BLOCKWIDTH 20 #endif /* Height of one framebuffer block. * Must evenly divide GDISP_SCREEN_WIDTH. */ #ifndef EINK_BLOCKHEIGHT -# define EINK_BLOCKHEIGHT 20 + #define EINK_BLOCKHEIGHT 20 #endif /* Number of block buffers to use for framebuffer emulation. */ #ifndef EINK_NUMBUFFERS -# define EINK_NUMBUFFERS 40 + #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 + #define EINK_BLINKCLEAR TRUE #endif /* Number of passes to use when clearing the display */ #ifndef EINK_CLEARCOUNT -# define EINK_CLEARCOUNT 10 + #define EINK_CLEARCOUNT 10 #endif /* Number of passes to use when writing to the display */ #ifndef EINK_WRITECOUNT -# define EINK_WRITECOUNT 4 + #define EINK_WRITECOUNT 4 #endif -/* ==================================== - * Lower level driver functions - * ==================================== */ +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ -#include "gdisp_lld_board.h" +#define PRIV(g) ((drvPriv *)g->priv) /** Delay between signal changes, to give time for IO pins to change state. */ -static inline void clockdelay() +static inline void clockdelay(void) { #if EINK_CLOCKDELAY & 1 asm("nop"); @@ -107,21 +112,21 @@ static inline void clockdelay() } /** Fast vertical clock pulse for gate driver, used during initializations */ -static void vclock_quick() +static void vclock_quick(GDisplay *g) { - setpin_ckv(TRUE); + setpin_ckv(g, TRUE); eink_delay(1); - setpin_ckv(FALSE); + setpin_ckv(g, FALSE); eink_delay(4); } /** Horizontal clock pulse for clocking data into source driver */ -static void hclock() +static void hclock(GDisplay *g) { clockdelay(); - setpin_cl(TRUE); + setpin_cl(g, TRUE); clockdelay(); - setpin_cl(FALSE); + setpin_cl(g, FALSE); } /** Start a new vertical gate driver scan from top. @@ -129,156 +134,156 @@ static void hclock() * so you should always scan through the whole display before * starting a new scan. */ -static void vscan_start() +static void vscan_start(GDisplay *g) { - setpin_gmode(TRUE); - vclock_quick(); - setpin_spv(FALSE); - vclock_quick(); - setpin_spv(TRUE); - vclock_quick(); + 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() +static void vscan_write(GDisplay *g) { - setpin_ckv(TRUE); - setpin_oe(TRUE); + setpin_ckv(g, TRUE); + setpin_oe(g, TRUE); eink_delay(5); - setpin_oe(FALSE); - setpin_ckv(FALSE); + 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() +static void vscan_bulkwrite(GDisplay *g) { - setpin_ckv(TRUE); + setpin_ckv(g, TRUE); eink_delay(20); - setpin_ckv(FALSE); + 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() +static void vscan_skip(GDisplay *g) { - setpin_ckv(TRUE); + setpin_ckv(g, TRUE); eink_delay(1); - setpin_ckv(FALSE); + 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() +static void vscan_stop(GDisplay *g) { - setpin_gmode(FALSE); - vclock_quick(); - vclock_quick(); - vclock_quick(); - vclock_quick(); - vclock_quick(); + 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() +static void hscan_start(GDisplay *g) { /* Disable latching and output enable while we are modifying the row. */ - setpin_le(FALSE); - setpin_oe(FALSE); + setpin_le(g, FALSE); + setpin_oe(g, FALSE); /* The start pulse should remain low for the duration of the row. */ - setpin_sph(FALSE); + setpin_sph(g, FALSE); } /** Write data to the horizontal row. */ -static void hscan_write(const uint8_t *data, int count) +static void hscan_write(GDisplay *g, const uint8_t *data, int count) { while (count--) { /* Set the next byte on the data pins */ - setpins_data(*data++); + setpins_data(g, *data++); /* Give a clock pulse to the shift register */ - hclock(); + 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() +static void hscan_stop(GDisplay *g) { /* End the scan */ - setpin_sph(TRUE); - hclock(); + setpin_sph(g, TRUE); + hclock(g); /* Latch the new data */ - setpin_le(TRUE); + setpin_le(g, TRUE); clockdelay(); - setpin_le(FALSE); + setpin_le(g, FALSE); } /** Turn on the power to the E-Ink panel, observing proper power sequencing. */ -static void power_on() +static void power_on(GDisplay *g) { 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); + 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(TRUE); + setpower_vneg(g, TRUE); gfxSleepMicroseconds(1000); /* Finally the positive voltages. */ - setpower_vpos(TRUE); + setpower_vpos(g, TRUE); /* Clear the vscan shift register */ - vscan_start(); + vscan_start(g); for (i = 0; i < GDISP_SCREEN_HEIGHT; i++) - vclock_quick(); - vscan_stop(); + vclock_quick(g); + vscan_stop(g); } /** Turn off the power, observing proper power sequencing. */ -static void power_off() +static void power_off(GDisplay *g) { /* First the high voltages */ - setpower_vpos(FALSE); - setpower_vneg(FALSE); + 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(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); + 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); } /* ==================================== @@ -286,56 +291,58 @@ static void power_off() * ==================================== */ #if EINK_PPB == 4 -#define PIXELMASK 3 -#define PIXEL_WHITE 2 -#define PIXEL_BLACK 1 -#define BYTE_WHITE 0xAA -#define BYTE_BLACK 0x55 + #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. + #error Unsupported EINK_PPB value. #endif #if GDISP_SCREEN_HEIGHT % EINK_BLOCKHEIGHT != 0 -#error GDISP_SCREEN_HEIGHT must be evenly divisible by EINK_BLOCKHEIGHT + #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 + #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 + #error EINK_BLOCKWIDTH must be evenly divisible by EINK_PPB #endif #if EINK_NUMBUFFERS > 254 -#error EINK_NUMBUFFERS must be at most 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) +#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]; +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. - */ -static uint8_t g_blockmap[BLOCKS_Y][BLOCKS_X]; + /* 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(unsigned by) +static bool_t blocks_on_row(GDisplay *g, unsigned by) { unsigned bx; for (bx = 0; bx < BLOCKS_X; bx++) { - if (g_blockmap[by][bx] != 0) + if (PRIV(g)->g_blockmap[by][bx] != 0) { return TRUE; } @@ -344,79 +351,47 @@ static bool_t blocks_on_row(unsigned by) } /** Write out a block row. */ -static void write_block_row(unsigned by) +static void write_block_row(GDisplay *g, unsigned by) { unsigned bx, dy, dx; for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) { - hscan_start(); + hscan_start(g); for (bx = 0; bx < BLOCKS_X; bx++) { - if (g_blockmap[by][bx] == 0) + if (PRIV(g)->g_blockmap[by][bx] == 0) { for (dx = 0; dx < WIDTH_BYTES; dx++) { const uint8_t dummy = 0; - hscan_write(&dummy, 1); + hscan_write(g, &dummy, 1); } } else { - block_t *block = &g_blocks[g_blockmap[by][bx] - 1]; - hscan_write(&block->data[dy][0], WIDTH_BYTES); + 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(); + hscan_stop(g); - vscan_write(); + vscan_write(g); } } /** Clear the block map, i.e. deallocate all blocks */ -static void clear_block_map() +static void clear_block_map(GDisplay *g) { unsigned bx, by; for (by = 0; by < BLOCKS_Y; by++) { for (bx = 0; bx < BLOCKS_X; bx++) { - g_blockmap[by][bx] = 0; + PRIV(g)->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(); + PRIV(g)->g_next_block = 0; } /** Initialize a newly allocated block. */ @@ -434,173 +409,217 @@ static void zero_block(block_t *block) /** Allocate a buffer * Automatically flushes if all buffers are full. */ -static block_t *alloc_buffer(unsigned bx, unsigned by) +static block_t *alloc_buffer(GDisplay *g, unsigned bx, unsigned by) { block_t *result; - if (g_blockmap[by][bx] == 0) + drvPriv *priv; + + priv = PRIV(g); + if (priv->g_blockmap[by][bx] == 0) { - if (g_next_block >= EINK_NUMBUFFERS) - { - flush_buffers(); - } + if (priv->g_next_block >= EINK_NUMBUFFERS) + gdisp_lld_flush(g); - result = &g_blocks[g_next_block]; - g_blockmap[by][bx] = g_next_block + 1; - g_next_block++; + 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 = &g_blocks[g_blockmap[by][bx] - 1]; + result = &priv->g_blocks[priv->g_blockmap[by][bx] - 1]; return result; } } -/* =============================== - * Public functions - * =============================== */ +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ -bool_t gdisp_lld_init(void) -{ - init_board(); +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(); + power_off(g); - 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 + 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; } -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_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay *g) { + unsigned by, dy, i; -#if !GDISP_NEED_CONTROL -#error You must enable GDISP_NEED_CONTROL for the E-Ink driver. + 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 -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; +#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_CONTROL_FLUSH: - flush_buffers(); + 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 (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; -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); -} + 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); -void gdisp_lld_clear(color_t color) -{ - unsigned i; - clear_block_map(); - - if (EINK_BLINKCLEAR) - { - subclear(!color); - gfxSleepMilliseconds(50); + 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); } - for (i = 0; i < EINK_CLEARCOUNT; i++) - { - subclear(color); - gfxSleepMilliseconds(10); + 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 +#endif // GFX_USE_GDISP diff --git a/drivers/gdisp/ED060SC4/gdisp_lld.mk b/drivers/gdisp/ED060SC4/gdisp_lld.mk index d5c1492f..fc62da03 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.c diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h b/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h deleted file mode 100644 index 68129bf8..00000000 --- a/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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/ED060SC4/gdisp_lld_config.h b/drivers/gdisp/ED060SC4/gdisp_lld_config.h index befd997c..d7e836c9 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld_config.h +++ b/drivers/gdisp/ED060SC4/gdisp_lld_config.h @@ -12,12 +12,9 @@ #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 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 - gdispControl(GDISP_CONTROL_FLUSH, 0); + gdispFlush(); The buffers are also flushed whenever you turn the display off using: