Merge remote-tracking branch 'adafruit/main' into rpi

This commit is contained in:
Scott Shawcroft 2021-11-24 14:23:23 -08:00
commit ee5536386d
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
31 changed files with 978 additions and 45 deletions

View File

@ -574,6 +574,7 @@ msgstr ""
#: shared-bindings/displayio/Display.c #: shared-bindings/displayio/Display.c
#: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c
#: shared-bindings/is31fl3741/is31fl3741.c
#: shared-bindings/rgbmatrix/RGBMatrix.c #: shared-bindings/rgbmatrix/RGBMatrix.c
msgid "Brightness must be 0-1.0" msgid "Brightness must be 0-1.0"
msgstr "" msgstr ""
@ -1461,6 +1462,10 @@ msgstr ""
msgid "Key must be 16, 24, or 32 bytes long" msgid "Key must be 16, 24, or 32 bytes long"
msgstr "" msgstr ""
#: shared-module/is31fl3741/is31fl3741.c
msgid "LED mappings must match display size"
msgstr ""
#: py/compile.c #: py/compile.c
msgid "LHS of keyword arg must be an id" msgid "LHS of keyword arg must be an id"
msgstr "" msgstr ""
@ -2085,6 +2090,10 @@ msgstr ""
msgid "Sample rate too high. It must be less than %d" msgid "Sample rate too high. It must be less than %d"
msgstr "" msgstr ""
#: shared-bindings/is31fl3741/is31fl3741.c
msgid "Scale dimensions must divide by 3"
msgstr ""
#: ports/nrf/common-hal/_bleio/Adapter.c #: ports/nrf/common-hal/_bleio/Adapter.c
msgid "Scan already in progess. Stop with stop_scan." msgid "Scan already in progess. Stop with stop_scan."
msgstr "" msgstr ""
@ -2342,7 +2351,7 @@ msgstr ""
msgid "Unable to create lock" msgid "Unable to create lock"
msgstr "" msgstr ""
#: shared-module/displayio/I2CDisplay.c #: shared-module/displayio/I2CDisplay.c shared-module/is31fl3741/is31fl3741.c
#, c-format #, c-format
msgid "Unable to find I2C Display at %x" msgid "Unable to find I2C Display at %x"
msgstr "" msgstr ""
@ -4453,6 +4462,7 @@ msgstr ""
msgid "width must be from 2 to 8 (inclusive), not %d" msgid "width must be from 2 to 8 (inclusive), not %d"
msgstr "" msgstr ""
#: shared-bindings/is31fl3741/is31fl3741.c
#: shared-bindings/rgbmatrix/RGBMatrix.c #: shared-bindings/rgbmatrix/RGBMatrix.c
msgid "width must be greater than zero" msgid "width must be greater than zero"
msgstr "" msgstr ""

8
main.c
View File

@ -678,7 +678,7 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
FATFS *fs = &vfs->fatfs; FATFS *fs = &vfs->fatfs;
boot_output = NULL; boot_output = NULL;
bool write_boot_output = (common_hal_mcu_processor_get_reset_reason() == RESET_REASON_POWER_ON); bool write_boot_output = true;
FIL boot_output_file; FIL boot_output_file;
if (f_open(fs, &boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) { if (f_open(fs, &boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
char *file_contents = m_new(char, boot_text.alloc); char *file_contents = m_new(char, boot_text.alloc);
@ -858,7 +858,11 @@ int __attribute__((used)) main(void) {
serial_write_compressed(translate("soft reboot\n")); serial_write_compressed(translate("soft reboot\n"));
} }
first_run = false; first_run = false;
skip_repl = run_code_py(safe_mode); if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
skip_repl = run_code_py(safe_mode);
} else {
skip_repl = false;
}
} else if (exit_code != 0) { } else if (exit_code != 0) {
break; break;
} }

View File

@ -13,6 +13,7 @@ CIRCUITPY_BUILTINS_POW3=0
CIRCUITPY_BUSDEVICE = 0 CIRCUITPY_BUSDEVICE = 0
CIRCUITPY_COUNTIO = 0 CIRCUITPY_COUNTIO = 0
CIRCUITPY_DISPLAYIO = 0 CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_IS31FL3741 = 0
CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_I2CPERIPHERAL = 0

View File

@ -19,6 +19,7 @@ CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_IS31FL3741 = 0
CIRCUITPY_JSON = 0 CIRCUITPY_JSON = 0
CIRCUITPY_KEYPAD = 0 CIRCUITPY_KEYPAD = 0
CIRCUITPY_MSGPACK = 0 CIRCUITPY_MSGPACK = 0

View File

@ -22,6 +22,7 @@ CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_ERRNO = 0 CIRCUITPY_ERRNO = 0
CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_GETPASS = 0 CIRCUITPY_GETPASS = 0
CIRCUITPY_IS31FL3741 = 0
CIRCUITPY_KEYPAD = 0 CIRCUITPY_KEYPAD = 0
CIRCUITPY_MSGPACK = 0 CIRCUITPY_MSGPACK = 0
CIRCUITPY_NEOPIXEL_WRITE = 0 CIRCUITPY_NEOPIXEL_WRITE = 0

View File

@ -32,6 +32,8 @@ CIRCUITPY_BLEIO ?= 1
# No I2CPeripheral implementation # No I2CPeripheral implementation
CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_IS31FL3741 ?= 1
CIRCUITPY_RTC ?= 1 CIRCUITPY_RTC ?= 1
# frequencyio not yet implemented # frequencyio not yet implemented

View File

