Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is31pixelbuf #5726

Merged
merged 17 commits into from
Feb 2, 2022
4 changes: 4 additions & 0 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
73 changes: 73 additions & 0 deletions shared-bindings/is31fl3741/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,89 @@
* THE SOFTWARE.
*/

#include "shared-bindings/is31fl3741/__init__.h"

#include <stdint.h>
#include <stdbool.h>

#include "py/obj.h"
#include "py/runtime.h"

#include "shared-bindings/busio/I2C.h"
#include "shared-bindings/is31fl3741/IS31FL3741.h"


//| """Low-level is31fl3741 implementation
//|
//| The `is31fl3741_write` module contains a helper method to write out bytes in
//| over the I2C bus."""
gamblor21 marked this conversation as resolved.
Show resolved Hide resolved
//|
//| def is31fl3741_write(i2c: busio.I2C, addr: int, mapping: Tuple[int, ...], buf: ReadableBuffer) -> None:
gamblor21 marked this conversation as resolved.
Show resolved Hide resolved
//| """Write buf out on the given I2C bus.
//|
//| :param ~busio.I2C i2c: the I2C bus to output with
//| :param ~int addr: the I2C address of the IS31FL3741 device
//| :param ~Tuple[int, ...] mapping: map the pixels in the buffer to the order addressed by the driver chip
//| :param ~_typing.ReadableBuffer buf: The bytes to clock out. No assumption is made about color order"""
//| ...
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);

//| def is31fl3741_init(i2c: busio.I2c, addr: int) -> None:
//| """Initialize the IS31FL3741 device.
//|
//| :param ~busio.I2C i2c: the I2C bus to output with
//| :param ~int addr: the I2C address of the IS31FL3741 device"""
//| ...
STATIC mp_obj_t is31fl3741_is31fl3741_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
gamblor21 marked this conversation as resolved.
Show resolved Hide resolved
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);
Expand Down
40 changes: 40 additions & 0 deletions shared-bindings/is31fl3741/__init__.h
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>
#include <stdbool.h>

#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 is31fl3741_begin_transaction(busio_i2c_obj_t *i2c);
void is31fl3741_end_transaction(busio_i2c_obj_t *i2c);

#endif // MICROPY_INCLUDED_SHARED_BINDINGS_NEOPIXEL_WRITE_H
13 changes: 5 additions & 8 deletions shared-module/is31fl3741/IS31FL3741.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void common_hal_is31fl3741_IS31FL3741_construct(is31fl3741_IS31FL3741_obj_t *sel

mp_obj_t *items;
size_t len;
mp_obj_list_get(mapping, &len, &items);
mp_obj_tuple_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"));
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -267,23 +267,20 @@ 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
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) {
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
Expand Down
78 changes: 78 additions & 0 deletions shared-module/is31fl3741/__init__.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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 is31fl3741_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 is31fl3741_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) {
is31fl3741_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);
}

is31fl3741_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) {
is31fl3741_begin_transaction(i2c);

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
}
}

is31fl3741_end_transaction(i2c);
}