Merge pull request #3269 from jepler/sharpdisplay-v2
Sharp Memory Display displayio support (v2)
This commit is contained in:
commit
7ffa2a103c
@ -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 ""
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -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)
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
92
shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c
Normal file
92
shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c
Normal file
@ -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,
|
||||
};
|
34
shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h
Normal file
34
shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h
Normal file
@ -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;
|
47
shared-bindings/sharpdisplay/__init__.c
Normal file
47
shared-bindings/sharpdisplay/__init__.c
Normal file
@ -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,
|
||||
};
|
0
shared-bindings/sharpdisplay/__init__.h
Normal file
0
shared-bindings/sharpdisplay/__init__.h
Normal file
@ -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,9 +107,13 @@ 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,9 +179,18 @@ 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.
|
||||
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
277
shared-module/sharpdisplay/SharpMemoryFramebuffer.c
Normal file
277
shared-module/sharpdisplay/SharpMemoryFramebuffer.c
Normal file
@ -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);
|
||||
}
|
60
shared-module/sharpdisplay/SharpMemoryFramebuffer.h
Normal file
60
shared-module/sharpdisplay/SharpMemoryFramebuffer.h
Normal file
@ -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*);
|
0
shared-module/sharpdisplay/__init__.c
Normal file
0
shared-module/sharpdisplay/__init__.c
Normal file
0
shared-module/sharpdisplay/__init__.h
Normal file
0
shared-module/sharpdisplay/__init__.h
Normal file
@ -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] = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user