@ -212,6 +212,9 @@ endif
ifeq ($(CIRCUITPY_IPADDRESS),1) ifeq ($(CIRCUITPY_IPADDRESS),1)
SRC_PATTERNS += ipaddress/% SRC_PATTERNS += ipaddress/%
endif endif
ifeq ($(CIRCUITPY_IS31FL3741),1)
SRC_PATTERNS += is31fl3741/%
endif
ifeq ($(CIRCUITPY_KEYPAD),1) ifeq ($(CIRCUITPY_KEYPAD),1)
SRC_PATTERNS += keypad/% SRC_PATTERNS += keypad/%
endif endif
@ -551,6 +554,8 @@ SRC_SHARED_MODULE_ALL = \
imagecapture/ParallelImageCapture.c \ imagecapture/ParallelImageCapture.c \
ipaddress/IPv4Address.c \ ipaddress/IPv4Address.c \
ipaddress/__init__.c \ ipaddress/__init__.c \
is31fl3741/IS31FL3741.c \
is31fl3741/__init__.c \
keypad/__init__.c \ keypad/__init__.c \
keypad/Event.c \ keypad/Event.c \
keypad/EventQueue.c \ keypad/EventQueue.c \

View File

@ -247,6 +247,9 @@ CFLAGS += -DCIRCUITPY_IMAGECAPTURE=$(CIRCUITPY_IMAGECAPTURE)
CIRCUITPY_IPADDRESS ?= $(CIRCUITPY_WIFI) CIRCUITPY_IPADDRESS ?= $(CIRCUITPY_WIFI)
CFLAGS += -DCIRCUITPY_IPADDRESS=$(CIRCUITPY_IPADDRESS) CFLAGS += -DCIRCUITPY_IPADDRESS=$(CIRCUITPY_IPADDRESS)
CIRCUITPY_IS31FL3741 ?= 0
CFLAGS += -DCIRCUITPY_IS31FL3741=$(CIRCUITPY_IS31FL3741)
CIRCUITPY_JSON ?= $(CIRCUITPY_FULL_BUILD) CIRCUITPY_JSON ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_JSON=$(CIRCUITPY_JSON) CFLAGS += -DCIRCUITPY_JSON=$(CIRCUITPY_JSON)

View File

