summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott@adafruit.com>2020-08-12 16:53:09 -0700
committerGitHub <noreply@github.com>2020-08-12 16:53:09 -0700
commit7ffa2a103cd0f00a4626b5cbae8b8d1c048342b3 (patch)
treebcbd0f9699ee59d02d4df9685e9592dcfbdb0052
parent3197c579e0acddf7aa962fe805cefd75b584d267 (diff)
parent195c0ea986fd44f3b56cc57f23e8259df1e18202 (diff)
Merge pull request #3269 from jepler/sharpdisplay-v2
Sharp Memory Display displayio support (v2)
-rw-r--r--locale/circuitpython.pot7
-rw-r--r--ports/atmel-samd/mpconfigport.mk3
-rwxr-xr-xports/nrf/Makefile17
-rw-r--r--ports/nrf/common-hal/busio/SPI.c16
-rw-r--r--ports/nrf/common-hal/microcontroller/Pin.c1
-rw-r--r--ports/nrf/supervisor/qspi_flash.c2
-rw-r--r--py/circuitpy_defns.mk5
-rw-r--r--py/circuitpy_mpconfig.h22
-rw-r--r--py/circuitpy_mpconfig.mk8
-rwxr-xr-xpy/qstr.c1
-rw-r--r--shared-bindings/rgbmatrix/RGBMatrix.c3
-rw-r--r--shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c92
-rw-r--r--shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h34
-rw-r--r--shared-bindings/sharpdisplay/__init__.c47
-rw-r--r--shared-bindings/sharpdisplay/__init__.h0
-rw-r--r--shared-module/displayio/__init__.c35
-rw-r--r--shared-module/displayio/__init__.h10
-rw-r--r--shared-module/framebufferio/FramebufferDisplay.c96
-rw-r--r--shared-module/framebufferio/FramebufferDisplay.h47
-rw-r--r--shared-module/sharpdisplay/SharpMemoryFramebuffer.c277
-rw-r--r--shared-module/sharpdisplay/SharpMemoryFramebuffer.h60
-rw-r--r--shared-module/sharpdisplay/__init__.c0
-rw-r--r--shared-module/sharpdisplay/__init__.h0
-rw-r--r--supervisor/shared/display.c22
24 files changed, 737 insertions, 68 deletions
diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot
index 510facece..32b5df5ee 100644
--- a/locale/circuitpython.pot
+++ b/locale/circuitpython.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-08-10 12:54-0500\n"
+"POT-Creation-Date: 2020-08-11 15:37-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -823,6 +823,11 @@ msgstr ""
msgid "File exists"
msgstr ""
+#: shared-module/framebufferio/FramebufferDisplay.c
+#, c-format
+msgid "Framebuffer requires %d bytes"
+msgstr ""
+
#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
msgid "Frequency captured is above capability. Capture Paused."
msgstr ""
diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk
index e4cf9ca83..5788a160b 100644
--- a/ports/atmel-samd/mpconfigport.mk
+++ b/ports/atmel-samd/mpconfigport.mk
@@ -39,6 +39,9 @@ endif
CIRCUITPY_SDCARDIO ?= 0
+# Not enough RAM for framebuffers
+CIRCUITPY_FRAMEBUFFERIO ?= 0
+
# SAMD21 needs separate endpoint pairs for MSC BULK IN and BULK OUT, otherwise it's erratic.
USB_MSC_EP_NUM_OUT = 1
diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile
index 13a148df3..3fef68e88 100755
--- a/ports/nrf/Makefile
+++ b/ports/nrf/Makefile
@@ -73,11 +73,11 @@ INC += -I$(BUILD)
INC += -I$(BUILD)/genhdr
INC += -I./../../lib/cmsis/inc
INC += -I./boards/$(BOARD)
-INC += -I./nrfx
-INC += -I./nrfx/hal
-INC += -I./nrfx/mdk
-INC += -I./nrfx/drivers/include
-INC += -I./nrfx/drivers/src
+INC += -isystem ./nrfx
+INC += -isystem ./nrfx/hal
+INC += -isystem ./nrfx/mdk
+INC += -isystem ./nrfx/drivers/include
+INC += -isystem ./nrfx/drivers/src
INC += -I./bluetooth
INC += -I./peripherals
INC += -I../../lib/mp-readline
@@ -100,8 +100,6 @@ CFLAGS += $(OPTIMIZATION_FLAGS)
CFLAGS += $(INC) -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT)
# Undo some warnings.
-# nrfx uses undefined preprocessor variables quite casually, so we can't do warning checks for these.
-CFLAGS += -Wno-undef
# nrfx does casts that increase alignment requirements.
CFLAGS += -Wno-cast-align
@@ -240,6 +238,11 @@ endif
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o))
+# nrfx uses undefined preprocessor variables quite casually, so we can't do
+# warning checks for these. Happily, we've confined the offenders to the NRFX
+# source files themselves.
+$(addprefix $(BUILD)/, $(SRC_NRFX:.c=.o)): CFLAGS += -Wno-undef
+
$(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os
$(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os
diff --git a/ports/nrf/common-hal/busio/SPI.c b/ports/nrf/common-hal/busio/SPI.c
index f27f0e267..fdfe61811 100644
--- a/ports/nrf/common-hal/busio/SPI.c
+++ b/ports/nrf/common-hal/busio/SPI.c
@@ -34,6 +34,22 @@
#include "nrfx_spim.h"
#include "nrf_gpio.h"
+#ifndef NRFX_SPIM3_ENABLED
+#define NRFX_SPIM3_ENABLED (0)
+#endif
+
+#ifndef NRFX_SPIM2_ENABLED
+#define NRFX_SPIM2_ENABLED (0)
+#endif
+
+#ifndef NRFX_SPIM1_ENABLED
+#define NRFX_SPIM1_ENABLED (0)
+#endif
+
+#ifndef NRFX_SPIM0_ENABLED
+#define NRFX_SPIM0_ENABLED (0)
+#endif
+
// These are in order from highest available frequency to lowest (32MHz first, then 8MHz).
STATIC spim_peripheral_t spim_peripherals[] = {
#if NRFX_CHECK(NRFX_SPIM3_ENABLED)
diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c
index 3132c7631..d294c1dd5 100644
--- a/ports/nrf/common-hal/microcontroller/Pin.c
+++ b/ports/nrf/common-hal/microcontroller/Pin.c
@@ -93,6 +93,7 @@ void reset_pin_number(uint8_t pin_number) {
// Clear claimed bit.
claimed_pins[nrf_pin_port(pin_number)] &= ~(1 << nrf_relative_pin_number(pin_number));
+ never_reset_pins[nrf_pin_port(pin_number)] &= ~(1 << nrf_relative_pin_number(pin_number));
#ifdef MICROPY_HW_NEOPIXEL
if (pin_number == MICROPY_HW_NEOPIXEL->number) {
diff --git a/ports/nrf/supervisor/qspi_flash.c b/ports/nrf/supervisor/qspi_flash.c
index 5ab56c6bc..7ca27d56c 100644
--- a/ports/nrf/supervisor/qspi_flash.c
+++ b/ports/nrf/supervisor/qspi_flash.c
@@ -201,7 +201,7 @@ void spi_flash_init(void) {
.irq_priority = 7,
};
-#if EXTERNAL_FLASH_QSPI_DUAL
+#if defined(EXTERNAL_FLASH_QSPI_DUAL)
qspi_cfg.pins.io1_pin = MICROPY_QSPI_DATA1;
qspi_cfg.prot_if.readoc = NRF_QSPI_READOC_READ2O;
qspi_cfg.prot_if.writeoc = NRF_QSPI_WRITEOC_PP2O;
diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk
index a39e0c9dd..515b386f9 100644
--- a/py/circuitpy_defns.mk
+++ b/py/circuitpy_defns.mk
@@ -222,6 +222,9 @@ endif
ifeq ($(CIRCUITPY_SDIOIO),1)
SRC_PATTERNS += sdioio/%
endif
+ifeq ($(CIRCUITPY_SHARPDISPLAY),1)
+SRC_PATTERNS += sharpdisplay/%
+endif
ifeq ($(CIRCUITPY_STAGE),1)
SRC_PATTERNS += _stage/%
endif
@@ -409,6 +412,8 @@ SRC_SHARED_MODULE_ALL = \
random/__init__.c \
rgbmatrix/RGBMatrix.c \
rgbmatrix/__init__.c \
+ sharpdisplay/SharpMemoryFramebuffer.c \
+ sharpdisplay/__init__.c \
socket/__init__.c \
storage/__init__.c \
struct/__init__.c \
diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h
index 255ab99b9..f0e8adffa 100644
--- a/py/circuitpy_mpconfig.h
+++ b/py/circuitpy_mpconfig.h
@@ -499,13 +499,6 @@ extern const struct _mp_obj_module_t pixelbuf_module;
#define PIXELBUF_MODULE
#endif
-#if CIRCUITPY_RGBMATRIX
-extern const struct _mp_obj_module_t rgbmatrix_module;
-#define RGBMATRIX_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rgbmatrix),(mp_obj_t)&rgbmatrix_module },
-#else
-#define RGBMATRIX_MODULE
-#endif
-
#if CIRCUITPY_PULSEIO
extern const struct _mp_obj_module_t pulseio_module;
#define PULSEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module },
@@ -520,6 +513,13 @@ extern const struct _mp_obj_module_t ps2io_module;
#define PS2IO_MODULE
#endif
+#if CIRCUITPY_RGBMATRIX
+extern const struct _mp_obj_module_t rgbmatrix_module;
+#define RGBMATRIX_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rgbmatrix),(mp_obj_t)&rgbmatrix_module },
+#else
+#define RGBMATRIX_MODULE
+#endif
+
#if CIRCUITPY_RANDOM
extern const struct _mp_obj_module_t random_module;
#define RANDOM_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module },
@@ -562,6 +562,13 @@ extern const struct _mp_obj_module_t sdioio_module;
#define SDIOIO_MODULE
#endif
+#if CIRCUITPY_SHARPDISPLAY
+extern const struct _mp_obj_module_t sharpdisplay_module;
+#define SHARPDISPLAY_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_sharpdisplay),(mp_obj_t)&sharpdisplay_module },
+#else
+#define SHARPDISPLAY_MODULE
+#endif
+
#if CIRCUITPY_STAGE
extern const struct _mp_obj_module_t stage_module;
#define STAGE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__stage), (mp_obj_t)&stage_module },
@@ -737,6 +744,7 @@ extern const struct _mp_obj_module_t watchdog_module;
SAMD_MODULE \
SDCARDIO_MODULE \
SDIOIO_MODULE \
+ SHARPDISPLAY_MODULE \
STAGE_MODULE \
STORAGE_MODULE \
STRUCT_MODULE \
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index 2cf8426e5..56060fa59 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -95,7 +95,11 @@ CFLAGS += -DCIRCUITPY_COUNTIO=$(CIRCUITPY_COUNTIO)
CIRCUITPY_DISPLAYIO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO)
+ifeq ($(CIRCUITPY_DISPLAYIO),1)
+CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD)
+else
CIRCUITPY_FRAMEBUFFERIO ?= 0
+endif
CFLAGS += -DCIRCUITPY_FRAMEBUFFERIO=$(CIRCUITPY_FRAMEBUFFERIO)
CIRCUITPY_VECTORIO ?= $(CIRCUITPY_DISPLAYIO)
@@ -144,7 +148,6 @@ CFLAGS += -DCIRCUITPY_OS=$(CIRCUITPY_OS)
CIRCUITPY_PIXELBUF ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_PIXELBUF=$(CIRCUITPY_PIXELBUF)
-# Only for SAMD boards for the moment
CIRCUITPY_RGBMATRIX ?= 0
CFLAGS += -DCIRCUITPY_RGBMATRIX=$(CIRCUITPY_RGBMATRIX)
@@ -176,6 +179,9 @@ CFLAGS += -DCIRCUITPY_SDCARDIO=$(CIRCUITPY_SDCARDIO)
CIRCUITPY_SDIOIO ?= 0
CFLAGS += -DCIRCUITPY_SDIOIO=$(CIRCUITPY_SDIOIO)
+CIRCUITPY_SHARPDISPLAY ?= $(CIRCUITPY_FRAMEBUFFERIO)
+CFLAGS += -DCIRCUITPY_SHARPDISPLAY=$(CIRCUITPY_SHARPDISPLAY)
+
# Currently always off.
CIRCUITPY_STAGE ?= 0
CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE)
diff --git a/py/qstr.c b/py/qstr.c
index 17d8517c9..c9ba298fb 100755
--- a/py/qstr.c
+++ b/py/qstr.c
@@ -137,6 +137,7 @@ STATIC const byte *find_qstr(qstr q) {
while (q < pool->total_prev_len) {
pool = pool->prev;
}
+ assert(q - pool->total_prev_len < pool->len);
return pool->qstrs[q - pool->total_prev_len];
}
diff --git a/shared-bindings/rgbmatrix/RGBMatrix.c b/shared-bindings/rgbmatrix/RGBMatrix.c
index d6b79f5eb..9cfc0d409 100644
--- a/shared-bindings/rgbmatrix/RGBMatrix.c
+++ b/shared-bindings/rgbmatrix/RGBMatrix.c
@@ -352,7 +352,8 @@ STATIC void rgbmatrix_rgbmatrix_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *
// These version exists so that the prototype matches the protocol,
// avoiding a type cast that can hide errors
-STATIC void rgbmatrix_rgbmatrix_swapbuffers(mp_obj_t self_in) {
+STATIC void rgbmatrix_rgbmatrix_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
+ (void)dirty_row_bitmap;
common_hal_rgbmatrix_rgbmatrix_refresh(self_in);
}
diff --git a/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c
new file mode 100644
index 000000000..e8f4e970a
--- /dev/null
+++ b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler 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.
+ */
+
+#include "py/objarray.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
+#include "shared-module/displayio/__init__.h"
+#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
+
+STATIC mp_obj_t sharpdisplay_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_spi_bus, ARG_chip_select, ARG_width, ARG_height, ARG_baudrate, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_spi_bus, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 2000000} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS );
+
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj);
+ busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi_bus].u_obj);
+
+ sharpdisplay_framebuffer_obj_t* self = &allocate_display_bus_or_raise()->sharpdisplay;
+ self->base.type = &sharpdisplay_framebuffer_type;
+
+ common_hal_sharpdisplay_framebuffer_construct(self, spi, chip_select, args[ARG_baudrate].u_int, args[ARG_width].u_int, args[ARG_height].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+
+STATIC mp_int_t sharpdisplay_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
+ sharpdisplay_framebuffer_obj_t *self = (sharpdisplay_framebuffer_obj_t*)self_in;
+ // a readonly framebuffer would be unusual but not impossible
+ if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
+ return 1;
+ }
+ *bufinfo = self->bufinfo;
+ return 0;
+}
+
+STATIC mp_obj_t sharpdisplay_framebuffer_deinit(mp_obj_t self_in) {
+ sharpdisplay_framebuffer_obj_t *self = (sharpdisplay_framebuffer_obj_t*)self_in;
+ common_hal_sharpdisplay_framebuffer_deinit(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(sharpdisplay_framebuffer_deinit_obj, sharpdisplay_framebuffer_deinit);
+
+STATIC const mp_rom_map_elem_t sharpdisplay_framebuffer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sharpdisplay_framebuffer_deinit_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(sharpdisplay_framebuffer_locals_dict, sharpdisplay_framebuffer_locals_dict_table);
+
+const mp_obj_type_t sharpdisplay_framebuffer_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SharpMemoryFramebuffer,
+ .buffer_p = { .get_buffer = sharpdisplay_framebuffer_get_buffer, },
+ .make_new = sharpdisplay_framebuffer_make_new,
+ .protocol = &sharpdisplay_framebuffer_proto,
+ .locals_dict = (mp_obj_dict_t*)&sharpdisplay_framebuffer_locals_dict,
+};
diff --git a/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h
new file mode 100644
index 000000000..30f1b867b
--- /dev/null
+++ b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler 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.
+ */
+
+#pragma once
+
+// #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
+// #include "shared-module/framebufferio/FramebufferDisplay.h"
+
+#include "py/objtype.h"
+
+extern const mp_obj_type_t sharpdisplay_framebuffer_type;
diff --git a/shared-bindings/sharpdisplay/__init__.c b/shared-bindings/sharpdisplay/__init__.c
new file mode 100644
index 000000000..d1f728c61
--- /dev/null
+++ b/shared-bindings/sharpdisplay/__init__.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler 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.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
+
+//| """Support for Sharp Memory Display framebuffers"""
+//|
+
+STATIC const mp_rom_map_elem_t sharpdisplay_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sharpdisplay) },
+ { MP_ROM_QSTR(MP_QSTR_SharpMemoryFramebuffer), MP_ROM_PTR(&sharpdisplay_framebuffer_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(sharpdisplay_module_globals, sharpdisplay_module_globals_table);
+
+const mp_obj_module_t sharpdisplay_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&sharpdisplay_module_globals,
+};
diff --git a/shared-bindings/sharpdisplay/__init__.h b/shared-bindings/sharpdisplay/__init__.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/shared-bindings/sharpdisplay/__init__.h
diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c
index efc28470f..5afcba35e 100644
--- a/shared-module/displayio/__init__.c
+++ b/shared-module/displayio/__init__.c
@@ -19,14 +19,19 @@
#include "supervisor/spi_flash_api.h"
#include "py/mpconfig.h"
+#if CIRCUITPY_SHARPDISPLAY
+#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
+#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
+#endif
+
primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT];
-#if CIRCUITPY_RGBMATRIX
-STATIC bool any_display_uses_this_rgbmatrix(rgbmatrix_rgbmatrix_obj_t* pm) {
+#if CIRCUITPY_RGBMATRIX || CIRCUITPY_SHARPDISPLAY
+STATIC bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) {
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
- if (displays[i].framebuffer_display.base.type == &framebufferio_framebufferdisplay_type) {
+ if (displays[i].display_base.type == &framebufferio_framebufferdisplay_type) {
framebufferio_framebufferdisplay_obj_t* display = &displays[i].framebuffer_display;
- if (display->framebuffer == pm) {
+ if (display->framebuffer == obj) {
return true;
}
}
@@ -102,10 +107,14 @@ void common_hal_displayio_release_displays(void) {
common_hal_displayio_i2cdisplay_deinit(&displays[i].i2cdisplay_bus);
} else if (bus_type == &displayio_parallelbus_type) {
common_hal_displayio_parallelbus_deinit(&displays[i].parallel_bus);
-#if CIRCUITPY_FRAMEBUFFERIO
+#if CIRCUITPY_RGBMATRIX
} else if (bus_type == &rgbmatrix_RGBMatrix_type) {
common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix);
#endif
+#if CIRCUITPY_SHARPDISPLAY
+ } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
+ common_hal_sharpdisplay_framebuffer_deinit(&displays[i].sharpdisplay);
+#endif
}
displays[i].fourwire_bus.base.type = &mp_type_NoneType;
}
@@ -170,10 +179,19 @@ void reset_displays(void) {
#if CIRCUITPY_RGBMATRIX
} else if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) {
rgbmatrix_rgbmatrix_obj_t * pm = &displays[i].rgbmatrix;
- if(!any_display_uses_this_rgbmatrix(pm)) {
+ if(!any_display_uses_this_framebuffer(&pm->base)) {
common_hal_rgbmatrix_rgbmatrix_deinit(pm);
}
#endif
+#if CIRCUITPY_SHARPDISPLAY
+ } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
+ sharpdisplay_framebuffer_obj_t * sharp = &displays[i].sharpdisplay;
+ if(any_display_uses_this_framebuffer(&sharp->base)) {
+ common_hal_sharpdisplay_framebuffer_reset(sharp);
+ } else {
+ common_hal_sharpdisplay_framebuffer_deinit(sharp);
+ }
+#endif
} else {
// Not an active display bus.
continue;
@@ -203,6 +221,11 @@ void displayio_gc_collect(void) {
rgbmatrix_rgbmatrix_collect_ptrs(&displays[i].rgbmatrix);
}
#endif
+#if CIRCUITPY_SHARPDISPLAY
+ if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
+ common_hal_sharpdisplay_framebuffer_collect_ptrs(&displays[i].sharpdisplay);
+ }
+#endif
if (displays[i].display.base.type == NULL) {
continue;
diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h
index 9eb10c28b..44ad5a9a9 100644
--- a/shared-module/displayio/__init__.h
+++ b/shared-module/displayio/__init__.h
@@ -36,18 +36,28 @@
#include "shared-bindings/displayio/Group.h"
#include "shared-bindings/displayio/I2CDisplay.h"
#include "shared-bindings/displayio/ParallelBus.h"
+#if CIRCUITPY_RGBMATRIX
#include "shared-bindings/rgbmatrix/RGBMatrix.h"
+#endif
+#if CIRCUITPY_SHARPDISPLAY
+#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
+#endif
typedef struct {
union {
+ mp_obj_base_t bus_base;
displayio_fourwire_obj_t fourwire_bus;
displayio_i2cdisplay_obj_t i2cdisplay_bus;
displayio_parallelbus_obj_t parallel_bus;
#if CIRCUITPY_RGBMATRIX
rgbmatrix_rgbmatrix_obj_t rgbmatrix;
#endif
+#if CIRCUITPY_SHARPDISPLAY
+ sharpdisplay_framebuffer_obj_t sharpdisplay;
+#endif
};
union {
+ mp_obj_base_t display_base;
displayio_display_obj_t display;
displayio_epaperdisplay_obj_t epaper_display;
#if CIRCUITPY_FRAMEBUFFERIO
diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c
index 2a90fa0d4..6b5346877 100644
--- a/shared-module/framebufferio/FramebufferDisplay.c
+++ b/shared-module/framebufferio/FramebufferDisplay.c
@@ -40,6 +40,11 @@
#include <stdint.h>
#include <string.h>
+#define fb_getter_default(method, default_value) \
+ (self->framebuffer_protocol->method \
+ ? self->framebuffer_protocol->method(self->framebuffer) \
+ : (default_value))
+
void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebufferdisplay_obj_t* self,
mp_obj_t framebuffer,
uint16_t rotation,
@@ -51,7 +56,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu
uint16_t ram_width = 0x100;
uint16_t ram_height = 0x100;
-
+ uint16_t depth = fb_getter_default(get_color_depth, 16);
displayio_display_core_construct(
&self->core,
NULL,
@@ -62,16 +67,29 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu
0,
0,
rotation,
- self->framebuffer_protocol->get_color_depth(self->framebuffer),
- false,
- false,
- self->framebuffer_protocol->get_bytes_per_cell(self->framebuffer),
- false,
- false);
+ depth,
+ fb_getter_default(get_grayscale, (depth < 8)),
+ fb_getter_default(get_pixels_in_byte_share_row, false),
+ fb_getter_default(get_bytes_per_cell, 2),
+ fb_getter_default(get_reverse_pixels_in_byte, false),
+ fb_getter_default(get_reverse_pixels_in_word, false)
+ );
+
+ self->first_pixel_offset = fb_getter_default(get_first_pixel_offset, 0);
+ self->row_stride = fb_getter_default(get_row_stride, 0);
+ if (self->row_stride == 0) {
+ self->row_stride = self->core.width * self->core.colorspace.depth/8;
+ }
+
+ self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo);
+ size_t framebuffer_size = self->first_pixel_offset + self->row_stride * self->core.height;
+ if (self->bufinfo.len < framebuffer_size) {
+ mp_raise_IndexError_varg(translate("Framebuffer requires %d bytes"), framebuffer_size);
+ }
self->first_manual_refresh = !auto_refresh;
- self->native_frames_per_second = self->framebuffer_protocol->get_native_frames_per_second(self->framebuffer);
+ self->native_frames_per_second = fb_getter_default(get_native_frames_per_second, 60);
self->native_ms_per_frame = 1000 / self->native_frames_per_second;
supervisor_start_terminal(self->core.width, self->core.height);
@@ -109,7 +127,7 @@ bool common_hal_framebufferio_framebufferdisplay_set_auto_brightness(framebuffer
}
mp_float_t common_hal_framebufferio_framebufferdisplay_get_brightness(framebufferio_framebufferdisplay_obj_t* self) {
- if (self->framebuffer_protocol->set_brightness) {
+ if (self->framebuffer_protocol->get_brightness) {
return self->framebuffer_protocol->get_brightness(self->framebuffer);
}
return -1;
@@ -138,7 +156,8 @@ STATIC const displayio_area_t* _get_refresh_areas(framebufferio_framebufferdispl
return NULL;
}
-STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const displayio_area_t* area) {
+#define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r/8] |= (1 << (r & 7)))
+STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const displayio_area_t* area, uint8_t *dirty_row_bitmask) {
uint16_t buffer_size = 128; // In uint32_ts
displayio_area_t clipped;
@@ -147,6 +166,14 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di
return true;
}
uint16_t subrectangles = 1;
+
+ // If pixels are packed by row then rows are on byte boundaries
+ if (self->core.colorspace.depth < 8 && self->core.colorspace.pixels_in_byte_share_row) {
+ int div = 8 / self->core.colorspace.depth;
+ clipped.x1 = (clipped.x1 / div) * div;
+ clipped.x2 = ((clipped.x2 + div - 1) / div) * div;
+ }
+
uint16_t rows_per_buffer = displayio_area_height(&clipped);
uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth;
uint16_t pixels_per_buffer = displayio_area_size(&clipped);
@@ -187,6 +214,7 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di
.x2 = clipped.x2,
.y2 = clipped.y1 + rows_per_buffer * (j + 1)
};
+
if (remaining_rows < rows_per_buffer) {
subrectangle.y2 = subrectangle.y1 + remaining_rows;
}
@@ -197,12 +225,18 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di
displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer);
- // COULDDO: this arithmetic only supports multiple-of-8 bpp
- uint8_t *dest = self->bufinfo.buf + (subrectangle.y1 * self->core.width + subrectangle.x1) * (self->core.colorspace.depth / 8);
+ uint8_t *buf = (uint8_t *)self->bufinfo.buf, *endbuf = buf + self->bufinfo.len;
+ (void)endbuf; // Hint to compiler that endbuf is "used" even if NDEBUG
+ buf += self->first_pixel_offset;
+
+ size_t rowstride = self->row_stride;
+ uint8_t *dest = buf + subrectangle.y1 * rowstride + subrectangle.x1 * self->core.colorspace.depth / 8;
uint8_t *src = (uint8_t*)buffer;
- size_t rowsize = (subrectangle.x2 - subrectangle.x1) * (self->core.colorspace.depth / 8);
- size_t rowstride = self->core.width * (self->core.colorspace.depth/8);
+ size_t rowsize = (subrectangle.x2 - subrectangle.x1) * self->core.colorspace.depth / 8;
+
for (uint16_t i = subrectangle.y1; i < subrectangle.y2; i++) {
+ assert(dest >= buf && dest < endbuf && dest+rowsize <= endbuf);
+ MARK_ROW_DIRTY(i);
memcpy(dest, src, rowsize);
dest += rowstride;
src += rowsize;
@@ -216,15 +250,23 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di
}
STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) {
- displayio_display_core_start_refresh(&self->core);
self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo);
+ if(!self->bufinfo.buf) {
+ return;
+ }
+ displayio_display_core_start_refresh(&self->core);
const displayio_area_t* current_area = _get_refresh_areas(self);
- while (current_area != NULL) {
- _refresh_area(self, current_area);
- current_area = current_area->next;
+ if (current_area) {
+ uint8_t dirty_row_bitmask[(self->core.height + 7) / 8];
+ memset(dirty_row_bitmask, 0, sizeof(dirty_row_bitmask));
+ self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo);
+ while (current_area != NULL) {
+ _refresh_area(self, current_area, dirty_row_bitmask);
+ current_area = current_area->next;
+ }
+ self->framebuffer_protocol->swapbuffers(self->framebuffer, dirty_row_bitmask);
}
displayio_display_core_finish_refresh(&self->core);
- self->framebuffer_protocol->swapbuffers(self->framebuffer);
}
void common_hal_framebufferio_framebufferdisplay_set_rotation(framebufferio_framebufferdisplay_obj_t* self, int rotation){
@@ -307,11 +349,7 @@ void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) {
common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, false);
release_display_core(&self->core);
self->framebuffer_protocol->deinit(self->framebuffer);
-}
-
-void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) {
- common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true);
- common_hal_framebufferio_framebufferdisplay_show(self, NULL);
+ self->base.type = &mp_type_NoneType;
}
void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisplay_obj_t* self) {
@@ -320,6 +358,12 @@ void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisp
}
void framebufferio_framebufferdisplay_reset(framebufferio_framebufferdisplay_obj_t* self) {
- common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true);
- common_hal_framebufferio_framebufferdisplay_show(self, NULL);
+ mp_obj_type_t *fb_type = mp_obj_get_type(self->framebuffer);
+ if(fb_type != NULL && fb_type != &mp_type_NoneType) {
+ common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true);
+ common_hal_framebufferio_framebufferdisplay_show(self, NULL);
+ self->core.full_refresh = true;
+ } else {
+ release_framebufferdisplay(self);
+ }
}
diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h
index ca1ab984a..89df0d27c 100644
--- a/shared-module/framebufferio/FramebufferDisplay.h
+++ b/shared-module/framebufferio/FramebufferDisplay.h
@@ -48,44 +48,65 @@ typedef struct {
uint64_t last_refresh_call;
uint16_t native_frames_per_second;
uint16_t native_ms_per_frame;
+ uint16_t first_pixel_offset;
+ uint16_t row_stride;
bool auto_refresh;
bool first_manual_refresh;
} framebufferio_framebufferdisplay_obj_t;
void framebufferio_framebufferdisplay_background(framebufferio_framebufferdisplay_obj_t* self);
void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self);
-void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self);
void framebufferio_framebufferdisplay_reset(framebufferio_framebufferdisplay_obj_t* self);
void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisplay_obj_t* self);
mp_obj_t common_hal_framebufferio_framebufferdisplay_get_framebuffer(framebufferio_framebufferdisplay_obj_t* self);
-typedef void (*framebuffer_get_bufinfo_fun)(mp_obj_t, mp_buffer_info_t *bufinfo);
-typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t);
-typedef void (*framebuffer_deinit_fun)(mp_obj_t);
-typedef bool (*framebuffer_set_brightness_fun)(mp_obj_t, mp_float_t);
-typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t);
-typedef bool (*framebuffer_set_auto_brightness_fun)(mp_obj_t, bool);
typedef bool (*framebuffer_get_auto_brightness_fun)(mp_obj_t);
-typedef int (*framebuffer_get_width_fun)(mp_obj_t);
-typedef int (*framebuffer_get_height_fun)(mp_obj_t);
-typedef int (*framebuffer_get_color_depth_fun)(mp_obj_t);
+typedef bool (*framebuffer_get_reverse_pixels_in_byte_fun)(mp_obj_t);
+typedef bool (*framebuffer_get_reverse_pixels_in_word_fun)(mp_obj_t);
+typedef bool (*framebuffer_set_auto_brightness_fun)(mp_obj_t, bool);
+typedef bool (*framebuffer_set_brightness_fun)(mp_obj_t, mp_float_t);
typedef int (*framebuffer_get_bytes_per_cell_fun)(mp_obj_t);
+typedef int (*framebuffer_get_color_depth_fun)(mp_obj_t);
+typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t);
+typedef int (*framebuffer_get_grayscale_fun)(mp_obj_t);
+typedef int (*framebuffer_get_height_fun)(mp_obj_t);
typedef int (*framebuffer_get_native_frames_per_second_fun)(mp_obj_t);
+typedef bool (*framebuffer_get_pixels_in_byte_share_row_fun)(mp_obj_t);
+typedef int (*framebuffer_get_row_stride_fun)(mp_obj_t);
+typedef int (*framebuffer_get_width_fun)(mp_obj_t);
+typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t);
+typedef void (*framebuffer_deinit_fun)(mp_obj_t);
+typedef void (*framebuffer_get_bufinfo_fun)(mp_obj_t, mp_buffer_info_t *bufinfo);
+typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t, uint8_t *dirty_row_bitmask);
typedef struct _framebuffer_p_t {
MP_PROTOCOL_HEAD // MP_QSTR_protocol_framebuffer
+
+ // Mandatory
framebuffer_get_bufinfo_fun get_bufinfo;
framebuffer_swapbuffers_fun swapbuffers;
framebuffer_deinit_fun deinit;
framebuffer_get_width_fun get_width;
framebuffer_get_height_fun get_height;
- framebuffer_get_color_depth_fun get_color_depth;
- framebuffer_get_bytes_per_cell_fun get_bytes_per_cell;
- framebuffer_get_native_frames_per_second_fun get_native_frames_per_second;
+
+ // Optional getters
+ framebuffer_get_bytes_per_cell_fun get_bytes_per_cell; // default: 2
+ framebuffer_get_color_depth_fun get_color_depth; // default: 16
+ framebuffer_get_first_pixel_offset_fun get_first_pixel_offset; // default: 0
+ framebuffer_get_grayscale_fun get_grayscale; // default: grayscale if depth < 8
+ framebuffer_get_native_frames_per_second_fun get_native_frames_per_second; // default: 60
+ framebuffer_get_pixels_in_byte_share_row_fun get_pixels_in_byte_share_row; // default: false
+ framebuffer_get_reverse_pixels_in_byte_fun get_reverse_pixels_in_byte; // default: false
+ framebuffer_get_reverse_pixels_in_word_fun get_reverse_pixels_in_word; // default: false
+ framebuffer_get_row_stride_fun get_row_stride; // default: 0 (no extra row padding)
+
+ // Optional -- default is no brightness control
framebuffer_get_brightness_fun get_brightness;
framebuffer_set_brightness_fun set_brightness;
+
+ // Optional -- default is no automatic brightness control
framebuffer_get_auto_brightness_fun get_auto_brightness;
framebuffer_set_auto_brightness_fun set_auto_brightness;
} framebuffer_p_t;
diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c
new file mode 100644
index 000000000..71e00d7f0
--- /dev/null
+++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c
@@ -0,0 +1,277 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler 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.
+ */
+
+#include <string.h>
+
+#include "py/gc.h"
+
+#include "shared-bindings/board/__init__.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
+#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
+
+#include "supervisor/memory.h"
+
+#define SHARPMEM_BIT_WRITECMD_LSB (0x80)
+#define SHARPMEM_BIT_VCOM_LSB (0x40)
+
+static inline void *hybrid_alloc(size_t sz) {
+ if (gc_alloc_possible()) {
+ return m_malloc(sz + sizeof(void*), true);
+ } else {
+ supervisor_allocation *allocation = allocate_memory(align32_size(sz), false);
+ if (!allocation) {
+ return NULL;
+ }
+ memset(allocation->ptr, 0, sz);
+ return allocation->ptr;
+ }
+}
+
+static inline void hybrid_free(void *ptr_in) {
+ supervisor_allocation *allocation = allocation_from_ptr(ptr_in);
+
+ if (allocation) {
+ free_memory(allocation);
+ }
+}
+
+STATIC uint8_t bitrev(uint8_t n) {
+ uint8_t r = 0;
+ for(int i=0;i<8;i++) r |= ((n>>i) & 1)<<(7-i);
+ return r;
+}
+
+int common_hal_sharpdisplay_framebuffer_get_width(sharpdisplay_framebuffer_obj_t *self) {
+ return self->width;
+}
+
+int common_hal_sharpdisplay_framebuffer_get_height(sharpdisplay_framebuffer_obj_t *self) {
+ return self->height;
+}
+
+int common_hal_sharpdisplay_framebuffer_get_row_stride(sharpdisplay_framebuffer_obj_t *self) {
+ return (self->width + 7) / 8 + 2;
+}
+
+int common_hal_sharpdisplay_framebuffer_get_first_pixel_offset(sharpdisplay_framebuffer_obj_t *self) {
+ return 2;
+}
+
+bool common_hal_sharpdisplay_framebuffer_get_reverse_pixels_in_byte(sharpdisplay_framebuffer_obj_t *self) {
+ return true;
+}
+
+bool common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(sharpdisplay_framebuffer_obj_t *self) {
+ return true;
+}
+
+void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self) {
+ if (!allocation_from_ptr(self->bufinfo.buf)) {
+ self->bufinfo.buf = NULL;
+ }
+
+ if (self->bus != &self->inline_bus
+#if BOARD_SPI
+ && self->bus != common_hal_board_get_spi()
+#endif
+ ) {
+ memcpy(&self->inline_bus, self->bus, sizeof(busio_spi_obj_t));
+ self->bus = &self->inline_bus;
+ }
+}
+
+void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self) {
+
+}
+
+void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo) {
+ if (!self->bufinfo.buf) {
+ int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self);
+ int height = common_hal_sharpdisplay_framebuffer_get_height(self);
+ self->bufinfo.len = row_stride * height + 2;
+ self->bufinfo.buf = hybrid_alloc(self->bufinfo.len);
+
+ uint8_t *data = self->bufinfo.buf;
+ *data++ = SHARPMEM_BIT_WRITECMD_LSB;
+
+ for(int y=0; y<height; y++) {
+ *data = bitrev(y+1);
+ data += row_stride;
+ }
+ self->full_refresh = true;
+ }
+ *bufinfo = self->bufinfo;
+}
+
+void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self) {
+ if (self->base.type != &sharpdisplay_framebuffer_type) {
+ return;
+ }
+
+ if (self->bus == &self->inline_bus) {
+ common_hal_busio_spi_deinit(self->bus);
+ }
+
+ common_hal_reset_pin(self->chip_select.pin);
+
+ hybrid_free(self->bufinfo.buf);
+
+ memset(self, 0, sizeof(*self));
+}
+
+void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *chip_select, int baudrate, int width, int height) {
+ common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select);
+ common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL);
+ common_hal_never_reset_pin(chip_select);
+
+ self->bus = spi;
+ common_hal_busio_spi_never_reset(self->bus);
+
+ self->width = width;
+ self->height = height;
+ self->baudrate = baudrate;
+
+ int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self);
+ self->bufinfo.len = row_stride * height + 2;
+ self->bufinfo.buf = gc_alloc(self->bufinfo.len, false, true);
+
+ uint8_t *data = self->bufinfo.buf;
+ *data++ = SHARPMEM_BIT_WRITECMD_LSB;
+
+ for(int y=0; y<self->height; y++) {
+ *data = bitrev(y+1);
+ data += row_stride;
+ }
+ self->full_refresh = true;
+}
+
+void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask) {
+ // claim SPI bus
+ if (!common_hal_busio_spi_try_lock(self->bus)) {
+ return;
+ }
+ common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8);
+
+ // set chip select high
+ common_hal_digitalio_digitalinout_set_value(&self->chip_select, true);
+
+ // output the toggling signal
+ uint8_t *data = self->bufinfo.buf;
+ data[0] ^= SHARPMEM_BIT_VCOM_LSB;
+
+ common_hal_busio_spi_write(self->bus, data++, 1);
+
+ // output each changed row
+ size_t row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self);
+ for(int y=0; y<self->height; y++) {
+ if(self->full_refresh || (dirty_row_bitmask[y/8] & (1 << (y & 7)))) {
+ common_hal_busio_spi_write(self->bus, data, row_stride);
+ }
+ data += row_stride;
+ }
+
+ // output a trailing zero
+ common_hal_busio_spi_write(self->bus, data, 1);
+
+ // set chip select low
+ common_hal_digitalio_digitalinout_set_value(&self->chip_select, false);
+
+ // release SPI bus
+ common_hal_busio_spi_unlock(self->bus);
+
+ self->full_refresh = false;
+}
+
+STATIC void sharpdisplay_framebuffer_deinit(mp_obj_t self_in) {
+ sharpdisplay_framebuffer_obj_t *self = self_in;
+ common_hal_sharpdisplay_framebuffer_deinit(self);
+}
+
+STATIC void sharpdisplay_framebuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
+ sharpdisplay_framebuffer_obj_t *self = self_in;
+ common_hal_sharpdisplay_framebuffer_get_bufinfo(self, bufinfo);
+}
+
+STATIC int sharpdisplay_framebuffer_get_color_depth(mp_obj_t self_in) {
+ return 1;
+}
+
+STATIC int sharpdisplay_framebuffer_get_height(mp_obj_t self_in) {
+ sharpdisplay_framebuffer_obj_t *self = self_in;
+ return common_hal_sharpdisplay_framebuffer_get_height(self);
+}
+
+STATIC int sharpdisplay_framebuffer_get_width(mp_obj_t self_in) {
+ sharpdisplay_framebuffer_obj_t *self = self_in;
+ return common_hal_sharpdisplay_framebuffer_get_width(self);
+}
+
+STATIC int sharpdisplay_framebuffer_get_first_pixel_offset(mp_obj_t self_in) {
+ sharpdisplay_framebuffer_obj_t *self = self_in;
+ return common_hal_sharpdisplay_framebuffer_get_first_pixel_offset(self);
+}
+
+STATIC bool sharpdisplay_framebuffer_get_pixels_in_byte_share_row(mp_obj_t self_in) {
+ sharpdisplay_framebuffer_obj_t *self = self_in;
+ return common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(self);
+}
+
+STATIC bool sharpdisplay_framebuffer_get_reverse_pixels_in_byte(mp_obj_t self_in) {
+ sharpdisplay_framebuffer_obj_t *self = self_in;
+ return common_hal_sharpdisplay_framebuffer_get_reverse_pixels_in_byte(self);
+}
+
+STATIC int sharpdisplay_framebuffer_get_row_stride(mp_obj_t self_in) {
+ sharpdisplay_framebuffer_obj_t *self = self_in;
+ return common_hal_sharpdisplay_framebuffer_get_row_stride(self);
+}
+
+STATIC void sharpdisplay_framebuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmask) {
+ sharpdisplay_framebuffer_obj_t *self = self_in;
+ common_hal_sharpdisplay_framebuffer_swapbuffers(self, dirty_row_bitmask);
+}
+
+const framebuffer_p_t sharpdisplay_framebuffer_proto = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer)
+ .deinit = sharpdisplay_framebuffer_deinit,
+ .get_bufinfo = sharpdisplay_framebuffer_get_bufinfo,
+ .get_color_depth = sharpdisplay_framebuffer_get_color_depth,
+ .get_height = sharpdisplay_framebuffer_get_height,
+ .get_width = sharpdisplay_framebuffer_get_width,
+ .swapbuffers = sharpdisplay_framebuffer_swapbuffers,
+
+ .get_first_pixel_offset = sharpdisplay_framebuffer_get_first_pixel_offset,
+ .get_pixels_in_byte_share_row = sharpdisplay_framebuffer_get_pixels_in_byte_share_row,
+ .get_reverse_pixels_in_byte = sharpdisplay_framebuffer_get_reverse_pixels_in_byte,
+ .get_row_stride = sharpdisplay_framebuffer_get_row_stride,
+};
+
+void common_hal_sharpdisplay_framebuffer_collect_ptrs(sharpdisplay_framebuffer_obj_t *self) {
+ gc_collect_ptr(self->framebuffer);
+ gc_collect_ptr(self->bus);
+ gc_collect_ptr(self->bufinfo.buf);
+}
diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.h b/shared-module/sharpdisplay/SharpMemoryFramebuffer.h
new file mode 100644
index 000000000..8acacc94e
--- /dev/null
+++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler 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.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+#include "shared-module/framebufferio/FramebufferDisplay.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ mp_obj_t framebuffer;
+ busio_spi_obj_t* bus;
+ busio_spi_obj_t inline_bus;
+ digitalio_digitalinout_obj_t chip_select;
+ mp_buffer_info_t bufinfo;
+
+ uint16_t width, height;
+ uint32_t baudrate;
+
+ bool full_refresh:1;
+} sharpdisplay_framebuffer_obj_t;
+
+void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *chip_select, int baudrate, int width, int height);
+void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask);
+void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self);
+void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo);
+int common_hal_sharpdisplay_framebuffer_get_height(sharpdisplay_framebuffer_obj_t *self);
+int common_hal_sharpdisplay_framebuffer_get_width(sharpdisplay_framebuffer_obj_t *self);
+void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask);
+void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self);
+void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self);
+
+extern const framebuffer_p_t sharpdisplay_framebuffer_proto;
+
+void common_hal_sharpdisplay_framebuffer_collect_ptrs(sharpdisplay_framebuffer_obj_t*);
diff --git a/shared-module/sharpdisplay/__init__.c b/shared-module/sharpdisplay/__init__.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/shared-module/sharpdisplay/__init__.c
diff --git a/shared-module/sharpdisplay/__init__.h b/shared-module/sharpdisplay/__init__.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/shared-module/sharpdisplay/__init__.h
diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c
index 9c074209b..08dd71404 100644
--- a/supervisor/shared/display.c
+++ b/supervisor/shared/display.c
@@ -38,6 +38,12 @@
#include "shared-module/displayio/__init__.h"
#endif
+#if CIRCUITPY_SHARPDISPLAY
+#include "shared-module/displayio/__init__.h"
+#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
+#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
+#endif
+
extern size_t blinka_bitmap_data[];
extern displayio_bitmap_t blinka_bitmap;
extern displayio_group_t circuitpython_splash;
@@ -116,15 +122,21 @@ void supervisor_display_move_memory(void) {
grid->inline_tiles = false;
}
MP_STATE_VM(terminal_tilegrid_tiles) = NULL;
- #if CIRCUITPY_RGBMATRIX
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
- if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) {
- rgbmatrix_rgbmatrix_obj_t * pm = &displays[i].rgbmatrix;
+ #if CIRCUITPY_RGBMATRIX
+ if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) {
+ rgbmatrix_rgbmatrix_obj_t * pm = &displays[i].rgbmatrix;
common_hal_rgbmatrix_rgbmatrix_reconstruct(pm, NULL);
- }
+ }
+ #endif
+ #if CIRCUITPY_SHARPDISPLAY
+ if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
+ sharpdisplay_framebuffer_obj_t * sharp = &displays[i].sharpdisplay;
+ common_hal_sharpdisplay_framebuffer_reconstruct(sharp);
+ }
+ #endif
}
#endif
- #endif
}
size_t blinka_bitmap_data[32] = {