Merged in PetteriAimonen/ugfx-ed06sc4 (pull request #1)

Add driver for ED060SC4 e-ink display panel
ugfx_release_2.6
Joel Bodenman 2013-09-24 21:27:19 +02:00
commit fd0196f765
8 changed files with 946 additions and 0 deletions

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

View File

@ -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

View File

@ -0,0 +1,2 @@
GFXSRC += $(GFXLIB)/drivers/gdisp/ED060SC4/gdisp_lld.c
GFXINC += $(GFXLIB)/drivers/gdisp/ED060SC4

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,27 @@
/*
* 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
*/
/* Supported features of the driver for ED060SC4 PrimeView E-Ink panel. */
#ifndef _GDISP_LLD_CONFIG_H
#define _GDISP_LLD_CONFIG_H
#if GFX_USE_GDISP
#define GDISP_DRIVER_NAME "ED060SC4"
#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
#endif
#endif

View File

@ -0,0 +1,85 @@
1. Introduction
This is a driver for ED060SC4 800x600 e-ink display panel manufactured by
Prime View. Note that this driver uses a direct connection to the panel from
the processor; it does not use a separate controller chip between the processor
and the panel.
To use the driver, you need to be able to control the following signals from
your processor:
Gate driver: SPV, CKV, GMODE.
Source driver: CL, LE, OE, SPH, D0-D7.
Power supply: +-15V, +22V, -20V, digital Vdd
The file "example_schematics.png" shows how to connect the signals to e.g. a
STM32L151 microcontroller. It also includes an example circuit for providing
the panel supply voltages.
Note that the larger panels (such as the 800x600) consist of multiple segments
with separate gate driver signals. These can be daisy chained as shown in the
example schematic.
2. Frame buffer emulation
Because there is not enough memory to store a full frame buffer on the
processor, this driver emulates a frame buffer by storing the display data in
blocks. It will buffer up to EINK_NUMBUFFERS blocks and then write them to the
screen. The following #defines control the buffering. Larger numbers will
result in faster drawing, but also use more RAM on the processor:
#define EINK_BLOCKWIDTH 20 // Width of a single block in buffer
#define EINK_BLOCKHEIGHT 20 // Height of a single block in buffers
#define EINK_NUMBUFFERS 40 // Number of blocks to buffer
After drawing your images, you should flush the buffers using the following
command:
#include <ed060sc4.h>
gdispControl(GDISP_CONTROL_FLUSH, 0);
The buffers are also flushed whenever you turn the display off using:
gdispSetPowerMode(powerOff);
3. Display clearing and writing waveforms
This driver does not know the official Prime View waveforms for driving the
display, mostly because those are trade secrets and not publicly available.
Instead, it uses reverse engineered waveforms that are mostly functional.
The following #defines control the waveforms:
#define EINK_BLINKCLEAR TRUE // Clear to opposite color first
#define EINK_CLEARCOUNT 10 // Number of sweeps to clear the display
#define EINK_WRITECOUNT 4 // Number of sweeps when writing to display
Increasing the clearcount and writecount can improve contrast, but will also
slow down the drawing and use more power.
4. Clock speeds
Because the driver bit bangs the display, the clock frequency of the processor
is quite significant. This is controlled by EINK_CLOCKDELAY variable. Set it
so that the delay is atleast 50 nanoseconds.
5. Support for other kinds of panels
Most of the Prime View panels should work using this driver, but only ED060SC4
has been tested so far. Some points of consideration:
- Some displays may use 4 bits per pixel. The driver currently assumes 2 bits
per pixel.
- Larger displays may require some other way of daisy chaining than shown in
the example schematics.