@ -664,7 +664,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_readinto_obj, 0, bitmaptools_readinto);
//| """The Floyd-Stenberg dither""" //| """The Floyd-Stenberg dither"""
//| //|
MAKE_ENUM_VALUE(bitmaptools_dither_algorithm_type, dither_algorithm, Atkinson, DITHER_ALGORITHM_ATKINSON); MAKE_ENUM_VALUE(bitmaptools_dither_algorithm_type, dither_algorithm, Atkinson, DITHER_ALGORITHM_ATKINSON);
MAKE_ENUM_VALUE(bitmaptools_dither_algorithm_type, dither_algorithm, FloydStenberg, DITHER_ALGORITHM_ATKINSON); MAKE_ENUM_VALUE(bitmaptools_dither_algorithm_type, dither_algorithm, FloydStenberg, DITHER_ALGORITHM_FLOYD_STENBERG);
MAKE_ENUM_MAP(bitmaptools_dither_algorithm) { MAKE_ENUM_MAP(bitmaptools_dither_algorithm) {
MAKE_ENUM_MAP_ENTRY(dither_algorithm, Atkinson), MAKE_ENUM_MAP_ENTRY(dither_algorithm, Atkinson),

View File

@ -0,0 +1,308 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Mark Komus
*
* 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/obj.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "py/objarray.h"
#include "shared-bindings/is31fl3741/IS31FL3741.h"
#include "shared-bindings/util.h"
#include "shared-module/displayio/__init__.h"
#include "shared-module/framebufferio/__init__.h"
#include "shared-module/framebufferio/FramebufferDisplay.h"
#include "shared-bindings/busio/I2C.h"
//| class IS31FL3741:
//| """Displays an in-memory framebuffer to a IS31FL3741 drive display."""
//|
//| def __init__(self, *, width: int) -> None:
//| """Create a IS31FL3741 object with the given attributes.
//|
//| The framebuffer is in "RGB888" format using 4 bytes per pixel.
//| Bits 24-31 are ignored. The format is in RGB order.
//|
//| If a framebuffer is not passed in, one is allocated and initialized
//| to all black. In any case, the framebuffer can be retrieved
//| by passing the Is31fl3741 object to memoryview().
//|
//| A Is31fl3741 is often used in conjunction with a
//| `framebufferio.FramebufferDisplay`."""
//|
STATIC mp_obj_t is31fl3741_IS31FL3741_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_width, ARG_height, ARG_i2c, ARG_addr, ARG_framebuffer, ARG_mapping, ARG_scale, ARG_gamma };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
{ MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
{ MP_QSTR_i2c, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
{ MP_QSTR_addr, MP_ARG_INT | MP_ARG_KW_ONLY, { .u_int = 0x30 } },
{ MP_QSTR_framebuffer, MP_ARG_OBJ | MP_ARG_KW_ONLY, { .u_obj = mp_const_none } },
{ MP_QSTR_mapping, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
{ MP_QSTR_scale, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = false } },
{ MP_QSTR_gamma, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = false } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus);
is31fl3741_IS31FL3741_obj_t *self = &allocate_display_bus_or_raise()->is31fl3741;
self->base.type = &is31fl3741_IS31FL3741_type;
if (args[ARG_width].u_int <= 0) {
mp_raise_ValueError(translate("width must be greater than zero"));
}
self->scale = args[ARG_scale].u_bool;
if (self->scale) {
if (((args[ARG_height].u_int % 3) != 0) || ((args[ARG_width].u_int % 3) != 0)) {
mp_raise_ValueError(translate("Scale dimensions must divide by 3"));
}
self->scale_width = args[ARG_width].u_int / 3;
self->scale_height = args[ARG_height].u_int / 3;
} else {
self->scale_width = args[ARG_width].u_int;
self->scale_height = args[ARG_height].u_int;
}
self->auto_gamma = args[ARG_gamma].u_bool;
mp_obj_t framebuffer = args[ARG_framebuffer].u_obj;
if (framebuffer == mp_const_none) {
int width = args[ARG_width].u_int;
int height = args[ARG_height].u_int;
int bufsize = 4 * width * height;
framebuffer = mp_obj_new_bytearray_of_zeros(bufsize);
}
common_hal_is31fl3741_IS31FL3741_construct(self,
args[ARG_width].u_int,
args[ARG_height].u_int,
framebuffer,
MP_OBJ_TO_PTR(i2c),
args[ARG_addr].u_int,
args[ARG_mapping].u_obj
);
return MP_OBJ_FROM_PTR(self);
}
//| def deinit(self) -> None:
//| """Free the resources associated with this
//| IS31FL3741 instance. After deinitialization, no further operations
//| may be performed."""
//| ...
//|
STATIC mp_obj_t is31fl3741_IS31FL3741_deinit(mp_obj_t self_in) {
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
common_hal_is31fl3741_IS31FL3741_deinit(self);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_deinit_obj, is31fl3741_IS31FL3741_deinit);
static void check_for_deinit(is31fl3741_IS31FL3741_obj_t *self) {
if (self->framebuffer == NULL) {
raise_deinited_error();
}
}
//| brightness: float
//| """In the current implementation, 0.0 turns the display off entirely
//| and any other value up to 1.0 turns the display on fully."""
//|
STATIC mp_obj_t is31fl3741_IS31FL3741_get_brightness(mp_obj_t self_in) {
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
check_for_deinit(self);
uint8_t current = common_hal_is31fl3741_IS31FL3741_get_global_current(self);
float brightness = (float)current / (float)0xFF;
return mp_obj_new_float(brightness);
}
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_get_brightness_obj, is31fl3741_IS31FL3741_get_brightness);
STATIC mp_obj_t is31fl3741_IS31FL3741_set_brightness(mp_obj_t self_in, mp_obj_t value_in) {
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
check_for_deinit(self);
mp_float_t brightness = mp_obj_get_float(value_in);
if (brightness < 0.0f || brightness > 1.0f) {
mp_raise_ValueError(translate("Brightness must be 0-1.0"));
}
uint8_t current = (uint8_t)(brightness * 0xFF);
common_hal_is31fl3741_IS31FL3741_set_global_current(self, current);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(is31fl3741_IS31FL3741_set_brightness_obj, is31fl3741_IS31FL3741_set_brightness);
const mp_obj_property_t is31fl3741_IS31FL3741_brightness_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&is31fl3741_IS31FL3741_get_brightness_obj,
(mp_obj_t)&is31fl3741_IS31FL3741_set_brightness_obj,
MP_ROM_NONE},
};
//| def refresh(self) -> None:
//| """Transmits the color data in the buffer to the pixels so that
//| they are shown."""
//| ...
//|
STATIC mp_obj_t is31fl3741_IS31FL3741_refresh(mp_obj_t self_in) {
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
check_for_deinit(self);
common_hal_is31fl3741_IS31FL3741_refresh(self, 0);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_refresh_obj, is31fl3741_IS31FL3741_refresh);
//| width: int
//| """The width of the display, in pixels"""
//|
STATIC mp_obj_t is31fl3741_IS31FL3741_get_width(mp_obj_t self_in) {
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_IS31FL3741_get_width(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_get_width_obj, is31fl3741_IS31FL3741_get_width);
const mp_obj_property_t is31fl3741_IS31FL3741_width_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&is31fl3741_IS31FL3741_get_width_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
//| height: int
//| """The height of the display, in pixels"""
//|
STATIC mp_obj_t is31fl3741_IS31FL3741_get_height(mp_obj_t self_in) {
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_IS31FL3741_get_height(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_get_height_obj, is31fl3741_IS31FL3741_get_height);
const mp_obj_property_t is31fl3741_IS31FL3741_height_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&is31fl3741_IS31FL3741_get_height_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
STATIC const mp_rom_map_elem_t is31fl3741_IS31FL3741_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&is31fl3741_IS31FL3741_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&is31fl3741_IS31FL3741_brightness_obj) },
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&is31fl3741_IS31FL3741_refresh_obj) },
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&is31fl3741_IS31FL3741_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&is31fl3741_IS31FL3741_height_obj) },
};
STATIC MP_DEFINE_CONST_DICT(is31fl3741_IS31FL3741_locals_dict, is31fl3741_IS31FL3741_locals_dict_table);
STATIC void is31fl3741_IS31FL3741_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
check_for_deinit(self);
*bufinfo = self->bufinfo;
}
STATIC void is31fl3741_IS31FL3741_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
common_hal_is31fl3741_IS31FL3741_refresh(self_in, dirty_row_bitmap);
}
STATIC void is31fl3741_IS31FL3741_deinit_proto(mp_obj_t self_in) {
common_hal_is31fl3741_IS31FL3741_deinit(self_in);
}
STATIC float is31fl3741_IS31FL3741_get_brightness_proto(mp_obj_t self_in) {
return common_hal_is31fl3741_IS31FL3741_get_paused(self_in) ? 0.0f : 1.0f;
}
STATIC bool is31fl3741_IS31FL3741_set_brightness_proto(mp_obj_t self_in, mp_float_t value) {
common_hal_is31fl3741_IS31FL3741_set_paused(self_in, value <= 0);
return true;
}
STATIC int is31fl3741_IS31FL3741_get_width_proto(mp_obj_t self_in) {
return common_hal_is31fl3741_IS31FL3741_get_width(self_in);
}
STATIC int is31fl3741_IS31FL3741_get_height_proto(mp_obj_t self_in) {
return common_hal_is31fl3741_IS31FL3741_get_height(self_in);
}
STATIC int is31fl3741_IS31FL3741_get_color_depth_proto(mp_obj_t self_in) {
// The way displayio works depth is used to calculate bytes
// We use an uint32_t for color already so setting to 24 causes
// more changes required
return 32;
}
STATIC int is31fl3741_IS31FL3741_get_bytes_per_cell_proto(mp_obj_t self_in) {
return 1;
}
STATIC int is31fl3741_IS31FL3741_get_native_frames_per_second_proto(mp_obj_t self_in) {
return 60; // This was just chosen may vary based on LEDs used?
}
STATIC const framebuffer_p_t is31fl3741_IS31FL3741_proto = {
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer)
.get_bufinfo = is31fl3741_IS31FL3741_get_bufinfo,
.set_brightness = is31fl3741_IS31FL3741_set_brightness_proto,
.get_brightness = is31fl3741_IS31FL3741_get_brightness_proto,
.get_width = is31fl3741_IS31FL3741_get_width_proto,
.get_height = is31fl3741_IS31FL3741_get_height_proto,
.get_color_depth = is31fl3741_IS31FL3741_get_color_depth_proto,
.get_bytes_per_cell = is31fl3741_IS31FL3741_get_bytes_per_cell_proto,
.get_native_frames_per_second = is31fl3741_IS31FL3741_get_native_frames_per_second_proto,
.swapbuffers = is31fl3741_IS31FL3741_swapbuffers,
.deinit = is31fl3741_IS31FL3741_deinit_proto,
};
STATIC mp_int_t is31fl3741_IS31FL3741_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_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;
bufinfo->typecode = 'H';
return 0;
}
const mp_obj_type_t is31fl3741_IS31FL3741_type = {
{ &mp_type_type },
.flags = MP_TYPE_FLAG_EXTENDED,
.name = MP_QSTR_is31fl3741,
.locals_dict = (mp_obj_dict_t *)&is31fl3741_IS31FL3741_locals_dict,
.make_new = is31fl3741_IS31FL3741_make_new,
MP_TYPE_EXTENDED_FIELDS(
.buffer_p = { .get_buffer = is31fl3741_IS31FL3741_get_buffer, },
.protocol = &is31fl3741_IS31FL3741_proto,
),
};

