diff --git a/shared-bindings/is31fl3741/is31fl3741.c b/shared-bindings/is31fl3741/is31fl3741.c index b6ed81a634..2343fe5522 100644 --- a/shared-bindings/is31fl3741/is31fl3741.c +++ b/shared-bindings/is31fl3741/is31fl3741.c @@ -85,14 +85,14 @@ //| 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 }; + enum { ARG_width, ARG_height, ARG_i2c, ARG_addr, ARG_framebuffer, ARG_scale }; 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_scale, 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); @@ -106,6 +106,9 @@ STATIC mp_obj_t is31fl3741_is31fl3741_make_new(const mp_obj_type_t *type, size_t mp_raise_ValueError(translate("width must be greater than zero")); } + // TODO make sure height/width divisible by 3 + self->scale = args[ARG_scale].u_bool; + mp_obj_t framebuffer = args[ARG_framebuffer].u_obj; if (framebuffer == mp_const_none) { int width = args[ARG_width].u_int; diff --git a/shared-bindings/is31fl3741/is31fl3741.h b/shared-bindings/is31fl3741/is31fl3741.h index 172e0820a3..83cb3d0549 100644 --- a/shared-bindings/is31fl3741/is31fl3741.h +++ b/shared-bindings/is31fl3741/is31fl3741.h @@ -38,6 +38,9 @@ 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); @@ -46,6 +49,5 @@ bool common_hal_is31fl3741_is31fl3741_get_paused(is31fl3741_is31fl3741_obj_t *se 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 rgbmatrix_rgbmatrix_collect_ptrs(rgbmatrix_rgbmatrix_obj_t *); -*/ + +void is31fl3741_is31fl3741_collect_ptrs(is31fl3741_is31fl3741_obj_t *self); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index eff86b81df..ca181406d7 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -66,7 +66,7 @@ displayio_buffer_transform_t null_transform = { }; -#if CIRCUITPY_RGBMATRIX +#if CIRCUITPY_RGBMATRIX || CIRCUITPY_IS31FL3741 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].display_base.type == &framebufferio_framebufferdisplay_type) { @@ -143,6 +143,10 @@ void common_hal_displayio_release_displays(void) { } else if (bus_type == &rgbmatrix_RGBMatrix_type) { common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix); #endif + #if CIRCUITPY_IS31FL3741 + } else if (bus_type == &is31fl3741_is31fl3741_type) { + common_hal_is31fl3741_is31fl3741_deinit(&displays[i].is31fl3741); + #endif #if CIRCUITPY_SHARPDISPLAY } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { common_hal_sharpdisplay_framebuffer_deinit(&displays[i].sharpdisplay); @@ -217,6 +221,15 @@ void reset_displays(void) { common_hal_rgbmatrix_rgbmatrix_set_paused(pm, true); } #endif + #if CIRCUITPY_IS31FL3741 + } else if (displays[i].is31fl3741.base.type == &is31fl3741_is31fl3741_type) { + is31fl3741_is31fl3741_obj_t *pm = &displays[i].is31fl3741; + if (!any_display_uses_this_framebuffer(&pm->base)) { + common_hal_is31fl3741_is31fl3741_deinit(pm); + } else { + common_hal_is31fl3741_is31fl3741_set_paused(pm, true); + } + #endif #if CIRCUITPY_SHARPDISPLAY } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { sharpdisplay_framebuffer_obj_t *sharp = &displays[i].sharpdisplay; @@ -251,6 +264,11 @@ void displayio_gc_collect(void) { rgbmatrix_rgbmatrix_collect_ptrs(&displays[i].rgbmatrix); } #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 (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { common_hal_sharpdisplay_framebuffer_collect_ptrs(&displays[i].sharpdisplay); diff --git a/shared-module/is31fl3741/is31fl3741.c b/shared-module/is31fl3741/is31fl3741.c index b3fca18d03..b4a96c9acd 100644 --- a/shared-module/is31fl3741/is31fl3741.c +++ b/shared-module/is31fl3741/is31fl3741.c @@ -47,10 +47,7 @@ uint8_t cur_page = 99; void send_unlock(busio_i2c_obj_t *i2c, uint8_t addr) { uint8_t unlock[2] = { 0xFE, 0xC5 }; // unlock command - uint8_t result = common_hal_busio_i2c_write(i2c, addr, unlock, 2, true); - if (result != 0) { - mp_printf(&mp_plat_print, "Unlock error %x\n", result); - } + common_hal_busio_i2c_write(i2c, addr, unlock, 2, true); } void set_page(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t p) { @@ -63,55 +60,35 @@ void set_page(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t p) { uint8_t page[2] = { 0xFD, 0x00 }; // page command page[1] = p; - uint8_t result = common_hal_busio_i2c_write(i2c, addr, page, 2, true); - if (result != 0) { - mp_printf(&mp_plat_print, "Set Page error %x\n", result); - } + common_hal_busio_i2c_write(i2c, addr, page, 2, true); } void send_enable(busio_i2c_obj_t *i2c, uint8_t addr) { set_page(i2c, addr, 4); uint8_t enable[2] = { 0x00, 0x01 }; // enable command - uint8_t result = common_hal_busio_i2c_write(i2c, addr, enable, 2, true); - if (result != 0) { - mp_printf(&mp_plat_print, "Enable error %x\n", result); - } + common_hal_busio_i2c_write(i2c, addr, enable, 2, true); } void send_reset(busio_i2c_obj_t *i2c, uint8_t addr) { set_page(i2c, addr, 4); uint8_t rst[2] = { 0x3F, 0xAE }; // reset command - uint8_t result = common_hal_busio_i2c_write(i2c, addr, rst, 2, true); - if (result != 0) { - mp_printf(&mp_plat_print, "reset error %x\n", result); - } + common_hal_busio_i2c_write(i2c, addr, rst, 2, true); } void set_current(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t current) { set_page(i2c, addr, 4); uint8_t gcur[2] = { 0x01, 0x00 }; // global current command gcur[1] = current; - uint8_t result = common_hal_busio_i2c_write(i2c, addr, gcur, 2, true); - if (result != 0) { - mp_printf(&mp_plat_print, "set current error %x\n", result); - } + common_hal_busio_i2c_write(i2c, addr, gcur, 2, true); } uint8_t get_current(busio_i2c_obj_t *i2c, uint8_t addr) { set_page(i2c, addr, 4); uint8_t gcur = 0x01; // global current command - - uint8_t result = common_hal_busio_i2c_write(i2c, addr, &gcur, 1, true); - if (result != 0) { - mp_printf(&mp_plat_print, "get current error %x\n", result); - } + common_hal_busio_i2c_write(i2c, addr, &gcur, 1, true); uint8_t data = 0; - result = common_hal_busio_i2c_read(i2c, addr, &data, 1); - if (result != 0) { - mp_printf(&mp_plat_print, "get current error %x\n", result); - } - + common_hal_busio_i2c_read(i2c, addr, &data, 1); return data; } @@ -129,10 +106,7 @@ void set_led(busio_i2c_obj_t *i2c, uint8_t addr, uint16_t led, uint8_t level, ui cmd[1] = level; - uint8_t result = common_hal_busio_i2c_write(i2c, addr, cmd, 2, true); - if (result != 0) { - mp_printf(&mp_plat_print, "set led error %x\n", result); - } + common_hal_busio_i2c_write(i2c, addr, cmd, 2, true); } void drawPixel(busio_i2c_obj_t *i2c, uint8_t addr, int16_t x, int16_t y, uint32_t color) { @@ -168,7 +142,7 @@ void common_hal_is31fl3741_is31fl3741_construct(is31fl3741_is31fl3741_obj_t *sel common_hal_is31fl3741_is31fl3741_reconstruct(self, framebuffer); - common_hal_busio_i2c_try_lock(i2c); + common_hal_displayio_is31fl3741_begin_transaction(self); uint8_t command = 0xFC; common_hal_busio_i2c_write(i2c, addr, &command, 1, false); @@ -184,7 +158,7 @@ void common_hal_is31fl3741_is31fl3741_construct(is31fl3741_is31fl3741_obj_t *sel set_led(i2c, addr, i, 0xFF, 2); } - common_hal_busio_i2c_unlock(i2c); + common_hal_displayio_is31fl3741_end_transaction(self); } void common_hal_is31fl3741_is31fl3741_reconstruct(is31fl3741_is31fl3741_obj_t *self, mp_obj_t framebuffer) { @@ -210,69 +184,12 @@ void common_hal_is31fl3741_is31fl3741_reconstruct(is31fl3741_is31fl3741_obj_t *s self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW; } -/* - memset(&self->protomatter, 0, sizeof(self->protomatter)); - ProtomatterStatus stat = _PM_init(&self->protomatter, - self->width, self->bit_depth, - self->rgb_count / 6, self->rgb_pins, - self->addr_count, self->addr_pins, - self->clock_pin, self->latch_pin, self->oe_pin, - self->doublebuffer, self->serpentine ? -self->tile : self->tile, - self->timer); + // initialize LEDs here - if (stat == PROTOMATTER_OK) { - _PM_protoPtr = &self->protomatter; - common_hal_is31fl3741_timer_enable(self->timer); - stat = _PM_begin(&self->protomatter); - - if (stat == PROTOMATTER_OK) { - _PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width); - _PM_swapbuffer_maybe(&self->protomatter); - } - } - - if (stat != PROTOMATTER_OK) { - common_hal_is31fl3741_is31fl3741_deinit(self); - switch (stat) { - case PROTOMATTER_ERR_PINS: - mp_raise_ValueError(translate("Invalid pin")); - break; - case PROTOMATTER_ERR_ARG: - mp_raise_ValueError(translate("Invalid argument")); - break; - case PROTOMATTER_ERR_MALLOC: - mp_raise_msg(&mp_type_MemoryError, NULL); - break; - default: - mp_raise_msg_varg(&mp_type_RuntimeError, - translate("Internal error #%d"), (int)stat); - break; - } - } -*/ self->paused = 0; } void common_hal_is31fl3741_is31fl3741_deinit(is31fl3741_is31fl3741_obj_t *self) { - /* - if (self->timer) { - common_hal_is31fl3741_timer_free(self->timer); - self->timer = 0; - } - - if (_PM_protoPtr == &self->protomatter) { - _PM_protoPtr = NULL; - } - - if (self->protomatter.rgbPins) { - _PM_deallocate(&self->protomatter); - } - memset(&self->protomatter, 0, sizeof(self->protomatter)); - - // If it was supervisor-allocated, it is supervisor-freed and the pointer - // is zeroed, otherwise the pointer is just zeroed - _PM_free(self->bufinfo.buf); - */ self->base.type = NULL; // If a framebuffer was passed in to the constructor, NULL the reference @@ -289,30 +206,67 @@ bool common_hal_is31fl3741_is31fl3741_get_paused(is31fl3741_is31fl3741_obj_t *se } void common_hal_is31fl3741_is31fl3741_set_global_current(is31fl3741_is31fl3741_obj_t *self, uint8_t current) { + common_hal_displayio_is31fl3741_begin_transaction(self); 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) { - return get_current(self->i2c, self->device_address); + common_hal_displayio_is31fl3741_begin_transaction(self); + uint8_t current = 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) { - uint8_t dirty_row_flags = 0xFF; + common_hal_displayio_is31fl3741_begin_transaction(self); + + uint8_t dirty_row_flags = 0xFF; // only supports 8 rows gotta fix if (dirtyrows != 0) { dirty_row_flags = *dirtyrows; } if (!self->paused) { - uint32_t *buffer = self->bufinfo.buf; - for (int y = 0; y < 5; y++) { - if ((dirty_row_flags >> y) & 0x1) { - for (int x = 0; x < 18; x++) { - drawPixel(self->i2c, self->device_address, x, y, *buffer); - buffer++; + if (self->scale) { + uint32_t *buffer = self->bufinfo.buf; + + for (int x = 0; x < 18; x++) { + uint32_t *ptr = &buffer[x * 3]; // Entry along top scan line w/x offset + for (int y = 0; y < 5; 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 += 54; // canvas->width(); // Advance one scan line + } + rsum = rsum / 9; + gsum = gsum / 9; + bsum = bsum / 9; + uint32_t color = (IS31GammaTable[rsum] << 16) + + (IS31GammaTable[gsum] << 8) + + (IS31GammaTable[bsum] / 9); + drawPixel(self->i2c, self->device_address, x, y, color); + } + } + } else { + uint32_t *buffer = self->bufinfo.buf; + for (int y = 0; y < self->height; y++) { + if ((dirty_row_flags >> y) & 0x1) { + for (int x = 0; x < self->width; x++) { + drawPixel(self->i2c, self->device_address, x, y, *buffer); + buffer++; + } } } } } + + common_hal_displayio_is31fl3741_end_transaction(self); } int common_hal_is31fl3741_is31fl3741_get_width(is31fl3741_is31fl3741_obj_t *self) { @@ -323,6 +277,16 @@ int common_hal_is31fl3741_is31fl3741_get_height(is31fl3741_is31fl3741_obj_t *sel 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; + } +} + +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; @@ -331,3 +295,7 @@ void *common_hal_is31fl3741_allocator_impl(size_t sz) { 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); +} diff --git a/shared-module/is31fl3741/is31fl3741.h b/shared-module/is31fl3741/is31fl3741.h index 280192e0d4..19471187fa 100644 --- a/shared-module/is31fl3741/is31fl3741.h +++ b/shared-module/is31fl3741/is31fl3741.h @@ -41,6 +41,7 @@ typedef struct { uint8_t bit_depth; bool paused; bool doublebuffer; + bool scale; } is31fl3741_is31fl3741_obj_t; static const uint16_t glassesmatrix_ledmap[18 * 5 * 3] = { @@ -135,3 +136,24 @@ static const uint16_t glassesmatrix_ledmap[18 * 5 * 3] = { 23, 25, 24, // (17,3) / 6 276, 22, 277, // (17,4) / 7 }; + +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 +};