From bdda66890a7d2b9b54468260b7315ab96aa059d4 Mon Sep 17 00:00:00 2001 From: ladyada Date: Tue, 1 Jan 2019 16:27:16 -0500 Subject: [PATCH 01/30] get rid of clear_display/clear_buffer and replace with just fill() --- adafruit_epd/epd.py | 11 ++++------- adafruit_epd/il0373.py | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index b315f51..c321ad4 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -42,6 +42,7 @@ class Adafruit_EPD: # pylint: disable=too-many-arguments def __init__(self, width, height, rst_pin, dc_pin, busy_pin, srcs_pin, cs_pin, spi): + # pylint: enable=too-many-arguments self.width = width self.height = height @@ -56,22 +57,18 @@ def __init__(self, width, height, rst_pin, dc_pin, busy_pin, srcs_pin, cs_pin, s # Setup dc pin. self._dc = dc_pin self._dc.direction = digitalio.Direction.OUTPUT + self._dc.value = False # Setup cs pin. self._cs = cs_pin self._cs.direction = digitalio.Direction.OUTPUT + self._cs.value = True self.spi_device = spi self.sram = mcp_sram.Adafruit_MCP_SRAM(srcs_pin, spi) - # pylint: enable=too-many-arguments - - def begin(self, reset=True): - """Begin display and reset if desired.""" - self._cs.value = True - self._dc.value = False - if reset: + if self._rst: self._rst.value = False time.sleep(.1) self._rst.value = True diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 5215826..78c08ac 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -65,8 +65,6 @@ def __init__(self, width, height, rst_pin, dc_pin, busy_pin, srcs_pin, cs_pin, s self.bw_bufsize = int(width * height / 8) self.red_bufsize = int(width * height / 8) - - self.begin() # pylint: enable=too-many-arguments def begin(self, reset=True): @@ -221,12 +219,14 @@ def draw_pixel(self, x, y, color): self.sram.write8(addr, current) return - def clear_buffer(self): - """clear the display buffer""" - self.sram.erase(0x00, self.bw_bufsize, 0xFF) - self.sram.erase(self.bw_bufsize, self.red_bufsize, 0xFF) - - def clear_display(self): - """clear the entire display""" - self.clear_buffer() - self.display() + def fill(self, color): + """fill the screen with the passed color""" + print("ffffil") + red_fill = 0xFF + black_fill = 0xFF + if color == Adafruit_EPD.BLACK: + black_fill = 0x00 + if color == Adafruit_EPD.RED: + red_fill = 0x00 + self.sram.erase(0x00, self.bw_bufsize, black_fill) + self.sram.erase(self.bw_bufsize, self.red_bufsize, red_fill) From 9c51956625cc58b081ed664f36a63f3bba40acd5 Mon Sep 17 00:00:00 2001 From: ladyada Date: Tue, 1 Jan 2019 17:07:51 -0500 Subject: [PATCH 02/30] charge arg order/kwarg, make busy/reset optional --- adafruit_epd/epd.py | 14 ++++++++------ adafruit_epd/il0373.py | 24 ++++++++++++++---------- examples/epd_simpletest.py | 9 +++++---- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index c321ad4..eb849b9 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -41,18 +41,20 @@ class Adafruit_EPD: LIGHT = 5 # pylint: disable=too-many-arguments - def __init__(self, width, height, rst_pin, dc_pin, busy_pin, srcs_pin, cs_pin, spi): + def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin): # pylint: enable=too-many-arguments self.width = width self.height = height - # Setup reset pin. + # Setup reset pin. self._rst = rst_pin - self._rst.direction = digitalio.Direction.OUTPUT + if rst_pin: + self._rst.direction = digitalio.Direction.OUTPUT - # Setup busy pin. + # Setup busy pin. self._busy = busy_pin - self._busy.direction = digitalio.Direction.INPUT + if busy_pin: + self._busy.direction = digitalio.Direction.INPUT # Setup dc pin. self._dc = dc_pin @@ -66,7 +68,7 @@ def __init__(self, width, height, rst_pin, dc_pin, busy_pin, srcs_pin, cs_pin, s self.spi_device = spi - self.sram = mcp_sram.Adafruit_MCP_SRAM(srcs_pin, spi) + self.sram = mcp_sram.Adafruit_MCP_SRAM(sramcs_pin, spi) if self._rst: self._rst.value = False diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 78c08ac..48d6b5b 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -31,8 +31,8 @@ from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.mcp_sram import Adafruit_MCP_SRAM -IL0373_PANEL_SETTING = const(0x00) IL0373_POWER_SETTING = const(0x01) +IL0373_PANEL_SETTING = const(0x00) IL0373_POWER_OFF = const(0x02) IL0373_POWER_OFF_SEQUENCE = const(0x03) IL0373_POWER_ON = const(0x04) @@ -59,9 +59,9 @@ class Adafruit_IL0373(Adafruit_EPD): """driver class for Adafruit IL0373 ePaper display breakouts""" # pylint: disable=too-many-arguments - def __init__(self, width, height, rst_pin, dc_pin, busy_pin, srcs_pin, cs_pin, spi): - super(Adafruit_IL0373, self).__init__(width, height, rst_pin, dc_pin, busy_pin, - srcs_pin, cs_pin, spi) + def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin): + super(Adafruit_IL0373, self).__init__(width, height, spi, cs_pin, dc_pin, + sramcs_pin, rst_pin, busy_pin) self.bw_bufsize = int(width * height / 8) self.red_bufsize = int(width * height / 8) @@ -81,8 +81,11 @@ def update(self): """update the display""" self.command(IL0373_DISPLAY_REFRESH) - while self._busy.value is False: - pass + if self._busy: + while self._busy.value is False: + pass + else: + time.sleep(15) # wait 15 seconds self.command(IL0373_CDI, bytearray([0x17])) self.command(IL0373_VCM_DC_SETTING, bytearray([0x00])) @@ -93,9 +96,11 @@ def power_up(self): """power up the display""" self.command(IL0373_POWER_ON) - while self._busy.value is False: - pass - + if self._busy: + while self._busy.value is False: + pass + else: + time.sleep(3) # wait a bit time.sleep(.2) self.command(IL0373_PANEL_SETTING, bytearray([0xCF])) @@ -221,7 +226,6 @@ def draw_pixel(self, x, y, color): def fill(self, color): """fill the screen with the passed color""" - print("ffffil") red_fill = 0xFF black_fill = 0xFF if color == Adafruit_EPD.BLACK: diff --git a/examples/epd_simpletest.py b/examples/epd_simpletest.py index 3e99257..7039ae6 100644 --- a/examples/epd_simpletest.py +++ b/examples/epd_simpletest.py @@ -16,7 +16,7 @@ display = Adafruit_IL0373(152, 152, rst, dc, busy, srcs, ecs, spi) # clear the buffer -display.clear_buffer() +display.fill(Adafruit_EPD.WHITE) r_width = 5 r_pos = display.height @@ -25,9 +25,10 @@ while r_pos > display.height/2: if r_pos < display.height - 50: color = Adafruit_EPD.RED - display.rect(display.width - r_pos, display.height - r_pos, + display.rect(display.width - r_pos, + display.height - r_pos, display.width - 2*(display.width - r_pos), - display.height - 2*(display.height - r_pos), color) + display.height - 2*(display.height - r_pos), + color) r_pos = r_pos - r_width - display.display() From fb19eea29fa126ec5aa17f3af54ec7ddb5b83db1 Mon Sep 17 00:00:00 2001 From: ladyada Date: Tue, 1 Jan 2019 17:31:18 -0500 Subject: [PATCH 03/30] fix bitmap example, tested! --- examples/epd_bitmap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/epd_bitmap.py b/examples/epd_bitmap.py index 1b5a344..445dc79 100644 --- a/examples/epd_bitmap.py +++ b/examples/epd_bitmap.py @@ -13,12 +13,14 @@ busy = digitalio.DigitalInOut(board.D6) # give them all to our driver -display = Adafruit_IL0373(152, 152, rst, dc, busy, srcs, ecs, spi) +display = Adafruit_IL0373(152, 152, spi, + cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, + rst_pin=rst, busy_pin=busy) FILENAME = "blinka.bmp" # clear the buffer -display.clear_buffer() +display.fill(Adafruit_EPD.WHITE) def read_le(s): # as of this writting, int.from_bytes does not have LE support, DIY! From c4002d039b77d48cc8800a56e22eaef1f477c1bc Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 5 Jan 2019 20:33:51 -0500 Subject: [PATCH 04/30] new format --- examples/epd_simpletest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/epd_simpletest.py b/examples/epd_simpletest.py index 7039ae6..77f1c48 100644 --- a/examples/epd_simpletest.py +++ b/examples/epd_simpletest.py @@ -13,7 +13,9 @@ busy = digitalio.DigitalInOut(board.D6) # give them all to our driver -display = Adafruit_IL0373(152, 152, rst, dc, busy, srcs, ecs, spi) +display = Adafruit_IL0373(152, 152, spi, + cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, + rst_pin=rst, busy_pin=busy) # clear the buffer display.fill(Adafruit_EPD.WHITE) From 346a9d47ff4942e5c7419eaf06582d08c179b718 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 5 Jan 2019 20:51:55 -0500 Subject: [PATCH 05/30] use mem buffer if no SRAM pin --- adafruit_epd/epd.py | 7 +- adafruit_epd/il0373.py | 149 ++++++++++++++++++++++++++--------------- 2 files changed, 101 insertions(+), 55 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index eb849b9..cf4999d 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -68,7 +68,12 @@ def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy self.spi_device = spi - self.sram = mcp_sram.Adafruit_MCP_SRAM(sramcs_pin, spi) + if sramcs_pin: + self.sram = mcp_sram.Adafruit_MCP_SRAM(sramcs_pin, spi) + else: + self.sram = None + self.bw_buffer = bytearray((width // 8) * height) + self.red_buffer = bytearray((width // 8) * height) if self._rst: self._rst.value = False diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 48d6b5b..3d3e276 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -118,54 +118,73 @@ def display(self): """show the contents of the display buffer""" self.power_up() - while not self.spi_device.try_lock(): - pass - self.sram.cs_pin.value = False - #send read command - self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_READ])) - #send start address - self.spi_device.write(bytearray([0x00, 0x00])) - self.spi_device.unlock() - - #first data byte from SRAM will be transfered in at the - #same time as the EPD command is transferred out - cmd = self.command(IL0373_DTM1, end=False) - - while not self.spi_device.try_lock(): - pass - self._dc.value = True - xfer = bytearray([cmd]) - outbuf = bytearray(1) - for _ in range(self.bw_bufsize): - outbuf[0] = xfer[0] - self.spi_device.write_readinto(outbuf, xfer) - self._cs.value = True - self.sram.cs_pin.value = True - - time.sleep(.002) - - self.sram.cs_pin.value = False - #send read command - self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_READ])) - #send start address - self.spi_device.write(bytearray([(self.bw_bufsize >> 8), (self.bw_bufsize & 0xFF)])) - self.spi_device.unlock() - - #first data byte from SRAM will be transfered in at the - #same time as the EPD command is transferred out - cmd = self.command(IL0373_DTM2, end=False) - - while not self.spi_device.try_lock(): - pass - self._dc.value = True - xfer = bytearray([cmd]) - outbuf = bytearray(1) - for _ in range(self.bw_bufsize): - outbuf[0] = xfer[0] - self.spi_device.write_readinto(outbuf, xfer) - self._cs.value = True - self.sram.cs_pin.value = True - self.spi_device.unlock() + if self.sram: + while not self.spi_device.try_lock(): + pass + self.sram.cs_pin.value = False + #send read command + self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_READ])) + #send start address + self.spi_device.write(bytearray([0x00, 0x00])) + self.spi_device.unlock() + + #first data byte from SRAM will be transfered in at the + #same time as the EPD command is transferred out + cmd = self.command(IL0373_DTM1, end=False) + + while not self.spi_device.try_lock(): + pass + self._dc.value = True + xfer = bytearray([cmd]) + outbuf = bytearray(1) + for _ in range(self.bw_bufsize): + outbuf[0] = xfer[0] + self.spi_device.write_readinto(outbuf, xfer) + self._cs.value = True + self.sram.cs_pin.value = True + + time.sleep(.002) + + self.sram.cs_pin.value = False + #send read command + self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_READ])) + #send start address + self.spi_device.write(bytearray([(self.bw_bufsize >> 8), (self.bw_bufsize & 0xFF)])) + self.spi_device.unlock() + + #first data byte from SRAM will be transfered in at the + #same time as the EPD command is transferred out + cmd = self.command(IL0373_DTM2, end=False) + + while not self.spi_device.try_lock(): + pass + self._dc.value = True + xfer = bytearray([cmd]) + outbuf = bytearray(1) + for _ in range(self.bw_bufsize): + outbuf[0] = xfer[0] + self.spi_device.write_readinto(outbuf, xfer) + self._cs.value = True + self.sram.cs_pin.value = True + self.spi_device.unlock() + else: + cmd = self.command(IL0373_DTM1, end=False) + while not self.spi_device.try_lock(): + pass + self._dc.value = True + self.spi_device.write(self.bw_buffer) + self._cs.value = True + self.spi_device.unlock() + + time.sleep(.02) + + cmd = self.command(IL0373_DTM2, end=False) + while not self.spi_device.try_lock(): + pass + self._dc.value = True + self.spi_device.write(self.red_buffer) + self._cs.value = True + self.spi_device.unlock() self.update() @@ -210,9 +229,17 @@ def draw_pixel(self, x, y, color): x = 1 addr = ((self.width - x) * self.height + y) // 8 - if color == Adafruit_EPD.RED: - addr = addr + self.bw_bufsize - current = self.sram.read8(addr) + + if self.sram: + if color == Adafruit_EPD.RED: + current = self.sram.read8(addr + self.bw_bufsize) + else: + current = self.sram.read8(addr) + else: + if color == Adafruit_EPD.RED: + current = self.red_buffer[addr] + else: + current = self.bw_buffer[addr] if color == Adafruit_EPD.WHITE: current = current | (1 << (7 - y%8)) @@ -221,7 +248,16 @@ def draw_pixel(self, x, y, color): elif color == Adafruit_EPD.INVERSE: current = current ^ (1 << (7 - y%8)) - self.sram.write8(addr, current) + if self.sram: + if color == Adafruit_EPD.RED: + current = self.sram.write8(addr + self.bw_bufsize, current) + else: + current = self.sram.write8(addr, current) + else: + if color == Adafruit_EPD.RED: + self.red_buffer[addr] = current + else: + self.bw_buffer[addr] = current return def fill(self, color): @@ -232,5 +268,10 @@ def fill(self, color): black_fill = 0x00 if color == Adafruit_EPD.RED: red_fill = 0x00 - self.sram.erase(0x00, self.bw_bufsize, black_fill) - self.sram.erase(self.bw_bufsize, self.red_bufsize, red_fill) + if self.sram: + self.sram.erase(0x00, self.bw_bufsize, black_fill) + self.sram.erase(self.bw_bufsize, self.red_bufsize, red_fill) + else: + for i in range(len(self.bw_buffer)): + self.bw_buffer[i] = black_fill + self.red_buffer[i] = red_fill From f7c350111d186be3f5e9cb5d40969c7c8151cbcc Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 5 Jan 2019 21:43:42 -0500 Subject: [PATCH 06/30] begin framebuffification --- adafruit_epd/epd.py | 74 +++++++++++++++++++----------------------- adafruit_epd/il0373.py | 54 ++++++++++++------------------ 2 files changed, 54 insertions(+), 74 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index cf4999d..0a9aac5 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -28,6 +28,7 @@ import time import digitalio +import adafruit_framebuf from adafruit_epd import mcp_sram class Adafruit_EPD: @@ -46,41 +47,47 @@ def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy self.width = width self.height = height - # Setup reset pin. + # Setup reset pin, if we have one self._rst = rst_pin if rst_pin: self._rst.direction = digitalio.Direction.OUTPUT - # Setup busy pin. + # Setup busy pin, if we have one self._busy = busy_pin if busy_pin: self._busy.direction = digitalio.Direction.INPUT - # Setup dc pin. + # Setup dc pin (required) self._dc = dc_pin self._dc.direction = digitalio.Direction.OUTPUT self._dc.value = False - # Setup cs pin. + # Setup cs pin (required) self._cs = cs_pin self._cs.direction = digitalio.Direction.OUTPUT self._cs.value = True + # SPI interface (required) self.spi_device = spi if sramcs_pin: self.sram = mcp_sram.Adafruit_MCP_SRAM(sramcs_pin, spi) else: self.sram = None - self.bw_buffer = bytearray((width // 8) * height) - self.red_buffer = bytearray((width // 8) * height) + self._bw_buffer = bytearray((width // 8) * height) + self._red_buffer = bytearray((width // 8) * height) + # since we have *two* framebuffers - one for red and one for black, we dont subclass but manage manually + self._red_framebuf = adafruit_framebuf.FrameBuffer(self._red_buffer, width, height, buf_format=adafruit_framebuf.MHMSB) + self._bw_framebuf = adafruit_framebuf.FrameBuffer(self._bw_buffer, width, height, buf_format=adafruit_framebuf.MHMSB) + # if we hav ea reset pin, do a hardware reset if self._rst: self._rst.value = False time.sleep(.1) self._rst.value = True time.sleep(.1) + def command(self, cmd, data=None, end=True): """Send command byte to display.""" self._cs.value = True @@ -109,42 +116,34 @@ def data(self, dat): self._cs.value = True self.spi_device.unlock() - def draw_pixel(self, x, y, color): + def fill(self, color): + #This should be overridden in the subclass + self._bw_framebuf.fill((color == Adafruit_EPD.BLACK) != self.black_invert) + self._red_framebuf.fill((color == Adafruit_EPD.RED) != self.red_invert) + + def pixel(self, x, y, color=None): """This should be overridden in the subclass""" - pass + self._bw_framebuf.pixel(x, y, (color == Adafruit_EPD.BLACK) != self.black_invert) + self._red_framebuf.pixel(x, y, (color == Adafruit_EPD.RED) != self.red_invert) - #framebuf methods - def fill(self, color): - """fill the screen with the passed color""" - self.fill_rect(0, 0, self.width, self.height, color) + def rect(self, x, y, width, height, color): + """draw a rectangle""" + self._bw_framebuf.rect(x, y, width, height, (color == Adafruit_EPD.BLACK) != self.black_invert) + self._red_framebuf.rect(x, y, width, height, (color == Adafruit_EPD.RED) != self.red_invert) # pylint: disable=too-many-arguments def fill_rect(self, x, y, width, height, color): """fill a rectangle with the passed color""" - if width < 1 or height < 1 or (x+width) <= 0: - return - if (y+height) <= 0 or y >= self.height or x >= self.width: - return - xend = min(self.width, x+width) - yend = min(self.height, y+height) - x = max(x, 0) - y = max(y, 0) - for _x in range(xend - x): - for _y in range(yend - y): - self.draw_pixel(x + _x, y + _y, color) - return + self._bw_framebuf.fill_rect(x, y, width, height, (color == Adafruit_EPD.BLACK) != self.black_invert) + self._red_framebuf.fill_rect(x, y, width, height, (color == Adafruit_EPD.RED) != self.red_invert) - def pixel(self, x, y, color=None): - """draw a pixel""" - if x < 0 or x >= self.width or y < 0 or y >= self.height: - return None - #TODO: figure this out when we know what framebuffer we - # will actually use - #if color is None: - # return self.get_pixel(self, x, y) + def line(self, x_0, y_0, x_1, y_1, color): + self._bw_framebuf.line(x_0, y_0, x_1, y_1, (color == Adafruit_EPD.BLACK) != self.black_invert) + self._red_framebuf.line(x_0, y_0, x_1, y_1, (color == Adafruit_EPD.RED) != self.red_invert) - self.draw_pixel(x, y, color) - return None + def text(self, string, x, y, color, *, font_name="font5x8.bin"): + self._bw_framebuf.text(string, x, y, (color == Adafruit_EPD.BLACK) != self.black_invert, font_name) + self._red_framebuf.text(string, x, y, (color == Adafruit_EPD.RED) != self.red_invert, font_name) def hline(self, x, y, width, color): """draw a horizontal line""" @@ -153,10 +152,3 @@ def hline(self, x, y, width, color): def vline(self, x, y, height, color): """draw a vertical line""" self.fill_rect(x, y, 1, height, color) - - def rect(self, x, y, width, height, color): - """draw a rectangle""" - self.fill_rect(x, y, width, 1, color) - self.fill_rect(x, y+height, width, 1, color) - self.fill_rect(x, y, 1, height, color) - self.fill_rect(x+width, y, 1, height, color) diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 3d3e276..2656a49 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -28,6 +28,7 @@ import time from micropython import const +import adafruit_framebuf from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.mcp_sram import Adafruit_MCP_SRAM @@ -65,6 +66,8 @@ def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, b self.bw_bufsize = int(width * height / 8) self.red_bufsize = int(width * height / 8) + self.black_invert = True + self.red_invert = True # pylint: enable=too-many-arguments def begin(self, reset=True): @@ -172,7 +175,7 @@ def display(self): while not self.spi_device.try_lock(): pass self._dc.value = True - self.spi_device.write(self.bw_buffer) + self.spi_device.write(self._bw_buffer) self._cs.value = True self.spi_device.unlock() @@ -182,7 +185,7 @@ def display(self): while not self.spi_device.try_lock(): pass self._dc.value = True - self.spi_device.write(self.red_buffer) + self.spi_device.write(self._red_buffer) self._cs.value = True self.spi_device.unlock() @@ -220,45 +223,32 @@ def image(self, image): self.sram.write8(addr, current) - def draw_pixel(self, x, y, color): + def pixel(self, x, y, color): """draw a single pixel in the display buffer""" - if (x < 0) or (x >= self.width) or (y < 0) or (y >= self.height): - return - - if x == 0: - x = 1 - - addr = ((self.width - x) * self.height + y) // 8 - if self.sram: + if (x < 0) or (x >= self.width) or (y < 0) or (y >= self.height): + return + if x == 0: + x = 1 + addr = ((self.width - x) * self.height + y) // 8 if color == Adafruit_EPD.RED: current = self.sram.read8(addr + self.bw_bufsize) else: current = self.sram.read8(addr) - else: - if color == Adafruit_EPD.RED: - current = self.red_buffer[addr] - else: - current = self.bw_buffer[addr] - if color == Adafruit_EPD.WHITE: - current = current | (1 << (7 - y%8)) - elif color in (Adafruit_EPD.RED, Adafruit_EPD.BLACK): - current = current & ~(1 << (7 - y%8)) - elif color == Adafruit_EPD.INVERSE: - current = current ^ (1 << (7 - y%8)) + if color == Adafruit_EPD.WHITE: + current = current | (1 << (7 - y%8)) + elif color in (Adafruit_EPD.RED, Adafruit_EPD.BLACK): + current = current & ~(1 << (7 - y%8)) + elif color == Adafruit_EPD.INVERSE: + current = current ^ (1 << (7 - y%8)) - if self.sram: if color == Adafruit_EPD.RED: - current = self.sram.write8(addr + self.bw_bufsize, current) + self.sram.write8(addr + self.bw_bufsize, current) else: - current = self.sram.write8(addr, current) + self.sram.write8(addr, current) else: - if color == Adafruit_EPD.RED: - self.red_buffer[addr] = current - else: - self.bw_buffer[addr] = current - return + super().pixel(x, y, color) def fill(self, color): """fill the screen with the passed color""" @@ -272,6 +262,4 @@ def fill(self, color): self.sram.erase(0x00, self.bw_bufsize, black_fill) self.sram.erase(self.bw_bufsize, self.red_bufsize, red_fill) else: - for i in range(len(self.bw_buffer)): - self.bw_buffer[i] = black_fill - self.red_buffer[i] = red_fill + super().fill(color) From 4f9b90c4c04e51c8117181530f53110afe5908ed Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 6 Jan 2019 11:45:12 -0500 Subject: [PATCH 07/30] add const underscores and rotation --- adafruit_epd/epd.py | 13 +++++-- adafruit_epd/il0373.py | 80 +++++++++++++++++++++--------------------- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index 0a9aac5..afb470d 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -142,8 +142,17 @@ def line(self, x_0, y_0, x_1, y_1, color): self._red_framebuf.line(x_0, y_0, x_1, y_1, (color == Adafruit_EPD.RED) != self.red_invert) def text(self, string, x, y, color, *, font_name="font5x8.bin"): - self._bw_framebuf.text(string, x, y, (color == Adafruit_EPD.BLACK) != self.black_invert, font_name) - self._red_framebuf.text(string, x, y, (color == Adafruit_EPD.RED) != self.red_invert, font_name) + self._bw_framebuf.text(string, x, y, (color == Adafruit_EPD.BLACK) != self.black_invert, font_name=font_name) + self._red_framebuf.text(string, x, y, (color == Adafruit_EPD.RED) != self.red_invert, font_name=font_name) + + @property + def rotation(self): + return self._bw_framebuf._rotation + + @rotation.setter + def rotation(self, val): + self._bw_framebuf.rotation = val + self._red_framebuf.rotation = val def hline(self, x, y, width, color): """draw a horizontal line""" diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 2656a49..d5b05c1 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -32,30 +32,30 @@ from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.mcp_sram import Adafruit_MCP_SRAM -IL0373_POWER_SETTING = const(0x01) -IL0373_PANEL_SETTING = const(0x00) -IL0373_POWER_OFF = const(0x02) -IL0373_POWER_OFF_SEQUENCE = const(0x03) -IL0373_POWER_ON = const(0x04) -IL0373_POWER_ON_MEASURE = const(0x05) -IL0373_BOOSTER_SOFT_START = const(0x06) -IL0373_DEEP_SLEEP = const(0x07) -IL0373_DTM1 = const(0x10) -IL0373_DATA_STOP = const(0x11) -IL0373_DISPLAY_REFRESH = const(0x12) -IL0373_DTM2 = const(0x13) -IL0373_PDTM1 = const(0x14) -IL0373_PDTM2 = const(0x15) -IL0373_PDRF = const(0x16) -IL0373_LUT1 = const(0x20) -IL0373_LUTWW = const(0x21) -IL0373_LUTBW = const(0x22) -IL0373_LUTWB = const(0x23) -IL0373_LUTBB = const(0x24) -IL0373_PLL = const(0x30) -IL0373_CDI = const(0x50) -IL0373_RESOLUTION = const(0x61) -IL0373_VCM_DC_SETTING = const(0x82) +_IL0373_POWER_SETTING = const(0x01) +_IL0373_PANEL_SETTING = const(0x00) +_IL0373_POWER_OFF = const(0x02) +_IL0373_POWER_OFF_SEQUENCE = const(0x03) +_IL0373_POWER_ON = const(0x04) +_IL0373_POWER_ON_MEASURE = const(0x05) +_IL0373_BOOSTER_SOFT_START = const(0x06) +_IL0373_DEEP_SLEEP = const(0x07) +_IL0373_DTM1 = const(0x10) +_IL0373_DATA_STOP = const(0x11) +_IL0373_DISPLAY_REFRESH = const(0x12) +_IL0373_DTM2 = const(0x13) +_IL0373_PDTM1 = const(0x14) +_IL0373_PDTM2 = const(0x15) +_IL0373_PDRF = const(0x16) +_IL0373_LUT1 = const(0x20) +_IL0373_LUTWW = const(0x21) +_IL0373_LUTBW = const(0x22) +_IL0373_LUTWB = const(0x23) +_IL0373_LUTBB = const(0x24) +_IL0373_PLL = const(0x30) +_IL0373_CDI = const(0x50) +_IL0373_RESOLUTION = const(0x61) +_IL0373_VCM_DC_SETTING = const(0x82) class Adafruit_IL0373(Adafruit_EPD): """driver class for Adafruit IL0373 ePaper display breakouts""" @@ -77,12 +77,12 @@ def begin(self, reset=True): while self._busy.value is False: pass - self.command(IL0373_POWER_SETTING, bytearray([0x03, 0x00, 0x2b, 0x2b, 0x09])) - self.command(IL0373_BOOSTER_SOFT_START, bytearray([0x17, 0x17, 0x17])) + self.command(_IL0373_POWER_SETTING, bytearray([0x03, 0x00, 0x2b, 0x2b, 0x09])) + self.command(_IL0373_BOOSTER_SOFT_START, bytearray([0x17, 0x17, 0x17])) def update(self): """update the display""" - self.command(IL0373_DISPLAY_REFRESH) + self.command(_IL0373_DISPLAY_REFRESH) if self._busy: while self._busy.value is False: @@ -90,14 +90,14 @@ def update(self): else: time.sleep(15) # wait 15 seconds - self.command(IL0373_CDI, bytearray([0x17])) - self.command(IL0373_VCM_DC_SETTING, bytearray([0x00])) - self.command(IL0373_POWER_OFF) + self.command(_IL0373_CDI, bytearray([0x17])) + self.command(_IL0373_VCM_DC_SETTING, bytearray([0x00])) + self.command(_IL0373_POWER_OFF) time.sleep(2) def power_up(self): """power up the display""" - self.command(IL0373_POWER_ON) + self.command(_IL0373_POWER_ON) if self._busy: while self._busy.value is False: @@ -106,15 +106,15 @@ def power_up(self): time.sleep(3) # wait a bit time.sleep(.2) - self.command(IL0373_PANEL_SETTING, bytearray([0xCF])) - self.command(IL0373_CDI, bytearray([0x37])) - self.command(IL0373_PLL, bytearray([0x29])) + self.command(_IL0373_PANEL_SETTING, bytearray([0xCF])) + self.command(_IL0373_CDI, bytearray([0x37])) + self.command(_IL0373_PLL, bytearray([0x29])) _b1 = self.height & 0xFF _b2 = (self.height >> 8) & 0xFF _b3 = self.width & 0xFF _b4 = (self.width >> 8) & 0xFF - self.command(IL0373_RESOLUTION, bytearray([_b1, _b2, _b3, _b4])) - self.command(IL0373_VCM_DC_SETTING, bytearray([0x0A])) + self.command(_IL0373_RESOLUTION, bytearray([_b1, _b2, _b3, _b4])) + self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A])) def display(self): @@ -133,7 +133,7 @@ def display(self): #first data byte from SRAM will be transfered in at the #same time as the EPD command is transferred out - cmd = self.command(IL0373_DTM1, end=False) + cmd = self.command(_IL0373_DTM1, end=False) while not self.spi_device.try_lock(): pass @@ -157,7 +157,7 @@ def display(self): #first data byte from SRAM will be transfered in at the #same time as the EPD command is transferred out - cmd = self.command(IL0373_DTM2, end=False) + cmd = self.command(_IL0373_DTM2, end=False) while not self.spi_device.try_lock(): pass @@ -171,7 +171,7 @@ def display(self): self.sram.cs_pin.value = True self.spi_device.unlock() else: - cmd = self.command(IL0373_DTM1, end=False) + cmd = self.command(_IL0373_DTM1, end=False) while not self.spi_device.try_lock(): pass self._dc.value = True @@ -181,7 +181,7 @@ def display(self): time.sleep(.02) - cmd = self.command(IL0373_DTM2, end=False) + cmd = self.command(_IL0373_DTM2, end=False) while not self.spi_device.try_lock(): pass self._dc.value = True From 0728206b49f6f3a21efcfb6e477a4b46b9d3603b Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 6 Jan 2019 14:35:24 -0500 Subject: [PATCH 08/30] fix none-8-bit boundary sizes --- adafruit_epd/epd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index afb470d..a28e409 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -74,8 +74,8 @@ def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy self.sram = mcp_sram.Adafruit_MCP_SRAM(sramcs_pin, spi) else: self.sram = None - self._bw_buffer = bytearray((width // 8) * height) - self._red_buffer = bytearray((width // 8) * height) + self._bw_buffer = bytearray((width * height) // 8) + self._red_buffer = bytearray((width * height) // 8) # since we have *two* framebuffers - one for red and one for black, we dont subclass but manage manually self._red_framebuf = adafruit_framebuf.FrameBuffer(self._red_buffer, width, height, buf_format=adafruit_framebuf.MHMSB) self._bw_framebuf = adafruit_framebuf.FrameBuffer(self._bw_buffer, width, height, buf_format=adafruit_framebuf.MHMSB) From cf49a1d23fcc3ed0f444895059e299a8436b3fcd Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 6 Jan 2019 14:45:01 -0500 Subject: [PATCH 09/30] ahh, orientation is always with inkdots at bottom --- adafruit_epd/il0373.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index d5b05c1..68cde36 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -109,10 +109,10 @@ def power_up(self): self.command(_IL0373_PANEL_SETTING, bytearray([0xCF])) self.command(_IL0373_CDI, bytearray([0x37])) self.command(_IL0373_PLL, bytearray([0x29])) - _b1 = self.height & 0xFF - _b2 = (self.height >> 8) & 0xFF - _b3 = self.width & 0xFF - _b4 = (self.width >> 8) & 0xFF + _b1 = self.width & 0xFF + _b2 = (self.width >> 8) & 0xFF + _b3 = self.height & 0xFF + _b4 = (self.height >> 8) & 0xFF self.command(_IL0373_RESOLUTION, bytearray([_b1, _b2, _b3, _b4])) self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A])) From 642cb0dada488d4a35092ece3b30595a510761e9 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 6 Jan 2019 15:08:38 -0500 Subject: [PATCH 10/30] width/height change with rotation --- adafruit_epd/epd.py | 16 ++++++++++++++-- adafruit_epd/il0373.py | 14 +++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index a28e409..bac1b84 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -44,8 +44,8 @@ class Adafruit_EPD: # pylint: disable=too-many-arguments def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin): # pylint: enable=too-many-arguments - self.width = width - self.height = height + self._width = width + self._height = height # Setup reset pin, if we have one self._rst = rst_pin @@ -145,6 +145,18 @@ def text(self, string, x, y, color, *, font_name="font5x8.bin"): self._bw_framebuf.text(string, x, y, (color == Adafruit_EPD.BLACK) != self.black_invert, font_name=font_name) self._red_framebuf.text(string, x, y, (color == Adafruit_EPD.RED) != self.red_invert, font_name=font_name) + @property + def width(self): + if self.rotation in (0, 2): + return self._width + return self._height + + @property + def height(self): + if self.rotation in (0, 2): + return self._height + return self._width + @property def rotation(self): return self._bw_framebuf._rotation diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 68cde36..390b803 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -109,10 +109,10 @@ def power_up(self): self.command(_IL0373_PANEL_SETTING, bytearray([0xCF])) self.command(_IL0373_CDI, bytearray([0x37])) self.command(_IL0373_PLL, bytearray([0x29])) - _b1 = self.width & 0xFF - _b2 = (self.width >> 8) & 0xFF - _b3 = self.height & 0xFF - _b4 = (self.height >> 8) & 0xFF + _b1 = self._width & 0xFF + _b2 = (self._width >> 8) & 0xFF + _b3 = self._height & 0xFF + _b4 = (self._height >> 8) & 0xFF self.command(_IL0373_RESOLUTION, bytearray([_b1, _b2, _b3, _b4])) self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A])) @@ -210,7 +210,7 @@ def image(self, image): x = 1 pixel = pix[x, y] - addr = int(((self.width - x) * self.height + y)/8) + addr = int(((self._width - x) * self._height + y)/8) if pixel == (0xFF, 0, 0): addr = addr + self.bw_bufsize @@ -226,11 +226,11 @@ def image(self, image): def pixel(self, x, y, color): """draw a single pixel in the display buffer""" if self.sram: - if (x < 0) or (x >= self.width) or (y < 0) or (y >= self.height): + if (x < 0) or (x >= self._width) or (y < 0) or (y >= self._height): return if x == 0: x = 1 - addr = ((self.width - x) * self.height + y) // 8 + addr = ((self._width - x) * self._height + y) // 8 if color == Adafruit_EPD.RED: current = self.sram.read8(addr + self.bw_bufsize) else: From 2c20e845ee3d5c60a0945112c2b6c7c0a2dece6d Mon Sep 17 00:00:00 2001 From: ladyada Date: Mon, 4 Mar 2019 21:30:52 -0500 Subject: [PATCH 11/30] fix incorrect init order --- adafruit_epd/il0373.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 390b803..55efe38 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -110,10 +110,9 @@ def power_up(self): self.command(_IL0373_CDI, bytearray([0x37])) self.command(_IL0373_PLL, bytearray([0x29])) _b1 = self._width & 0xFF - _b2 = (self._width >> 8) & 0xFF + _b2 = (self._height >> 8) & 0xFF _b3 = self._height & 0xFF - _b4 = (self._height >> 8) & 0xFF - self.command(_IL0373_RESOLUTION, bytearray([_b1, _b2, _b3, _b4])) + self.command(_IL0373_RESOLUTION, bytearray([_b1, _b2, _b3])) self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A])) From 7fd35d081a18b9cd47420286b6ac499c1192f36d Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 30 Mar 2019 22:31:15 -0400 Subject: [PATCH 12/30] big refactor but now works with ram or sram --- adafruit_epd/epd.py | 195 ++++++++++++++++++++++++++-------- adafruit_epd/il0373.py | 221 +++++++++------------------------------ adafruit_epd/mcp_sram.py | 74 +++++++------ 3 files changed, 242 insertions(+), 248 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index bac1b84..459e510 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -27,7 +27,7 @@ """ import time -import digitalio +from digitalio import Direction import adafruit_framebuf from adafruit_epd import mcp_sram @@ -50,43 +50,113 @@ def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy # Setup reset pin, if we have one self._rst = rst_pin if rst_pin: - self._rst.direction = digitalio.Direction.OUTPUT + self._rst.direction = Direction.OUTPUT # Setup busy pin, if we have one self._busy = busy_pin if busy_pin: - self._busy.direction = digitalio.Direction.INPUT + self._busy.direction = Direction.INPUT # Setup dc pin (required) self._dc = dc_pin - self._dc.direction = digitalio.Direction.OUTPUT + self._dc.direction = Direction.OUTPUT self._dc.value = False # Setup cs pin (required) self._cs = cs_pin - self._cs.direction = digitalio.Direction.OUTPUT + self._cs.direction = Direction.OUTPUT self._cs.value = True # SPI interface (required) self.spi_device = spi + self.sram = None if sramcs_pin: self.sram = mcp_sram.Adafruit_MCP_SRAM(sramcs_pin, spi) + + self._buffer1_size = self._buffer2_size = 0 + self._buffer1 = self._buffer2 = None + self.hardware_reset() + + def display(self): + """show the contents of the display buffer""" + self.power_up() + + self.set_ram_address(0, 0) + + if self.sram: + while not self.spi_device.try_lock(): + pass + self.sram.cs_pin.value = False + #send read command + self.spi_device.write(bytearray([mcp_sram.Adafruit_MCP_SRAM.SRAM_READ])) + #send start address + self.spi_device.write(bytearray([0x00, 0x00])) + self.spi_device.unlock() + + #first data byte from SRAM will be transfered in at the + #same time as the EPD command is transferred out + cmd = self.write_ram(0) + + while not self.spi_device.try_lock(): + pass + self._dc.value = True + + if self.sram: + xfer = bytearray([cmd]) + outbuf = bytearray(1) + for _ in range(self._buffer1_size): + outbuf[0] = xfer[0] + self.spi_device.write_readinto(outbuf, xfer) + self.sram.cs_pin.value = True + else: + self.spi_device.write(self._buffer1) + + self._cs.value = True + self.spi_device.unlock() + time.sleep(.002) + + + if self.sram: + while not self.spi_device.try_lock(): + pass + self.sram.cs_pin.value = False + #send read command + self.spi_device.write(bytearray([mcp_sram.Adafruit_MCP_SRAM.SRAM_READ])) + #send start address + self.spi_device.write(bytearray([(self._buffer1_size >> 8), (self._buffer1_size & 0xFF)])) + self.spi_device.unlock() + + #first data byte from SRAM will be transfered in at the + #same time as the EPD command is transferred out + cmd = self.write_ram(1) + + while not self.spi_device.try_lock(): + pass + self._dc.value = True + + if self.sram: + xfer = bytearray([cmd]) + outbuf = bytearray(1) + for _ in range(self._buffer1_size): + outbuf[0] = xfer[0] + self.spi_device.write_readinto(outbuf, xfer) + self.sram.cs_pin.value = True else: - self.sram = None - self._bw_buffer = bytearray((width * height) // 8) - self._red_buffer = bytearray((width * height) // 8) - # since we have *two* framebuffers - one for red and one for black, we dont subclass but manage manually - self._red_framebuf = adafruit_framebuf.FrameBuffer(self._red_buffer, width, height, buf_format=adafruit_framebuf.MHMSB) - self._bw_framebuf = adafruit_framebuf.FrameBuffer(self._bw_buffer, width, height, buf_format=adafruit_framebuf.MHMSB) - - # if we hav ea reset pin, do a hardware reset + self.spi_device.write(self._buffer2) + + self._cs.value = True + self.spi_device.unlock() + self.update() + + + def hardware_reset(self): + # if we have a reset pin, do a hardware reset if self._rst: self._rst.value = False - time.sleep(.1) + time.sleep(0.1) self._rst.value = True - time.sleep(.1) - + time.sleep(0.1) def command(self, cmd, data=None, end=True): """Send command byte to display.""" @@ -100,50 +170,54 @@ def command(self, cmd, data=None, end=True): self.spi_device.write_readinto(bytearray([cmd]), outbuf) if data is not None: - self.data(data) - else: - self.spi_device.unlock() - + self._dc.value = True + self.spi_device.write(data) if end: self._cs.value = True + self.spi_device.unlock() return outbuf[0] - def data(self, dat): - """Send data to display.""" - self._dc.value = True - self.spi_device.write(dat) - self._cs.value = True - self.spi_device.unlock() + + def pixel(self, x, y, color): + """draw a single pixel in the display buffer""" + self._framebuf1.pixel(x, y, (color == Adafruit_EPD.BLACK) != self.black_invert) + self._framebuf2.pixel(x, y, (color == Adafruit_EPD.RED) != self.red_invert) def fill(self, color): - #This should be overridden in the subclass - self._bw_framebuf.fill((color == Adafruit_EPD.BLACK) != self.black_invert) - self._red_framebuf.fill((color == Adafruit_EPD.RED) != self.red_invert) + """fill the screen with the passed color""" + red_fill = (color == Adafruit_EPD.RED) != self.red_invert + black_fill = (color == Adafruit_EPD.BLACK) != self.black_invert + if red_fill: + red_fill = 0xFF + if black_fill: + black_fill = 0xFF - def pixel(self, x, y, color=None): - """This should be overridden in the subclass""" - self._bw_framebuf.pixel(x, y, (color == Adafruit_EPD.BLACK) != self.black_invert) - self._red_framebuf.pixel(x, y, (color == Adafruit_EPD.RED) != self.red_invert) + if self.sram: + self.sram.erase(0x00, self._buffer1_size, black_fill) + self.sram.erase(self._buffer1_size, self._buffer2_size, red_fill) + else: + self._framebuf1.fill(black_fill) + self._framebuf2.fill(red_fill) def rect(self, x, y, width, height, color): """draw a rectangle""" - self._bw_framebuf.rect(x, y, width, height, (color == Adafruit_EPD.BLACK) != self.black_invert) - self._red_framebuf.rect(x, y, width, height, (color == Adafruit_EPD.RED) != self.red_invert) + self._framebuf1.rect(x, y, width, height, (color == Adafruit_EPD.BLACK) != self.black_invert) + self._framebuf2.rect(x, y, width, height, (color == Adafruit_EPD.RED) != self.red_invert) # pylint: disable=too-many-arguments def fill_rect(self, x, y, width, height, color): """fill a rectangle with the passed color""" - self._bw_framebuf.fill_rect(x, y, width, height, (color == Adafruit_EPD.BLACK) != self.black_invert) - self._red_framebuf.fill_rect(x, y, width, height, (color == Adafruit_EPD.RED) != self.red_invert) + self._framebuf1.fill_rect(x, y, width, height, (color == Adafruit_EPD.BLACK) != self.black_invert) + self._framebuf2.fill_rect(x, y, width, height, (color == Adafruit_EPD.RED) != self.red_invert) def line(self, x_0, y_0, x_1, y_1, color): - self._bw_framebuf.line(x_0, y_0, x_1, y_1, (color == Adafruit_EPD.BLACK) != self.black_invert) - self._red_framebuf.line(x_0, y_0, x_1, y_1, (color == Adafruit_EPD.RED) != self.red_invert) + self._framebuf1.line(x_0, y_0, x_1, y_1, (color == Adafruit_EPD.BLACK) != self.black_invert) + self._framebuf2.line(x_0, y_0, x_1, y_1, (color == Adafruit_EPD.RED) != self.red_invert) def text(self, string, x, y, color, *, font_name="font5x8.bin"): - self._bw_framebuf.text(string, x, y, (color == Adafruit_EPD.BLACK) != self.black_invert, font_name=font_name) - self._red_framebuf.text(string, x, y, (color == Adafruit_EPD.RED) != self.red_invert, font_name=font_name) + self._framebuf1.text(string, x, y, (color == Adafruit_EPD.BLACK) != self.black_invert, font_name=font_name) + self._framebuf2.text(string, x, y, (color == Adafruit_EPD.RED) != self.red_invert, font_name=font_name) @property def width(self): @@ -159,12 +233,12 @@ def height(self): @property def rotation(self): - return self._bw_framebuf._rotation + return self._framebuf1._rotation @rotation.setter def rotation(self, val): - self._bw_framebuf.rotation = val - self._red_framebuf.rotation = val + self._framebuf1.rotation = val + self._framebuf2.rotation = val def hline(self, x, y, width, color): """draw a horizontal line""" @@ -173,3 +247,36 @@ def hline(self, x, y, width, color): def vline(self, x, y, height, color): """draw a vertical line""" self.fill_rect(x, y, 1, height, color) + + + def image(self, image): + """Set buffer to value of Python Imaging Library image. The image should + be in RGB mode and a size equal to the display size. + """ + if image.mode != 'RGB': + raise ValueError('Image must be in mode RGB.') + imwidth, imheight = image.size + if imwidth != self.width or imheight != self.height: + raise ValueError('Image must be same dimensions as display ({0}x{1}).' \ + .format(self.width, self.height)) + # Grab all the pixels from the image, faster than getpixel. + pix = image.load() + + for y in iter(range(image.size[1])): + for x in iter(range(image.size[0])): + if x == 0: + x = 1 + pixel = pix[x, y] + + addr = int(((self._width - x) * self._height + y)/8) + + if pixel == (0xFF, 0, 0): + addr = addr + self.bw_bufsize + current = self.sram.read8(addr) + + if pixel in ((0xFF, 0, 0), (0, 0, 0)): + current = current & ~(1 << (7 - y%8)) + else: + current = current | (1 << (7 - y%8)) + + self.sram.write8(addr, current) diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 55efe38..b9aab0d 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -64,8 +64,20 @@ def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, b super(Adafruit_IL0373, self).__init__(width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin) - self.bw_bufsize = int(width * height / 8) - self.red_bufsize = int(width * height / 8) + self._buffer1_size = int(width * height / 8) + self._buffer2_size = int(width * height / 8) + + if sramcs_pin: + self._buffer1_addr = 0 + self._buffer2_addr = self._buffer1_size + self._framebuf1 = adafruit_framebuf.FrameBuffer(self.sram.get_view(0), height, width, buf_format=adafruit_framebuf.MHMSB) + self._framebuf2 = adafruit_framebuf.FrameBuffer(self.sram.get_view(self._buffer1_size), height, width, buf_format=adafruit_framebuf.MHMSB) + else: + self._buffer1 = bytearray((width * height) // 8) + self._buffer2 = bytearray((width * height) // 8) + # since we have *two* framebuffers - one for red and one for black, we dont subclass but manage manually + self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, height, width, buf_format=adafruit_framebuf.MHMSB) + self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, height, width, buf_format=adafruit_framebuf.MHMSB) self.black_invert = True self.red_invert = True # pylint: enable=too-many-arguments @@ -73,192 +85,57 @@ def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, b def begin(self, reset=True): """Begin communication with the display and set basic settings""" super(Adafruit_IL0373, self).begin(reset) + self.power_down() - while self._busy.value is False: - pass - - self.command(_IL0373_POWER_SETTING, bytearray([0x03, 0x00, 0x2b, 0x2b, 0x09])) - self.command(_IL0373_BOOSTER_SOFT_START, bytearray([0x17, 0x17, 0x17])) - - def update(self): - """update the display""" - self.command(_IL0373_DISPLAY_REFRESH) - + def busy_wait(self): if self._busy: - while self._busy.value is False: + while not self._busy.value: pass else: - time.sleep(15) # wait 15 seconds - - self.command(_IL0373_CDI, bytearray([0x17])) - self.command(_IL0373_VCM_DC_SETTING, bytearray([0x00])) - self.command(_IL0373_POWER_OFF) - time.sleep(2) + time.sleep(0.5) def power_up(self): """power up the display""" + + self.hardware_reset() + self.busy_wait() + + self.command(_IL0373_POWER_SETTING, bytearray([0x03, 0x00, 0x2b, 0x2b, 0x09])) + self.command(_IL0373_BOOSTER_SOFT_START, bytearray([0x17, 0x17, 0x17])) self.command(_IL0373_POWER_ON) - if self._busy: - while self._busy.value is False: - pass - else: - time.sleep(3) # wait a bit - time.sleep(.2) + self.busy_wait() + time.sleep(0.2) self.command(_IL0373_PANEL_SETTING, bytearray([0xCF])) self.command(_IL0373_CDI, bytearray([0x37])) self.command(_IL0373_PLL, bytearray([0x29])) - _b1 = self._width & 0xFF - _b2 = (self._height >> 8) & 0xFF - _b3 = self._height & 0xFF + _b1 = self._height & 0xFF + _b2 = (self._width >> 8) & 0xFF + _b3 = self._width & 0xFF self.command(_IL0373_RESOLUTION, bytearray([_b1, _b2, _b3])) self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A])) + time.sleep(0.05) + def power_down(): + self.command(_IL0373_CDI, bytearray([0x17])) + self.command(_IL0373_VCM_DC_SETTING, bytearray([0x00])) + self.command(_IL0373_POWER_OFF) - def display(self): - """show the contents of the display buffer""" - self.power_up() - - if self.sram: - while not self.spi_device.try_lock(): - pass - self.sram.cs_pin.value = False - #send read command - self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_READ])) - #send start address - self.spi_device.write(bytearray([0x00, 0x00])) - self.spi_device.unlock() - - #first data byte from SRAM will be transfered in at the - #same time as the EPD command is transferred out - cmd = self.command(_IL0373_DTM1, end=False) - - while not self.spi_device.try_lock(): - pass - self._dc.value = True - xfer = bytearray([cmd]) - outbuf = bytearray(1) - for _ in range(self.bw_bufsize): - outbuf[0] = xfer[0] - self.spi_device.write_readinto(outbuf, xfer) - self._cs.value = True - self.sram.cs_pin.value = True - - time.sleep(.002) - - self.sram.cs_pin.value = False - #send read command - self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_READ])) - #send start address - self.spi_device.write(bytearray([(self.bw_bufsize >> 8), (self.bw_bufsize & 0xFF)])) - self.spi_device.unlock() - - #first data byte from SRAM will be transfered in at the - #same time as the EPD command is transferred out - cmd = self.command(_IL0373_DTM2, end=False) - - while not self.spi_device.try_lock(): - pass - self._dc.value = True - xfer = bytearray([cmd]) - outbuf = bytearray(1) - for _ in range(self.bw_bufsize): - outbuf[0] = xfer[0] - self.spi_device.write_readinto(outbuf, xfer) - self._cs.value = True - self.sram.cs_pin.value = True - self.spi_device.unlock() - else: - cmd = self.command(_IL0373_DTM1, end=False) - while not self.spi_device.try_lock(): - pass - self._dc.value = True - self.spi_device.write(self._bw_buffer) - self._cs.value = True - self.spi_device.unlock() - - time.sleep(.02) - - cmd = self.command(_IL0373_DTM2, end=False) - while not self.spi_device.try_lock(): - pass - self._dc.value = True - self.spi_device.write(self._red_buffer) - self._cs.value = True - self.spi_device.unlock() - - self.update() - - def image(self, image): - """Set buffer to value of Python Imaging Library image. The image should - be in RGB mode and a size equal to the display size. - """ - if image.mode != 'RGB': - raise ValueError('Image must be in mode RGB.') - imwidth, imheight = image.size - if imwidth != self.width or imheight != self.height: - raise ValueError('Image must be same dimensions as display ({0}x{1}).' \ - .format(self.width, self.height)) - # Grab all the pixels from the image, faster than getpixel. - pix = image.load() - - for y in iter(range(image.size[1])): - for x in iter(range(image.size[0])): - if x == 0: - x = 1 - pixel = pix[x, y] - - addr = int(((self._width - x) * self._height + y)/8) - - if pixel == (0xFF, 0, 0): - addr = addr + self.bw_bufsize - current = self.sram.read8(addr) - - if pixel in ((0xFF, 0, 0), (0, 0, 0)): - current = current & ~(1 << (7 - y%8)) - else: - current = current | (1 << (7 - y%8)) - - self.sram.write8(addr, current) - - def pixel(self, x, y, color): - """draw a single pixel in the display buffer""" - if self.sram: - if (x < 0) or (x >= self._width) or (y < 0) or (y >= self._height): - return - if x == 0: - x = 1 - addr = ((self._width - x) * self._height + y) // 8 - if color == Adafruit_EPD.RED: - current = self.sram.read8(addr + self.bw_bufsize) - else: - current = self.sram.read8(addr) - - if color == Adafruit_EPD.WHITE: - current = current | (1 << (7 - y%8)) - elif color in (Adafruit_EPD.RED, Adafruit_EPD.BLACK): - current = current & ~(1 << (7 - y%8)) - elif color == Adafruit_EPD.INVERSE: - current = current ^ (1 << (7 - y%8)) + def update(self): + """update the display""" + self.command(_IL0373_DISPLAY_REFRESH) + time.sleep(0.1) + self.busy_wait() + if not self._busy: + time.sleep(15) # wait 15 seconds - if color == Adafruit_EPD.RED: - self.sram.write8(addr + self.bw_bufsize, current) - else: - self.sram.write8(addr, current) - else: - super().pixel(x, y, color) + def write_ram(self, index): + if index == 0: + return self.command(_IL0373_DTM1, end=False) + if index == 1: + return self.command(_IL0373_DTM2, end=False) + raise RuntimeError("RAM index must be 0 or 1") - def fill(self, color): - """fill the screen with the passed color""" - red_fill = 0xFF - black_fill = 0xFF - if color == Adafruit_EPD.BLACK: - black_fill = 0x00 - if color == Adafruit_EPD.RED: - red_fill = 0x00 - if self.sram: - self.sram.erase(0x00, self.bw_bufsize, black_fill) - self.sram.erase(self.bw_bufsize, self.red_bufsize, red_fill) - else: - super().fill(color) + def set_ram_address(self, x, y): + return # on this chip it does nothing diff --git a/adafruit_epd/mcp_sram.py b/adafruit_epd/mcp_sram.py index fd3d1da..91f3bd5 100644 --- a/adafruit_epd/mcp_sram.py +++ b/adafruit_epd/mcp_sram.py @@ -28,9 +28,23 @@ from micropython import const import digitalio +import adafruit_bus_device.spi_device as spi_device SRAM_SEQUENTIAL_MODE = const(1 << 6) +class Adafruit_MCP_SRAM_View: + def __init__(self, sram, offset): + self._sram = sram + self._offset = offset + self._buf = [0] + + def __getitem__(self, i): + return self._sram.read(self._offset+i, 1)[0] + + def __setitem__(self, i, val): + self._buf[0] = val + self._sram.write(self._offset+i, self._buf) + class Adafruit_MCP_SRAM: """supporting class for communicating with Microchip SRAM chips""" @@ -41,40 +55,38 @@ class Adafruit_MCP_SRAM: def __init__(self, cs_pin, spi): # Handle hardware SPI + self._spi = spi_device.SPIDevice(spi,cs_pin, baudrate=8000000) self.spi_device = spi self.cs_pin = cs_pin + self._buf = bytearray(3) + self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRSR + self._buf[1] = 0x43 + with self._spi as spi: + spi.write(self._buf, end=2) - self.cs_pin.direction = digitalio.Direction.OUTPUT - while not self.spi_device.try_lock(): - pass - self.cs_pin.value = False - self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_WRSR, 0x43])) - self.cs_pin.value = True - self.spi_device.unlock() + def get_view(self, offset): + return Adafruit_MCP_SRAM_View(self, offset) def write(self, addr, buf, reg=SRAM_WRITE): """write the passed buffer to the passed address""" - cmd = bytearray([reg, (addr >> 8) & 0xFF, addr & 0xFF] + buf) + self._buf[0] = reg + self._buf[1] = addr >> 8 + self._buf[2] = addr - while not self.spi_device.try_lock(): - pass - self.cs_pin.value = False - self.spi_device.write(cmd) - self.cs_pin.value = True - self.spi_device.unlock() + with self._spi as spi: + spi.write(self._buf, end=3) + spi.write(bytearray(buf)) def read(self, addr, length, reg=SRAM_READ): """read passed number of bytes at the passed address""" - cmd = bytearray([reg, (addr >> 8) & 0xFF, addr & 0xFF]) + self._buf[0] = reg + self._buf[1] = addr >> 8 + self._buf[2] = addr buf = bytearray(length) - while not self.spi_device.try_lock(): - pass - self.cs_pin.value = False - self.spi_device.write(cmd) - self.spi_device.readinto(buf) - self.cs_pin.value = True - self.spi_device.unlock() + with self._spi as spi: + spi.write(self._buf, end=3) + spi.readinto(buf) return buf def read8(self, addr, reg=SRAM_READ): @@ -96,13 +108,11 @@ def write16(self, addr, value, reg=SRAM_WRITE): def erase(self, addr, length, value): """erase the passed number of bytes starting at the passed address""" - cmd = bytearray([Adafruit_MCP_SRAM.SRAM_WRITE, (addr >> 8) & 0xFF, addr & 0xFF]) - - while not self.spi_device.try_lock(): - pass - self.cs_pin.value = False - self.spi_device.write(cmd) - for _ in range(length): - self.spi_device.write(bytearray([value])) - self.cs_pin.value = True - self.spi_device.unlock() + self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRITE + self._buf[1] = addr >> 8 + self._buf[2] = addr + fill = bytearray([value]) + with self._spi as spi: + spi.write(self._buf, end=3) + for _ in range(length): + self.spi_device.write(fill) From b32893c9302dfd07bd59006479bd557154fb1650 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 30 Mar 2019 23:26:56 -0400 Subject: [PATCH 13/30] fix width and height --- adafruit_epd/il0373.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index b9aab0d..f5ee7ce 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -70,14 +70,14 @@ def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, b if sramcs_pin: self._buffer1_addr = 0 self._buffer2_addr = self._buffer1_size - self._framebuf1 = adafruit_framebuf.FrameBuffer(self.sram.get_view(0), height, width, buf_format=adafruit_framebuf.MHMSB) - self._framebuf2 = adafruit_framebuf.FrameBuffer(self.sram.get_view(self._buffer1_size), height, width, buf_format=adafruit_framebuf.MHMSB) + self._framebuf1 = adafruit_framebuf.FrameBuffer(self.sram.get_view(0), width, height, buf_format=adafruit_framebuf.MHMSB) + self._framebuf2 = adafruit_framebuf.FrameBuffer(self.sram.get_view(self._buffer1_size), width, height, buf_format=adafruit_framebuf.MHMSB) else: self._buffer1 = bytearray((width * height) // 8) self._buffer2 = bytearray((width * height) // 8) # since we have *two* framebuffers - one for red and one for black, we dont subclass but manage manually - self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, height, width, buf_format=adafruit_framebuf.MHMSB) - self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, height, width, buf_format=adafruit_framebuf.MHMSB) + self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB) + self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB) self.black_invert = True self.red_invert = True # pylint: enable=too-many-arguments @@ -110,9 +110,9 @@ def power_up(self): self.command(_IL0373_PANEL_SETTING, bytearray([0xCF])) self.command(_IL0373_CDI, bytearray([0x37])) self.command(_IL0373_PLL, bytearray([0x29])) - _b1 = self._height & 0xFF - _b2 = (self._width >> 8) & 0xFF - _b3 = self._width & 0xFF + _b1 = self._width & 0xFF + _b2 = (self._height >> 8) & 0xFF + _b3 = self._height & 0xFF self.command(_IL0373_RESOLUTION, bytearray([_b1, _b2, _b3])) self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A])) time.sleep(0.05) From fe0cb4d9f4fb4ff8f97c35b3d6ba4e1eb045599a Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 01:18:08 -0400 Subject: [PATCH 14/30] linty!@ --- adafruit_epd/epd.py | 106 +++++++++++++++++++++++++++------------ adafruit_epd/il0373.py | 36 +++++++------ adafruit_epd/mcp_sram.py | 11 ++-- 3 files changed, 102 insertions(+), 51 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index 459e510..1e951c9 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -27,23 +27,22 @@ """ import time +from micropython import const from digitalio import Direction -import adafruit_framebuf from adafruit_epd import mcp_sram -class Adafruit_EPD: +class Adafruit_EPD: # pylint: disable=too-many-instance-attributes """Base class for EPD displays """ - BLACK = 0 - WHITE = 1 - INVERSE = 2 - RED = 3 - DARK = 4 - LIGHT = 5 - - # pylint: disable=too-many-arguments - def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin): - # pylint: enable=too-many-arguments + BLACK = const(0) + WHITE = const(1) + INVERSE = const(2) + RED = const(3) + DARK = const(4) + LIGHT = const(5) + + + def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin): # pylint: disable=too-many-arguments self._width = width self._height = height @@ -74,8 +73,11 @@ def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy if sramcs_pin: self.sram = mcp_sram.Adafruit_MCP_SRAM(sramcs_pin, spi) + self._buf = bytearray(3) self._buffer1_size = self._buffer2_size = 0 self._buffer1 = self._buffer2 = None + self._framebuf1 = self._framebuf2 = None + self.black_invert = self.red_invert = True self.hardware_reset() def display(self): @@ -89,9 +91,11 @@ def display(self): pass self.sram.cs_pin.value = False #send read command - self.spi_device.write(bytearray([mcp_sram.Adafruit_MCP_SRAM.SRAM_READ])) + self._buf[0] = mcp_sram.Adafruit_MCP_SRAM.SRAM_READ #send start address - self.spi_device.write(bytearray([0x00, 0x00])) + self._buf[1] = 0 + self._buf[2] = 0 + self.spi_device.write(self._buf, end=3) self.spi_device.unlock() #first data byte from SRAM will be transfered in at the @@ -122,9 +126,11 @@ def display(self): pass self.sram.cs_pin.value = False #send read command - self.spi_device.write(bytearray([mcp_sram.Adafruit_MCP_SRAM.SRAM_READ])) + self._buf[0] = mcp_sram.Adafruit_MCP_SRAM.SRAM_READ #send start address - self.spi_device.write(bytearray([(self._buffer1_size >> 8), (self._buffer1_size & 0xFF)])) + self._buf[1] = self._buffer1_size >> 8 + self._buf[2] = self._buffer1_size + self.spi_device.write(self._buf, end=3) self.spi_device.unlock() #first data byte from SRAM will be transfered in at the @@ -151,7 +157,7 @@ def display(self): def hardware_reset(self): - # if we have a reset pin, do a hardware reset + """If we have a reset pin, do a hardware reset by toggling it""" if self._rst: self._rst.value = False time.sleep(0.1) @@ -178,6 +184,28 @@ def command(self, cmd, data=None, end=True): return outbuf[0] + def power_up(self): + """Power up the display in preparation for writing RAM and updating. + must be implemented in subclass""" + raise NotImplementedError() + + def power_down(self): + """Power down the display, must be implemented in subclass""" + raise NotImplementedError() + + def update(self): + """Update the display from internal memory, must be implemented in subclass""" + raise NotImplementedError() + + def write_ram(self, index): + """Send the one byte command for starting the RAM write process. Returns + the byte read at the same time over SPI. index is the RAM buffer, can be + 0 or 1 for tri-color displays. must be implemented in subclass""" + raise NotImplementedError() + + def set_ram_address(self, x, y): + """Set the RAM address location, must be implemented in subclass""" + raise NotImplementedError() def pixel(self, x, y, color): """draw a single pixel in the display buffer""" @@ -200,40 +228,54 @@ def fill(self, color): self._framebuf1.fill(black_fill) self._framebuf2.fill(red_fill) - def rect(self, x, y, width, height, color): + def rect(self, x, y, width, height, color): # pylint: disable=too-many-arguments """draw a rectangle""" - self._framebuf1.rect(x, y, width, height, (color == Adafruit_EPD.BLACK) != self.black_invert) - self._framebuf2.rect(x, y, width, height, (color == Adafruit_EPD.RED) != self.red_invert) + self._framebuf1.rect(x, y, width, height, + (color == Adafruit_EPD.BLACK) != self.black_invert) + self._framebuf2.rect(x, y, width, height, + (color == Adafruit_EPD.RED) != self.red_invert) - # pylint: disable=too-many-arguments - def fill_rect(self, x, y, width, height, color): + def fill_rect(self, x, y, width, height, color): # pylint: disable=too-many-arguments """fill a rectangle with the passed color""" - self._framebuf1.fill_rect(x, y, width, height, (color == Adafruit_EPD.BLACK) != self.black_invert) - self._framebuf2.fill_rect(x, y, width, height, (color == Adafruit_EPD.RED) != self.red_invert) - - def line(self, x_0, y_0, x_1, y_1, color): - self._framebuf1.line(x_0, y_0, x_1, y_1, (color == Adafruit_EPD.BLACK) != self.black_invert) - self._framebuf2.line(x_0, y_0, x_1, y_1, (color == Adafruit_EPD.RED) != self.red_invert) + self._framebuf1.fill_rect(x, y, width, height, + (color == Adafruit_EPD.BLACK) != self.black_invert) + self._framebuf2.fill_rect(x, y, width, height, + (color == Adafruit_EPD.RED) != self.red_invert) + + def line(self, x_0, y_0, x_1, y_1, color): # pylint: disable=too-many-arguments + """Draw a line from (x_0, y_0) to (x_1, y_1) in passed color""" + self._framebuf1.line(x_0, y_0, x_1, y_1, + (color == Adafruit_EPD.BLACK) != self.black_invert) + self._framebuf2.line(x_0, y_0, x_1, y_1, + (color == Adafruit_EPD.RED) != self.red_invert) def text(self, string, x, y, color, *, font_name="font5x8.bin"): - self._framebuf1.text(string, x, y, (color == Adafruit_EPD.BLACK) != self.black_invert, font_name=font_name) - self._framebuf2.text(string, x, y, (color == Adafruit_EPD.RED) != self.red_invert, font_name=font_name) + """Write text string at location (x, y) in given color, using font file""" + self._framebuf1.text(string, x, y, + (color == Adafruit_EPD.BLACK) != self.black_invert, + font_name=font_name) + self._framebuf2.text(string, x, y, + (color == Adafruit_EPD.RED) != self.red_invert, + font_name=font_name) @property def width(self): + """The width of the display, accounting for rotation""" if self.rotation in (0, 2): return self._width return self._height @property def height(self): + """The height of the display, accounting for rotation""" if self.rotation in (0, 2): return self._height return self._width @property def rotation(self): - return self._framebuf1._rotation + """The rotation of the display, can be one of (0, 1, 2, 3)""" + return self._framebuf1.rotation @rotation.setter def rotation(self, val): @@ -271,7 +313,7 @@ def image(self, image): addr = int(((self._width - x) * self._height + y)/8) if pixel == (0xFF, 0, 0): - addr = addr + self.bw_bufsize + addr = addr + self._buffer1_size current = self.sram.read8(addr) if pixel in ((0xFF, 0, 0), (0, 0, 0)): diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index f5ee7ce..2b574fb 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -30,7 +30,6 @@ from micropython import const import adafruit_framebuf from adafruit_epd.epd import Adafruit_EPD -from adafruit_epd.mcp_sram import Adafruit_MCP_SRAM _IL0373_POWER_SETTING = const(0x01) _IL0373_PANEL_SETTING = const(0x00) @@ -68,26 +67,30 @@ def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, b self._buffer2_size = int(width * height / 8) if sramcs_pin: - self._buffer1_addr = 0 - self._buffer2_addr = self._buffer1_size - self._framebuf1 = adafruit_framebuf.FrameBuffer(self.sram.get_view(0), width, height, buf_format=adafruit_framebuf.MHMSB) - self._framebuf2 = adafruit_framebuf.FrameBuffer(self.sram.get_view(self._buffer1_size), width, height, buf_format=adafruit_framebuf.MHMSB) + self._buffer1 = self.sram.get_view(0) + self._buffer2 = self.sram.get_view(self._buffer1_size) else: self._buffer1 = bytearray((width * height) // 8) self._buffer2 = bytearray((width * height) // 8) - # since we have *two* framebuffers - one for red and one for black, we dont subclass but manage manually - self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB) - self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB) + # since we have *two* framebuffers - one for red and one for black + # we dont subclass but manage manually + self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, width, height, + buf_format=adafruit_framebuf.MHMSB) + self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height, + buf_format=adafruit_framebuf.MHMSB) self.black_invert = True self.red_invert = True # pylint: enable=too-many-arguments def begin(self, reset=True): """Begin communication with the display and set basic settings""" - super(Adafruit_IL0373, self).begin(reset) + if reset: + self.hardware_reset() self.power_down() def busy_wait(self): + """Wait for display to be done with current task, either by polling the + busy pin, or pausing""" if self._busy: while not self._busy.value: pass @@ -95,8 +98,7 @@ def busy_wait(self): time.sleep(0.5) def power_up(self): - """power up the display""" - + """Power up the display in preparation for writing RAM and updating""" self.hardware_reset() self.busy_wait() @@ -117,13 +119,14 @@ def power_up(self): self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A])) time.sleep(0.05) - def power_down(): + def power_down(self): + """Power down the display - required when not actively displaying!""" self.command(_IL0373_CDI, bytearray([0x17])) self.command(_IL0373_VCM_DC_SETTING, bytearray([0x00])) self.command(_IL0373_POWER_OFF) def update(self): - """update the display""" + """Update the display from internal memory""" self.command(_IL0373_DISPLAY_REFRESH) time.sleep(0.1) self.busy_wait() @@ -131,11 +134,16 @@ def update(self): time.sleep(15) # wait 15 seconds def write_ram(self, index): + """Send the one byte command for starting the RAM write process. Returns + the byte read at the same time over SPI. index is the RAM buffer, can be + 0 or 1 for tri-color displays.""" if index == 0: return self.command(_IL0373_DTM1, end=False) if index == 1: return self.command(_IL0373_DTM2, end=False) raise RuntimeError("RAM index must be 0 or 1") - def set_ram_address(self, x, y): + def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use + """Set the RAM address location, not used on this chipset but required by + the superclass""" return # on this chip it does nothing diff --git a/adafruit_epd/mcp_sram.py b/adafruit_epd/mcp_sram.py index 91f3bd5..d721189 100644 --- a/adafruit_epd/mcp_sram.py +++ b/adafruit_epd/mcp_sram.py @@ -27,12 +27,12 @@ """ from micropython import const -import digitalio -import adafruit_bus_device.spi_device as spi_device +from adafruit_bus_device import spi_device SRAM_SEQUENTIAL_MODE = const(1 << 6) class Adafruit_MCP_SRAM_View: + """A interface class that turns an SRAM chip into something like a memoryview""" def __init__(self, sram, offset): self._sram = sram self._offset = offset @@ -55,16 +55,17 @@ class Adafruit_MCP_SRAM: def __init__(self, cs_pin, spi): # Handle hardware SPI - self._spi = spi_device.SPIDevice(spi,cs_pin, baudrate=8000000) + self._spi = spi_device.SPIDevice(spi, cs_pin, baudrate=8000000) self.spi_device = spi self.cs_pin = cs_pin self._buf = bytearray(3) self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRSR self._buf[1] = 0x43 - with self._spi as spi: - spi.write(self._buf, end=2) + with self._spi as spidev: + spidev.write(self._buf, end=2) def get_view(self, offset): + """Create an object that can be used as a memoryview, with a given offset""" return Adafruit_MCP_SRAM_View(self, offset) def write(self, addr, buf, reg=SRAM_WRITE): From ad5b467d403de9c806e46e1a3f95f6be22b0213a Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 01:22:54 -0400 Subject: [PATCH 15/30] fix pylint spi.write complaint --- adafruit_epd/mcp_sram.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/adafruit_epd/mcp_sram.py b/adafruit_epd/mcp_sram.py index d721189..bccb733 100644 --- a/adafruit_epd/mcp_sram.py +++ b/adafruit_epd/mcp_sram.py @@ -62,7 +62,7 @@ def __init__(self, cs_pin, spi): self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRSR self._buf[1] = 0x43 with self._spi as spidev: - spidev.write(self._buf, end=2) + spidev.write(self._buf, end=2) # pylint: disable=no-member def get_view(self, offset): """Create an object that can be used as a memoryview, with a given offset""" @@ -75,8 +75,8 @@ def write(self, addr, buf, reg=SRAM_WRITE): self._buf[2] = addr with self._spi as spi: - spi.write(self._buf, end=3) - spi.write(bytearray(buf)) + spi.write(self._buf, end=3) # pylint: disable=no-member + spi.write(bytearray(buf)) # pylint: disable=no-member def read(self, addr, length, reg=SRAM_READ): """read passed number of bytes at the passed address""" @@ -86,8 +86,8 @@ def read(self, addr, length, reg=SRAM_READ): buf = bytearray(length) with self._spi as spi: - spi.write(self._buf, end=3) - spi.readinto(buf) + spi.write(self._buf, end=3) # pylint: disable=no-member + spi.readinto(buf) # pylint: disable=no-member return buf def read8(self, addr, reg=SRAM_READ): @@ -114,6 +114,6 @@ def erase(self, addr, length, value): self._buf[2] = addr fill = bytearray([value]) with self._spi as spi: - spi.write(self._buf, end=3) + spi.write(self._buf, end=3) # pylint: disable=no-member for _ in range(length): - self.spi_device.write(fill) + spi.write(fill) # pylint: disable=no-member From d908c69726a2734a744f3aeefc53eaf9ec855d83 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 01:25:11 -0400 Subject: [PATCH 16/30] lint examples --- examples/epd_bitmap.py | 6 +++--- examples/epd_blinka.py | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/epd_bitmap.py b/examples/epd_bitmap.py index 445dc79..d9986be 100644 --- a/examples/epd_bitmap.py +++ b/examples/epd_bitmap.py @@ -78,11 +78,11 @@ class BMPError(Exception): for col in range(bmpWidth): b, g, r = bytearray(f.read(3)) # BMP files store RGB in BGR if r < 0x80 and g < 0x80 and b < 0x80: - display.draw_pixel(row, col, Adafruit_EPD.BLACK) + display.pixel(row, col, Adafruit_EPD.BLACK) elif r >= 0x80 and g >= 0x80 and b >= 0x80: - display.draw_pixel(row, col, Adafruit_EPD.WHITE) + display.pixel(row, col, Adafruit_EPD.WHITE) elif r >= 0x80: - display.draw_pixel(row, col, Adafruit_EPD.RED) + display.pixel(row, col, Adafruit_EPD.RED) except OSError as e: if e.args[0] == 28: diff --git a/examples/epd_blinka.py b/examples/epd_blinka.py index bbc20b6..e883b1f 100644 --- a/examples/epd_blinka.py +++ b/examples/epd_blinka.py @@ -9,10 +9,6 @@ # create the spi device and pins we will need spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) -while not spi.try_lock(): - pass -spi.configure(baudrate=16000000) -spi.unlock() ecs = digitalio.DigitalInOut(board.D22) dc = digitalio.DigitalInOut(board.D13) @@ -20,8 +16,14 @@ rst = digitalio.DigitalInOut(board.D19) busy = digitalio.DigitalInOut(board.D26) + # give them all to our driver -display = Adafruit_IL0373(152, 152, rst, dc, busy, srcs, ecs, spi) +print("Creating display") +display = Adafruit_IL0373(104, 212, spi, + cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, + rst_pin=rst, busy_pin=busy) + + # Create blank image for drawing. # Make sure to create image with mode '1' for 1-bit color. width = display.width From cf64f48eeb5e85588af394bfc6683a014a58a1bc Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 01:27:01 -0400 Subject: [PATCH 17/30] so close! --- examples/epd_blinka.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/epd_blinka.py b/examples/epd_blinka.py index e883b1f..2a1103e 100644 --- a/examples/epd_blinka.py +++ b/examples/epd_blinka.py @@ -35,7 +35,7 @@ BLACK = (0x00, 0x00, 0x00) # clear the buffer -display.clear_buffer() +display.fill(Adafruit_EPD.WHITE) # Get drawing object to draw on image. draw = ImageDraw.Draw(image) From 42de3be9f6e809b7cba388edbb3e8b992b754f92 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 01:29:43 -0400 Subject: [PATCH 18/30] lintylint --- examples/epd_blinka.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/epd_blinka.py b/examples/epd_blinka.py index 2a1103e..8b9b57a 100644 --- a/examples/epd_blinka.py +++ b/examples/epd_blinka.py @@ -5,6 +5,7 @@ from PIL import Image from PIL import ImageDraw from PIL import ImageFont +from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.il0373 import Adafruit_IL0373 # create the spi device and pins we will need From e69578744a73455467340921cbfcf41ea5f73d5a Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 15:46:12 -0400 Subject: [PATCH 19/30] add 2.7" tricolor and single byte transfer support for weird chips --- adafruit_epd/epd.py | 42 ++++++---- adafruit_epd/il91874.py | 170 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 17 deletions(-) create mode 100644 adafruit_epd/il91874.py diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index 1e951c9..dbc9659 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -68,6 +68,8 @@ def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy # SPI interface (required) self.spi_device = spi + self._spibuf = bytearray(1) + self._single_byte_tx = False self.sram = None if sramcs_pin: @@ -100,21 +102,19 @@ def display(self): #first data byte from SRAM will be transfered in at the #same time as the EPD command is transferred out - cmd = self.write_ram(0) + databyte = self.write_ram(0) while not self.spi_device.try_lock(): pass self._dc.value = True if self.sram: - xfer = bytearray([cmd]) - outbuf = bytearray(1) for _ in range(self._buffer1_size): - outbuf[0] = xfer[0] - self.spi_device.write_readinto(outbuf, xfer) + databyte = self._spi_transfer(databyte) self.sram.cs_pin.value = True else: - self.spi_device.write(self._buffer1) + for databyte in self._buffer1: + self._spi_transfer(databyte) self._cs.value = True self.spi_device.unlock() @@ -135,21 +135,19 @@ def display(self): #first data byte from SRAM will be transfered in at the #same time as the EPD command is transferred out - cmd = self.write_ram(1) + databyte = self.write_ram(1) while not self.spi_device.try_lock(): pass self._dc.value = True if self.sram: - xfer = bytearray([cmd]) - outbuf = bytearray(1) - for _ in range(self._buffer1_size): - outbuf[0] = xfer[0] - self.spi_device.write_readinto(outbuf, xfer) + for _ in range(self._buffer2_size): + databyte = self._spi_transfer(databyte) self.sram.cs_pin.value = True else: - self.spi_device.write(self._buffer2) + for databyte in self._buffer2: + self._spi_transfer(databyte) self._cs.value = True self.spi_device.unlock() @@ -169,20 +167,30 @@ def command(self, cmd, data=None, end=True): self._cs.value = True self._dc.value = False self._cs.value = False - outbuf = bytearray(1) while not self.spi_device.try_lock(): pass - self.spi_device.write_readinto(bytearray([cmd]), outbuf) + ret = self._spi_transfer(cmd) if data is not None: self._dc.value = True - self.spi_device.write(data) + for b in data: + self._spi_transfer(b) if end: self._cs.value = True self.spi_device.unlock() - return outbuf[0] + return ret + + def _spi_transfer(self, databyte): + """Transfer one byte, toggling the cs pin if required by the EPD chipset""" + self._spibuf[0] = databyte + if self._single_byte_tx: + self._cs.value = False + self.spi_device.write_readinto(self._spibuf, self._spibuf) + if self._single_byte_tx: + self._cs.value = True + return self._spibuf[0] def power_up(self): """Power up the display in preparation for writing RAM and updating. diff --git a/adafruit_epd/il91874.py b/adafruit_epd/il91874.py new file mode 100644 index 0000000..b7db3e6 --- /dev/null +++ b/adafruit_epd/il91874.py @@ -0,0 +1,170 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Dean Miller for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`adafruit_epd.il91874` - Adafruit IL91874 - ePaper display driver +==================================================================================== +CircuitPython driver for Adafruit IL91874 display breakouts +* Author(s): Dean Miller, Ladyada +""" + +import time +from micropython import const +import adafruit_framebuf +from adafruit_epd.epd import Adafruit_EPD + +_IL91874_PANEL_SETTING = const(0x00) +_IL91874_POWER_SETTING = const(0x01) +_IL91874_POWER_OFF = const(0x02) +_IL91874_POWER_OFF_SEQUENCE = const(0x03) +_IL91874_POWER_ON = const(0x04) +_IL91874_POWER_ON_MEASURE = const(0x05) +_IL91874_BOOSTER_SOFT_START = const(0x06) +_IL91874_DEEP_SLEEP = const(0x07) +_IL91874_DTM1 = const(0x10) +_IL91874_DATA_STOP = const(0x11) +_IL91874_DISPLAY_REFRESH = const(0x12) +_IL91874_DTM2 = const(0x13) +_IL91874_PDTM1 = const(0x14) +_IL91874_PDTM2 = const(0x15) +_IL91874_PDRF = const(0x16) +_IL91874_LUT1 = const(0x20) +_IL91874_LUTWW = const(0x21) +_IL91874_LUTBW = const(0x22) +_IL91874_LUTWB = const(0x23) +_IL91874_LUTBB = const(0x24) +_IL91874_PLL = const(0x30) +_IL91874_CDI = const(0x50) +_IL91874_RESOLUTION = const(0x61) +_IL91874_VCM_DC_SETTING = const(0x82) + +_LUT_VCOMDC = b'\x00\x00\x00\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x00\x0e\x01\x0e\x01\x10\x00\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01' +_LUT_WW = b'\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01' +_LUT_BW = b'\xa0\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x90\n\n\x00\x00\x08\xb0\x04\x10\x00\x00\x05\xb0\x03\x0e\x00\x00\n\xc0#\x00\x00\x00\x01' +_LUT_BB = b'\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01' +_LUT_WB = b'\x90\x1a\x1a\x00\x00\x01 \n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x10\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01' + +class Adafruit_IL91874(Adafruit_EPD): + """driver class for Adafruit IL91874 ePaper display breakouts""" + # pylint: disable=too-many-arguments + def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin): + super(Adafruit_IL91874, self).__init__(width, height, spi, cs_pin, dc_pin, + sramcs_pin, rst_pin, busy_pin) + + self._buffer1_size = int(width * height / 8) + self._buffer2_size = int(width * height / 8) + + if sramcs_pin: + self._buffer1 = self.sram.get_view(0) + self._buffer2 = self.sram.get_view(self._buffer1_size) + else: + self._buffer1 = bytearray((width * height) // 8) + self._buffer2 = bytearray((width * height) // 8) + # since we have *two* framebuffers - one for red and one for black + # we dont subclass but manage manually + self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, width, height, + buf_format=adafruit_framebuf.MHMSB) + self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height, + buf_format=adafruit_framebuf.MHMSB) + self.black_invert = True + self.red_invert = False + self._single_byte_tx = True + + def begin(self, reset=True): + """Begin communication with the display and set basic settings""" + if reset: + self.hardware_reset() + + self.power_down() + + def busy_wait(self): + """Wait for display to be done with current task, either by polling the + busy pin, or pausing""" + if self._busy: + while not self._busy.value: + pass + else: + time.sleep(0.5) + + def power_up(self): + """Power up the display in preparation for writing RAM and updating""" + self.hardware_reset() + time.sleep(0.2) + self.command(_IL91874_POWER_ON) + self.busy_wait() + + self.command(_IL91874_PANEL_SETTING, bytearray([0xAF])) + self.command(_IL91874_PLL, bytearray([0x3A])) + self.command(_IL91874_POWER_SETTING, bytearray([0x03, 0x00, 0x2b, 0x2b, 0x09])) + self.command(_IL91874_BOOSTER_SOFT_START, bytearray([0x07, 0x07, 0x17])) + + self.command(0xF8, bytearray([0x60, 0xA5])) # mystery command in example code + self.command(0xF8, bytearray([0x89, 0xA5])) # mystery command in example code + self.command(0xF8, bytearray([0x90, 0x00])) # mystery command in example code + self.command(0xF8, bytearray([0x93, 0xA2])) # mystery command in example code + self.command(0xF8, bytearray([0x73, 0x41])) # mystery command in example code + + self.command(_IL91874_VCM_DC_SETTING, bytearray([0x12])) + self.command(_IL91874_CDI, bytearray([0x87])) + + # Look Up Tables + self.command(_IL91874_LUT1, _LUT_VCOMDC); + self.command(_IL91874_LUTWW, _LUT_WW); + self.command(_IL91874_LUTBW, _LUT_BW); + self.command(_IL91874_LUTWB, _LUT_WB); + self.command(_IL91874_LUTBB, _LUT_BB); + + _b0 = (self._width >> 8) & 0xFF + _b1 = self._width & 0xFF + _b2 = (self._height >> 8) & 0xFF + _b3 = self._height & 0xFF + self.command(_IL91874_RESOLUTION, bytearray([_b0, _b1, _b2, _b3])) + self.command(_IL91874_PDRF, bytearray([0x00])) + + def power_down(self): + """Power down the display - required when not actively displaying!""" + self.command(_IL91874_POWER_OFF, bytearray([0x17])) + self.busy_wait() + + if self._rst: # Only deep sleep if we can get out of it + self.command(_IL91874_DEEP_SLEEP, bytearray([0xA5])) + + def update(self): + """Update the display from internal memory""" + self.command(_IL91874_DISPLAY_REFRESH) + self.busy_wait() + if not self._busy: + time.sleep(16) # wait 16 seconds + + def write_ram(self, index): + """Send the one byte command for starting the RAM write process. Returns + the byte read at the same time over SPI. index is the RAM buffer, can be + 0 or 1 for tri-color displays.""" + if index == 0: + return self.command(_IL91874_DTM1, end=False) + if index == 1: + return self.command(_IL91874_DTM2, end=False) + raise RuntimeError("RAM index must be 0 or 1") + + def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use + """Set the RAM address location, not used on this chipset but required by + the superclass""" + return # on this chip it does nothing From 9010050ded2b04f0761981fdb2a6b6bd853a2b96 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 15:53:46 -0400 Subject: [PATCH 20/30] linting --- adafruit_epd/epd.py | 3 +-- adafruit_epd/il91874.py | 12 +++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index dbc9659..9b30b27 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -82,7 +82,7 @@ def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy self.black_invert = self.red_invert = True self.hardware_reset() - def display(self): + def display(self): # pylint: disable=too-many-branches """show the contents of the display buffer""" self.power_up() @@ -120,7 +120,6 @@ def display(self): self.spi_device.unlock() time.sleep(.002) - if self.sram: while not self.spi_device.try_lock(): pass diff --git a/adafruit_epd/il91874.py b/adafruit_epd/il91874.py index b7db3e6..8b275a4 100644 --- a/adafruit_epd/il91874.py +++ b/adafruit_epd/il91874.py @@ -56,11 +56,13 @@ _IL91874_RESOLUTION = const(0x61) _IL91874_VCM_DC_SETTING = const(0x82) +# pylint: disable=line-too-long _LUT_VCOMDC = b'\x00\x00\x00\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x00\x0e\x01\x0e\x01\x10\x00\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01' _LUT_WW = b'\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01' _LUT_BW = b'\xa0\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x90\n\n\x00\x00\x08\xb0\x04\x10\x00\x00\x05\xb0\x03\x0e\x00\x00\n\xc0#\x00\x00\x00\x01' _LUT_BB = b'\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01' _LUT_WB = b'\x90\x1a\x1a\x00\x00\x01 \n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x10\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01' +# pylint: enable=line-too-long class Adafruit_IL91874(Adafruit_EPD): """driver class for Adafruit IL91874 ePaper display breakouts""" @@ -126,11 +128,11 @@ def power_up(self): self.command(_IL91874_CDI, bytearray([0x87])) # Look Up Tables - self.command(_IL91874_LUT1, _LUT_VCOMDC); - self.command(_IL91874_LUTWW, _LUT_WW); - self.command(_IL91874_LUTBW, _LUT_BW); - self.command(_IL91874_LUTWB, _LUT_WB); - self.command(_IL91874_LUTBB, _LUT_BB); + self.command(_IL91874_LUT1, _LUT_VCOMDC) + self.command(_IL91874_LUTWW, _LUT_WW) + self.command(_IL91874_LUTBW, _LUT_BW) + self.command(_IL91874_LUTWB, _LUT_WB) + self.command(_IL91874_LUTBB, _LUT_BB) _b0 = (self._width >> 8) & 0xFF _b1 = self._width & 0xFF From 09213806747677396ef90eb6414de7699bc02417 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 16:01:35 -0400 Subject: [PATCH 21/30] add line for 2.7" and also more complete framebuf test --- examples/epd_simpletest.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/examples/epd_simpletest.py b/examples/epd_simpletest.py index 77f1c48..d52ba49 100644 --- a/examples/epd_simpletest.py +++ b/examples/epd_simpletest.py @@ -3,34 +3,38 @@ import board from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.il0373 import Adafruit_IL0373 +from adafruit_epd.il91874 import Adafruit_IL91874 # create the spi device and pins we will need spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) ecs = digitalio.DigitalInOut(board.D10) dc = digitalio.DigitalInOut(board.D9) -srcs = digitalio.DigitalInOut(board.D8) -rst = digitalio.DigitalInOut(board.D7) -busy = digitalio.DigitalInOut(board.D6) +srcs = digitalio.DigitalInOut(board.D7) # can be None to use internal memory +rst = digitalio.DigitalInOut(board.D11) # can be None to not use this pin +busy = digitalio.DigitalInOut(board.D12) # can be None to not use this pin # give them all to our driver -display = Adafruit_IL0373(152, 152, spi, +print("Creating display") +display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display +#display = Adafruit_IL0373(104, 212, spi, # 2.13" Tri-color display cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, rst_pin=rst, busy_pin=busy) +display.rotation = 2 + # clear the buffer +print("Clear buffer") display.fill(Adafruit_EPD.WHITE) -r_width = 5 -r_pos = display.height - -color = Adafruit_EPD.BLACK -while r_pos > display.height/2: - if r_pos < display.height - 50: - color = Adafruit_EPD.RED - display.rect(display.width - r_pos, - display.height - r_pos, - display.width - 2*(display.width - r_pos), - display.height - 2*(display.height - r_pos), - color) - r_pos = r_pos - r_width +print("Draw Rectangles") +display.fill_rect(5, 5, 10, 10, Adafruit_EPD.RED) +display.rect(0, 0, 20, 30, Adafruit_EPD.BLACK) + +print("Draw lines") +display.line(0, 0, display.width-1, display.height-1, Adafruit_EPD.BLACK) +display.line(0, display.height-1, display.width-1, 0, Adafruit_EPD.RED) + +print("Draw text") +display.text('hello world', 25, 10, Adafruit_EPD.BLACK) + display.display() From 11c3179f08d40c60d84922905ad4771a2e3658a2 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 17:56:59 -0400 Subject: [PATCH 22/30] allow rearranging of buffers (for flex displays) --- adafruit_epd/epd.py | 76 ++++++++++++++++++++++++++---------------- adafruit_epd/il0373.py | 4 +-- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index 9b30b27..936fda6 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -79,7 +79,8 @@ def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy self._buffer1_size = self._buffer2_size = 0 self._buffer1 = self._buffer2 = None self._framebuf1 = self._framebuf2 = None - self.black_invert = self.red_invert = True + self._colorframebuf = self._blackframebuf = None + self._black_inverted = self._color_inverted = True self.hardware_reset() def display(self): # pylint: disable=too-many-branches @@ -214,56 +215,73 @@ def set_ram_address(self, x, y): """Set the RAM address location, must be implemented in subclass""" raise NotImplementedError() + def set_black_buffer(self, index, inverted): + """Set the index for the black buffer data (0 or 1) and whether its inverted""" + if index == 0: + self._blackframebuf = self._framebuf1 + elif index == 1: + self._blackframebuf = self._framebuf2 + else: + raise RuntimeError("Buffer index must be 0 or 1") + self._black_inverted = inverted + + def set_color_buffer(self, index, inverted): + """Set the index for the color buffer data (0 or 1) and whether its inverted""" + if index == 0: + self._colorframebuf = self._framebuf1 + elif index == 1: + self._colorframebuf = self._framebuf2 + else: + raise RuntimeError("Buffer index must be 0 or 1") + self._color_inverted = inverted + + def _color_dup(self, func, args, color): + black = getattr(self._blackframebuf, func) + red = getattr(self._colorframebuf, func) + if self._blackframebuf is self._colorframebuf: # monochrome + black(*args, color=(color != Adafruit_EPD.WHITE) != self._black_inverted) + else: + black(*args, color=(color == Adafruit_EPD.BLACK) != self._black_inverted) + red(*args, color=(color == Adafruit_EPD.RED) != self._color_inverted) + def pixel(self, x, y, color): """draw a single pixel in the display buffer""" - self._framebuf1.pixel(x, y, (color == Adafruit_EPD.BLACK) != self.black_invert) - self._framebuf2.pixel(x, y, (color == Adafruit_EPD.RED) != self.red_invert) + self._color_dup('pixel', (x, y), color) def fill(self, color): """fill the screen with the passed color""" - red_fill = (color == Adafruit_EPD.RED) != self.red_invert - black_fill = (color == Adafruit_EPD.BLACK) != self.black_invert - if red_fill: - red_fill = 0xFF - if black_fill: - black_fill = 0xFF + red_fill = ((color == Adafruit_EPD.RED) != self._color_inverted) * 0xFF + black_fill = ((color == Adafruit_EPD.BLACK) != self._black_inverted) * 0xFF if self.sram: self.sram.erase(0x00, self._buffer1_size, black_fill) self.sram.erase(self._buffer1_size, self._buffer2_size, red_fill) else: - self._framebuf1.fill(black_fill) - self._framebuf2.fill(red_fill) + self._blackframebuf.fill(black_fill) + self._colorframebuf.fill(red_fill) def rect(self, x, y, width, height, color): # pylint: disable=too-many-arguments """draw a rectangle""" - self._framebuf1.rect(x, y, width, height, - (color == Adafruit_EPD.BLACK) != self.black_invert) - self._framebuf2.rect(x, y, width, height, - (color == Adafruit_EPD.RED) != self.red_invert) + self._color_dup('rect', (x, y, width, height), color) def fill_rect(self, x, y, width, height, color): # pylint: disable=too-many-arguments """fill a rectangle with the passed color""" - self._framebuf1.fill_rect(x, y, width, height, - (color == Adafruit_EPD.BLACK) != self.black_invert) - self._framebuf2.fill_rect(x, y, width, height, - (color == Adafruit_EPD.RED) != self.red_invert) + self._color_dup('fill_rect', (x, y, width, height), color) def line(self, x_0, y_0, x_1, y_1, color): # pylint: disable=too-many-arguments """Draw a line from (x_0, y_0) to (x_1, y_1) in passed color""" - self._framebuf1.line(x_0, y_0, x_1, y_1, - (color == Adafruit_EPD.BLACK) != self.black_invert) - self._framebuf2.line(x_0, y_0, x_1, y_1, - (color == Adafruit_EPD.RED) != self.red_invert) + self._color_dup('line', (x_0, y_0, x_1, y_1), color) def text(self, string, x, y, color, *, font_name="font5x8.bin"): """Write text string at location (x, y) in given color, using font file""" - self._framebuf1.text(string, x, y, - (color == Adafruit_EPD.BLACK) != self.black_invert, - font_name=font_name) - self._framebuf2.text(string, x, y, - (color == Adafruit_EPD.RED) != self.red_invert, - font_name=font_name) + if self._blackframebuf is self._colorframebuf: # monochrome + self._blackframebuf.text(string, x, y, font_name=font_name, + color=(color != Adafruit_EPD.WHITE) != self._black_inverted) + else: + self._blackframebuf.text(string, x, y, font_name=font_name, + color=(color == Adafruit_EPD.BLACK) != self._black_inverted) + self._colorframebuf.text(string, x, y, font_name=font_name, + color=(color == Adafruit_EPD.RED) != self._color_inverted) @property def width(self): diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 2b574fb..79472d6 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -78,8 +78,8 @@ def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, b buf_format=adafruit_framebuf.MHMSB) self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB) - self.black_invert = True - self.red_invert = True + self.set_black_buffer(0, True) + self.set_color_buffer(1, True) # pylint: enable=too-many-arguments def begin(self, reset=True): From d37b6432cda3390399804cb855f4479190cd2f73 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 17:58:37 -0400 Subject: [PATCH 23/30] matchy up 2.7" to new buffer assignment --- adafruit_epd/il91874.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_epd/il91874.py b/adafruit_epd/il91874.py index 8b275a4..5efe627 100644 --- a/adafruit_epd/il91874.py +++ b/adafruit_epd/il91874.py @@ -86,8 +86,8 @@ def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, b buf_format=adafruit_framebuf.MHMSB) self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB) - self.black_invert = True - self.red_invert = False + self.set_black_buffer(0, True) + self.set_color_buffer(1, False) self._single_byte_tx = True def begin(self, reset=True): From eb8fe0532923efd78b1a52f480f00154740fddce Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 18:10:33 -0400 Subject: [PATCH 24/30] add tri-color 4.2" --- adafruit_epd/il0398.py | 149 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 adafruit_epd/il0398.py diff --git a/adafruit_epd/il0398.py b/adafruit_epd/il0398.py new file mode 100644 index 0000000..7fafa05 --- /dev/null +++ b/adafruit_epd/il0398.py @@ -0,0 +1,149 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Dean Miller for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`adafruit_epd.il0398` - Adafruit IL0398 - ePaper display driver +==================================================================================== +CircuitPython driver for Adafruit IL0398 display breakouts +* Author(s): Dean Miller, ladyada +""" + +import time +from micropython import const +import adafruit_framebuf +from adafruit_epd.epd import Adafruit_EPD + +_IL0398_PANEL_SETTING = const(0x00) +_IL0398_POWER_SETTING = const(0x01) +_IL0398_POWER_OFF = const(0x02) +_IL0398_POWER_OFF_SEQUENCE = const(0x03) +_IL0398_POWER_ON = const(0x04) +_IL0398_POWER_ON_MEASURE = const(0x05) +_IL0398_BOOSTER_SOFT_START = const(0x06) +_IL0398_DEEP_SLEEP = const(0x07) +_IL0398_DTM1 = const(0x10) +_IL0398_DATA_STOP = const(0x11) +_IL0398_DISPLAY_REFRESH = const(0x12) +_IL0398_DTM2 = const(0x13) +_IL0398_PDTM1 = const(0x14) +_IL0398_PDTM2 = const(0x15) +_IL0398_PDRF = const(0x16) +_IL0398_LUT1 = const(0x20) +_IL0398_LUTWW = const(0x21) +_IL0398_LUTBW = const(0x22) +_IL0398_LUTWB = const(0x23) +_IL0398_LUTBB = const(0x24) +_IL0398_PLL = const(0x30) +_IL0398_CDI = const(0x50) +_IL0398_RESOLUTION = const(0x61) +_IL0398_GETSTATUS = const(0x71) +_IL0398_VCM_DC_SETTING = const(0x82) + +class Adafruit_IL0398(Adafruit_EPD): + """driver class for Adafruit IL0373 ePaper display breakouts""" + # pylint: disable=too-many-arguments + def __init__(self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin): + super(Adafruit_IL0398, self).__init__(width, height, spi, cs_pin, dc_pin, + sramcs_pin, rst_pin, busy_pin) + + self._buffer1_size = int(width * height / 8) + self._buffer2_size = int(width * height / 8) + + if sramcs_pin: + self._buffer1 = self.sram.get_view(0) + self._buffer2 = self.sram.get_view(self._buffer1_size) + else: + self._buffer1 = bytearray((width * height) // 8) + self._buffer2 = bytearray((width * height) // 8) + # since we have *two* framebuffers - one for red and one for black + # we dont subclass but manage manually + self._framebuf1 = adafruit_framebuf.FrameBuffer(self._buffer1, width, height, + buf_format=adafruit_framebuf.MHMSB) + self._framebuf2 = adafruit_framebuf.FrameBuffer(self._buffer2, width, height, + buf_format=adafruit_framebuf.MHMSB) + self.set_black_buffer(0, True) + self.set_color_buffer(1, True) + # pylint: enable=too-many-arguments + + def begin(self, reset=True): + """Begin communication with the display and set basic settings""" + if reset: + self.hardware_reset() + self.power_down() + + def busy_wait(self): + """Wait for display to be done with current task, either by polling the + busy pin, or pausing""" + if self._busy: + while not self._busy.value: + #self.command(_IL0398_GETSTATUS) + time.sleep(0.01) + else: + time.sleep(0.5) + + def power_up(self): + """Power up the display in preparation for writing RAM and updating""" + self.hardware_reset() + self.busy_wait() + + self.command(_IL0398_BOOSTER_SOFT_START, bytearray([0x17, 0x17, 0x17])) + self.command(_IL0398_POWER_ON) + + self.busy_wait() + time.sleep(0.2) + + self.command(_IL0398_PANEL_SETTING, bytearray([0x0F])) + _b0 = (self._width >> 8) & 0xFF + _b1 = self._width & 0xFF + _b2 = (self._height >> 8) & 0xFF + _b3 = self._height & 0xFF + self.command(_IL0398_RESOLUTION, bytearray([_b0, _b1, _b2, _b3])) + time.sleep(0.05) + + def power_down(self): + """Power down the display - required when not actively displaying!""" + self.command(_IL0398_CDI, bytearray([0xF7])) + self.command(_IL0398_POWER_OFF) + self.busy_wait(); + self.command(_IL0398_DEEP_SLEEP, bytearray([0xA5])) + + def update(self): + """Update the display from internal memory""" + self.command(_IL0398_DISPLAY_REFRESH) + time.sleep(0.1) + self.busy_wait() + if not self._busy: + time.sleep(15) # wait 15 seconds + + def write_ram(self, index): + """Send the one byte command for starting the RAM write process. Returns + the byte read at the same time over SPI. index is the RAM buffer, can be + 0 or 1 for tri-color displays.""" + if index == 0: + return self.command(_IL0398_DTM1, end=False) + if index == 1: + return self.command(_IL0398_DTM2, end=False) + raise RuntimeError("RAM index must be 0 or 1") + + def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use + """Set the RAM address location, not used on this chipset but required by + the superclass""" + return # on this chip it does nothing From f8081ff8689af95e21f1b990d97a114be9993632 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 18:11:10 -0400 Subject: [PATCH 25/30] add more displays --- examples/epd_simpletest.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/examples/epd_simpletest.py b/examples/epd_simpletest.py index d52ba49..c1ba923 100644 --- a/examples/epd_simpletest.py +++ b/examples/epd_simpletest.py @@ -4,27 +4,36 @@ from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.il0373 import Adafruit_IL0373 from adafruit_epd.il91874 import Adafruit_IL91874 +from adafruit_epd.il0398 import Adafruit_IL0398 # create the spi device and pins we will need spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) ecs = digitalio.DigitalInOut(board.D10) dc = digitalio.DigitalInOut(board.D9) -srcs = digitalio.DigitalInOut(board.D7) # can be None to use internal memory +srcs = None #digitalio.DigitalInOut(board.D7) # can be None to use internal memory rst = digitalio.DigitalInOut(board.D11) # can be None to not use this pin busy = digitalio.DigitalInOut(board.D12) # can be None to not use this pin # give them all to our driver print("Creating display") -display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display -#display = Adafruit_IL0373(104, 212, spi, # 2.13" Tri-color display +#display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display +display = Adafruit_IL0373(104, 212, spi, # 2.13" Tri-color display +#display = Adafruit_IL0373(152, 152, spi, # 1.54" Tri-color display +#display = Adafruit_IL0373(128, 296, spi, # 2.9" Tri-color display +#display = Adafruit_IL0398(400, 300, spi, # 4.2" Tri-color display cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, rst_pin=rst, busy_pin=busy) -display.rotation = 2 +# IF YOU HAVE A FLEXIBLE DISPLAY (2.13" or 2.9") uncomment these lines! +#display.set_black_buffer(1, False) +#display.set_color_buffer(1, False) + +display.rotation = 1 # clear the buffer print("Clear buffer") display.fill(Adafruit_EPD.WHITE) +display.pixel(10, 100, Adafruit_EPD.BLACK) print("Draw Rectangles") display.fill_rect(5, 5, 10, 10, Adafruit_EPD.RED) @@ -36,5 +45,4 @@ print("Draw text") display.text('hello world', 25, 10, Adafruit_EPD.BLACK) - display.display() From 59827d66732d5c220f8cc2326c2a544a625d7dbd Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 18:11:50 -0400 Subject: [PATCH 26/30] woops forgot to unset --- examples/epd_simpletest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/epd_simpletest.py b/examples/epd_simpletest.py index c1ba923..d02dfd9 100644 --- a/examples/epd_simpletest.py +++ b/examples/epd_simpletest.py @@ -10,7 +10,7 @@ spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) ecs = digitalio.DigitalInOut(board.D10) dc = digitalio.DigitalInOut(board.D9) -srcs = None #digitalio.DigitalInOut(board.D7) # can be None to use internal memory +srcs = digitalio.DigitalInOut(board.D7) # can be None to use internal memory rst = digitalio.DigitalInOut(board.D11) # can be None to not use this pin busy = digitalio.DigitalInOut(board.D12) # can be None to not use this pin From b04d3e7ab5ea233befdcc39ee4e3a6cba16d6464 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 18:16:31 -0400 Subject: [PATCH 27/30] lint --- adafruit_epd/epd.py | 4 ++-- adafruit_epd/il0373.py | 2 +- adafruit_epd/il0398.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/adafruit_epd/epd.py b/adafruit_epd/epd.py index 936fda6..a768f6b 100644 --- a/adafruit_epd/epd.py +++ b/adafruit_epd/epd.py @@ -31,7 +31,7 @@ from digitalio import Direction from adafruit_epd import mcp_sram -class Adafruit_EPD: # pylint: disable=too-many-instance-attributes +class Adafruit_EPD: # pylint: disable=too-many-instance-attributes, too-many-public-methods """Base class for EPD displays """ BLACK = const(0) @@ -281,7 +281,7 @@ def text(self, string, x, y, color, *, font_name="font5x8.bin"): self._blackframebuf.text(string, x, y, font_name=font_name, color=(color == Adafruit_EPD.BLACK) != self._black_inverted) self._colorframebuf.text(string, x, y, font_name=font_name, - color=(color == Adafruit_EPD.RED) != self._color_inverted) + color=(color == Adafruit_EPD.RED) != self._color_inverted) @property def width(self): diff --git a/adafruit_epd/il0373.py b/adafruit_epd/il0373.py index 79472d6..bc10951 100644 --- a/adafruit_epd/il0373.py +++ b/adafruit_epd/il0373.py @@ -31,8 +31,8 @@ import adafruit_framebuf from adafruit_epd.epd import Adafruit_EPD -_IL0373_POWER_SETTING = const(0x01) _IL0373_PANEL_SETTING = const(0x00) +_IL0373_POWER_SETTING = const(0x01) _IL0373_POWER_OFF = const(0x02) _IL0373_POWER_OFF_SEQUENCE = const(0x03) _IL0373_POWER_ON = const(0x04) diff --git a/adafruit_epd/il0398.py b/adafruit_epd/il0398.py index 7fafa05..3d110a6 100644 --- a/adafruit_epd/il0398.py +++ b/adafruit_epd/il0398.py @@ -122,7 +122,7 @@ def power_down(self): """Power down the display - required when not actively displaying!""" self.command(_IL0398_CDI, bytearray([0xF7])) self.command(_IL0398_POWER_OFF) - self.busy_wait(); + self.busy_wait() self.command(_IL0398_DEEP_SLEEP, bytearray([0xA5])) def update(self): From f10cbbd61edd7d956d11215e7e9a73dc663168f0 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 18:18:27 -0400 Subject: [PATCH 28/30] linted example --- examples/epd_simpletest.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/epd_simpletest.py b/examples/epd_simpletest.py index d02dfd9..6498a27 100644 --- a/examples/epd_simpletest.py +++ b/examples/epd_simpletest.py @@ -3,8 +3,8 @@ import board from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.il0373 import Adafruit_IL0373 -from adafruit_epd.il91874 import Adafruit_IL91874 -from adafruit_epd.il0398 import Adafruit_IL0398 +from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import +from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import # create the spi device and pins we will need spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) @@ -16,11 +16,11 @@ # give them all to our driver print("Creating display") -#display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display -display = Adafruit_IL0373(104, 212, spi, # 2.13" Tri-color display +#display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display #display = Adafruit_IL0373(152, 152, spi, # 1.54" Tri-color display -#display = Adafruit_IL0373(128, 296, spi, # 2.9" Tri-color display -#display = Adafruit_IL0398(400, 300, spi, # 4.2" Tri-color display +#display = Adafruit_IL0373(128, 296, spi, # 2.9" Tri-color display +#display = Adafruit_IL0398(400, 300, spi, # 4.2" Tri-color display +display = Adafruit_IL0373(104, 212, spi, # 2.13" Tri-color display cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, rst_pin=rst, busy_pin=busy) From 0e5395497affa83825bd409f09cb4202c315d1c0 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 18:59:25 -0400 Subject: [PATCH 29/30] upcoming shield --- examples/epd_shieldtest.py | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 examples/epd_shieldtest.py diff --git a/examples/epd_shieldtest.py b/examples/epd_shieldtest.py new file mode 100644 index 0000000..c9843cb --- /dev/null +++ b/examples/epd_shieldtest.py @@ -0,0 +1,60 @@ +# EInk Shield test +import digitalio +import busio +import board +import time +from analogio import AnalogIn +from adafruit_epd.epd import Adafruit_EPD +from adafruit_epd.il91874 import Adafruit_IL91874 + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.D10) +dc = digitalio.DigitalInOut(board.D9) +srcs = digitalio.DigitalInOut(board.D8) # can be None to use internal memory + +# give them all to our driver +print("Creating display") +display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display + cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, + rst_pin=None, busy_pin=None) + +display.rotation = 1 + +def read_buttons(): + with AnalogIn(board.A3) as ain: + reading = ain.value / 65535 + if reading > 0.75: + return None + if reading > 0.4: + return 4 + if reading > 0.25: + return 3 + if reading > 0.13: + return 2 + return 1 + +while True: + button = read_buttons() + if not button: + continue + print("Button #%d pressed" % button) + if button == 1: + print("Clear buffer") + display.fill(Adafruit_EPD.WHITE) + display.display() + if button == 2: + print("Draw Rectangles") + display.fill_rect(5, 5, 10, 10, Adafruit_EPD.RED) + display.rect(0, 0, 20, 30, Adafruit_EPD.BLACK) + display.display() + if button == 3: + print("Draw lines") + display.line(0, 0, display.width-1, display.height-1, Adafruit_EPD.BLACK) + display.line(0, display.height-1, display.width-1, 0, Adafruit_EPD.RED) + display.display() + if button == 4: + print("Draw text") + display.text('hello world', 25, 10, Adafruit_EPD.BLACK) + display.display() + time.sleep(0.01) From 09f16e05d5cde6178c8fab5672506f40b88c1c38 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 19:21:07 -0400 Subject: [PATCH 30/30] lint example --- examples/epd_shieldtest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/epd_shieldtest.py b/examples/epd_shieldtest.py index c9843cb..7d61998 100644 --- a/examples/epd_shieldtest.py +++ b/examples/epd_shieldtest.py @@ -1,8 +1,8 @@ # EInk Shield test +import time import digitalio import busio import board -import time from analogio import AnalogIn from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.il91874 import Adafruit_IL91874 @@ -16,8 +16,8 @@ # give them all to our driver print("Creating display") display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display - cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, - rst_pin=None, busy_pin=None) + cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, + rst_pin=None, busy_pin=None) display.rotation = 1