View File

@ -0,0 +1,61 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Mark Komus
*
* 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/is31fl3741/IS31FL3741.h"
extern const mp_obj_type_t is31fl3741_IS31FL3741_type;
void common_hal_is31fl3741_IS31FL3741_construct(is31fl3741_IS31FL3741_obj_t *self, int width, int height, mp_obj_t framebuffer, busio_i2c_obj_t *i2c, uint8_t addr, mp_obj_t mapping);
void common_hal_is31fl3741_IS31FL3741_deinit(is31fl3741_IS31FL3741_obj_t *);
int common_hal_is31fl3741_IS31FL3741_get_width(is31fl3741_IS31FL3741_obj_t *self);
int common_hal_is31fl3741_IS31FL3741_get_height(is31fl3741_IS31FL3741_obj_t *self);
void common_hal_displayio_is31fl3741_begin_transaction(is31fl3741_IS31FL3741_obj_t *self);
void common_hal_displayio_is31fl3741_end_transaction(is31fl3741_IS31FL3741_obj_t *self);
void common_hal_is31fl3741_IS31FL3741_set_global_current(is31fl3741_IS31FL3741_obj_t *self, uint8_t current);
uint8_t common_hal_is31fl3741_IS31FL3741_get_global_current(is31fl3741_IS31FL3741_obj_t *self);
void common_hal_is31fl3741_IS31FL3741_set_paused(is31fl3741_IS31FL3741_obj_t *self, bool paused);
bool common_hal_is31fl3741_IS31FL3741_get_paused(is31fl3741_IS31FL3741_obj_t *self);
void common_hal_is31fl3741_IS31FL3741_refresh(is31fl3741_IS31FL3741_obj_t *self, uint8_t *dirtyrows);
void common_hal_is31fl3741_IS31FL3741_reconstruct(is31fl3741_IS31FL3741_obj_t *self, mp_obj_t framebuffer);
void is31fl3741_IS31FL3741_collect_ptrs(is31fl3741_IS31FL3741_obj_t *self);
void is31fl3741_send_unlock(busio_i2c_obj_t *i2c, uint8_t addr);
void is31fl3741_set_page(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t p);
void is31fl3741_send_enable(busio_i2c_obj_t *i2c, uint8_t addr);
void is31fl3741_send_reset(busio_i2c_obj_t *i2c, uint8_t addr);
void is31fl3741_set_current(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t current);
uint8_t is31fl3741_get_current(busio_i2c_obj_t *i2c, uint8_t addr);
void is31fl3741_set_led(busio_i2c_obj_t *i2c, uint8_t addr, uint16_t led, uint8_t level, uint8_t page);
void is31fl3741_draw_pixel(busio_i2c_obj_t *i2c, uint8_t addr, int16_t x, int16_t y, uint32_t color, uint16_t *mapping);

View File

@ -0,0 +1,46 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Mark Komus
*
* 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/is31fl3741/IS31FL3741.h"
STATIC const mp_rom_map_elem_t is31fl3741_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_is31fl3741) },
{ MP_ROM_QSTR(MP_QSTR_IS31FL3741), MP_ROM_PTR(&is31fl3741_IS31FL3741_type) },
};
STATIC MP_DEFINE_CONST_DICT(is31fl3741_module_globals, is31fl3741_module_globals_table);
const mp_obj_module_t is31fl3741_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&is31fl3741_module_globals,
};
MP_REGISTER_MODULE(MP_QSTR_is31fl3741, is31fl3741_module, CIRCUITPY_IS31FL3741);

View File

