From 9fafd7d7fdb979d889cdfffb0314693badaa1d0f Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Sat, 4 Dec 2021 12:16:35 -0600 Subject: [PATCH] Initial commit --- locale/circuitpython.pot | 4 ++ shared-bindings/is31fl3741/__init__.c | 80 +++++++++++++++++++++++++++ shared-bindings/is31fl3741/__init__.h | 40 ++++++++++++++ shared-module/is31fl3741/IS31FL3741.c | 11 ++-- shared-module/is31fl3741/__init__.c | 74 +++++++++++++++++++++++++ 5 files changed, 202 insertions(+), 7 deletions(-) create mode 100644 shared-bindings/is31fl3741/__init__.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 835ef9538b..5047615abf 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1490,6 +1490,10 @@ msgstr "" msgid "MOSI pin init failed." msgstr "" +#: shared-bindings/is31fl3741/__init__.c +msgid "Mapping must be a tuple" +msgstr "" + #: shared-module/displayio/Shape.c #, c-format msgid "Maximum x value when mirrored is %d" diff --git a/shared-bindings/is31fl3741/__init__.c b/shared-bindings/is31fl3741/__init__.c index 90b9426a4d..c1e127aecc 100644 --- a/shared-bindings/is31fl3741/__init__.c +++ b/shared-bindings/is31fl3741/__init__.c @@ -24,16 +24,96 @@ * THE SOFTWARE. */ +#include "shared-bindings/is31fl3741/__init__.h" + #include +#include #include "py/obj.h" #include "py/runtime.h" +#include "shared-bindings/busio/I2C.h" #include "shared-bindings/is31fl3741/IS31FL3741.h" + +//| """Low-level neopixel implementation +//| +//| The `neopixel_write` module contains a helper method to write out bytes in +//| the 800khz neopixel protocol. +//| +//| For example, to turn off a single neopixel (like the status pixel on Express +//| boards.) +//| +//| .. code-block:: python +//| +//| import board +//| import neopixel_write +//| import digitalio +//| +//| pin = digitalio.DigitalInOut(board.NEOPIXEL) +//| pin.direction = digitalio.Direction.OUTPUT +//| pixel_off = bytearray([0, 0, 0]) +//| neopixel_write.neopixel_write(pin, pixel_off)""" +//| +//| def neopixel_write(digitalinout: digitalio.DigitalInOut, buf: ReadableBuffer) -> None: +//| """Write buf out on the given DigitalInOut. +//| +//| :param ~digitalio.DigitalInOut digitalinout: the DigitalInOut to output with +//| :param ~_typing.ReadableBuffer buf: The bytes to clock out. No assumption is made about color order""" +//| ... +// STATIC mp_obj_t is31fl3741_is31fl3741_write(mp_obj_t i2c_obj, mp_obj_t device_addr_obj, mp_obj_t mapping, mp_obj_t buf) { +STATIC mp_obj_t is31fl3741_is31fl3741_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_i2c, ARG_addr, ARG_mapping, ARG_buffer }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x30 } }, + { MP_QSTR_mapping, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_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); + + mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus); + + if (!mp_obj_is_tuple_compatible(args[ARG_mapping].u_obj)) { + mp_raise_ValueError(translate("Mapping must be a tuple")); + } + + mp_obj_t *map_items; + size_t map_len; + mp_obj_tuple_get(args[ARG_mapping].u_obj, &map_len, &map_items); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); + + common_hal_is31fl3741_write(i2c, args[ARG_addr].u_int, map_items, (uint8_t *)bufinfo.buf, bufinfo.len); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(is31fl3741_is31fl3741_write_obj, 0, is31fl3741_is31fl3741_write); + +STATIC mp_obj_t is31fl3741_is31fl3741_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_i2c, ARG_addr }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x30 } }, + }; + + 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); + + mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus); + + common_hal_is31fl3741_init(i2c, args[ARG_addr].u_int); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(is31fl3741_is31fl3741_init_obj, 0, is31fl3741_is31fl3741_init); + 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) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_is31fl3741_init), (mp_obj_t)&is31fl3741_is31fl3741_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_is31fl3741_write), (mp_obj_t)&is31fl3741_is31fl3741_write_obj }, }; STATIC MP_DEFINE_CONST_DICT(is31fl3741_module_globals, is31fl3741_module_globals_table); diff --git a/shared-bindings/is31fl3741/__init__.h b/shared-bindings/is31fl3741/__init__.h new file mode 100644 index 0000000000..ba5c734f14 --- /dev/null +++ b/shared-bindings/is31fl3741/__init__.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_NEOPIXEL_WRITE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_NEOPIXEL_WRITE_H + +#include +#include + +#include "shared-bindings/busio/I2C.h" + +extern void common_hal_is31fl3741_init(busio_i2c_obj_t *i2c, uint8_t addr); +extern void common_hal_is31fl3741_write(busio_i2c_obj_t *i2c, uint8_t addr, const mp_obj_t *mapping, const uint8_t *pixels, size_t numBytes); +void begin_transaction(busio_i2c_obj_t *i2c); +void end_transaction(busio_i2c_obj_t *i2c); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_NEOPIXEL_WRITE_H diff --git a/shared-module/is31fl3741/IS31FL3741.c b/shared-module/is31fl3741/IS31FL3741.c index 9d7316e1cd..ae27100694 100644 --- a/shared-module/is31fl3741/IS31FL3741.c +++ b/shared-module/is31fl3741/IS31FL3741.c @@ -115,7 +115,7 @@ void common_hal_is31fl3741_IS31FL3741_reconstruct(is31fl3741_IS31FL3741_obj_t *s is31fl3741_set_current(self->i2c, self->device_address, 0xFF); // set scale (brightness) to max for all LEDs - for (int i; i < 351; i++) { + for (int i = 0; i < 351; i++) { is31fl3741_set_led(self->i2c, self->device_address, i, 0xFF, 2); } @@ -267,11 +267,8 @@ void is31fl3741_IS31FL3741_collect_ptrs(is31fl3741_IS31FL3741_obj_t *self) { 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 +uint8_t is31fl3741_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 @@ -279,11 +276,11 @@ 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) { - if (p == cur_page) { + if (p == is31fl3741_cur_page) { return; } - cur_page = p; + is31fl3741_cur_page = p; is31fl3741_send_unlock(i2c, addr); uint8_t page[2] = { 0xFD, 0x00 }; // page command diff --git a/shared-module/is31fl3741/__init__.c b/shared-module/is31fl3741/__init__.c index e69de29bb2..5a9decfe3f 100644 --- a/shared-module/is31fl3741/__init__.c +++ b/shared-module/is31fl3741/__init__.c @@ -0,0 +1,74 @@ +/* + * 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 "shared-bindings/is31fl3741/__init__.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/is31fl3741/IS31FL3741.h" + +void begin_transaction(busio_i2c_obj_t *i2c) { + while (!common_hal_busio_i2c_try_lock(i2c)) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + break; + } + } +} + +void end_transaction(busio_i2c_obj_t *i2c) { + common_hal_busio_i2c_unlock(i2c); +} + +void common_hal_is31fl3741_init(busio_i2c_obj_t *i2c, uint8_t addr) { + begin_transaction(i2c); + + uint8_t command = 0xFC; // device ID + common_hal_busio_i2c_write(i2c, addr, &command, 1, false); + uint8_t data = 0; + common_hal_busio_i2c_read(i2c, addr, &data, 1); + + is31fl3741_send_reset(i2c, addr); + is31fl3741_send_enable(i2c, addr); + is31fl3741_set_current(i2c, addr, 0xFF); + + // set scale (brightness) to max for all LEDs + for (int i = 0; i < 351; i++) { + is31fl3741_set_led(i2c, addr, i, 0xFF, 2); + } + + end_transaction(i2c); +} + +void common_hal_is31fl3741_write(busio_i2c_obj_t *i2c, uint8_t addr, const mp_obj_t *mapping, const uint8_t *pixels, size_t numBytes) { + for (size_t i = 0; i < numBytes; i += 3) { + uint16_t ridx = mp_obj_get_int(mapping[i]); + if (ridx != 65535) { + is31fl3741_set_led(i2c, addr, ridx, IS31GammaTable[pixels[i]], 0); // red + is31fl3741_set_led(i2c, addr, mp_obj_get_int(mapping[i + 1]), IS31GammaTable[pixels[i + 1]], 0); // green + is31fl3741_set_led(i2c, addr, mp_obj_get_int(mapping[i + 2]), IS31GammaTable[pixels[i + 2]], 0); // blue + } + } +}