From eaf8bc0abe323c7ee2c0ee855eb191718bf14f6d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 29 Oct 2021 14:01:47 -0500 Subject: [PATCH 1/5] bitmaptools: add dither This can convert a BGR565_SWAPPED bitmap to B&W in about 82ms on esp32-s2. --- locale/circuitpython.pot | 20 +++ shared-bindings/bitmaptools/__init__.c | 90 ++++++++++- shared-bindings/bitmaptools/__init__.h | 9 ++ shared-module/bitmaptools/__init__.c | 201 ++++++++++++++++++++++++- 4 files changed, 317 insertions(+), 3 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index e39fef97e7..79b0464e3d 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -2611,6 +2611,10 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" +msgstr "" + #: extmod/modurandom.c msgid "bits must be 32 or less" msgstr "" @@ -4102,6 +4106,18 @@ msgstr "" msgid "source palette too large" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" +msgstr "" + #: py/objstr.c msgid "start/end indices" msgstr "" @@ -4350,6 +4366,10 @@ msgstr "" msgid "unsupported colorspace for GifWriter" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" +msgstr "" + #: py/objstr.c #, c-format msgid "unsupported format character '%c' (0x%x) at index %d" diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c index ad814e8881..69e2a35b01 100644 --- a/shared-bindings/bitmaptools/__init__.c +++ b/shared-bindings/bitmaptools/__init__.c @@ -25,11 +25,14 @@ */ #include "shared-bindings/displayio/Bitmap.h" +#include "shared-bindings/displayio/Palette.h" +#include "shared-bindings/displayio/ColorConverter.h" #include "shared-bindings/bitmaptools/__init__.h" #include #include "py/binary.h" +#include "py/enum.h" #include "py/obj.h" #include "py/runtime.h" @@ -565,9 +568,92 @@ STATIC mp_obj_t bitmaptools_readinto(size_t n_args, const mp_obj_t *pos_args, mp return mp_const_none; } - MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_readinto_obj, 0, bitmaptools_readinto); +//| class DitherAlgorithm: +//| """Identifies the algorith for dither to use""" +//| +//| Atkinson: object +//| """The classic Atkinson dither, often associated with the Hypercard esthetic""" +//| +//| FloydStenberg: object +//| """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, FloydStenberg, DITHER_ALGORITHM_ATKINSON); + +MAKE_ENUM_MAP(bitmaptools_dither_algorithm) { + MAKE_ENUM_MAP_ENTRY(dither_algorithm, Atkinson), + MAKE_ENUM_MAP_ENTRY(dither_algorithm, FloydStenberg), +}; +STATIC MP_DEFINE_CONST_DICT(bitmaptools_dither_algorithm_locals_dict, bitmaptools_dither_algorithm_locals_table); + +MAKE_PRINTER(bitmaptools, bitmaptools_dither_algorithm); + +MAKE_ENUM_TYPE(bitmaptools, DitherAlgorithm, bitmaptools_dither_algorithm); + +//| def dither(dest_bitmap: displayio.Bitmap, source_bitmapp: displayio.Bitmap, source_colorspace: displayio.Colorspace, algorithm: DitherAlgorithm=DitherAlgorithm.Atkinson) -> None: +//| """Convert the input image into a 2-level output image using the given dither algorithm. +//| +//| :param bitmap dest_bitmap: Destination bitmap. It must have a value_count of 2 or 65536. The stored values are 0 and the maximum pixel value. +//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be dithered. It must have a value_count of 65536. +//| :param colorspace: The colorspace of the image. The supported colorspaces are ``RGB565``, ``BGR565``, ``RGB565_SWAPPED``, and ``BGR565_SWAPPED`` +//| :param algorithm: The dither algorithm to use, one of the `DitherAlgorithm `values. +//| """ +//| ... +//| +STATIC mp_obj_t bitmaptools_dither(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_dest_bitmap, ARG_source_bitmap, ARG_source_colorspace, ARG_algorithm }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_source_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_algorithm, MP_ARG_OBJ, { .u_obj = MP_ROM_PTR((void *)&dither_algorithm_Atkinson_obj) } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + displayio_bitmap_t *source_bitmap = mp_arg_validate_type(args[ARG_source_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap); + displayio_bitmap_t *dest_bitmap = mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap); + bitmaptools_dither_algorithm_t algorithm = cp_enum_value(&bitmaptools_dither_algorithm_type, args[ARG_algorithm].u_obj); + displayio_colorspace_t colorspace = cp_enum_value(&displayio_colorspace_type, args[ARG_source_colorspace].u_obj); + + if (source_bitmap->width != dest_bitmap->width || source_bitmap->height != dest_bitmap->height) { + mp_raise_TypeError(translate("bitmap sizes must match")); + } + + if (dest_bitmap->bits_per_value != 16 && dest_bitmap->bits_per_value != 1) { + mp_raise_TypeError(translate("source_bitmap must have value_count of 2 or 65536")); + } + + + switch (colorspace) { + case DISPLAYIO_COLORSPACE_RGB565: + case DISPLAYIO_COLORSPACE_RGB565_SWAPPED: + case DISPLAYIO_COLORSPACE_BGR565: + case DISPLAYIO_COLORSPACE_BGR565_SWAPPED: + if (source_bitmap->bits_per_value != 16) { + mp_raise_TypeError(translate("source_bitmap must have value_count of 65536")); + } + break; + + case DISPLAYIO_COLORSPACE_L8: + if (source_bitmap->bits_per_value != 8) { + mp_raise_TypeError(translate("source_bitmap must have value_count of 8")); + } + break; + + default: + mp_raise_TypeError(translate("unsupported colorspace for dither")); + } + + + common_hal_bitmaptools_dither(dest_bitmap, source_bitmap, colorspace, algorithm); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_dither_obj, 0, bitmaptools_dither); + + STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bitmaptools) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitmaptools_readinto_obj) }, @@ -576,6 +662,8 @@ STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) }, { MP_ROM_QSTR(MP_QSTR_boundary_fill), MP_ROM_PTR(&bitmaptools_boundary_fill_obj) }, { MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&bitmaptools_dither_obj) }, + { MP_ROM_QSTR(MP_QSTR_DitherAlgorithm), MP_ROM_PTR(&bitmaptools_dither_algorithm_type) }, }; STATIC MP_DEFINE_CONST_DICT(bitmaptools_module_globals, bitmaptools_module_globals_table); diff --git a/shared-bindings/bitmaptools/__init__.h b/shared-bindings/bitmaptools/__init__.h index 6415b20258..fb9d783e55 100644 --- a/shared-bindings/bitmaptools/__init__.h +++ b/shared-bindings/bitmaptools/__init__.h @@ -28,9 +28,17 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H #include "shared-module/displayio/Bitmap.h" +#include "shared-module/displayio/Palette.h" +#include "shared-bindings/displayio/ColorConverter.h" #include "py/obj.h" #include "extmod/vfs_fat.h" +typedef enum { + DITHER_ALGORITHM_ATKINSON, DITHER_ALGORITHM_FLOYD_STENBERG, +} bitmaptools_dither_algorithm_t; + +extern const mp_obj_type_t bitmaptools_dither_algorithm_type; + void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16_t oy, int16_t dest_clip0_x, int16_t dest_clip0_y, int16_t dest_clip1_x, int16_t dest_clip1_y, @@ -57,5 +65,6 @@ void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination, void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, pyb_file_obj_t *file, int element_size, int bits_per_pixel, bool reverse_pixels_in_word, bool swap_bytes, bool reverse_rows); void common_hal_bitmaptools_arrayblit(displayio_bitmap_t *self, void *data, int element_size, int x1, int y1, int x2, int y2, bool skip_specified, uint32_t skip_index); +void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bitmap_t *source_bitmap, displayio_colorspace_t colorspace, bitmaptools_dither_algorithm_t algorithm); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H diff --git a/shared-module/bitmaptools/__init__.c b/shared-module/bitmaptools/__init__.c index b6e0764fdb..c75bc599cb 100644 --- a/shared-module/bitmaptools/__init__.c +++ b/shared-module/bitmaptools/__init__.c @@ -26,13 +26,17 @@ #include "shared-bindings/bitmaptools/__init__.h" #include "shared-bindings/displayio/Bitmap.h" +#include "shared-bindings/displayio/Palette.h" +#include "shared-bindings/displayio/ColorConverter.h" #include "shared-module/displayio/Bitmap.h" #include "py/runtime.h" #include "py/mperrno.h" -#include "math.h" -#include "stdlib.h" +#include +#include +#include +#include void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16_t oy, int16_t dest_clip0_x, int16_t dest_clip0_y, @@ -602,3 +606,196 @@ void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, pyb_file_obj_t *f } } } + +typedef struct { + uint8_t count; // The number of items in terms[] + uint8_t mx; // the maximum of the absolute value of the dx values + uint8_t dl; // the scaled dither value applied to the pixel at distance [1,0] + struct { // dl is the scaled dither values applied to the pixel at [dx,dy] + int8_t dx, dy, dl; + } terms[]; +} bitmaptools_dither_algorithm_info_t; + +static bitmaptools_dither_algorithm_info_t atkinson = { + 4, 2, 256 / 8, { + {2, 0, 256 / 8}, + {-1, 1, 256 / 8}, + {0, 1, 256 / 8}, + {0, 2, 256 / 8}, + } +}; + +static bitmaptools_dither_algorithm_info_t floyd_stenberg = { + 3, 1, 7 * 256 / 16, + { + {-1, 1, 3 * 256 / 16}, + {0, 1, 5 * 256 / 16}, + {1, 1, 1 * 256 / 16}, + } +}; + +bitmaptools_dither_algorithm_info_t *algorithms[] = { + [DITHER_ALGORITHM_ATKINSON] = &atkinson, + [DITHER_ALGORITHM_FLOYD_STENBERG] = &floyd_stenberg, +}; + +enum { + SWAP_BYTES = 1 << 0, + SWAP_RB = 1 << 1, +}; + +STATIC void fill_row(displayio_bitmap_t *bitmap, int swap, int16_t *luminance_data, int y, int mx) { + if (y >= bitmap->height) { + return; + } + + // zero out padding area + for (int i = 0; i < mx; i++) { + luminance_data[-mx + i] = 0; + luminance_data[bitmap->width + i] = 0; + } + + if (bitmap->bits_per_value == 8) { + uint8_t *pixel_data = (uint8_t *)(bitmap->data + bitmap->stride * y); + for (int x = 0; x < bitmap->width; x++) { + *luminance_data++ = *pixel_data++; + } + } else { + uint16_t *pixel_data = (uint16_t *)(bitmap->data + bitmap->stride * y); + for (int x = 0; x < bitmap->width; x++) { + uint16_t pixel = *pixel_data++; + if (swap & SWAP_BYTES) { + pixel = __builtin_bswap16(pixel); + } + int r = (pixel >> 8) & 0xf8; + int g = (pixel >> 3) & 0xfc; + int b = (pixel << 3) & 0xf8; + + if (swap & SWAP_RB) { + uint8_t tmp = r; + r = b; + b = tmp; + } + + // ideal coefficients are around .299, .587, .114 (according to + // ppmtopnm), this differs from the 'other' luma-converting + // function in circuitpython (why?) + + // we correct for the fact that the input ranges are 0..0xf8 (or + // 0xfc) rather than 0x00..0xff + // Check: (0xf8 * 78 + 0xfc * 154 + 0xf8 * 29) // 256 == 255 + *luminance_data++ = (r * 78 + g * 154 + b * 29) / 256; + } + } +} + +static void write_pixels(displayio_bitmap_t *bitmap, int y, bool *data) { + if (bitmap->bits_per_value == 1) { + uint32_t *pixel_data = (uint32_t *)(bitmap->data + bitmap->stride * y); + for (int i = 0; i < bitmap->stride; i++) { + uint32_t p = 0; + for (int j = 0; j < 32; i++) { + p = (p << 1); + if (*data++) { + p |= 1; + } + } + *pixel_data++ = p; + } + } else { + uint16_t *pixel_data = (uint16_t *)(bitmap->data + bitmap->stride * y); + for (int i = 0; i < bitmap->width; i++) { + *pixel_data++ = *data++ ? 65535 : 0; + } + } +} + +void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bitmap_t *source_bitmap, displayio_colorspace_t colorspace, bitmaptools_dither_algorithm_t algorithm) { + int height = dest_bitmap->height, width = dest_bitmap->width; + + int swap = 0; + if (colorspace == DISPLAYIO_COLORSPACE_RGB565_SWAPPED || colorspace == DISPLAYIO_COLORSPACE_BGR565_SWAPPED) { + swap |= SWAP_BYTES; + } + if (colorspace == DISPLAYIO_COLORSPACE_BGR565 || colorspace == DISPLAYIO_COLORSPACE_BGR565_SWAPPED) { + swap |= SWAP_RB; + } + + bitmaptools_dither_algorithm_info_t *info = algorithms[algorithm]; + // rowdata holds 3 rows of data. Each one is larger than the input + // bitmap's width, beacuse `mx` extra pixels are allocated at the start and + // end of the row so that no conditionals are needed when storing the error data. + int16_t rowdata[(width + 2 * info->mx) * 3]; + int16_t *rows[3] = { + rowdata + info->mx, rowdata + width + info->mx * 3, rowdata + 2 * width + info->mx * 5 + }; + // out holds one output row of pixels, and is padded to be a multiple of 32 so that the 1bpp storage loop can be simplified + bool out[(width + 31) / 32 * 32]; + + fill_row(source_bitmap, swap, rows[0], 0, info->mx); + fill_row(source_bitmap, swap, rows[1], 1, info->mx); + fill_row(source_bitmap, swap, rows[2], 2, info->mx); + + int16_t err = 0; + + for (int y = 0; y < height; y++) { + + // Serpentine dither. Going left-to-right... + for (int x = 0; x < width; x++) { + int32_t pixel_in = rows[0][x] + err; + bool pixel_out = pixel_in >= 128; + out[x] = pixel_out; + + err = pixel_in - (pixel_out ? 255 : 0); + + for (int i = 0; i < info->count; i++) { + int x1 = x + info->terms[i].dx; + int dy = info->terms[i].dy; + + rows[dy][x1] = ((info->terms[i].dl * err) >> 8) + rows[dy][x1]; + } + err = err * info->dl >> 8; + } + write_pixels(dest_bitmap, y, out); + + // Cycle the rows by shuffling pointers, this is faster than copying the data. + int16_t *tmp = rows[0]; + rows[0] = rows[1]; + rows[1] = rows[2]; + rows[2] = tmp; + + fill_row(source_bitmap, swap, rows[2], y + 2, info->mx); + + y++; + if (y == height) { + break; + } + + // Serpentine dither. Going right-to-left... + for (int x = width; x--;) { + int16_t pixel_in = rows[0][x] + err; + bool pixel_out = pixel_in >= 128; + out[x] = pixel_out; + err = pixel_in - (pixel_out ? 255 : 0); + + for (int i = 0; i < info->count; i++) { + int x1 = x - info->terms[i].dx; + int dy = info->terms[i].dy; + + rows[dy][x1] = ((info->terms[i].dl * err) >> 8) + rows[dy][x1]; + } + err = err * info->dl >> 8; + } + write_pixels(dest_bitmap, y, out); + + tmp = rows[0]; + rows[0] = rows[1]; + rows[1] = rows[2]; + rows[2] = tmp; + + fill_row(source_bitmap, swap, rows[2], y + 2, info->mx); + } + + displayio_area_t a = { 0, 0, width, height }; + displayio_bitmap_set_dirty_area(dest_bitmap, &a); +} From b453d18579e1cfb53268bf1f423098d04cd1987c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 8 Nov 2021 10:36:39 -0600 Subject: [PATCH 2/5] ColorConverter: fix a docstring --- shared-bindings/displayio/ColorConverter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index 2f40d8bd36..f2ca006ced 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -39,7 +39,7 @@ //| class ColorConverter: //| """Converts one color format to another.""" //| -//| def __init__(self, *, colorspace: Colorspace=Colorspace.RGB888, dither: bool = False) -> None: +//| def __init__(self, *, input_colorspace: Colorspace=Colorspace.RGB888, dither: bool = False) -> None: //| """Create a ColorConverter object to convert color formats. //| //| :param Colorspace colorspace: The source colorspace, one of the Colorspace constants From 6351de6ad11c97a5d3e66493fb0572bbbc2a62c1 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 8 Nov 2021 10:38:05 -0600 Subject: [PATCH 3/5] espressif: Allow -DENABLE_JTAG=0 to force JTAG off With the Kaluga devkit, the camera interferes with the JTAG function. However, having DEBUG turned on e.g., to get extended debug information on the UART debug connection remains useful. Now, by arranging to add to CFLAGS += -DDEBUG -DENABLE_JTAG=0, this configuration is easy to achieve. --- ports/espressif/supervisor/port.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 2aa9bdef4f..7425bb615e 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -127,7 +127,11 @@ safe_mode_t port_init(void) { heap = NULL; never_reset_module_internal_pins(); - #if defined(DEBUG) + #ifndef DEBUG + #define DEBUG (0) + #endif + + #if DEBUG // debug UART #ifdef CONFIG_IDF_TARGET_ESP32C3 common_hal_never_reset_pin(&pin_GPIO20); @@ -138,7 +142,11 @@ safe_mode_t port_init(void) { #endif #endif - #if defined(DEBUG) || defined(ENABLE_JTAG) + #ifndef ENABLE_JTAG + #define ENABLE_JTAG (defined(DEBUG) && DEBUG) + #endif + + #if ENABLE_JTAG // JTAG #ifdef CONFIG_IDF_TARGET_ESP32C3 common_hal_never_reset_pin(&pin_GPIO4); From ff9b10c7b62b9a96a9b73e01095a293103a1045f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 8 Nov 2021 16:46:44 -0600 Subject: [PATCH 4/5] fix doc build problems --- shared-bindings/bitmaptools/__init__.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c index 9268d56d77..99039ba1ba 100644 --- a/shared-bindings/bitmaptools/__init__.c +++ b/shared-bindings/bitmaptools/__init__.c @@ -650,10 +650,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_readinto_obj, 0, bitmaptools_readinto); //| class DitherAlgorithm: //| """Identifies the algorith for dither to use""" //| -//| Atkinson: object +//| Atkinson: "DitherAlgorithm" //| """The classic Atkinson dither, often associated with the Hypercard esthetic""" //| -//| FloydStenberg: object +//| FloydStenberg: "DitherAlgorithm" //| """The Floyd-Stenberg dither""" //| MAKE_ENUM_VALUE(bitmaptools_dither_algorithm_type, dither_algorithm, Atkinson, DITHER_ALGORITHM_ATKINSON); @@ -675,7 +675,7 @@ MAKE_ENUM_TYPE(bitmaptools, DitherAlgorithm, bitmaptools_dither_algorithm); //| :param bitmap dest_bitmap: Destination bitmap. It must have a value_count of 2 or 65536. The stored values are 0 and the maximum pixel value. //| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be dithered. It must have a value_count of 65536. //| :param colorspace: The colorspace of the image. The supported colorspaces are ``RGB565``, ``BGR565``, ``RGB565_SWAPPED``, and ``BGR565_SWAPPED`` -//| :param algorithm: The dither algorithm to use, one of the `DitherAlgorithm `values. +//| :param algorithm: The dither algorithm to use, one of the `DitherAlgorithm` values. //| """ //| ... //| From 20cbd5e635bc8f045f743b67716c50284859431b Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 8 Nov 2021 18:58:33 -0600 Subject: [PATCH 5/5] Disable bitmapio on some boards where it no longer fits --- ports/stm/boards/meowbit_v121/mpconfigboard.mk | 1 + ports/stm/boards/thunderpack_v12/mpconfigboard.mk | 1 + 2 files changed, 2 insertions(+) diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.mk b/ports/stm/boards/meowbit_v121/mpconfigboard.mk index 589f0bce10..15ae33c4c8 100644 --- a/ports/stm/boards/meowbit_v121/mpconfigboard.mk +++ b/ports/stm/boards/meowbit_v121/mpconfigboard.mk @@ -21,6 +21,7 @@ LD_FILE = boards/STM32F401xe_boot.ld # LD_FILE = boards/STM32F401xe_fs.ld CIRCUITPY_AESIO = 0 +CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_GIFIO = 0 CIRCUITPY_ULAB = 0 diff --git a/ports/stm/boards/thunderpack_v12/mpconfigboard.mk b/ports/stm/boards/thunderpack_v12/mpconfigboard.mk index 1c09fe64c1..16a0c60f2a 100644 --- a/ports/stm/boards/thunderpack_v12/mpconfigboard.mk +++ b/ports/stm/boards/thunderpack_v12/mpconfigboard.mk @@ -12,6 +12,7 @@ SPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = GD25Q16C CIRCUITPY_NVM = 1 +CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_BLEIO_HCI = 0 MCU_SERIES = F4