@ -749,9 +749,9 @@ void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bi
int x1 = x + info->terms[i].dx; int x1 = x + info->terms[i].dx;
int dy = info->terms[i].dy; int dy = info->terms[i].dy;
rows[dy][x1] = ((info->terms[i].dl * err) >> 8) + rows[dy][x1]; rows[dy][x1] = ((info->terms[i].dl * err) / 256) + rows[dy][x1];
} }
err = err * info->dl >> 8; err = (err * info->dl) / 256;
} }
write_pixels(dest_bitmap, y, out); write_pixels(dest_bitmap, y, out);
@ -761,13 +761,13 @@ void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bi
rows[1] = rows[2]; rows[1] = rows[2];
rows[2] = tmp; rows[2] = tmp;
fill_row(source_bitmap, swap, rows[2], y + 2, info->mx);
y++; y++;
if (y == height) { if (y == height) {
break; break;
} }
fill_row(source_bitmap, swap, rows[2], y + 2, info->mx);
// Serpentine dither. Going right-to-left... // Serpentine dither. Going right-to-left...
for (int x = width; x--;) { for (int x = width; x--;) {
int16_t pixel_in = rows[0][x] + err; int16_t pixel_in = rows[0][x] + err;
@ -779,9 +779,9 @@ void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bi
int x1 = x - info->terms[i].dx; int x1 = x - info->terms[i].dx;
int dy = info->terms[i].dy; int dy = info->terms[i].dy;
rows[dy][x1] = ((info->terms[i].dl * err) >> 8) + rows[dy][x1]; rows[dy][x1] = ((info->terms[i].dl * err) / 256) + rows[dy][x1];
} }
err = err * info->dl >> 8; err = (err * info->dl) / 256;
} }
write_pixels(dest_bitmap, y, out); write_pixels(dest_bitmap, y, out);
@ -790,7 +790,7 @@ void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bi
rows[1] = rows[2]; rows[1] = rows[2];
rows[2] = tmp; rows[2] = tmp;
fill_row(source_bitmap, swap, rows[2], y + 2, info->mx); fill_row(source_bitmap, swap, rows[2], y + 3, info->mx);
} }
displayio_area_t a = { 0, 0, width, height, NULL }; displayio_area_t a = { 0, 0, width, height, NULL };

View File

@ -98,6 +98,8 @@ bool displayio_palette_get_color(displayio_palette_t *self, const _displayio_col
*color = packed; *color = packed;
} else if (colorspace->depth == 32) { } else if (colorspace->depth == 32) {
*color = self->colors[palette_index].rgb888; *color = self->colors[palette_index].rgb888;
} else {
return false;
} }
return true; return true;

View File

@ -474,7 +474,7 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self,
if (colorspace->depth == 16) { if (colorspace->depth == 16) {
*(((uint16_t *)buffer) + offset) = output_pixel.pixel; *(((uint16_t *)buffer) + offset) = output_pixel.pixel;
} else if (colorspace->depth == 32) { } else if (colorspace->depth == 32) {
buffer[offset] = output_pixel.pixel; *(((uint32_t *)buffer) + offset) = output_pixel.pixel;
} else if (colorspace->depth == 8) { } else if (colorspace->depth == 8) {
*(((uint8_t *)buffer) + offset) = output_pixel.pixel; *(((uint8_t *)buffer) + offset) = output_pixel.pixel;
} else if (colorspace->depth < 8) { } else if (colorspace->depth < 8) {

View File

@ -65,8 +65,7 @@ displayio_buffer_transform_t null_transform = {
.transpose_xy = false .transpose_xy = false
}; };
#if CIRCUITPY_RGBMATRIX || CIRCUITPY_IS31FL3741 || CIRCUITPY_VIDEOCORE
#if CIRCUITPY_RGBMATRIX || CIRCUITPY_VIDEOCORE
STATIC bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) { STATIC bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) {
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].display_base.type == &framebufferio_framebufferdisplay_type) { if (displays[i].display_base.type == &framebufferio_framebufferdisplay_type) {
@ -143,6 +142,10 @@ void common_hal_displayio_release_displays(void) {
} else if (bus_type == &rgbmatrix_RGBMatrix_type) { } else if (bus_type == &rgbmatrix_RGBMatrix_type) {
common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix); common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix);
#endif #endif
#if CIRCUITPY_IS31FL3741
} else if (bus_type == &is31fl3741_IS31FL3741_type) {
common_hal_is31fl3741_IS31FL3741_deinit(&displays[i].is31fl3741);
#endif
#if CIRCUITPY_SHARPDISPLAY #if CIRCUITPY_SHARPDISPLAY
} else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
common_hal_sharpdisplay_framebuffer_deinit(&displays[i].sharpdisplay); common_hal_sharpdisplay_framebuffer_deinit(&displays[i].sharpdisplay);
@ -221,6 +224,37 @@ void reset_displays(void) {
common_hal_rgbmatrix_rgbmatrix_set_paused(pm, true); common_hal_rgbmatrix_rgbmatrix_set_paused(pm, true);
} }
#endif #endif
#if CIRCUITPY_IS31FL3741
} else if (displays[i].is31fl3741.base.type == &is31fl3741_IS31FL3741_type) {
is31fl3741_IS31FL3741_obj_t *is31 = &displays[i].is31fl3741;
if (((uint32_t)is31->i2c) < ((uint32_t)&displays) ||
((uint32_t)is31->i2c) > ((uint32_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) {
busio_i2c_obj_t *original_i2c = is31->i2c;
#if BOARD_I2C
// We don't need to move original_i2c if it is the board.I2C object because it is
// statically allocated already. (Doing so would also make it impossible to reference in
// a subsequent VM run.)
if (original_i2c == common_hal_board_get_i2c()) {
continue;
}
#endif
memcpy(&is31->inline_i2c, original_i2c, sizeof(busio_i2c_obj_t));
is31->i2c = &is31->inline_i2c;
// Check for other displays that use the same i2c bus and swap them too.
/*for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) {
if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type &&
displays[i].i2cdisplay_bus.bus == original_i2c) {
displays[i].i2cdisplay_bus.bus = &i2c->inline_bus;
}
}*/
}
if (!any_display_uses_this_framebuffer(&is31->base)) {
common_hal_is31fl3741_IS31FL3741_deinit(is31);
} else {
common_hal_is31fl3741_IS31FL3741_set_paused(is31, true);
}
#endif
#if CIRCUITPY_SHARPDISPLAY #if CIRCUITPY_SHARPDISPLAY
} else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
sharpdisplay_framebuffer_obj_t *sharp = &displays[i].sharpdisplay; sharpdisplay_framebuffer_obj_t *sharp = &displays[i].sharpdisplay;
@ -264,6 +298,11 @@ void displayio_gc_collect(void) {
rgbmatrix_rgbmatrix_collect_ptrs(&displays[i].rgbmatrix); rgbmatrix_rgbmatrix_collect_ptrs(&displays[i].rgbmatrix);
} }
#endif #endif
#if CIRCUITPY_IS31FL3741
if (displays[i].is31fl3741.base.type == &is31fl3741_IS31FL3741_type) {
is31fl3741_IS31FL3741_collect_ptrs(&displays[i].is31fl3741);
}
#endif
#if CIRCUITPY_SHARPDISPLAY #if CIRCUITPY_SHARPDISPLAY
if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
common_hal_sharpdisplay_framebuffer_collect_ptrs(&displays[i].sharpdisplay); common_hal_sharpdisplay_framebuffer_collect_ptrs(&displays[i].sharpdisplay);

View File

@ -41,6 +41,9 @@
#if CIRCUITPY_RGBMATRIX #if CIRCUITPY_RGBMATRIX
#include "shared-bindings/rgbmatrix/RGBMatrix.h" #include "shared-bindings/rgbmatrix/RGBMatrix.h"
#endif #endif
#if CIRCUITPY_IS31FL3741
#include "shared-bindings/is31fl3741/IS31FL3741.h"
#endif
#if CIRCUITPY_SHARPDISPLAY #if CIRCUITPY_SHARPDISPLAY
#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
#endif #endif
@ -59,6 +62,9 @@ typedef struct {
#if CIRCUITPY_RGBMATRIX #if CIRCUITPY_RGBMATRIX
rgbmatrix_rgbmatrix_obj_t rgbmatrix; rgbmatrix_rgbmatrix_obj_t rgbmatrix;
#endif #endif
#if CIRCUITPY_IS31FL3741
is31fl3741_IS31FL3741_obj_t is31fl3741;
#endif
#if CIRCUITPY_SHARPDISPLAY #if CIRCUITPY_SHARPDISPLAY
sharpdisplay_framebuffer_obj_t sharpdisplay; sharpdisplay_framebuffer_obj_t sharpdisplay;
#endif #endif

View File

@ -0,0 +1,353 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Mark Komus
*
* 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 "py/obj.h"
#include "py/objarray.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "shared-module/is31fl3741/allocator.h"
#include "shared-bindings/is31fl3741/IS31FL3741.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/util.h"
#include "shared-module/framebufferio/FramebufferDisplay.h"
#include "shared-bindings/busio/I2C.h"
void common_hal_is31fl3741_IS31FL3741_construct(is31fl3741_IS31FL3741_obj_t *self, int width, int height, mp_obj_t framebuffer, busio_i2c_obj_t *i2c, uint8_t addr, mp_obj_t mapping) {
self->width = width;
self->height = height;
self->bufsize = sizeof(uint32_t) * width * height;
// Probe the bus to see if a device acknowledges the given address.
if (!common_hal_busio_i2c_probe(i2c, addr)) {
self->base.type = &mp_type_NoneType;
mp_raise_ValueError_varg(translate("Unable to find I2C Display at %x"), addr);
}
self->i2c = i2c;
self->device_address = addr;
common_hal_busio_i2c_never_reset(self->i2c);
// Our object is statically allocated off the heap so make sure the bus object lives to the end
// of the heap as well.
gc_never_free(self->i2c);
mp_obj_t *items;
size_t len;
mp_obj_list_get(mapping, &len, &items);
if (len != (size_t)(self->scale_width * self->scale_height * 3)) {
mp_raise_ValueError(translate("LED mappings must match display size"));
}
self->mapping = common_hal_is31fl3741_allocator_impl(sizeof(uint16_t) * len);
for (size_t i = 0; i < len; i++) {
mp_int_t value = mp_obj_get_int(items[i]);
// We only store up to 16 bits
if (value > 0xFFFF) {
value = 0xFFFF;
}
self->mapping[i] = (uint16_t)value;
}
common_hal_is31fl3741_IS31FL3741_reconstruct(self, framebuffer);
}
void common_hal_is31fl3741_IS31FL3741_reconstruct(is31fl3741_IS31FL3741_obj_t *self, mp_obj_t framebuffer) {
self->paused = 1;
if (framebuffer) {
self->framebuffer = framebuffer;
mp_get_buffer_raise(self->framebuffer, &self->bufinfo, MP_BUFFER_READ);
if (mp_get_buffer(self->framebuffer, &self->bufinfo, MP_BUFFER_RW)) {
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
} else {
self->bufinfo.typecode = 'H';
}
// verify that the matrix is big enough
mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize - 1), false);
} else {
common_hal_is31fl3741_free_impl(self->bufinfo.buf);
self->framebuffer = NULL;
self->bufinfo.buf = common_hal_is31fl3741_allocator_impl(self->bufsize);
self->bufinfo.len = self->bufsize;
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
}
common_hal_displayio_is31fl3741_begin_transaction(self);
uint8_t command = 0xFC; // device ID
common_hal_busio_i2c_write(self->i2c, self->device_address, &command, 1, false);
uint8_t data = 0;
common_hal_busio_i2c_read(self->i2c, self->device_address, &data, 1);
is31fl3741_send_reset(self->i2c, self->device_address);
is31fl3741_send_enable(self->i2c, self->device_address);
is31fl3741_set_current(self->i2c, self->device_address, 0xFF);
// set scale (brightness) to max for all LEDs
for (int i; i < 351; i++) {
is31fl3741_set_led(self->i2c, self->device_address, i, 0xFF, 2);
}
common_hal_displayio_is31fl3741_end_transaction(self);
self->paused = 0;
}
void common_hal_is31fl3741_IS31FL3741_deinit(is31fl3741_IS31FL3741_obj_t *self) {
common_hal_displayio_is31fl3741_end_transaction(self); // in case we still had a lock
if (self->i2c == &self->inline_i2c) {
common_hal_busio_i2c_deinit(self->i2c);
self->i2c = NULL;
}
if (self->mapping != 0) {
common_hal_is31fl3741_free_impl(self->mapping);
self->mapping = 0;
}
self->base.type = NULL;
// If a framebuffer was passed in to the constructor, NULL the reference
// here so that it will become GC'able
self->framebuffer = NULL;
}
void common_hal_is31fl3741_IS31FL3741_set_paused(is31fl3741_IS31FL3741_obj_t *self, bool paused) {
self->paused = paused;
}
bool common_hal_is31fl3741_IS31FL3741_get_paused(is31fl3741_IS31FL3741_obj_t *self) {
return self->paused;
}
void common_hal_is31fl3741_IS31FL3741_set_global_current(is31fl3741_IS31FL3741_obj_t *self, uint8_t current) {
common_hal_displayio_is31fl3741_begin_transaction(self);
is31fl3741_set_current(self->i2c, self->device_address, current);
common_hal_displayio_is31fl3741_end_transaction(self);
}
uint8_t common_hal_is31fl3741_IS31FL3741_get_global_current(is31fl3741_IS31FL3741_obj_t *self) {
common_hal_displayio_is31fl3741_begin_transaction(self);
uint8_t current = is31fl3741_get_current(self->i2c, self->device_address);
common_hal_displayio_is31fl3741_end_transaction(self);
return current;
}
void common_hal_is31fl3741_IS31FL3741_refresh(is31fl3741_IS31FL3741_obj_t *self, uint8_t *dirtyrows) {
common_hal_displayio_is31fl3741_begin_transaction(self);
if (!self->paused) {
uint8_t dirty_row_flags = 0xFF; // only supports 8 rows gotta fix
if (self->scale) {
// Based on the Arduino IS31FL3741 driver code
// dirtyrows flag current not implemented for scaled displays
uint32_t *buffer = self->bufinfo.buf;
for (int x = 0; x < self->scale_width; x++) {
uint32_t *ptr = &buffer[x * 3]; // Entry along top scan line w/x offset
for (int y = 0; y < self->scale_height; y++) {
uint16_t rsum = 0, gsum = 0, bsum = 0;
// Inner x/y loops are row-major on purpose (less pointer math)
for (uint8_t yy = 0; yy < 3; yy++) {
for (uint8_t xx = 0; xx < 3; xx++) {
uint32_t rgb = ptr[xx];
rsum += rgb >> 16 & 0xFF;
gsum += (rgb >> 8) & 0xFF;
bsum += rgb & 0xFF;
}
ptr += self->width; // Advance one scan line
}
rsum = rsum / 9;
gsum = gsum / 9;
bsum = bsum / 9;
uint32_t color = 0;
if (self->auto_gamma) {
color = (IS31GammaTable[rsum] << 16) +
(IS31GammaTable[gsum] << 8) +
IS31GammaTable[bsum];
} else {
color = (rsum << 16) + (gsum << 8) + bsum;
}
is31fl3741_draw_pixel(self->i2c, self->device_address, x, y, color, self->mapping);
}
}
} else {
uint32_t *buffer = self->bufinfo.buf;
for (int y = 0; y < self->height; y++) {
if ((dirtyrows != 0) && ((y % 8) == 0)) {
dirty_row_flags = *dirtyrows++;
}
if ((dirty_row_flags >> (y % 8)) & 0x1) {
uint32_t color = 0;
if (self->auto_gamma) {
color = IS31GammaTable[((*buffer) >> 16 & 0xFF)] +
IS31GammaTable[((*buffer) >> 8 & 0xFF)] +
IS31GammaTable[((*buffer) & 0xFF)];
} else {
color = *buffer;
}
for (int x = 0; x < self->width; x++) {
is31fl3741_draw_pixel(self->i2c, self->device_address, x, y, color, self->mapping);
buffer++;
}
}
}
}
}
common_hal_displayio_is31fl3741_end_transaction(self);
}
int common_hal_is31fl3741_IS31FL3741_get_width(is31fl3741_IS31FL3741_obj_t *self) {
return self->width;
}
int common_hal_is31fl3741_IS31FL3741_get_height(is31fl3741_IS31FL3741_obj_t *self) {
return self->height;
}
void common_hal_displayio_is31fl3741_begin_transaction(is31fl3741_IS31FL3741_obj_t *self) {
while (!common_hal_busio_i2c_try_lock(self->i2c)) {
RUN_BACKGROUND_TASKS;
if (mp_hal_is_interrupted()) {
break;
}
}
}
void common_hal_displayio_is31fl3741_end_transaction(is31fl3741_IS31FL3741_obj_t *self) {
common_hal_busio_i2c_unlock(self->i2c);
}
void *common_hal_is31fl3741_allocator_impl(size_t sz) {
supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, true);
return allocation ? allocation->ptr : NULL;
}
void common_hal_is31fl3741_free_impl(void *ptr_in) {
free_memory(allocation_from_ptr(ptr_in));
}
void is31fl3741_IS31FL3741_collect_ptrs(is31fl3741_IS31FL3741_obj_t *self) {
gc_collect_ptr(self->framebuffer);
gc_collect_ptr(self->mapping);
}
// The following are routines to manipulate the IS31FL3741 chip
// They are not meant to be called by user code but only used
// internally.
uint8_t cur_page = 99; // set to invalid page to start
void is31fl3741_send_unlock(busio_i2c_obj_t *i2c, uint8_t addr) {
uint8_t unlock[2] = { 0xFE, 0xC5 }; // unlock command
common_hal_busio_i2c_write(i2c, addr, unlock, 2, true);
}
void is31fl3741_set_page(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t p) {
if (p == cur_page) {
return;
}
cur_page = p;
is31fl3741_send_unlock(i2c, addr);
uint8_t page[2] = { 0xFD, 0x00 }; // page command
page[1] = p;
common_hal_busio_i2c_write(i2c, addr, page, 2, true);
}
void is31fl3741_send_enable(busio_i2c_obj_t *i2c, uint8_t addr) {
is31fl3741_set_page(i2c, addr, 4);
uint8_t enable[2] = { 0x00, 0x01 }; // enable command
common_hal_busio_i2c_write(i2c, addr, enable, 2, true);
}
void is31fl3741_send_reset(busio_i2c_obj_t *i2c, uint8_t addr) {
is31fl3741_set_page(i2c, addr, 4);
uint8_t rst[2] = { 0x3F, 0xAE }; // reset command
common_hal_busio_i2c_write(i2c, addr, rst, 2, true);
}
void is31fl3741_set_current(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t current) {
is31fl3741_set_page(i2c, addr, 4);
uint8_t gcur[2] = { 0x01, 0x00 }; // global current command
gcur[1] = current;
common_hal_busio_i2c_write(i2c, addr, gcur, 2, true);
}
uint8_t is31fl3741_get_current(busio_i2c_obj_t *i2c, uint8_t addr) {
is31fl3741_set_page(i2c, addr, 4);
uint8_t gcur = 0x01; // global current command
common_hal_busio_i2c_write(i2c, addr, &gcur, 1, true);
uint8_t data = 0;
common_hal_busio_i2c_read(i2c, addr, &data, 1);
return data;
}
void is31fl3741_set_led(busio_i2c_obj_t *i2c, uint8_t addr, uint16_t led, uint8_t level, uint8_t page) {
uint8_t cmd[2] = { 0x00, 0x00 };
if (led < 180) {
is31fl3741_set_page(i2c, addr, page);
cmd[0] = (uint8_t)led;
} else {
is31fl3741_set_page(i2c, addr, page + 1);
cmd[0] = (uint8_t)(led - 180);
}
cmd[1] = level;
common_hal_busio_i2c_write(i2c, addr, cmd, 2, true);
}
void is31fl3741_draw_pixel(busio_i2c_obj_t *i2c, uint8_t addr, int16_t x, int16_t y, uint32_t color, uint16_t *mapping) {
uint8_t r = color >> 16 & 0xFF;
uint8_t g = color >> 8 & 0xFF;
uint8_t b = color & 0xFF;
int16_t x1 = (x * 5 + y) * 3;
uint16_t ridx = mapping[x1 + 2];
if (ridx != 65535) {
uint16_t gidx = mapping[x1 + 1];
uint16_t bidx = mapping[x1 + 0];
is31fl3741_set_led(i2c, addr, ridx, r, 0);
is31fl3741_set_led(i2c, addr, gidx, g, 0);
is31fl3741_set_led(i2c, addr, bidx, b, 0);
}
}

View File

@ -0,0 +1,69 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Mark Komus
*
* 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 "lib/protomatter/src/core.h"
#include "shared-bindings/busio/I2C.h"
extern const mp_obj_type_t is31fl3741_is31fl3741_type;
typedef struct {
mp_obj_base_t base;
mp_obj_t framebuffer;
mp_buffer_info_t bufinfo;
uint16_t bufsize, width, height, scale_width, scale_height;
busio_i2c_obj_t *i2c;
busio_i2c_obj_t inline_i2c;
uint8_t device_address;
uint16_t *mapping;
uint8_t bit_depth;
bool paused;
bool scale;
bool auto_gamma;
} is31fl3741_IS31FL3741_obj_t;
// Gamma correction table
static const uint8_t IS31GammaTable[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3,
3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6,
6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17,
17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 34, 34, 35,
36, 37, 38, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 80, 81,
82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 97, 99, 100, 102,
103, 105, 106, 108, 109, 111, 112, 114, 115, 117, 119, 120, 122, 124, 125,
127, 129, 130, 132, 134, 136, 137, 139, 141, 143, 145, 146, 148, 150, 152,
154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182,
184, 186, 188, 191, 193, 195, 197, 199, 202, 204, 206, 209, 211, 213, 215,
218, 220, 223, 225, 227, 230, 232, 235, 237, 240, 242, 245, 247, 250, 252,
255
};

View File

View File

View File

@ -0,0 +1,35 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Mark Komus
*
* 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 <stdbool.h>
#include "py/gc.h"
#include "py/misc.h"
#include "supervisor/memory.h"
extern void *common_hal_is31fl3741_allocator_impl(size_t sz);
extern void common_hal_is31fl3741_free_impl(void *);

View File

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

View File

@ -0,0 +1,18 @@
import bitmaptools
import displayio
import _bmp16
if "/" in __file__:
here = __file__.rsplit("/", 1)[0]
else:
here = "."
c = displayio.Colorspace.BGR565
b1 = _bmp16.loadbmp16(here + "/minerva16.bmp")
b3 = displayio.Bitmap(320, 240, 65536)
bitmaptools.dither(b3, b1, c)
_bmp16.writebmp16(f"dither-atkinson.bmp", b3)
bitmaptools.dither(b3, b1, c, bitmaptools.DitherAlgorithm.FloydStenberg)
_bmp16.writebmp16(f"dither-floydstenberg.bmp", b3)

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

View File

@ -1,31 +0,0 @@
import bitmaptools
import displayio
import _bmp16
if "/" in __file__:
here = __file__.rsplit("/", 1)[0]
else:
here = "."
c = displayio.Colorspace.BGR565
b1 = _bmp16.loadbmp16(here + "/minerva16.bmp")
b3 = displayio.Bitmap(320, 240, 65536)
for i in (
0,
1 / 64,
3 / 64,
3 / 32,
3 / 16,
0.5,
1 - 3 / 16,
1 - 3 / 32,
1 - 3 / 64,
1 - 1 / 64,
1,
):
bitmaptools.dither(b3, b1, c)
_bmp16.writebmp16(f"dither-atkinson.bmp", b3)
bitmaptools.dither(b3, b1, c, bitmaptools.DitherAlgorithm.FloydStenberg)
_bmp16.writebmp16(f"dither-floydstenberg.bmp", b3)