From b74b371d2b73aa09e6d36fe3b52cb15c68aabc7d Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 10 Mar 2023 18:14:57 +0000 Subject: [PATCH 01/23] JPEGDEC: Don't pass filename through std::string. The result of GET_STR_DATA_LEN should be null terminated, so converting to a std::string and then using .c_str() is both redundant and need s heap. --- micropython/modules/jpegdec/jpegdec.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index 8c3c12a7..7e0eb208 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -247,10 +247,8 @@ mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args if(mp_obj_is_str_or_bytes(self->file)){ GET_STR_DATA_LEN(self->file, str, str_len); - std::string t((const char*)str); - result = self->jpeg->open( - t.c_str(), + (const char*)str, jpegdec_open_callback, jpegdec_close_callback, jpegdec_read_callback, From 375df60ff34af863f4b3db99ef96745681591d27 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 10 Mar 2023 20:36:21 +0000 Subject: [PATCH 02/23] PicoGraphics: Switch to string_view. MicroPython's GET_STR_DATA_LEN macro returns a const byte array and len, which std::string would copy into heap. Using string_view lets us wrap the existing const values. --- libraries/bitmap_fonts/bitmap_fonts.cpp | 4 ++-- libraries/bitmap_fonts/bitmap_fonts.hpp | 5 +++-- libraries/hershey_fonts/hershey_fonts.cpp | 4 ++-- libraries/hershey_fonts/hershey_fonts.hpp | 4 ++-- libraries/pico_graphics/pico_graphics.cpp | 10 +++++----- libraries/pico_graphics/pico_graphics.hpp | 7 ++++--- micropython/modules/badger2040-micropython.cmake | 3 +++ micropython/modules/micropython-badger2040w.cmake | 3 +++ micropython/modules/micropython-pico.cmake | 3 +++ micropython/modules/micropython-picolipo_16mb.cmake | 3 +++ micropython/modules/micropython-picolipo_4mb.cmake | 3 +++ micropython/modules/micropython-picow.cmake | 3 +++ .../modules/micropython-picow_cosmic_unicorn.cmake | 3 +++ micropython/modules/micropython-picow_enviro.cmake | 3 +++ .../modules/micropython-picow_galactic_unicorn.cmake | 3 +++ micropython/modules/micropython-picow_inky_frame.cmake | 3 +++ micropython/modules/micropython-tiny2040.cmake | 3 +++ micropython/modules/micropython-tufty2040.cmake | 3 +++ micropython/modules/picographics/picographics.cpp | 8 ++++---- 19 files changed, 58 insertions(+), 20 deletions(-) diff --git a/libraries/bitmap_fonts/bitmap_fonts.cpp b/libraries/bitmap_fonts/bitmap_fonts.cpp index a47a9be9..c7608e88 100644 --- a/libraries/bitmap_fonts/bitmap_fonts.cpp +++ b/libraries/bitmap_fonts/bitmap_fonts.cpp @@ -21,7 +21,7 @@ namespace bitmap { return font->widths[char_index] * scale; } - int32_t measure_text(const font_t *font, const std::string &t, const uint8_t scale, const uint8_t letter_spacing) { + int32_t measure_text(const font_t *font, const std::string_view &t, const uint8_t scale, const uint8_t letter_spacing) { int32_t text_width = 0; unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195; for(auto c : t) { @@ -119,7 +119,7 @@ namespace bitmap { } } - void text(const font_t *font, rect_func rectangle, const std::string &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale, const uint8_t letter_spacing) { + void text(const font_t *font, rect_func rectangle, const std::string_view &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale, const uint8_t letter_spacing) { uint32_t co = 0, lo = 0; // character and line (if wrapping) offset unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195; diff --git a/libraries/bitmap_fonts/bitmap_fonts.hpp b/libraries/bitmap_fonts/bitmap_fonts.hpp index 9860e00d..b7b31e6d 100644 --- a/libraries/bitmap_fonts/bitmap_fonts.hpp +++ b/libraries/bitmap_fonts/bitmap_fonts.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "common/unicode_sorta.hpp" @@ -19,8 +20,8 @@ namespace bitmap { typedef std::function rect_func; int32_t measure_character(const font_t *font, const char c, const uint8_t scale, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195); - int32_t measure_text(const font_t *font, const std::string &t, const uint8_t scale = 2, const uint8_t letter_spacing = 1); + int32_t measure_text(const font_t *font, const std::string_view &t, const uint8_t scale = 2, const uint8_t letter_spacing = 1); void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale = 2, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195); - void text(const font_t *font, rect_func rectangle, const std::string &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale = 2, const uint8_t letter_spacing = 1); + void text(const font_t *font, rect_func rectangle, const std::string_view &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale = 2, const uint8_t letter_spacing = 1); } \ No newline at end of file diff --git a/libraries/hershey_fonts/hershey_fonts.cpp b/libraries/hershey_fonts/hershey_fonts.cpp index 7234488c..2179c3b9 100644 --- a/libraries/hershey_fonts/hershey_fonts.cpp +++ b/libraries/hershey_fonts/hershey_fonts.cpp @@ -41,7 +41,7 @@ namespace hershey { return gd->width * s; } - int32_t measure_text(const font_t* font, std::string message, float s) { + int32_t measure_text(const font_t* font, std::string_view message, float s) { int32_t width = 0; for(auto &c : message) { width += measure_glyph(font, c, s); @@ -93,7 +93,7 @@ namespace hershey { return gd->width * s; } - void text(const font_t* font, line_func line, std::string message, int32_t x, int32_t y, float s, float a) { + void text(const font_t* font, line_func line, std::string_view message, int32_t x, int32_t y, float s, float a) { int32_t cx = x; int32_t cy = y; diff --git a/libraries/hershey_fonts/hershey_fonts.hpp b/libraries/hershey_fonts/hershey_fonts.hpp index eeea917f..5b6fa786 100644 --- a/libraries/hershey_fonts/hershey_fonts.hpp +++ b/libraries/hershey_fonts/hershey_fonts.hpp @@ -44,7 +44,7 @@ namespace hershey { inline float deg2rad(float degrees); const font_glyph_t* glyph_data(const font_t* font, unsigned char c); int32_t measure_glyph(const font_t* font, unsigned char c, float s); - int32_t measure_text(const font_t* font, std::string message, float s); + int32_t measure_text(const font_t* font, std::string_view message, float s); int32_t glyph(const font_t* font, line_func line, unsigned char c, int32_t x, int32_t y, float s, float a); - void text(const font_t* font, line_func line, std::string message, int32_t x, int32_t y, float s, float a); + void text(const font_t* font, line_func line, std::string_view message, int32_t x, int32_t y, float s, float a); } \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index fbf1dcc0..01fa9a71 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -35,7 +35,7 @@ namespace pimoroni { this->hershey_font = font; } - void PicoGraphics::set_font(std::string name){ + void PicoGraphics::set_font(std::string_view name){ if (name == "bitmap6") { set_font(&font6); } else if (name == "bitmap8") { @@ -44,8 +44,8 @@ namespace pimoroni { set_font(&font14_outline); } else { // check that font exists and assign it - if(hershey::fonts.find(name) != hershey::fonts.end()) { - set_font(hershey::fonts[name]); + if(hershey::fonts.find((std::string)name) != hershey::fonts.end()) { + set_font(hershey::fonts[(std::string)name]); } } } @@ -144,7 +144,7 @@ namespace pimoroni { } } - void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, float s, float a, uint8_t letter_spacing) { + void PicoGraphics::text(const std::string_view &t, const Point &p, int32_t wrap, float s, float a, uint8_t letter_spacing) { if (bitmap_font) { bitmap::text(bitmap_font, [this](int32_t x, int32_t y, int32_t w, int32_t h) { rectangle(Rect(x, y, w, h)); @@ -166,7 +166,7 @@ namespace pimoroni { } } - int32_t PicoGraphics::measure_text(const std::string &t, float s, uint8_t letter_spacing) { + int32_t PicoGraphics::measure_text(const std::string_view &t, float s, uint8_t letter_spacing) { if (bitmap_font) return bitmap::measure_text(bitmap_font, t, std::max(1.0f, s), letter_spacing); if (hershey_font) return hershey::measure_text(hershey_font, t, s); return 0; diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 491716de..2a6671f7 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -268,7 +269,7 @@ namespace pimoroni { void set_font(const bitmap::font_t *font); void set_font(const hershey::font_t *font); - void set_font(std::string font); + void set_font(std::string_view name); void set_dimensions(int width, int height); void set_framebuffer(void *frame_buffer); @@ -285,8 +286,8 @@ namespace pimoroni { void rectangle(const Rect &r); void circle(const Point &p, int32_t r); void character(const char c, const Point &p, float s = 2.0f, float a = 0.0f); - void text(const std::string &t, const Point &p, int32_t wrap, float s = 2.0f, float a = 0.0f, uint8_t letter_spacing = 1); - int32_t measure_text(const std::string &t, float s = 2.0f, uint8_t letter_spacing = 1); + void text(const std::string_view &t, const Point &p, int32_t wrap, float s = 2.0f, float a = 0.0f, uint8_t letter_spacing = 1); + int32_t measure_text(const std::string_view &t, float s = 2.0f, uint8_t letter_spacing = 1); void polygon(const std::vector &points); void triangle(Point p1, Point p2, Point p3); void line(Point p1, Point p2); diff --git a/micropython/modules/badger2040-micropython.cmake b/micropython/modules/badger2040-micropython.cmake index 32e5b7c6..0adad2f2 100644 --- a/micropython/modules/badger2040-micropython.cmake +++ b/micropython/modules/badger2040-micropython.cmake @@ -3,6 +3,9 @@ include_directories(${CMAKE_CURRENT_LIST_DIR}/../../) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) diff --git a/micropython/modules/micropython-badger2040w.cmake b/micropython/modules/micropython-badger2040w.cmake index 2b4b67e8..ec479692 100644 --- a/micropython/modules/micropython-badger2040w.cmake +++ b/micropython/modules/micropython-badger2040w.cmake @@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + # Essential include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) diff --git a/micropython/modules/micropython-pico.cmake b/micropython/modules/micropython-pico.cmake index d7f7a2ca..4f7e7280 100644 --- a/micropython/modules/micropython-pico.cmake +++ b/micropython/modules/micropython-pico.cmake @@ -4,4 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + include(micropython-common) diff --git a/micropython/modules/micropython-picolipo_16mb.cmake b/micropython/modules/micropython-picolipo_16mb.cmake index f4e90728..eb6a12fb 100644 --- a/micropython/modules/micropython-picolipo_16mb.cmake +++ b/micropython/modules/micropython-picolipo_16mb.cmake @@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + include(micropython-common) enable_ulab() diff --git a/micropython/modules/micropython-picolipo_4mb.cmake b/micropython/modules/micropython-picolipo_4mb.cmake index f4e90728..eb6a12fb 100644 --- a/micropython/modules/micropython-picolipo_4mb.cmake +++ b/micropython/modules/micropython-picolipo_4mb.cmake @@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + include(micropython-common) enable_ulab() diff --git a/micropython/modules/micropython-picow.cmake b/micropython/modules/micropython-picow.cmake index bd75adab..0e5621a4 100644 --- a/micropython/modules/micropython-picow.cmake +++ b/micropython/modules/micropython-picow.cmake @@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + # Essential include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) diff --git a/micropython/modules/micropython-picow_cosmic_unicorn.cmake b/micropython/modules/micropython-picow_cosmic_unicorn.cmake index 9318dc68..eaf68349 100644 --- a/micropython/modules/micropython-picow_cosmic_unicorn.cmake +++ b/micropython/modules/micropython-picow_cosmic_unicorn.cmake @@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + # Essential include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) diff --git a/micropython/modules/micropython-picow_enviro.cmake b/micropython/modules/micropython-picow_enviro.cmake index 80a2b926..cf10daaa 100644 --- a/micropython/modules/micropython-picow_enviro.cmake +++ b/micropython/modules/micropython-picow_enviro.cmake @@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + # Essential include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) diff --git a/micropython/modules/micropython-picow_galactic_unicorn.cmake b/micropython/modules/micropython-picow_galactic_unicorn.cmake index c05755d9..daff274b 100644 --- a/micropython/modules/micropython-picow_galactic_unicorn.cmake +++ b/micropython/modules/micropython-picow_galactic_unicorn.cmake @@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + # Essential include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) diff --git a/micropython/modules/micropython-picow_inky_frame.cmake b/micropython/modules/micropython-picow_inky_frame.cmake index b9e4ebdc..168b5ffa 100644 --- a/micropython/modules/micropython-picow_inky_frame.cmake +++ b/micropython/modules/micropython-picow_inky_frame.cmake @@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + # Essential include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) diff --git a/micropython/modules/micropython-tiny2040.cmake b/micropython/modules/micropython-tiny2040.cmake index d7f7a2ca..4f7e7280 100644 --- a/micropython/modules/micropython-tiny2040.cmake +++ b/micropython/modules/micropython-tiny2040.cmake @@ -4,4 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + include(micropython-common) diff --git a/micropython/modules/micropython-tufty2040.cmake b/micropython/modules/micropython-tufty2040.cmake index fd880836..6b2db598 100644 --- a/micropython/modules/micropython-tufty2040.cmake +++ b/micropython/modules/micropython-tufty2040.cmake @@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + # Essential include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 6d3bbe25..f49494b4 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -23,10 +23,10 @@ extern "C" { #include "py/reader.h" #include "extmod/vfs.h" -std::string mp_obj_to_string_r(const mp_obj_t &obj) { +const std::string_view mp_obj_to_string_r(const mp_obj_t &obj) { if(mp_obj_is_str_or_bytes(obj)) { GET_STR_DATA_LEN(obj, str, str_len); - return (const char*)str; + return std::string_view((const char*)str, str_len); } mp_raise_TypeError("can't convert object to str implicitly"); } @@ -935,7 +935,7 @@ mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t GET_STR_DATA_LEN(text_obj, str, str_len); - std::string t((const char*)str); + const std::string_view t((const char*)str, str_len); int x = args[ARG_x].u_int; int y = args[ARG_y].u_int; @@ -969,7 +969,7 @@ mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, m GET_STR_DATA_LEN(text_obj, str, str_len); - std::string t((const char*)str); + const std::string_view t((const char*)str, str_len); float scale = args[ARG_scale].u_obj == mp_const_none ? 2.0f : mp_obj_get_float(args[ARG_scale].u_obj); int letter_spacing = args[ARG_spacing].u_int; From 73f50e43ec4c3f8a881f162d1b7df4f13c0d2c90 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 10 Mar 2023 21:44:03 +0000 Subject: [PATCH 03/23] Hershey Fonts: Replace map lookup to avoid std::string. --- libraries/hershey_fonts/hershey_fonts.cpp | 20 ++++++++++++++++++++ libraries/hershey_fonts/hershey_fonts.hpp | 3 +++ libraries/pico_graphics/pico_graphics.cpp | 4 ++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/libraries/hershey_fonts/hershey_fonts.cpp b/libraries/hershey_fonts/hershey_fonts.cpp index 2179c3b9..cd1ad432 100644 --- a/libraries/hershey_fonts/hershey_fonts.cpp +++ b/libraries/hershey_fonts/hershey_fonts.cpp @@ -14,6 +14,26 @@ namespace hershey { //{ "serif_bold", ×rb } }; + bool has_font(std::string_view font) { + if(font == "sans" + || font == "gothic" + || font == "cursive" + || font == "serif_italic" + || font == "serif") { + return true; + } + return false; + } + + const font_t* font(std::string_view font) { + if(font == "sans") return &futural; + else if(font == "gothic") return &gothgbt; + else if(font == "cursive") return &scripts; + else if(font == "serif_italic") return ×i; + else if(font == "serif") return ×r; + return &futural; + } + inline float deg2rad(float degrees) { return (degrees * M_PI) / 180.0f; } diff --git a/libraries/hershey_fonts/hershey_fonts.hpp b/libraries/hershey_fonts/hershey_fonts.hpp index 5b6fa786..824351ce 100644 --- a/libraries/hershey_fonts/hershey_fonts.hpp +++ b/libraries/hershey_fonts/hershey_fonts.hpp @@ -47,4 +47,7 @@ namespace hershey { int32_t measure_text(const font_t* font, std::string_view message, float s); int32_t glyph(const font_t* font, line_func line, unsigned char c, int32_t x, int32_t y, float s, float a); void text(const font_t* font, line_func line, std::string_view message, int32_t x, int32_t y, float s, float a); + + bool has_font(std::string_view font); + const font_t* font(std::string_view font); } \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 01fa9a71..e8f34a49 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -44,8 +44,8 @@ namespace pimoroni { set_font(&font14_outline); } else { // check that font exists and assign it - if(hershey::fonts.find((std::string)name) != hershey::fonts.end()) { - set_font(hershey::fonts[(std::string)name]); + if(hershey::has_font(name)) { + set_font(hershey::font(name)); } } } From 59ae1079825a85b363916049f6dec468e9e357c6 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 09:34:56 +0000 Subject: [PATCH 04/23] BME280: Avoid runtime memory allocation. --- drivers/bme280/bme280.cpp | 5 ++++- drivers/bme280/bme280.hpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/bme280/bme280.cpp b/drivers/bme280/bme280.cpp index 5091162a..1e7090ec 100644 --- a/drivers/bme280/bme280.cpp +++ b/drivers/bme280/bme280.cpp @@ -11,7 +11,10 @@ namespace pimoroni { gpio_pull_up(interrupt); } - device.intf_ptr = new i2c_intf_ptr{.i2c = i2c, .address = address}; + i2c_interface.i2c = i2c; + i2c_interface.address = address; + + device.intf_ptr = &i2c_interface; device.intf = bme280_intf::BME280_I2C_INTF; device.read = (bme280_read_fptr_t)&read_bytes; device.write = (bme280_write_fptr_t)&write_bytes; diff --git a/drivers/bme280/bme280.hpp b/drivers/bme280/bme280.hpp index cc255e54..706d87c3 100644 --- a/drivers/bme280/bme280.hpp +++ b/drivers/bme280/bme280.hpp @@ -26,6 +26,8 @@ namespace pimoroni { bool status; }; + i2c_intf_ptr i2c_interface; + bool debug = false; bool init(); From bcebccca1d2242ae866004e13b90655f8b754648 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 09:39:51 +0000 Subject: [PATCH 05/23] BME68X: Avoid runtime memory allocation. --- drivers/bme68x/bme68x.cpp | 4 +++- drivers/bme68x/bme68x.hpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/bme68x/bme68x.cpp b/drivers/bme68x/bme68x.cpp index 59cfb8ee..c4c9e4e6 100644 --- a/drivers/bme68x/bme68x.cpp +++ b/drivers/bme68x/bme68x.cpp @@ -11,8 +11,10 @@ namespace pimoroni { gpio_pull_up(interrupt); } - device.intf_ptr = new i2c_intf_ptr{.i2c = i2c, .address = address}; + i2c_interface.i2c = i2c; + i2c_interface.address = address; + device.intf_ptr = &i2c_interface; device.intf = bme68x_intf::BME68X_I2C_INTF; device.read = (bme68x_read_fptr_t)&read_bytes; device.write = (bme68x_write_fptr_t)&write_bytes; diff --git a/drivers/bme68x/bme68x.hpp b/drivers/bme68x/bme68x.hpp index c4d8c2f1..eaf44d42 100644 --- a/drivers/bme68x/bme68x.hpp +++ b/drivers/bme68x/bme68x.hpp @@ -18,6 +18,8 @@ namespace pimoroni { int8_t address; }; + i2c_intf_ptr i2c_interface; + bool debug = true; bool init(); From 1f0302bd66abeeded90180abdcdfecf6d3a94651 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 12:35:39 +0000 Subject: [PATCH 06/23] BME280: Check read status and throw error on fail. --- .../modules/breakout_bme280/breakout_bme280.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/micropython/modules/breakout_bme280/breakout_bme280.cpp b/micropython/modules/breakout_bme280/breakout_bme280.cpp index e3103e5a..61c52b73 100644 --- a/micropython/modules/breakout_bme280/breakout_bme280.cpp +++ b/micropython/modules/breakout_bme280/breakout_bme280.cpp @@ -48,11 +48,15 @@ mp_obj_t BreakoutBME280_read(mp_obj_t self_in) { breakout_bme280_BreakoutBME280_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_bme280_BreakoutBME280_obj_t); BME280::bme280_reading result = self->breakout->read_forced(); - mp_obj_t tuple[3]; - tuple[0] = mp_obj_new_float(result.temperature); - tuple[1] = mp_obj_new_float(result.pressure); - tuple[2] = mp_obj_new_float(result.humidity); - return mp_obj_new_tuple(3, tuple); + if(result.status) { + mp_obj_t tuple[3]; + tuple[0] = mp_obj_new_float(result.temperature); + tuple[1] = mp_obj_new_float(result.pressure); + tuple[2] = mp_obj_new_float(result.humidity); + return mp_obj_new_tuple(3, tuple); + } + + mp_raise_msg(&mp_type_RuntimeError, "BME280: read failed."); } mp_obj_t BreakoutBME280_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { From a0ab44067fd1d7a2ee031ea9d037b6353115debb Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 13:35:23 +0000 Subject: [PATCH 07/23] BMP280: Avoid runtime memory allocation. --- drivers/bmp280/bmp280.cpp | 5 ++++- drivers/bmp280/bmp280.hpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/bmp280/bmp280.cpp b/drivers/bmp280/bmp280.cpp index 019f3b2e..28b2e2f8 100644 --- a/drivers/bmp280/bmp280.cpp +++ b/drivers/bmp280/bmp280.cpp @@ -11,7 +11,10 @@ namespace pimoroni { gpio_pull_up(interrupt); } - device.intf_ptr = new i2c_intf_ptr{.i2c = i2c, .address = address}; + i2c_interface.i2c = i2c; + i2c_interface.address = address; + + device.intf_ptr = &i2c_interface; device.intf = BMP280_I2C_INTF; device.read = (bmp280_com_fptr_t)&read_bytes; device.write = (bmp280_com_fptr_t)&write_bytes; diff --git a/drivers/bmp280/bmp280.hpp b/drivers/bmp280/bmp280.hpp index 02249b0c..1a1d3b68 100644 --- a/drivers/bmp280/bmp280.hpp +++ b/drivers/bmp280/bmp280.hpp @@ -25,6 +25,8 @@ namespace pimoroni { bool status; }; + i2c_intf_ptr i2c_interface; + bool debug = false; bool init(); From 157841f9db17b382e91db5402365ccec40b7eaa4 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 13:38:01 +0000 Subject: [PATCH 08/23] MicroPython: Add tracked alloc/free class helpers. --- micropython/modules/util.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/micropython/modules/util.hpp b/micropython/modules/util.hpp index 6765de9f..75db4d94 100644 --- a/micropython/modules/util.hpp +++ b/micropython/modules/util.hpp @@ -13,4 +13,7 @@ #define m_new_class(cls, ...) new(m_new(cls, 1)) cls(__VA_ARGS__) -#define m_del_class(cls, ptr) ptr->~cls();m_del(cls, ptr, 1) \ No newline at end of file +#define m_del_class(cls, ptr) ptr->~cls();m_del(cls, ptr, 1) + +#define m_tracked_alloc_class(cls, ...) new(m_tracked_calloc(1, sizeof(cls))) cls(__VA_ARGS__) +#define m_tracked_free_class(cls, ptr) ptr->~cls();m_tracked_free(ptr) \ No newline at end of file From e4cb7ce95f1b7ffb8a7e08cdfde1a43a93b1dbe0 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 13:35:53 +0000 Subject: [PATCH 09/23] Pico RGB Keypad: Use tracked alloc. --- micropython/modules/pico_rgb_keypad/pico_rgb_keypad.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.cpp b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.cpp index 36c38c2a..e71fbb5d 100644 --- a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.cpp +++ b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.cpp @@ -2,6 +2,7 @@ #include "hardware/sync.h" #include "pico/binary_info.h" +#include "micropython/modules/util.hpp" #include "libraries/pico_rgb_keypad/pico_rgb_keypad.hpp" using namespace pimoroni; @@ -16,7 +17,7 @@ extern "C" { mp_obj_t picokeypad_init() { if(keypad == nullptr) { - keypad = new PicoRGBKeypad(); + keypad = m_tracked_alloc_class(PicoRGBKeypad); keypad->init(); } return mp_const_none; From dd7ea6fdc3421a5d572b8863f9e50ae69f0925fc Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 13:36:04 +0000 Subject: [PATCH 10/23] Pico Scroll: Use tracked alloc. --- micropython/modules/pico_scroll/pico_scroll.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/micropython/modules/pico_scroll/pico_scroll.cpp b/micropython/modules/pico_scroll/pico_scroll.cpp index fe6cd88c..1a09f2fa 100644 --- a/micropython/modules/pico_scroll/pico_scroll.cpp +++ b/micropython/modules/pico_scroll/pico_scroll.cpp @@ -3,6 +3,7 @@ #include "pico/binary_info.h" #include "pico/stdlib.h" +#include "micropython/modules/util.hpp" #include "libraries/pico_scroll/pico_scroll.hpp" using namespace pimoroni; @@ -19,7 +20,7 @@ extern "C" { mp_obj_t picoscroll_init() { if(scroll == nullptr) - scroll = new PicoScroll(); + scroll = m_tracked_alloc_class(PicoScroll); scroll->init(); return mp_const_none; } From aa91450f59ad6843edd3473e2fc1d7078990c152 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 13:36:17 +0000 Subject: [PATCH 11/23] Pico Unicorn: Use tracked alloc. --- micropython/modules/pico_unicorn/pico_unicorn.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/micropython/modules/pico_unicorn/pico_unicorn.cpp b/micropython/modules/pico_unicorn/pico_unicorn.cpp index 59e3e525..86f4e90f 100644 --- a/micropython/modules/pico_unicorn/pico_unicorn.cpp +++ b/micropython/modules/pico_unicorn/pico_unicorn.cpp @@ -2,6 +2,7 @@ #include "hardware/sync.h" #include "pico/binary_info.h" +#include "micropython/modules/util.hpp" #include "libraries/pico_unicorn/pico_unicorn.hpp" using namespace pimoroni; @@ -16,7 +17,7 @@ extern "C" { mp_obj_t picounicorn_init() { if(unicorn == nullptr) - unicorn = new PicoUnicorn(); + unicorn = m_tracked_alloc_class(PicoUnicorn); unicorn->init(); return mp_const_none; } From a45eeb16238871b33d03a83d83c2f37ca2349a1d Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 13:36:34 +0000 Subject: [PATCH 12/23] Pico Wireless: Use tracked alloc. --- micropython/modules/pico_wireless/pico_wireless.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/micropython/modules/pico_wireless/pico_wireless.cpp b/micropython/modules/pico_wireless/pico_wireless.cpp index fc612a3e..ae37dfa1 100644 --- a/micropython/modules/pico_wireless/pico_wireless.cpp +++ b/micropython/modules/pico_wireless/pico_wireless.cpp @@ -2,6 +2,7 @@ #include "hardware/sync.h" #include "pico/binary_info.h" +#include "micropython/modules/util.hpp" #include "libraries/pico_wireless/pico_wireless.hpp" using namespace pimoroni; @@ -51,7 +52,7 @@ mp_obj_t mp_ip_to_obj(IPAddress ip) { mp_obj_t picowireless_init() { if(wireless == nullptr) - wireless = new PicoWireless(); + wireless = m_tracked_alloc_class(PicoWireless); wireless->init(); return mp_const_none; } From af2b74d65d0808ea690e01f4d7f7458db3748c3d Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 14:44:42 +0000 Subject: [PATCH 13/23] Servo/Motor/PWM: Avoid runtime memory alloc. --- drivers/motor/motor_cluster.cpp | 6 +----- drivers/motor/motor_cluster.hpp | 7 +++++-- drivers/pwm/pwm_cluster.cpp | 12 ++---------- drivers/pwm/pwm_cluster.hpp | 3 ++- drivers/servo/calibration.cpp | 17 +++++------------ drivers/servo/calibration.hpp | 4 +++- drivers/servo/servo_cluster.cpp | 8 -------- drivers/servo/servo_cluster.hpp | 6 ++++-- 8 files changed, 22 insertions(+), 41 deletions(-) diff --git a/drivers/motor/motor_cluster.cpp b/drivers/motor/motor_cluster.cpp index d953b7f6..52291b2a 100644 --- a/drivers/motor/motor_cluster.cpp +++ b/drivers/motor/motor_cluster.cpp @@ -29,8 +29,6 @@ namespace motor { } MotorCluster::~MotorCluster() { - delete[] states; - delete[] configs; } bool MotorCluster::init() { @@ -713,10 +711,8 @@ namespace motor { float deadzone, DecayMode mode, bool auto_phase) { uint8_t motor_count = pwms.get_chan_pair_count(); if(motor_count > 0) { - states = new MotorState[motor_count]; - configs = new motor_config[motor_count]; - for(uint motor = 0; motor < motor_count; motor++) { + configs[motor] = motor_config(); states[motor] = MotorState(direction, speed_scale, zeropoint, deadzone); configs[motor].phase = (auto_phase) ? (float)motor / (float)motor_count : 0.0f; configs[motor].mode = mode; diff --git a/drivers/motor/motor_cluster.hpp b/drivers/motor/motor_cluster.hpp index d6d4a2d8..f3c1d495 100644 --- a/drivers/motor/motor_cluster.hpp +++ b/drivers/motor/motor_cluster.hpp @@ -22,12 +22,15 @@ namespace motor { //-------------------------------------------------- // Variables //-------------------------------------------------- + public: + static const uint MAX_MOTOR_CHANNELS = 16; + private: PWMCluster pwms; uint32_t pwm_period; float pwm_frequency; - MotorState* states; - motor_config* configs; + MotorState states[MAX_MOTOR_CHANNELS]; + motor_config configs[MAX_MOTOR_CHANNELS]; //-------------------------------------------------- diff --git a/drivers/pwm/pwm_cluster.cpp b/drivers/pwm/pwm_cluster.cpp index 0e6f28a7..3b49d8a4 100644 --- a/drivers/pwm/pwm_cluster.cpp +++ b/drivers/pwm/pwm_cluster.cpp @@ -27,7 +27,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_mask, bool loading_zone) , sm(sm) , pin_mask(pin_mask & ((1u << NUM_BANK0_GPIOS) - 1)) , channel_count(0) -, channels(nullptr) , wrap_level(0) , loading_zone(loading_zone) { @@ -48,7 +47,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_base, uint pin_count, bool loa , sm(sm) , pin_mask(0x00000000) , channel_count(0) -, channels(nullptr) , wrap_level(0) , loading_zone(loading_zone) { @@ -68,7 +66,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, const uint8_t *pins, uint32_t length, b , sm(sm) , pin_mask(0x00000000) , channel_count(0) -, channels(nullptr) , wrap_level(0) , loading_zone(loading_zone) { @@ -90,7 +87,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list pins, bo , sm(sm) , pin_mask(0x00000000) , channel_count(0) -, channels(nullptr) , wrap_level(0) , loading_zone(loading_zone) { @@ -111,7 +107,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, const pin_pair *pin_pairs, uint32_t len , sm(sm) , pin_mask(0x00000000) , channel_count(0) -, channels(nullptr) , wrap_level(0) , loading_zone(loading_zone) { @@ -137,7 +132,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list pin_pai , sm(sm) , pin_mask(0x00000000) , channel_count(0) -, channels(nullptr) , wrap_level(0) , loading_zone(loading_zone) { @@ -159,8 +153,8 @@ PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list pin_pai void PWMCluster::constructor_common() { // Initialise all the channels this PWM will control - if(channel_count > 0) { - channels = new ChannelState[channel_count]; + for(uint i = 0; i < channel_count; i++) { + channels[i] = ChannelState(); } // Set up the transition buffers @@ -216,8 +210,6 @@ PWMCluster::~PWMCluster() { gpio_set_function(channel_to_pin_map[channel], GPIO_FUNC_NULL); } } - - delete[] channels; } void PWMCluster::dma_interrupt_handler() { diff --git a/drivers/pwm/pwm_cluster.hpp b/drivers/pwm/pwm_cluster.hpp index 76392327..e233551a 100644 --- a/drivers/pwm/pwm_cluster.hpp +++ b/drivers/pwm/pwm_cluster.hpp @@ -24,6 +24,7 @@ namespace pimoroni { public: static const uint BUFFER_SIZE = 64; // Set to 64, the maximum number of single rises and falls for 32 channels within a looping time period static const uint NUM_BUFFERS = 3; + static const uint MAX_PWM_CHANNELS = 32; //-------------------------------------------------- @@ -104,7 +105,7 @@ namespace pimoroni { int dma_channel; uint pin_mask; uint8_t channel_count; - ChannelState* channels; + ChannelState channels[NUM_BANK0_GPIOS]; uint8_t channel_to_pin_map[NUM_BANK0_GPIOS]; uint wrap_level; diff --git a/drivers/servo/calibration.cpp b/drivers/servo/calibration.cpp index 6c6959d4..9de1fa07 100644 --- a/drivers/servo/calibration.cpp +++ b/drivers/servo/calibration.cpp @@ -10,7 +10,7 @@ namespace servo { } Calibration::Calibration() - : calibration(nullptr), calibration_size(0), limit_lower(true), limit_upper(true) { + : calibration_size(0), limit_lower(true), limit_upper(true) { } Calibration::Calibration(CalibrationType default_type) @@ -19,7 +19,7 @@ namespace servo { } Calibration::Calibration(const Calibration &other) - : calibration(nullptr), calibration_size(0), limit_lower(other.limit_lower), limit_upper(other.limit_upper) { + : calibration_size(0), limit_lower(other.limit_lower), limit_upper(other.limit_upper) { uint size = other.size(); apply_blank_pairs(size); for(uint i = 0; i < size; i++) { @@ -28,10 +28,6 @@ namespace servo { } Calibration::~Calibration() { - if(calibration != nullptr) { - delete[] calibration; - calibration = nullptr; - } } Calibration &Calibration::operator=(const Calibration &other) { @@ -57,16 +53,13 @@ namespace servo { } void Calibration::apply_blank_pairs(uint size) { - if(calibration != nullptr) { - delete[] calibration; - } - if(size > 0) { - calibration = new Pair[size]; + for(auto i = 0u; i < size; i++) { + calibration[i] = Pair(); + } calibration_size = size; } else { - calibration = nullptr; calibration_size = 0; } } diff --git a/drivers/servo/calibration.hpp b/drivers/servo/calibration.hpp index cf874e7a..bf126b45 100644 --- a/drivers/servo/calibration.hpp +++ b/drivers/servo/calibration.hpp @@ -19,6 +19,8 @@ namespace servo { static constexpr float DEFAULT_MID_PULSE = 1500.0f; // in microseconds static constexpr float DEFAULT_MAX_PULSE = 2500.0f; // in microseconds + static const uint MAX_CALIBRATION_PAIRS = 32; + private: static constexpr float LOWER_HARD_LIMIT = 400.0f; // The minimum microsecond pulse to send static constexpr float UPPER_HARD_LIMIT = 2600.0f; // The maximum microsecond pulse to send @@ -110,7 +112,7 @@ namespace servo { // Variables //-------------------------------------------------- private: - Pair* calibration; + Pair calibration[MAX_CALIBRATION_PAIRS]; uint calibration_size; bool limit_lower; bool limit_upper; diff --git a/drivers/servo/servo_cluster.cpp b/drivers/servo/servo_cluster.cpp index cd58d249..be3dd9ac 100644 --- a/drivers/servo/servo_cluster.cpp +++ b/drivers/servo/servo_cluster.cpp @@ -44,8 +44,6 @@ namespace servo { } ServoCluster::~ServoCluster() { - delete[] states; - delete[] servo_phases; } bool ServoCluster::init() { @@ -502,9 +500,6 @@ namespace servo { void ServoCluster::create_servo_states(CalibrationType default_type, bool auto_phase) { uint8_t servo_count = pwms.get_chan_count(); if(servo_count > 0) { - states = new ServoState[servo_count]; - servo_phases = new float[servo_count]; - for(uint servo = 0; servo < servo_count; servo++) { states[servo] = ServoState(default_type); servo_phases[servo] = (auto_phase) ? (float)servo / (float)servo_count : 0.0f; @@ -515,9 +510,6 @@ namespace servo { void ServoCluster::create_servo_states(const Calibration& calibration, bool auto_phase) { uint8_t servo_count = pwms.get_chan_count(); if(servo_count > 0) { - states = new ServoState[servo_count]; - servo_phases = new float[servo_count]; - for(uint servo = 0; servo < servo_count; servo++) { states[servo] = ServoState(calibration); servo_phases[servo] = (auto_phase) ? (float)servo / (float)servo_count : 0.0f; diff --git a/drivers/servo/servo_cluster.hpp b/drivers/servo/servo_cluster.hpp index e6ee0b5b..19d59063 100644 --- a/drivers/servo/servo_cluster.hpp +++ b/drivers/servo/servo_cluster.hpp @@ -12,12 +12,14 @@ namespace servo { //-------------------------------------------------- // Variables //-------------------------------------------------- + public: + static const uint MAX_SERVO_CHANNELS = 32; private: PWMCluster pwms; uint32_t pwm_period; float pwm_frequency; - ServoState* states; - float* servo_phases; + ServoState states[MAX_SERVO_CHANNELS]; + float servo_phases[MAX_SERVO_CHANNELS]; //-------------------------------------------------- From 9964ed716b91b06b10e7e002f5aa73818bbb7295 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 14:45:06 +0000 Subject: [PATCH 14/23] Servo/Motor: Use m_new instead of new. --- micropython/modules/motor/motor.cpp | 8 ++-- micropython/modules/servo/servo.cpp | 72 ++++++++++++++--------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/micropython/modules/motor/motor.cpp b/micropython/modules/motor/motor.cpp index 4fb88b38..bef55d85 100644 --- a/micropython/modules/motor/motor.cpp +++ b/micropython/modules/motor/motor.cpp @@ -32,11 +32,11 @@ void pimoroni_tuple_or_list(const mp_obj_t &object, mp_obj_t **items, size_t *le } uint8_t* pimoroni_motors_from_items(mp_obj_t *items, size_t length, int motor_count) { - uint8_t *motors = new uint8_t[length]; + uint8_t *motors = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int motor = mp_obj_get_int(items[i]); if(motor < 0 || motor >= motor_count) { - delete[] motors; + m_free(motors); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a motor in the list or tuple is out of range. Expected 0 to %d"), motor_count - 1); } else { @@ -636,7 +636,7 @@ mp_obj_t MotorCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t else { // Specific check for is a single 2 pin list/tuple was provided if(pair_count == 2 && mp_obj_is_int(items[0]) && mp_obj_is_int(items[1])) { - pins = new pin_pair[1]; + pins = m_new(pin_pair, 1); pair_count = 1; int pos = mp_obj_get_int(items[0]); @@ -656,7 +656,7 @@ mp_obj_t MotorCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t } else { // Create and populate a local array of pins - pins = new pin_pair[pair_count]; + pins = m_new(pin_pair, pair_count); for(size_t i = 0; i < pair_count; i++) { mp_obj_t obj = items[i]; if(!mp_obj_is_type(obj, &mp_type_tuple)) { diff --git a/micropython/modules/servo/servo.cpp b/micropython/modules/servo/servo.cpp index 35dd0779..b02e6eb7 100644 --- a/micropython/modules/servo/servo.cpp +++ b/micropython/modules/servo/servo.cpp @@ -1289,11 +1289,11 @@ mp_obj_t ServoCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of pins - pins = new uint8_t[pin_count]; + pins = m_new(uint8_t, pin_count); for(size_t i = 0; i < pin_count; i++) { int pin = mp_obj_get_int(items[i]); if(pin < 0 || pin >= (int)NUM_BANK0_GPIOS) { - delete[] pins; + m_free(pins); mp_raise_ValueError("a pin in the list or tuple is out of range. Expected 0 to 29"); } else { @@ -1348,7 +1348,7 @@ mp_obj_t ServoCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t // Cleanup the pins array if(pins != nullptr) - delete[] pins; + m_free(pins); if(!cluster->init()) { m_del_class(ServoCluster, cluster); @@ -1449,11 +1449,11 @@ extern mp_obj_t ServoCluster_enable(size_t n_args, const mp_obj_t *pos_args, mp_ mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -1461,7 +1461,7 @@ extern mp_obj_t ServoCluster_enable(size_t n_args, const mp_obj_t *pos_args, mp_ } } self->cluster->enable(servos, length, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -1533,11 +1533,11 @@ extern mp_obj_t ServoCluster_disable(size_t n_args, const mp_obj_t *pos_args, mp mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -1545,7 +1545,7 @@ extern mp_obj_t ServoCluster_disable(size_t n_args, const mp_obj_t *pos_args, mp } } self->cluster->disable(servos, length, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -1668,11 +1668,11 @@ extern mp_obj_t ServoCluster_pulse(size_t n_args, const mp_obj_t *pos_args, mp_m mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -1681,7 +1681,7 @@ extern mp_obj_t ServoCluster_pulse(size_t n_args, const mp_obj_t *pos_args, mp_m } float pulse = mp_obj_get_float(args[ARG_pulse].u_obj); self->cluster->pulse(servos, length, pulse, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -1786,11 +1786,11 @@ extern mp_obj_t ServoCluster_value(size_t n_args, const mp_obj_t *pos_args, mp_m mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -1799,7 +1799,7 @@ extern mp_obj_t ServoCluster_value(size_t n_args, const mp_obj_t *pos_args, mp_m } float value = mp_obj_get_float(args[ARG_value].u_obj); self->cluster->value(servos, length, value, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -1904,11 +1904,11 @@ extern mp_obj_t ServoCluster_phase(size_t n_args, const mp_obj_t *pos_args, mp_m mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -1917,7 +1917,7 @@ extern mp_obj_t ServoCluster_phase(size_t n_args, const mp_obj_t *pos_args, mp_m } float phase = mp_obj_get_float(args[ARG_phase].u_obj); self->cluster->phase(servos, length, phase, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -2108,11 +2108,11 @@ extern mp_obj_t ServoCluster_to_min(size_t n_args, const mp_obj_t *pos_args, mp_ mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -2120,7 +2120,7 @@ extern mp_obj_t ServoCluster_to_min(size_t n_args, const mp_obj_t *pos_args, mp_ } } self->cluster->to_min(servos, length, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -2196,11 +2196,11 @@ extern mp_obj_t ServoCluster_to_mid(size_t n_args, const mp_obj_t *pos_args, mp_ mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -2208,7 +2208,7 @@ extern mp_obj_t ServoCluster_to_mid(size_t n_args, const mp_obj_t *pos_args, mp_ } } self->cluster->to_mid(servos, length, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -2284,11 +2284,11 @@ extern mp_obj_t ServoCluster_to_max(size_t n_args, const mp_obj_t *pos_args, mp_ mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -2296,7 +2296,7 @@ extern mp_obj_t ServoCluster_to_max(size_t n_args, const mp_obj_t *pos_args, mp_ } } self->cluster->to_max(servos, length, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -2376,11 +2376,11 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args, mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -2389,7 +2389,7 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args, } float in = mp_obj_get_float(args[ARG_in].u_obj); self->cluster->to_percent(servos, length, in, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -2448,11 +2448,11 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args, mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -2463,7 +2463,7 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args, float in_min = mp_obj_get_float(args[ARG_in_min].u_obj); float in_max = mp_obj_get_float(args[ARG_in_max].u_obj); self->cluster->to_percent(servos, length, in, in_min, in_max, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } @@ -2526,11 +2526,11 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args, mp_raise_TypeError("list or tuple must contain at least one integer"); else { // Create and populate a local array of servo indices - uint8_t *servos = new uint8_t[length]; + uint8_t *servos = m_new(uint8_t, length); for(size_t i = 0; i < length; i++) { int servo = mp_obj_get_int(items[i]); if(servo < 0 || servo >= servo_count) { - delete[] servos; + m_free(servos); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1); } else { @@ -2543,7 +2543,7 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args, float value_min = mp_obj_get_float(args[ARG_value_min].u_obj); float value_max = mp_obj_get_float(args[ARG_value_max].u_obj); self->cluster->to_percent(servos, length, in, in_min, in_max, value_min, value_max, args[ARG_load].u_bool); - delete[] servos; + m_free(servos); } } } From bd3651d97d22beb6ae0769552297e0831989200f Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 18:20:50 +0000 Subject: [PATCH 15/23] Pico RGB Keypad: Refactor to class. Because `mp_tracked_calloc` does not survive a soft reset but the memory region will, resulting in half-initialised frankenclasses that behave unpredictably. Using the class pattern fixes this since it's always guaranteed to be initialised when a user instantiates it, and __del__ can handle cleanup. --- libraries/pico_rgb_keypad/pico_rgb_keypad.cpp | 5 + libraries/pico_rgb_keypad/pico_rgb_keypad.hpp | 1 + micropython/examples/pico_rgb_keypad/demo.py | 4 +- .../modules/pico_rgb_keypad/pico_rgb_keypad.c | 56 ++++-- .../pico_rgb_keypad/pico_rgb_keypad.cpp | 159 +++++++++--------- .../modules/pico_rgb_keypad/pico_rgb_keypad.h | 19 ++- 6 files changed, 136 insertions(+), 108 deletions(-) diff --git a/libraries/pico_rgb_keypad/pico_rgb_keypad.cpp b/libraries/pico_rgb_keypad/pico_rgb_keypad.cpp index ccc0f907..3bc24b7a 100644 --- a/libraries/pico_rgb_keypad/pico_rgb_keypad.cpp +++ b/libraries/pico_rgb_keypad/pico_rgb_keypad.cpp @@ -17,6 +17,11 @@ enum pin { namespace pimoroni { + PicoRGBKeypad::~PicoRGBKeypad() { + clear(); + update(); + } + void PicoRGBKeypad::init() { memset(buffer, 0, sizeof(buffer)); led_data = buffer + 4; diff --git a/libraries/pico_rgb_keypad/pico_rgb_keypad.hpp b/libraries/pico_rgb_keypad/pico_rgb_keypad.hpp index 0f7ec356..05b0d549 100644 --- a/libraries/pico_rgb_keypad/pico_rgb_keypad.hpp +++ b/libraries/pico_rgb_keypad/pico_rgb_keypad.hpp @@ -16,6 +16,7 @@ namespace pimoroni { uint8_t *led_data; public: + ~PicoRGBKeypad(); void init(); void update(); void set_brightness(float brightness); diff --git a/micropython/examples/pico_rgb_keypad/demo.py b/micropython/examples/pico_rgb_keypad/demo.py index ac792734..40eadb4d 100644 --- a/micropython/examples/pico_rgb_keypad/demo.py +++ b/micropython/examples/pico_rgb_keypad/demo.py @@ -1,7 +1,7 @@ import time -import picokeypad as keypad +import picokeypad -keypad.init() +keypad = picokeypad.PicoKeypad() keypad.set_brightness(1.0) lit = 0 diff --git a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.c b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.c index dfe3967a..4c14e79a 100644 --- a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.c +++ b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.c @@ -5,21 +5,20 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /***** Module Functions *****/ -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_init_obj, picokeypad_init); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_get_width_obj, picokeypad_get_width); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_get_height_obj, picokeypad_get_height); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_get_num_pads_obj, picokeypad_get_num_pads); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_update_obj, picokeypad_update); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_set_brightness_obj, picokeypad_set_brightness); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picokeypad_illuminate_xy_obj, 5, 5, picokeypad_illuminate_xy); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picokeypad_illuminate_obj, 4, 4, picokeypad_illuminate); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_clear_obj, picokeypad_clear); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_get_button_states_obj, picokeypad_get_button_states); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad___del___obj, picokeypad___del__); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_get_width_obj, picokeypad_get_width); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_get_height_obj, picokeypad_get_height); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_get_num_pads_obj, picokeypad_get_num_pads); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_update_obj, picokeypad_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(picokeypad_set_brightness_obj, picokeypad_set_brightness); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picokeypad_illuminate_xy_obj, 6, 6, picokeypad_illuminate_xy); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picokeypad_illuminate_obj, 5, 5, picokeypad_illuminate); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_clear_obj, picokeypad_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_get_button_states_obj, picokeypad_get_button_states); -/***** Globals Table *****/ -STATIC const mp_map_elem_t picokeypad_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picokeypad) }, - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picokeypad_init_obj) }, +/* Class Methods */ +STATIC const mp_rom_map_elem_t picokeypad_locals[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&picokeypad___del___obj) }, { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picokeypad_get_width_obj) }, { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picokeypad_get_height_obj) }, { MP_ROM_QSTR(MP_QSTR_get_num_pads), MP_ROM_PTR(&picokeypad_get_num_pads_obj) }, @@ -30,9 +29,34 @@ STATIC const mp_map_elem_t picokeypad_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picokeypad_clear_obj) }, { MP_ROM_QSTR(MP_QSTR_get_button_states), MP_ROM_PTR(&picokeypad_get_button_states_obj) }, }; -STATIC MP_DEFINE_CONST_DICT(mp_module_picokeypad_globals, picokeypad_globals_table); +STATIC MP_DEFINE_CONST_DICT(mp_module_picokeypad_locals, picokeypad_locals); + +#ifdef MP_DEFINE_CONST_OBJ_TYPE +MP_DEFINE_CONST_OBJ_TYPE( + PicoKeypad_type, + MP_QSTR_PicoKeypad, + MP_TYPE_FLAG_NONE, + make_new, picokeypad_make_new, + locals_dict, (mp_obj_dict_t*)&mp_module_picokeypad_locals +); +#else +const mp_obj_type_t PicoKeypad_type = { + { &mp_type_type }, + .name = MP_QSTR_PicoKeypad, + .make_new = picokeypad_make_new, + .locals_dict = (mp_obj_dict_t*)&mp_module_picokeypad_locals, +}; +#endif + +/* Module Globals */ +STATIC const mp_map_elem_t picokeypad_globals[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_picokeypad) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PicoKeypad), (mp_obj_t)&PicoKeypad_type }, + { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(4) }, + { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(4) }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_picokeypad_globals, picokeypad_globals); -/***** Module Definition *****/ const mp_obj_module_t picokeypad_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_picokeypad_globals, diff --git a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.cpp b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.cpp index e71fbb5d..7e95916f 100644 --- a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.cpp +++ b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.cpp @@ -7,130 +7,125 @@ using namespace pimoroni; -PicoRGBKeypad *keypad = nullptr; - - extern "C" { #include "pico_rgb_keypad.h" -#define NOT_INITIALISED_MSG "Cannot call this function, as picokeypad is not initialised. Call picokeypad.init() first." +typedef struct _PicoKeypad_obj_t { + mp_obj_base_t base; + PicoRGBKeypad* keypad; +} PicoKeypad_obj_t; -mp_obj_t picokeypad_init() { - if(keypad == nullptr) { - keypad = m_tracked_alloc_class(PicoRGBKeypad); - keypad->init(); - } +mp_obj_t picokeypad_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + _PicoKeypad_obj_t *self = nullptr; + + self = m_new_obj_with_finaliser(PicoKeypad_obj_t); + self->base.type = &PicoKeypad_type; + + self->keypad = m_new_class(PicoRGBKeypad); + self->keypad->init(); + + return MP_OBJ_FROM_PTR(self); +} + +mp_obj_t picokeypad___del__(mp_obj_t self_in) { + PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t); + m_del_class(PicoRGBKeypad, self->keypad); return mp_const_none; } -mp_obj_t picokeypad_get_width() { +mp_obj_t picokeypad_get_width(mp_obj_t self_in) { + (void)self_in; return mp_obj_new_int(PicoRGBKeypad::WIDTH); } -mp_obj_t picokeypad_get_height() { +mp_obj_t picokeypad_get_height(mp_obj_t self_in) { + (void)self_in; return mp_obj_new_int(PicoRGBKeypad::HEIGHT); } -mp_obj_t picokeypad_get_num_pads() { +mp_obj_t picokeypad_get_num_pads(mp_obj_t self_in) { + (void)self_in; return mp_obj_new_int(PicoRGBKeypad::NUM_PADS); } -mp_obj_t picokeypad_update() { - if(keypad != nullptr) - keypad->update(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); +mp_obj_t picokeypad_update(mp_obj_t self_in) { + PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t); + self->keypad->update(); return mp_const_none; } -mp_obj_t picokeypad_set_brightness(mp_obj_t brightness_obj) { - if(keypad != nullptr) { - float brightness = mp_obj_get_float(brightness_obj); +mp_obj_t picokeypad_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) { + PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t); - if(brightness < 0 || brightness > 1.0f) - mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); - else - keypad->set_brightness(brightness); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + float brightness = mp_obj_get_float(brightness_obj); + + if(brightness < 0 || brightness > 1.0f) + mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); + + self->keypad->set_brightness(brightness); return mp_const_none; } mp_obj_t picokeypad_illuminate_xy(mp_uint_t n_args, const mp_obj_t *args) { - (void)n_args; //Unused input parameter, we know it's 5 + (void)n_args; //Unused input parameter, we know it's self + 5 + + PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoKeypad_obj_t); - if(keypad != nullptr) { - int x = mp_obj_get_int(args[0]); - int y = mp_obj_get_int(args[1]); - int r = mp_obj_get_int(args[2]); - int g = mp_obj_get_int(args[3]); - int b = mp_obj_get_int(args[4]); + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + int r = mp_obj_get_int(args[3]); + int g = mp_obj_get_int(args[4]); + int b = mp_obj_get_int(args[5]); - if(x < 0 || x >= PicoRGBKeypad::WIDTH || y < 0 || y >= PicoRGBKeypad::HEIGHT) - mp_raise_ValueError("x or y out of range."); - else { - if(r < 0 || r > 255) - mp_raise_ValueError("r out of range. Expected 0 to 255"); - else if(g < 0 || g > 255) - mp_raise_ValueError("g out of range. Expected 0 to 255"); - else if(b < 0 || b > 255) - mp_raise_ValueError("b out of range. Expected 0 to 255"); - else - keypad->illuminate(x, y, r, g, b); - } - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + if(x < 0 || x >= PicoRGBKeypad::WIDTH || y < 0 || y >= PicoRGBKeypad::HEIGHT) + mp_raise_ValueError("x or y out of range."); + if(r < 0 || r > 255) + mp_raise_ValueError("r out of range. Expected 0 to 255"); + if(g < 0 || g > 255) + mp_raise_ValueError("g out of range. Expected 0 to 255"); + if(b < 0 || b > 255) + mp_raise_ValueError("b out of range. Expected 0 to 255"); + self->keypad->illuminate(x, y, r, g, b); + return mp_const_none; } mp_obj_t picokeypad_illuminate(mp_uint_t n_args, const mp_obj_t *args) { - (void)n_args; //Unused input parameter, we know it's 5 + (void)n_args; //Unused input parameter, we know it's self + 5 + + PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoKeypad_obj_t); - if(keypad != nullptr) { - int i = mp_obj_get_int(args[0]); - int r = mp_obj_get_int(args[1]); - int g = mp_obj_get_int(args[2]); - int b = mp_obj_get_int(args[3]); + int i = mp_obj_get_int(args[1]); + int r = mp_obj_get_int(args[2]); + int g = mp_obj_get_int(args[3]); + int b = mp_obj_get_int(args[4]); - if(i < 0 || i >= PicoRGBKeypad::NUM_PADS) - mp_raise_ValueError("x or y out of range."); - else { - if(r < 0 || r > 255) - mp_raise_ValueError("r out of range. Expected 0 to 255"); - else if(g < 0 || g > 255) - mp_raise_ValueError("g out of range. Expected 0 to 255"); - else if(b < 0 || b > 255) - mp_raise_ValueError("b out of range. Expected 0 to 255"); - else - keypad->illuminate(i, r, g, b); - } - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + if(i < 0 || i >= PicoRGBKeypad::NUM_PADS) + mp_raise_ValueError("x or y out of range."); + if(r < 0 || r > 255) + mp_raise_ValueError("r out of range. Expected 0 to 255"); + if(g < 0 || g > 255) + mp_raise_ValueError("g out of range. Expected 0 to 255"); + if(b < 0 || b > 255) + mp_raise_ValueError("b out of range. Expected 0 to 255"); + + self->keypad->illuminate(i, r, g, b); return mp_const_none; } -mp_obj_t picokeypad_clear() { - if(keypad != nullptr) - keypad->clear(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - +mp_obj_t picokeypad_clear(mp_obj_t self_in) { + PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t); + self->keypad->clear(); return mp_const_none; } -mp_obj_t picokeypad_get_button_states() { +mp_obj_t picokeypad_get_button_states(mp_obj_t self_in) { + PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t); uint16_t states = 0; - if(keypad != nullptr) - states = keypad->get_button_states(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - + states = self->keypad->get_button_states(); return mp_obj_new_int(states); } } \ No newline at end of file diff --git a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.h b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.h index 0d9e083c..b5ee60e4 100644 --- a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.h +++ b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.h @@ -1,14 +1,17 @@ // Include MicroPython API. #include "py/runtime.h" +extern const mp_obj_type_t PicoKeypad_type; + // Declare the functions we'll make available in Python -extern mp_obj_t picokeypad_init(); -extern mp_obj_t picokeypad_get_width(); -extern mp_obj_t picokeypad_get_height(); -extern mp_obj_t picokeypad_get_num_pads(); -extern mp_obj_t picokeypad_update(); -extern mp_obj_t picokeypad_set_brightness(mp_obj_t brightness_obj); +extern mp_obj_t picokeypad_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); +extern mp_obj_t picokeypad___del__(mp_obj_t self_in); +extern mp_obj_t picokeypad_get_width(mp_obj_t self_in); +extern mp_obj_t picokeypad_get_height(mp_obj_t self_in); +extern mp_obj_t picokeypad_get_num_pads(mp_obj_t self_in); +extern mp_obj_t picokeypad_update(mp_obj_t self_in); +extern mp_obj_t picokeypad_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj); extern mp_obj_t picokeypad_illuminate_xy(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picokeypad_illuminate(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picokeypad_clear(); -extern mp_obj_t picokeypad_get_button_states(); \ No newline at end of file +extern mp_obj_t picokeypad_clear(mp_obj_t self_in); +extern mp_obj_t picokeypad_get_button_states(mp_obj_t self_in); \ No newline at end of file From 044313551bb6945d5b485547e3be163a5a450935 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Mar 2023 19:39:33 +0000 Subject: [PATCH 16/23] Pico Scroll: Refactor to class. --- libraries/pico_scroll/pico_scroll.cpp | 5 + libraries/pico_scroll/pico_scroll.hpp | 1 + libraries/pico_scroll/pico_scroll_font.cpp | 7 +- micropython/examples/pico_scroll/demo.py | 18 +- .../examples/pico_scroll/scroll_text.py | 4 +- micropython/modules/pico_scroll/README.md | 31 +-- micropython/modules/pico_scroll/pico_scroll.c | 64 +++-- .../modules/pico_scroll/pico_scroll.cpp | 255 ++++++++++-------- micropython/modules/pico_scroll/pico_scroll.h | 26 +- 9 files changed, 237 insertions(+), 174 deletions(-) diff --git a/libraries/pico_scroll/pico_scroll.cpp b/libraries/pico_scroll/pico_scroll.cpp index 06477639..9522d4d5 100644 --- a/libraries/pico_scroll/pico_scroll.cpp +++ b/libraries/pico_scroll/pico_scroll.cpp @@ -35,6 +35,11 @@ enum reg { namespace pimoroni { + PicoScroll::~PicoScroll() { + clear(); + update(); + } + void PicoScroll::init() { // setup i2c interface i2c_init(i2c0, 400000); diff --git a/libraries/pico_scroll/pico_scroll.hpp b/libraries/pico_scroll/pico_scroll.hpp index 4cef0e3d..a7142fb2 100644 --- a/libraries/pico_scroll/pico_scroll.hpp +++ b/libraries/pico_scroll/pico_scroll.hpp @@ -19,6 +19,7 @@ namespace pimoroni { uint8_t __fb[BUFFER_SIZE]; public: + ~PicoScroll(); void init(); void update(); void set_pixels(const char *pixels); diff --git a/libraries/pico_scroll/pico_scroll_font.cpp b/libraries/pico_scroll/pico_scroll_font.cpp index 1f0c39d3..eac8f533 100644 --- a/libraries/pico_scroll/pico_scroll_font.cpp +++ b/libraries/pico_scroll/pico_scroll_font.cpp @@ -1,4 +1,5 @@ #include "pico_scroll_font.hpp" +#include /* static font data */ static const unsigned char __bitmap[256][5] = { @@ -135,13 +136,15 @@ static const unsigned char __bitmap[256][5] = { /* render a text string to a pre-allocated buffer - strlen(text) * 6 bytes */ int render_text(const char *text, unsigned int nchr, unsigned char *buffer, unsigned int nbfr) { // TODO check nbfr >= 6 * nchr + memset(buffer, 0, nbfr); for (unsigned int i = 0; i < nchr; i++) { const unsigned char *symbol = __bitmap[(unsigned int)text[i]]; for (unsigned int j = 0; j < 5; j++) { - buffer[i * 6 + j] = symbol[j]; + unsigned int offset = i * 6 + j; + if (offset >= nbfr) return -1; + buffer[offset] = symbol[j]; } - buffer[i * 6 + 5] = 0x0; } return 0; } diff --git a/micropython/examples/pico_scroll/demo.py b/micropython/examples/pico_scroll/demo.py index 82b5c9aa..405cb71e 100644 --- a/micropython/examples/pico_scroll/demo.py +++ b/micropython/examples/pico_scroll/demo.py @@ -1,30 +1,28 @@ import time -import picoscroll as scroll +from picoscroll import PicoScroll, WIDTH, HEIGHT + +scroll = PicoScroll() -scroll.init() i = 0 loop = 18 br_mult = 1 br_pressed = 32 tail = 12 -width = scroll.get_width() -height = scroll.get_height() - while True: scroll.clear() - for y in range(0, height): - for x in range(0, width): + for y in range(0, HEIGHT): + for x in range(0, WIDTH): if x < 3 and y < 3 and scroll.is_pressed(scroll.BUTTON_A): scroll.set_pixel(x, y, br_pressed) elif x < 3 and y > 3 and scroll.is_pressed(scroll.BUTTON_B): scroll.set_pixel(x, y, br_pressed) - elif x > width - 4 and y < 3 and scroll.is_pressed(scroll.BUTTON_X): + elif x > WIDTH - 4 and y < 3 and scroll.is_pressed(scroll.BUTTON_X): scroll.set_pixel(x, y, br_pressed) - elif x > width - 4 and y > 3 and scroll.is_pressed(scroll.BUTTON_Y): + elif x > WIDTH - 4 and y > 3 and scroll.is_pressed(scroll.BUTTON_Y): scroll.set_pixel(x, y, br_pressed) else: - m = (x + (y * width)) % loop + m = (x + (y * WIDTH)) % loop for b in range(0, loop): if m == (i + (loop - b)) % loop and b < tail: scroll.set_pixel(x, y, br_mult * (tail - b)) diff --git a/micropython/examples/pico_scroll/scroll_text.py b/micropython/examples/pico_scroll/scroll_text.py index 57011826..a628081d 100644 --- a/micropython/examples/pico_scroll/scroll_text.py +++ b/micropython/examples/pico_scroll/scroll_text.py @@ -1,7 +1,7 @@ import time -import picoscroll as scroll +from picoscroll import PicoScroll -scroll.init() +scroll = PicoScroll() while True: scroll.scroll_text("Hello World", 128, 80) diff --git a/micropython/modules/pico_scroll/README.md b/micropython/modules/pico_scroll/README.md index a1908b24..67a184cd 100644 --- a/micropython/modules/pico_scroll/README.md +++ b/micropython/modules/pico_scroll/README.md @@ -5,28 +5,27 @@ Our Pico Scroll Pack offers a 17x7 white LED matrix for your Raspberry Pi Pico. We've included helper functions to handle every aspect of drawing to the matrix and interfacing with the buttons. See the [function reference](#function-reference) for details. - [Example Program](#example-program) -- [Function Reference](#function-reference) - - [init](#init) - - [get_width](#get_width) - - [get_height](#get_height) - - [set_pixel](#set_pixel) - - [set_pixels](#set_pixels) - - [show_text](#show_text) - - [scroll_text](#scroll_text) - - [show_bitmap_1d](#show_bitmap_1d) +- [Function reference](#function-reference) + - [get\_width](#get_width) + - [get\_height](#get_height) + - [set\_pixel](#set_pixel) + - [set\_pixels](#set_pixels) + - [show\_text](#show_text) + - [scroll\_text](#scroll_text) + - [show\_bitmap\_1d](#show_bitmap_1d) - [update](#update) - [clear](#clear) - - [is_pressed](#is_pressed) + - [is\_pressed](#is_pressed) ## Example Program The following example sets up the matrix, sets each pixel to an increasing brightnesses level, and then clears the matrix only after button A is pressed. ```python -import picoscroll +from picoscroll import PicoScroll # Initialise the board -picoscroll.init() +picoscroll = PicoScroll() brightness = 0 @@ -51,14 +50,6 @@ picoscroll.update() ## Function reference -### init - -Sets up the Pico Scroll Pack. The `init` function must be called before any other functions as it configures the required pins on the Pico board. - -```python -picoscroll.init() -``` - ### get_width ### get_height diff --git a/micropython/modules/pico_scroll/pico_scroll.c b/micropython/modules/pico_scroll/pico_scroll.c index 7727a9a4..eae44483 100644 --- a/micropython/modules/pico_scroll/pico_scroll.c +++ b/micropython/modules/pico_scroll/pico_scroll.c @@ -15,22 +15,21 @@ enum buttons //////////////////////////////////////////////////////////////////////////////////////////////////// /***** Module Functions *****/ -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_init_obj, picoscroll_init); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_get_width_obj, picoscroll_get_width); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_get_height_obj, picoscroll_get_height); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_update_obj, picoscroll_update); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoscroll_set_pixel_obj, picoscroll_set_pixel); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_set_pixels_obj, picoscroll_set_pixels); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoscroll_show_text_obj, picoscroll_show_text); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoscroll_scroll_text_obj, picoscroll_scroll_text); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoscroll_show_bitmap_1d_obj, picoscroll_show_bitmap_1d); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_clear_obj, picoscroll_clear); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_is_pressed_obj, picoscroll_is_pressed); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll___del___obj, picoscroll___del__); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_get_width_obj, picoscroll_get_width); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_get_height_obj, picoscroll_get_height); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_update_obj, picoscroll_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_set_pixel_obj, 4, 4, picoscroll_set_pixel); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoscroll_set_pixels_obj, picoscroll_set_pixels); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_show_text_obj, 4, 4, picoscroll_show_text); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_scroll_text_obj, 4, 4, picoscroll_scroll_text); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_show_bitmap_1d_obj, 4, 4, picoscroll_show_bitmap_1d); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_clear_obj, picoscroll_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoscroll_is_pressed_obj, picoscroll_is_pressed); -/***** Globals Table *****/ -STATIC const mp_map_elem_t picoscroll_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picoscroll) }, - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picoscroll_init_obj) }, +/* Class Methods */ +STATIC const mp_rom_map_elem_t picoscroll_locals[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&picoscroll___del___obj) }, { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picoscroll_get_width_obj) }, { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picoscroll_get_height_obj) }, { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picoscroll_update_obj) }, @@ -40,15 +39,44 @@ STATIC const mp_map_elem_t picoscroll_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_scroll_text), MP_ROM_PTR(&picoscroll_scroll_text_obj) }, { MP_ROM_QSTR(MP_QSTR_show_bitmap_1d), MP_ROM_PTR(&picoscroll_show_bitmap_1d_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picoscroll_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picoscroll_is_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picoscroll_is_pressed_obj) }, { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) }, { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) }, { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) }, { MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) }, }; -STATIC MP_DEFINE_CONST_DICT(mp_module_picoscroll_globals, picoscroll_globals_table); +STATIC MP_DEFINE_CONST_DICT(mp_module_picoscroll_locals, picoscroll_locals); + +#ifdef MP_DEFINE_CONST_OBJ_TYPE +MP_DEFINE_CONST_OBJ_TYPE( + PicoScroll_type, + MP_QSTR_PicoScroll, + MP_TYPE_FLAG_NONE, + make_new, picoscroll_make_new, + locals_dict, (mp_obj_dict_t*)&mp_module_picoscroll_locals +); +#else +const mp_obj_type_t PicoScroll_type = { + { &mp_type_type }, + .name = MP_QSTR_PicoScroll, + .make_new = picoscroll_make_new, + .locals_dict = (mp_obj_dict_t*)&mp_module_picoscroll_locals, +}; +#endif + +/* Module Globals */ +STATIC const mp_map_elem_t picoscroll_globals[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_picoscroll) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PicoScroll), (mp_obj_t)&PicoScroll_type }, + { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(17) }, + { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(7) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_picoscroll_globals, picoscroll_globals); -/***** Module Definition *****/ const mp_obj_module_t picoscroll_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_picoscroll_globals, diff --git a/micropython/modules/pico_scroll/pico_scroll.cpp b/micropython/modules/pico_scroll/pico_scroll.cpp index 1a09f2fa..7e4d2800 100644 --- a/micropython/modules/pico_scroll/pico_scroll.cpp +++ b/micropython/modules/pico_scroll/pico_scroll.cpp @@ -1,3 +1,4 @@ +#include #include "hardware/spi.h" #include "hardware/sync.h" #include "pico/binary_info.h" @@ -5,6 +6,7 @@ #include "micropython/modules/util.hpp" #include "libraries/pico_scroll/pico_scroll.hpp" +#include "libraries/pico_scroll/pico_scroll_font.hpp" using namespace pimoroni; @@ -14,163 +16,194 @@ PicoScroll *scroll = nullptr; extern "C" { #include "pico_scroll.h" -#define NOT_INITIALISED_MSG "Cannot call this function, as picoscroll is not initialised. Call picoscroll.init() first." #define BUFFER_TOO_SMALL_MSG "bytearray too small: len(image) < width * height." #define INCORRECT_SIZE_MSG "Scroll height wrong: > 8 pixels." -mp_obj_t picoscroll_init() { - if(scroll == nullptr) - scroll = m_tracked_alloc_class(PicoScroll); - scroll->init(); +typedef struct _PicoScroll_obj_t { + mp_obj_base_t base; + PicoScroll* scroll; +} PicoScroll_obj_t; + +mp_obj_t picoscroll_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + _PicoScroll_obj_t *self = nullptr; + + self = m_new_obj_with_finaliser(PicoScroll_obj_t); + self->base.type = &PicoScroll_type; + + self->scroll = m_new_class(PicoScroll); + self->scroll->init(); + + return MP_OBJ_FROM_PTR(self); +} + +mp_obj_t picoscroll___del__(mp_obj_t self_in) { + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); + m_del_class(PicoScroll, self->scroll); return mp_const_none; } -mp_obj_t picoscroll_get_width() { +mp_obj_t picoscroll_get_width(mp_obj_t self_in) { + (void)self_in; return mp_obj_new_int(PicoScroll::WIDTH); } -mp_obj_t picoscroll_get_height() { +mp_obj_t picoscroll_get_height(mp_obj_t self_in) { + (void)self_in; return mp_obj_new_int(PicoScroll::HEIGHT); } -mp_obj_t picoscroll_update() { - if(scroll != nullptr) - scroll->update(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); +mp_obj_t picoscroll_update(mp_obj_t self_in) { + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); + self->scroll->update(); return mp_const_none; } -mp_obj_t picoscroll_set_pixel(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj) { - if (scroll != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - int val = mp_obj_get_int(v_obj); +mp_obj_t picoscroll_set_pixel(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; //Unused input parameter, we know it's self + 3 + + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t); - if (x < 0 || x >= PicoScroll::WIDTH || y < 0 || y >= PicoScroll::HEIGHT) - mp_raise_ValueError("x or y out of range."); - else { - if (val < 0 || val > 255) - mp_raise_ValueError("val out of range. Expected 0 to 255"); - else - scroll->set_pixel(x, y, val); + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + int val = mp_obj_get_int(args[3]); + + if (x < 0 || x >= PicoScroll::WIDTH || y < 0 || y >= PicoScroll::HEIGHT) + mp_raise_ValueError("x or y out of range."); + if (val < 0 || val > 255) + mp_raise_ValueError("val out of range. Expected 0 to 255"); + + self->scroll->set_pixel(x, y, val); + + return mp_const_none; +} + +mp_obj_t picoscroll_scroll_text(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; //Unused input parameter, we know it's self + 3 + + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t); + + int brightness = mp_obj_get_int(args[2]); + int delay_ms = mp_obj_get_int(args[3]); + + if(mp_obj_is_str_or_bytes(args[1])) { + GET_STR_DATA_LEN(args[1], str, str_len); + + int draw_buffer_len = 6 * str_len; + char *draw_buffer = m_new(char, draw_buffer_len); + + render_text((const char *)str, str_len, (unsigned char *)draw_buffer, draw_buffer_len); + + for (int offset = -PicoScroll::WIDTH; offset < draw_buffer_len; offset++) { + self->scroll->clear(); + self->scroll->set_bitmap_1d((const char *)draw_buffer, draw_buffer_len, brightness, offset); + self->scroll->update(); + MICROPY_EVENT_POLL_HOOK + sleep_ms(delay_ms); } - } else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - return mp_const_none; -} + m_free(draw_buffer); -mp_obj_t picoscroll_scroll_text(mp_obj_t text_obj, mp_obj_t brightness_obj, - mp_obj_t delay_ms_obj) { - if (scroll != nullptr) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(text_obj, &bufinfo, MP_BUFFER_READ); - int brightness = mp_obj_get_int(brightness_obj); - int delay_ms = mp_obj_get_int(delay_ms_obj); - - scroll->scroll_text((const char *)bufinfo.buf, bufinfo.len, brightness, delay_ms); - - } else { - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + self->scroll->clear(); + self->scroll->update(); } return mp_const_none; } -mp_obj_t picoscroll_show_text(mp_obj_t text_obj, mp_obj_t brightness_obj, - mp_obj_t offset_obj) { - if (scroll != nullptr) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(text_obj, &bufinfo, MP_BUFFER_READ); - int brightness = mp_obj_get_int(brightness_obj); - int offset = mp_obj_get_int(offset_obj); +mp_obj_t picoscroll_show_text(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; //Unused input parameter, we know it's self + 3 + + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t); - scroll->set_text((const char *)bufinfo.buf, bufinfo.len, brightness, offset); - } else { - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + int brightness = mp_obj_get_int(args[2]); + int offset = mp_obj_get_int(args[3]); + + if(mp_obj_is_str_or_bytes(args[1])) { + GET_STR_DATA_LEN(args[1], str, str_len); + + int draw_buffer_len = 6 * str_len; + char *draw_buffer = m_new(char, draw_buffer_len); + + render_text((const char *)str, str_len, (unsigned char *)draw_buffer, draw_buffer_len); + self->scroll->set_bitmap_1d((const char *)draw_buffer, draw_buffer_len, brightness, offset); + + m_free(draw_buffer); } return mp_const_none; } -mp_obj_t picoscroll_set_pixels(mp_obj_t image_obj) { - if (scroll != nullptr) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(image_obj, &bufinfo, MP_BUFFER_RW); +mp_obj_t picoscroll_set_pixels(mp_obj_t self_in, mp_obj_t image_obj) { + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); - if (bufinfo.len < (PicoScroll::WIDTH * PicoScroll::HEIGHT)) { - mp_raise_msg(&mp_type_IndexError, BUFFER_TOO_SMALL_MSG); - } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(image_obj, &bufinfo, MP_BUFFER_RW); - scroll->set_pixels((const char*)bufinfo.buf); - } else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoscroll_show_bitmap_1d(mp_obj_t bitmap_obj, mp_obj_t brightness_obj, - mp_obj_t offset_obj) { - if (scroll != nullptr) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(bitmap_obj, &bufinfo, MP_BUFFER_RW); - int offset = mp_obj_get_int(offset_obj); - int brightness = mp_obj_get_int(brightness_obj); - int length = bufinfo.len; - - // clear the scroll, so only need to write visible bytes - scroll->clear(); - - if ((offset < -PicoScroll::WIDTH) || (offset > length)) { - return mp_const_none; - } - - scroll->set_bitmap_1d((const char *)bufinfo.buf, bufinfo.len, brightness, offset); - } else { - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + if (bufinfo.len < (PicoScroll::WIDTH * PicoScroll::HEIGHT)) { + mp_raise_msg(&mp_type_IndexError, BUFFER_TOO_SMALL_MSG); } + self->scroll->set_pixels((const char*)bufinfo.buf); + return mp_const_none; } -mp_obj_t picoscroll_clear() { - if (scroll != nullptr) - scroll->clear(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); +mp_obj_t picoscroll_show_bitmap_1d(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; //Unused input parameter, we know it's self + 3 + + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_RW); + int offset = mp_obj_get_int(args[3]); + int brightness = mp_obj_get_int(args[2]); + int length = bufinfo.len; + + // clear the scroll, so only need to write visible bytes + self->scroll->clear(); + + if ((offset < -PicoScroll::WIDTH) || (offset > length)) { + return mp_const_none; + } + + self->scroll->set_bitmap_1d((const char *)bufinfo.buf, bufinfo.len, brightness, offset); + return mp_const_none; } -mp_obj_t picoscroll_is_pressed(mp_obj_t button_obj) { +mp_obj_t picoscroll_clear(mp_obj_t self_in) { + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); + self->scroll->clear(); + return mp_const_none; +} + +mp_obj_t picoscroll_is_pressed(mp_obj_t self_in, mp_obj_t button_obj) { + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); + bool buttonPressed = false; - - if(scroll != nullptr) { - int buttonID = mp_obj_get_int(button_obj); - switch(buttonID) { - case 0: - buttonPressed = scroll->is_pressed(PicoScroll::A); - break; - case 1: - buttonPressed = scroll->is_pressed(PicoScroll::B); - break; + int buttonID = mp_obj_get_int(button_obj); + switch(buttonID) { + case 0: + buttonPressed = self->scroll->is_pressed(PicoScroll::A); + break; - case 2: - buttonPressed = scroll->is_pressed(PicoScroll::X); - break; + case 1: + buttonPressed = self->scroll->is_pressed(PicoScroll::B); + break; - case 3: - buttonPressed = scroll->is_pressed(PicoScroll::Y); - break; + case 2: + buttonPressed = self->scroll->is_pressed(PicoScroll::X); + break; - default: - mp_raise_ValueError("button not valid. Expected 0 to 3"); - break; - } + case 3: + buttonPressed = self->scroll->is_pressed(PicoScroll::Y); + break; + + default: + mp_raise_ValueError("button not valid. Expected 0 to 3"); + break; } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); return buttonPressed ? mp_const_true : mp_const_false; } diff --git a/micropython/modules/pico_scroll/pico_scroll.h b/micropython/modules/pico_scroll/pico_scroll.h index a8e11890..e841f0cd 100644 --- a/micropython/modules/pico_scroll/pico_scroll.h +++ b/micropython/modules/pico_scroll/pico_scroll.h @@ -1,15 +1,19 @@ // Include MicroPython API. #include "py/runtime.h" +#include "py/objstr.h" + +extern const mp_obj_type_t PicoScroll_type; // Declare the functions we'll make available in Python -extern mp_obj_t picoscroll_init(); -extern mp_obj_t picoscroll_get_width(); -extern mp_obj_t picoscroll_get_height(); -extern mp_obj_t picoscroll_update(); -extern mp_obj_t picoscroll_set_pixel(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj); -extern mp_obj_t picoscroll_set_pixels(mp_obj_t image_obj); -extern mp_obj_t picoscroll_show_text(mp_obj_t text_obj, mp_obj_t brightness, mp_obj_t offset); -extern mp_obj_t picoscroll_scroll_text(mp_obj_t text_obj, mp_obj_t brightness, mp_obj_t delay); -extern mp_obj_t picoscroll_show_bitmap_1d(mp_obj_t bitmap_obj, mp_obj_t brightness, mp_obj_t offset); -extern mp_obj_t picoscroll_clear(); -extern mp_obj_t picoscroll_is_pressed(mp_obj_t button_obj); +extern mp_obj_t picoscroll_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); +extern mp_obj_t picoscroll___del__(mp_obj_t self_in); +extern mp_obj_t picoscroll_get_width(mp_obj_t self_in); +extern mp_obj_t picoscroll_get_height(mp_obj_t self_in); +extern mp_obj_t picoscroll_update(mp_obj_t self_in); +extern mp_obj_t picoscroll_set_pixel(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picoscroll_set_pixels(mp_obj_t self_in, mp_obj_t image_obj); +extern mp_obj_t picoscroll_show_text(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picoscroll_scroll_text(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picoscroll_show_bitmap_1d(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picoscroll_clear(mp_obj_t self_in); +extern mp_obj_t picoscroll_is_pressed(mp_obj_t self_in, mp_obj_t button_obj); From 3eb42336e68938b580567f54ecbf836e39611ec1 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 25 Jul 2022 11:36:15 +0100 Subject: [PATCH 17/23] Pico Unicorn: Refactor into class. Borrow heavily from Galactic/Cosmic Unicorn for the PIO/chained-DMA setup. --- examples/pico_unicorn/demo.cpp | 3 - libraries/pico_unicorn/README.md | 16 +- libraries/pico_unicorn/pico_unicorn.cpp | 210 ++++++++++-------- libraries/pico_unicorn/pico_unicorn.hpp | 22 +- micropython/examples/pico_unicorn/demo.py | 4 +- micropython/examples/pico_unicorn/rainbow.py | 4 +- .../modules/pico_unicorn/pico_unicorn.c | 55 +++-- .../modules/pico_unicorn/pico_unicorn.cpp | 152 ++++++------- .../modules/pico_unicorn/pico_unicorn.h | 20 +- 9 files changed, 264 insertions(+), 222 deletions(-) diff --git a/examples/pico_unicorn/demo.cpp b/examples/pico_unicorn/demo.cpp index 3ec174fb..0e5f67c7 100644 --- a/examples/pico_unicorn/demo.cpp +++ b/examples/pico_unicorn/demo.cpp @@ -10,9 +10,6 @@ using namespace pimoroni; PicoUnicorn pico_unicorn; int main() { - - pico_unicorn.init(); - bool a_pressed = false; bool b_pressed = false; bool x_pressed = false; diff --git a/libraries/pico_unicorn/README.md b/libraries/pico_unicorn/README.md index c2d80406..29ffc16b 100644 --- a/libraries/pico_unicorn/README.md +++ b/libraries/pico_unicorn/README.md @@ -12,13 +12,12 @@ We've included helper functions to handle every aspect of drawing to the display - [Buttons](#buttons) - [WIDTH / HEIGHT](#width--height) - [Functions](#functions) - - [init](#init) - - [set_pixel](#set_pixel) - - [is_pressed](#is_pressed) + - [set\_pixel](#set_pixel) + - [is\_pressed](#is_pressed) ## Example Program -The following example sets up Pico Unicorn, displays some basic demo text and graphics and will illuminate the RGB LED green if the A button is presse +The following example sets up Pico Unicorn, displays some basic demo text and graphics and will illuminate the RGB LED green if the A button is pressed. ```c++ @@ -48,15 +47,6 @@ int num_pixels = pico_unicorn.WIDTH * pico_unicorn.HEIGHT; ### Functions -#### init - -Sets up Pico Unicorn. `init` must be called before any other functions since it configures the PIO and require GPIO inputs. Just call `init()` like so: - -```c++ -PicoUnicorn pico_unicorn; -pico_unicorn.init(); -``` - #### set_pixel ```c++ diff --git a/libraries/pico_unicorn/pico_unicorn.cpp b/libraries/pico_unicorn/pico_unicorn.cpp index 4548ee0d..39576a4d 100644 --- a/libraries/pico_unicorn/pico_unicorn.cpp +++ b/libraries/pico_unicorn/pico_unicorn.cpp @@ -44,82 +44,53 @@ enum pin { Y = 15, }; -constexpr uint32_t ROW_COUNT = 7; -constexpr uint32_t ROW_BYTES = 12; -constexpr uint32_t BCD_FRAMES = 15; // includes fet discharge frame -constexpr uint32_t BITSTREAM_LENGTH = (ROW_COUNT * ROW_BYTES * BCD_FRAMES); - -// must be aligned for 32bit dma transfer -alignas(4) static uint8_t bitstream[BITSTREAM_LENGTH] = {0}; - static uint32_t dma_channel; - -static inline void unicorn_jetpack_program_init(PIO pio, uint sm, uint offset) { - pio_gpio_init(pio, pin::LED_DATA); - pio_gpio_init(pio, pin::LED_CLOCK); - pio_gpio_init(pio, pin::LED_LATCH); - pio_gpio_init(pio, pin::LED_BLANK); - pio_gpio_init(pio, pin::ROW_0); - pio_gpio_init(pio, pin::ROW_1); - pio_gpio_init(pio, pin::ROW_2); - pio_gpio_init(pio, pin::ROW_3); - pio_gpio_init(pio, pin::ROW_4); - pio_gpio_init(pio, pin::ROW_5); - pio_gpio_init(pio, pin::ROW_6); - - pio_sm_set_consecutive_pindirs(pio, sm, pin::LED_DATA, 4, true); - pio_sm_set_consecutive_pindirs(pio, sm, pin::ROW_6, 7, true); - - pio_sm_config c = unicorn_program_get_default_config(offset); - - // osr shifts right, autopull on, autopull threshold 8 - sm_config_set_out_shift(&c, true, false, 32); - - // configure out, set, and sideset pins - sm_config_set_out_pins(&c, pin::ROW_6, 7); - sm_config_set_sideset_pins(&c, pin::LED_CLOCK); - sm_config_set_set_pins(&c, pin::LED_DATA, 4); - - // join fifos as only tx needed (gives 8 deep fifo instead of 4) - sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); - - pio_sm_init(pio, sm, offset, &c); - pio_sm_set_enabled(pio, sm, true); -} +static uint32_t dma_ctrl_channel; namespace pimoroni { + PicoUnicorn* PicoUnicorn::unicorn = nullptr; + PIO PicoUnicorn::bitstream_pio = pio0; + uint PicoUnicorn::bitstream_sm = 0; + uint PicoUnicorn::bitstream_sm_offset = 0; - // once the dma transfer of the scanline is complete we move to the - // next scanline (or quit if we're finished) - void __isr dma_complete() { - if (dma_hw->ints0 & (1u << dma_channel)) { - dma_hw->ints0 = (1u << dma_channel); // clear irq flag - dma_channel_set_trans_count(dma_channel, BITSTREAM_LENGTH / 4, false); - dma_channel_set_read_addr(dma_channel, bitstream, true); + PicoUnicorn::~PicoUnicorn() { + if(unicorn == this) { + partial_teardown(); + + dma_channel_unclaim(dma_ctrl_channel); // This works now the teardown behaves correctly + dma_channel_unclaim(dma_channel); // This works now the teardown behaves correctly + pio_sm_unclaim(bitstream_pio, bitstream_sm); + pio_remove_program(bitstream_pio, &unicorn_program, bitstream_sm_offset); + + unicorn = nullptr; } } - PicoUnicorn::~PicoUnicorn() { - // stop and release the dma channel - irq_set_enabled(DMA_IRQ_0, false); - dma_channel_set_irq0_enabled(dma_channel, false); - irq_set_enabled(pio_get_dreq(bitstream_pio, bitstream_sm, true), false); - irq_remove_handler(DMA_IRQ_0, dma_complete); + void PicoUnicorn::partial_teardown() { + // Stop the bitstream SM + pio_sm_set_enabled(bitstream_pio, bitstream_sm, false); - dma_channel_wait_for_finish_blocking(dma_channel); - dma_channel_unclaim(dma_channel); + // Make sure the display is off and switch it to an invisible row, to be safe + const uint pins_to_set = 0b1111111 << ROW_6; + pio_sm_set_pins_with_mask(bitstream_pio, bitstream_sm, pins_to_set, pins_to_set); - // release the pio and sm - pio_sm_unclaim(bitstream_pio, bitstream_sm); - pio_clear_instruction_memory(bitstream_pio); - pio_sm_restart(bitstream_pio, bitstream_sm); + dma_hw->ch[dma_ctrl_channel].al1_ctrl = (dma_hw->ch[dma_ctrl_channel].al1_ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) | (dma_ctrl_channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB); + dma_hw->ch[dma_channel].al1_ctrl = (dma_hw->ch[dma_channel].al1_ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) | (dma_channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB); + // Abort any in-progress DMA transfer + dma_safe_abort(dma_ctrl_channel); + dma_safe_abort(dma_channel); } + [[deprecated("Handled by constructor.")]] void PicoUnicorn::init() { - // todo: shouldn't need to do this if things were cleaned up properly but without - // this any attempt to run a micropython script twice will fail - static bool already_init = false; + return; + } + PicoUnicorn::PicoUnicorn() { + if(unicorn != nullptr) { + partial_teardown(); + } + // setup pins gpio_init(pin::LED_DATA); gpio_set_dir(pin::LED_DATA, GPIO_OUT); gpio_init(pin::LED_CLOCK); gpio_set_dir(pin::LED_CLOCK, GPIO_OUT); @@ -171,47 +142,81 @@ namespace pimoroni { gpio_set_function(pin::X, GPIO_FUNC_SIO); gpio_set_dir(pin::X, GPIO_IN); gpio_pull_up(pin::X); gpio_set_function(pin::Y, GPIO_FUNC_SIO); gpio_set_dir(pin::Y, GPIO_IN); gpio_pull_up(pin::Y); - if(already_init) { - // stop and release the dma channel - irq_set_enabled(DMA_IRQ_0, false); - dma_channel_abort(dma_channel); - dma_channel_wait_for_finish_blocking(dma_channel); - - dma_channel_set_irq0_enabled(dma_channel, false); - irq_set_enabled(pio_get_dreq(bitstream_pio, bitstream_sm, true), false); - irq_remove_handler(DMA_IRQ_0, dma_complete); - - dma_channel_unclaim(dma_channel); - - // release the pio and sm - pio_sm_unclaim(bitstream_pio, bitstream_sm); - pio_clear_instruction_memory(bitstream_pio); - pio_sm_restart(bitstream_pio, bitstream_sm); - //return; - } - // setup the pio bitstream_pio = pio0; - bitstream_sm = pio_claim_unused_sm(pio0, true); - sm_offset = pio_add_program(bitstream_pio, &unicorn_program); - unicorn_jetpack_program_init(bitstream_pio, bitstream_sm, sm_offset); + if(unicorn == nullptr) { + bitstream_sm = pio_claim_unused_sm(bitstream_pio, true); + bitstream_sm_offset = pio_add_program(bitstream_pio, &unicorn_program); + } + + pio_gpio_init(bitstream_pio, pin::LED_DATA); + pio_gpio_init(bitstream_pio, pin::LED_CLOCK); + pio_gpio_init(bitstream_pio, pin::LED_LATCH); + pio_gpio_init(bitstream_pio, pin::LED_BLANK); + pio_gpio_init(bitstream_pio, pin::ROW_0); + pio_gpio_init(bitstream_pio, pin::ROW_1); + pio_gpio_init(bitstream_pio, pin::ROW_2); + pio_gpio_init(bitstream_pio, pin::ROW_3); + pio_gpio_init(bitstream_pio, pin::ROW_4); + pio_gpio_init(bitstream_pio, pin::ROW_5); + pio_gpio_init(bitstream_pio, pin::ROW_6); - // setup dma transfer for pixel data to the pio + pio_sm_set_consecutive_pindirs(bitstream_pio, bitstream_sm, pin::LED_DATA, 4, true); + pio_sm_set_consecutive_pindirs(bitstream_pio, bitstream_sm, pin::ROW_6, 7, true); + + pio_sm_config c = unicorn_program_get_default_config(bitstream_sm_offset); + + // osr shifts right, autopull on, autopull threshold 8 + sm_config_set_out_shift(&c, true, false, 32); + + // configure out, set, and sideset pins + sm_config_set_out_pins(&c, pin::ROW_6, 7); + sm_config_set_sideset_pins(&c, pin::LED_CLOCK); + sm_config_set_set_pins(&c, pin::LED_DATA, 4); + + // join fifos as only tx needed (gives 8 deep fifo instead of 4) + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + + // setup chained dma transfer for pixel data to the pio dma_channel = dma_claim_unused_channel(true); + dma_ctrl_channel = dma_claim_unused_channel(true); + + dma_channel_config ctrl_config = dma_channel_get_default_config(dma_ctrl_channel); + channel_config_set_transfer_data_size(&ctrl_config, DMA_SIZE_32); + channel_config_set_read_increment(&ctrl_config, false); + channel_config_set_write_increment(&ctrl_config, false); + channel_config_set_chain_to(&ctrl_config, dma_channel); + + dma_channel_configure( + dma_ctrl_channel, + &ctrl_config, + &dma_hw->ch[dma_channel].read_addr, + &bitstream_addr, + 1, + false + ); + dma_channel_config config = dma_channel_get_default_config(dma_channel); channel_config_set_transfer_data_size(&config, DMA_SIZE_32); channel_config_set_bswap(&config, false); // byte swap to reverse little endian channel_config_set_dreq(&config, pio_get_dreq(bitstream_pio, bitstream_sm, true)); - dma_channel_configure(dma_channel, &config, &bitstream_pio->txf[bitstream_sm], NULL, 0, false); - dma_channel_set_irq0_enabled(dma_channel, true); - irq_set_enabled(pio_get_dreq(bitstream_pio, bitstream_sm, true), true); - irq_set_exclusive_handler(DMA_IRQ_0, dma_complete); - irq_set_enabled(DMA_IRQ_0, true); + channel_config_set_chain_to(&config, dma_ctrl_channel); - dma_channel_set_trans_count(dma_channel, BITSTREAM_LENGTH / 4, false); - dma_channel_set_read_addr(dma_channel, bitstream, true); + dma_channel_configure( + dma_channel, + &config, + &bitstream_pio->txf[bitstream_sm], + NULL, + BITSTREAM_LENGTH / 4, + false); - already_init = true; + pio_sm_init(bitstream_pio, bitstream_sm, bitstream_sm_offset, &c); + pio_sm_set_enabled(bitstream_pio, bitstream_sm, true); + + // start the control channel + dma_start_channel_mask(1u << dma_ctrl_channel); + + unicorn = this; } void PicoUnicorn::clear() { @@ -269,4 +274,21 @@ namespace pimoroni { return !gpio_get(button); } + void PicoUnicorn::dma_safe_abort(uint channel) { + // Tear down the DMA channel. + // This is copied from: https://github.com/raspberrypi/pico-sdk/pull/744/commits/5e0e8004dd790f0155426e6689a66e08a83cd9fc + uint32_t irq0_save = dma_hw->inte0 & (1u << channel); + hw_clear_bits(&dma_hw->inte0, irq0_save); + + dma_hw->abort = 1u << channel; + + // To fence off on in-flight transfers, the BUSY bit should be polled + // rather than the ABORT bit, because the ABORT bit can clear prematurely. + while (dma_hw->ch[channel].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS) tight_loop_contents(); + + // Clear the interrupt (if any) and restore the interrupt masks. + dma_hw->ints0 = 1u << channel; + hw_set_bits(&dma_hw->inte0, irq0_save); + } + } diff --git a/libraries/pico_unicorn/pico_unicorn.hpp b/libraries/pico_unicorn/pico_unicorn.hpp index 9c7f9570..a251ecd1 100644 --- a/libraries/pico_unicorn/pico_unicorn.hpp +++ b/libraries/pico_unicorn/pico_unicorn.hpp @@ -12,11 +12,24 @@ namespace pimoroni { static const uint8_t B = 13; static const uint8_t X = 14; static const uint8_t Y = 15; + + static const uint32_t ROW_COUNT = 7; + static const uint32_t ROW_BYTES = 12; + static const uint32_t BCD_FRAMES = 15; // includes fet discharge frame + static const uint32_t BITSTREAM_LENGTH = (ROW_COUNT * ROW_BYTES * BCD_FRAMES); + private: - PIO bitstream_pio = pio0; - uint bitstream_sm = 0; - uint sm_offset = 0; + static PIO bitstream_pio; + static uint bitstream_sm; + static uint bitstream_sm_offset; + + // must be aligned for 32bit dma transfer + alignas(4) uint8_t bitstream[BITSTREAM_LENGTH] = {0}; + const uint32_t bitstream_addr = (uint32_t)bitstream; + static PicoUnicorn* unicorn; + public: + PicoUnicorn(); ~PicoUnicorn(); void init(); @@ -26,6 +39,9 @@ namespace pimoroni { void set_pixel(uint8_t x, uint8_t y, uint8_t v); bool is_pressed(uint8_t button); + private: + void partial_teardown(); + void dma_safe_abort(uint channel); }; } \ No newline at end of file diff --git a/micropython/examples/pico_unicorn/demo.py b/micropython/examples/pico_unicorn/demo.py index 9a3cb8ba..f488ee41 100644 --- a/micropython/examples/pico_unicorn/demo.py +++ b/micropython/examples/pico_unicorn/demo.py @@ -1,6 +1,6 @@ -import picounicorn +from picounicorn import PicoUnicorn -picounicorn.init() +picounicorn = PicoUnicorn() # From CPython Lib/colorsys.py diff --git a/micropython/examples/pico_unicorn/rainbow.py b/micropython/examples/pico_unicorn/rainbow.py index 40b2d26f..073a2b28 100644 --- a/micropython/examples/pico_unicorn/rainbow.py +++ b/micropython/examples/pico_unicorn/rainbow.py @@ -1,7 +1,7 @@ -import picounicorn +from picounicorn import PicoUnicorn import time -picounicorn.init() +picounicorn = PicoUnicorn() # From CPython Lib/colorsys.py diff --git a/micropython/modules/pico_unicorn/pico_unicorn.c b/micropython/modules/pico_unicorn/pico_unicorn.c index 8fcc54ad..37b80c29 100755 --- a/micropython/modules/pico_unicorn/pico_unicorn.c +++ b/micropython/modules/pico_unicorn/pico_unicorn.c @@ -16,30 +16,53 @@ enum buttons //////////////////////////////////////////////////////////////////////////////////////////////////// /***** Module Functions *****/ -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_init_obj, picounicorn_init); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_get_width_obj, picounicorn_get_width); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_get_height_obj, picounicorn_get_height); -//STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_update_obj, picounicorn_update); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picounicorn_set_pixel_obj, 5, 5, picounicorn_set_pixel); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picounicorn_set_pixel_value_obj, picounicorn_set_pixel_value); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_clear_obj, picounicorn_clear); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_is_pressed_obj, picounicorn_is_pressed); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn__del__obj, picounicorn__del__); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picounicorn_set_pixel_obj, 6, 6, picounicorn_set_pixel); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picounicorn_set_pixel_value_obj, 4, 4, picounicorn_set_pixel_value); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_clear_obj, picounicorn_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(picounicorn_is_pressed_obj, picounicorn_is_pressed); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_get_width_obj, picounicorn_get_width); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_get_height_obj, picounicorn_get_height); -/***** Globals Table *****/ -STATIC const mp_rom_map_elem_t picounicorn_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picounicorn) }, - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picounicorn_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picounicorn_get_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picounicorn_get_height_obj) }, - //{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picounicorn_update_obj) }, +STATIC const mp_rom_map_elem_t picounicorn_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&picounicorn__del__obj) }, { MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&picounicorn_set_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pixel_value), MP_ROM_PTR(&picounicorn_set_pixel_value_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picounicorn_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picounicorn_is_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picounicorn_is_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picounicorn_get_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picounicorn_get_height_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(picounicorn_locals_dict, picounicorn_locals_dict_table); + +#ifdef MP_DEFINE_CONST_OBJ_TYPE +MP_DEFINE_CONST_OBJ_TYPE( + picounicorn_type, + MP_QSTR_PicoUnicorn, + MP_TYPE_FLAG_NONE, + make_new, picounicorn_make_new, + locals_dict, (mp_obj_dict_t*)&picounicorn_locals_dict +); +#else +const mp_obj_type_t picounicorn_type = { + { &mp_type_type }, + .name = MP_QSTR_PicoUnicorn, + .make_new = picounicorn_make_new, + .locals_dict = (mp_obj_dict_t*)&picounicorn_locals_dict, +}; +#endif + +/***** Globals Table *****/ +STATIC const mp_rom_map_elem_t picounicorn_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picounicorn) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PicoUnicorn), (mp_obj_t)&picounicorn_type }, { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) }, { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) }, { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) }, { MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(16) }, + { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(7) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_picounicorn_globals, picounicorn_globals_table); diff --git a/micropython/modules/pico_unicorn/pico_unicorn.cpp b/micropython/modules/pico_unicorn/pico_unicorn.cpp index 86f4e90f..eab23eff 100644 --- a/micropython/modules/pico_unicorn/pico_unicorn.cpp +++ b/micropython/modules/pico_unicorn/pico_unicorn.cpp @@ -7,122 +7,116 @@ using namespace pimoroni; -PicoUnicorn *unicorn = nullptr; - extern "C" { #include "pico_unicorn.h" -#define NOT_INITIALISED_MSG "Cannot call this function, as picounicorn is not initialised. Call picounicorn.init() first." +typedef struct _picounicorn_obj_t { + mp_obj_base_t base; + PicoUnicorn *unicorn; +} picounicorn_obj_t; -mp_obj_t picounicorn_init() { - if(unicorn == nullptr) - unicorn = m_tracked_alloc_class(PicoUnicorn); - unicorn->init(); +mp_obj_t picounicorn_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + picounicorn_obj_t *self = m_new_obj_with_finaliser(picounicorn_obj_t); + self->base.type = &picounicorn_type; + self->unicorn = m_new_class(PicoUnicorn); + return MP_OBJ_FROM_PTR(self); +} + +mp_obj_t picounicorn__del__(mp_obj_t self_in) { + picounicorn_obj_t *self = MP_OBJ_TO_PTR2(self_in, picounicorn_obj_t); + m_del_class(PicoUnicorn, self->unicorn); return mp_const_none; } -mp_obj_t picounicorn_get_width() { +mp_obj_t picounicorn_get_width(mp_obj_t self_in) { + (void)self_in; return mp_obj_new_int(PicoUnicorn::WIDTH); } -mp_obj_t picounicorn_get_height() { +mp_obj_t picounicorn_get_height(mp_obj_t self_in) { + (void)self_in; return mp_obj_new_int(PicoUnicorn::HEIGHT); } -// mp_obj_t picounicorn_update() { -// unicorn.update(); -// return mp_const_none; -// } - mp_obj_t picounicorn_set_pixel(mp_uint_t n_args, const mp_obj_t *args) { - (void)n_args; //Unused input parameter, we know it's 5 + (void)n_args; // Unused input parameter, we know it's 5 - if(unicorn != nullptr) { - int x = mp_obj_get_int(args[0]); - int y = mp_obj_get_int(args[1]); - int r = mp_obj_get_int(args[2]); - int g = mp_obj_get_int(args[3]); - int b = mp_obj_get_int(args[4]); + enum { ARG_self, ARG_x, ARG_y, ARG_r, ARG_g, ARG_b }; - if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT) - mp_raise_ValueError("x or y out of range."); - else - { - if(r < 0 || r > 255) - mp_raise_ValueError("r out of range. Expected 0 to 255"); - else if(g < 0 || g > 255) - mp_raise_ValueError("g out of range. Expected 0 to 255"); - else if(b < 0 || b > 255) - mp_raise_ValueError("b out of range. Expected 0 to 255"); - else - unicorn->set_pixel(x, y, r, g, b); - } + picounicorn_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], picounicorn_obj_t); + + int x = mp_obj_get_int(args[ARG_x]); + int y = mp_obj_get_int(args[ARG_y]); + int r = mp_obj_get_int(args[ARG_r]); + int g = mp_obj_get_int(args[ARG_g]); + int b = mp_obj_get_int(args[ARG_b]); + + if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT) { + mp_raise_ValueError("x or y out of range."); } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + if(r < 0 || r > 255) mp_raise_ValueError("r out of range. Expected 0 to 255"); + if(g < 0 || g > 255) mp_raise_ValueError("g out of range. Expected 0 to 255"); + if(b < 0 || b > 255) mp_raise_ValueError("b out of range. Expected 0 to 255"); + self->unicorn->set_pixel(x, y, r, g, b); return mp_const_none; } -mp_obj_t picounicorn_set_pixel_value(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj) { - if(unicorn != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - int val = mp_obj_get_int(v_obj); +mp_obj_t picounicorn_set_pixel_value(size_t n_args, const mp_obj_t *args) { + enum { ARG_self, ARG_x, ARG_y, ARG_v }; - if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT) - mp_raise_ValueError("x or y out of range."); - else { - if(val < 0 || val > 255) - mp_raise_ValueError("val out of range. Expected 0 to 255"); - else - unicorn->set_pixel(x, y, val); - } + picounicorn_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], picounicorn_obj_t); + + int x = mp_obj_get_int(args[ARG_x]); + int y = mp_obj_get_int(args[ARG_y]); + int val = mp_obj_get_int(args[ARG_v]); + + if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT) { + mp_raise_ValueError("x or y out of range."); } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + if(val < 0 || val > 255) mp_raise_ValueError("val out of range. Expected 0 to 255"); + + self->unicorn->set_pixel(x, y, val); return mp_const_none; } -mp_obj_t picounicorn_clear() { - if(unicorn != nullptr) - unicorn->clear(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); +mp_obj_t picounicorn_clear(mp_obj_t self_in) { + picounicorn_obj_t *self = MP_OBJ_TO_PTR2(self_in, picounicorn_obj_t); + self->unicorn->clear(); return mp_const_none; } -mp_obj_t picounicorn_is_pressed(mp_obj_t button_obj) { +mp_obj_t picounicorn_is_pressed(mp_obj_t self_in, mp_obj_t button_obj) { + picounicorn_obj_t *self = MP_OBJ_TO_PTR2(self_in, picounicorn_obj_t); + bool buttonPressed = false; - - if(unicorn != nullptr) { - int buttonID = mp_obj_get_int(button_obj); - switch(buttonID) { - case 0: - buttonPressed = unicorn->is_pressed(PicoUnicorn::A); - break; + int buttonID = mp_obj_get_int(button_obj); - case 1: - buttonPressed = unicorn->is_pressed(PicoUnicorn::B); - break; + switch(buttonID) { + case 0: + buttonPressed = self->unicorn->is_pressed(PicoUnicorn::A); + break; - case 2: - buttonPressed = unicorn->is_pressed(PicoUnicorn::X); - break; + case 1: + buttonPressed = self->unicorn->is_pressed(PicoUnicorn::B); + break; - case 3: - buttonPressed = unicorn->is_pressed(PicoUnicorn::Y); - break; + case 2: + buttonPressed = self->unicorn->is_pressed(PicoUnicorn::X); + break; - default: - mp_raise_ValueError("button not valid. Expected 0 to 3"); - break; - } + case 3: + buttonPressed = self->unicorn->is_pressed(PicoUnicorn::Y); + break; + + default: + mp_raise_ValueError("button not valid. Expected 0 to 3"); + break; } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); return buttonPressed ? mp_const_true : mp_const_false; } diff --git a/micropython/modules/pico_unicorn/pico_unicorn.h b/micropython/modules/pico_unicorn/pico_unicorn.h index cf3d43cc..0ffa5f91 100644 --- a/micropython/modules/pico_unicorn/pico_unicorn.h +++ b/micropython/modules/pico_unicorn/pico_unicorn.h @@ -1,13 +1,13 @@ -// Include MicroPython API. -//#include "py/obj.h" #include "py/runtime.h" -// Declare the functions we'll make available in Python -extern mp_obj_t picounicorn_init(); -extern mp_obj_t picounicorn_get_width(); -extern mp_obj_t picounicorn_get_height(); -//extern mp_obj_t picounicorn_update(); +extern const mp_obj_type_t picounicorn_type; + +extern mp_obj_t picounicorn_get_width(mp_obj_t self_in); +extern mp_obj_t picounicorn_get_height(mp_obj_t self_in); + +extern mp_obj_t picounicorn__del__(mp_obj_t self_in); +extern mp_obj_t picounicorn_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); extern mp_obj_t picounicorn_set_pixel(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picounicorn_set_pixel_value(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj); -extern mp_obj_t picounicorn_clear(); -extern mp_obj_t picounicorn_is_pressed(mp_obj_t button_obj); \ No newline at end of file +extern mp_obj_t picounicorn_set_pixel_value(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picounicorn_clear(mp_obj_t self_in); +extern mp_obj_t picounicorn_is_pressed(mp_obj_t self_in, mp_obj_t button_obj); \ No newline at end of file From f2751ba6e90249aebb73c79119db0cfc3ffba8d9 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 16 Mar 2023 13:24:53 +0000 Subject: [PATCH 18/23] Pico Unicorn: Add support for PicoGraphics. --- examples/pico_unicorn/CMakeLists.txt | 2 +- examples/pico_unicorn_plasma/CMakeLists.txt | 2 +- libraries/pico_unicorn/pico_unicorn.cmake | 2 +- libraries/pico_unicorn/pico_unicorn.cpp | 53 +++++++++++++++++++ libraries/pico_unicorn/pico_unicorn.hpp | 3 ++ .../modules/pico_unicorn/micropython.cmake | 1 + .../modules/pico_unicorn/pico_unicorn.c | 2 + .../modules/pico_unicorn/pico_unicorn.cpp | 24 +++++++++ .../modules/pico_unicorn/pico_unicorn.h | 5 +- .../modules/picographics/picographics.c | 1 + .../modules/picographics/picographics.cpp | 21 +++++--- .../modules/picographics/picographics.h | 3 +- 12 files changed, 107 insertions(+), 12 deletions(-) diff --git a/examples/pico_unicorn/CMakeLists.txt b/examples/pico_unicorn/CMakeLists.txt index bdc84672..51120b99 100644 --- a/examples/pico_unicorn/CMakeLists.txt +++ b/examples/pico_unicorn/CMakeLists.txt @@ -4,7 +4,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(unicorn pico_stdlib hardware_pio hardware_dma pico_unicorn) +target_link_libraries(unicorn pico_stdlib hardware_pio hardware_dma pico_graphics pico_unicorn) # create map/bin/hex file etc. pico_add_extra_outputs(unicorn) diff --git a/examples/pico_unicorn_plasma/CMakeLists.txt b/examples/pico_unicorn_plasma/CMakeLists.txt index 9af28bee..44559f42 100644 --- a/examples/pico_unicorn_plasma/CMakeLists.txt +++ b/examples/pico_unicorn_plasma/CMakeLists.txt @@ -8,7 +8,7 @@ pico_enable_stdio_usb(unicornplasma 1) pico_enable_stdio_uart(unicornplasma 1) # Pull in pico libraries that we need -target_link_libraries(unicornplasma pico_stdlib hardware_pio hardware_dma pico_unicorn) +target_link_libraries(unicornplasma pico_stdlib hardware_pio hardware_dma pico_graphics pico_unicorn) # create map/bin/hex file etc. pico_add_extra_outputs(unicornplasma) diff --git a/libraries/pico_unicorn/pico_unicorn.cmake b/libraries/pico_unicorn/pico_unicorn.cmake index fd2a3c5c..ab622d8b 100644 --- a/libraries/pico_unicorn/pico_unicorn.cmake +++ b/libraries/pico_unicorn/pico_unicorn.cmake @@ -9,4 +9,4 @@ target_sources(pico_unicorn INTERFACE target_include_directories(pico_unicorn INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(pico_unicorn INTERFACE pico_stdlib hardware_pio hardware_dma) +target_link_libraries(pico_unicorn INTERFACE pico_stdlib pico_graphics hardware_pio hardware_dma) diff --git a/libraries/pico_unicorn/pico_unicorn.cpp b/libraries/pico_unicorn/pico_unicorn.cpp index 39576a4d..294d546e 100644 --- a/libraries/pico_unicorn/pico_unicorn.cpp +++ b/libraries/pico_unicorn/pico_unicorn.cpp @@ -291,4 +291,57 @@ namespace pimoroni { hw_set_bits(&dma_hw->inte0, irq0_save); } + void PicoUnicorn::update(PicoGraphics *graphics) { + if(unicorn == this) { + if(graphics->pen_type == PicoGraphics::PEN_RGB888) { + uint32_t *p = (uint32_t *)graphics->frame_buffer; + + for(int y = 0; y < HEIGHT; y++) { + for(int x = 0; x < WIDTH; x++) { + uint32_t col = *p; + uint8_t r = (col & 0xff0000) >> 16; + uint8_t g = (col & 0x00ff00) >> 8; + uint8_t b = (col & 0x0000ff) >> 0; + p++; + + set_pixel(x, y, r, g, b); + } + } + } + else if(graphics->pen_type == PicoGraphics::PEN_RGB565) { + uint16_t *p = (uint16_t *)graphics->frame_buffer; + for(int y = 0; y < HEIGHT; y++) { + for(int x = 0; x < WIDTH; x++) { + uint16_t col = __builtin_bswap16(*p); + uint8_t r = (col & 0b1111100000000000) >> 8; + uint8_t g = (col & 0b0000011111100000) >> 3; + uint8_t b = (col & 0b0000000000011111) << 3; + p++; + + set_pixel(x, y, r, g, b); + } + } + } + else if(graphics->pen_type == PicoGraphics::PEN_P8 || graphics->pen_type == PicoGraphics::PEN_P4) { + int offset = 0; + graphics->frame_convert(PicoGraphics::PEN_RGB888, [this, offset](void *data, size_t length) mutable { + uint32_t *p = (uint32_t *)data; + for(auto i = 0u; i < length / 4; i++) { + int x = offset % WIDTH; + int y = offset / WIDTH; + + uint32_t col = *p; + uint8_t r = (col & 0xff0000) >> 16; + uint8_t g = (col & 0x00ff00) >> 8; + uint8_t b = (col & 0x0000ff) >> 0; + + set_pixel(x, y, r, g, b); + offset++; + p++; + } + }); + } + } + } + } diff --git a/libraries/pico_unicorn/pico_unicorn.hpp b/libraries/pico_unicorn/pico_unicorn.hpp index a251ecd1..176a075a 100644 --- a/libraries/pico_unicorn/pico_unicorn.hpp +++ b/libraries/pico_unicorn/pico_unicorn.hpp @@ -1,6 +1,7 @@ #pragma once #include "hardware/pio.h" +#include "pico_graphics.hpp" namespace pimoroni { @@ -39,6 +40,8 @@ namespace pimoroni { void set_pixel(uint8_t x, uint8_t y, uint8_t v); bool is_pressed(uint8_t button); + + void update(PicoGraphics *graphics); private: void partial_teardown(); void dma_safe_abort(uint channel); diff --git a/micropython/modules/pico_unicorn/micropython.cmake b/micropython/modules/pico_unicorn/micropython.cmake index 261efebb..9190c767 100644 --- a/micropython/modules/pico_unicorn/micropython.cmake +++ b/micropython/modules/pico_unicorn/micropython.cmake @@ -10,6 +10,7 @@ pico_generate_pio_header(usermod_pico_unicorn ${CMAKE_CURRENT_LIST_DIR}/../../.. target_include_directories(usermod_pico_unicorn INTERFACE ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/ ) target_compile_definitions(usermod_pico_unicorn INTERFACE diff --git a/micropython/modules/pico_unicorn/pico_unicorn.c b/micropython/modules/pico_unicorn/pico_unicorn.c index 37b80c29..b97767e9 100755 --- a/micropython/modules/pico_unicorn/pico_unicorn.c +++ b/micropython/modules/pico_unicorn/pico_unicorn.c @@ -23,9 +23,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_clear_obj, picounicorn_clear); STATIC MP_DEFINE_CONST_FUN_OBJ_2(picounicorn_is_pressed_obj, picounicorn_is_pressed); STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_get_width_obj, picounicorn_get_width); STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_get_height_obj, picounicorn_get_height); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(picounicorn_update_obj, picounicorn_update); STATIC const mp_rom_map_elem_t picounicorn_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&picounicorn__del__obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picounicorn_update_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&picounicorn_set_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pixel_value), MP_ROM_PTR(&picounicorn_set_pixel_value_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picounicorn_clear_obj) }, diff --git a/micropython/modules/pico_unicorn/pico_unicorn.cpp b/micropython/modules/pico_unicorn/pico_unicorn.cpp index eab23eff..b5312344 100644 --- a/micropython/modules/pico_unicorn/pico_unicorn.cpp +++ b/micropython/modules/pico_unicorn/pico_unicorn.cpp @@ -4,18 +4,32 @@ #include "micropython/modules/util.hpp" #include "libraries/pico_unicorn/pico_unicorn.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" using namespace pimoroni; extern "C" { #include "pico_unicorn.h" +#include "micropython/modules/pimoroni_i2c/pimoroni_i2c.h" +#include "py/builtin.h" typedef struct _picounicorn_obj_t { mp_obj_base_t base; PicoUnicorn *unicorn; } picounicorn_obj_t; +// from picographics/picographics.cpp +// used to support accepting a PicoGraphics class +typedef struct _ModPicoGraphics_obj_t { + mp_obj_base_t base; + PicoGraphics *graphics; + DisplayDriver *display; + void *spritedata; + void *buffer; + _PimoroniI2C_obj_t *i2c; +} ModPicoGraphics_obj_t; + mp_obj_t picounicorn_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { picounicorn_obj_t *self = m_new_obj_with_finaliser(picounicorn_obj_t); self->base.type = &picounicorn_type; @@ -120,4 +134,14 @@ mp_obj_t picounicorn_is_pressed(mp_obj_t self_in, mp_obj_t button_obj) { return buttonPressed ? mp_const_true : mp_const_false; } + +mp_obj_t picounicorn_update(mp_obj_t self_in, mp_obj_t graphics_in) { + picounicorn_obj_t *self = MP_OBJ_TO_PTR2(self_in, picounicorn_obj_t); + ModPicoGraphics_obj_t *picographics = MP_OBJ_TO_PTR2(graphics_in, ModPicoGraphics_obj_t); + + if(picographics->base.type == &ModPicoGraphics_type) { + self->unicorn->update(picographics->graphics); + } + return mp_const_none; +} } \ No newline at end of file diff --git a/micropython/modules/pico_unicorn/pico_unicorn.h b/micropython/modules/pico_unicorn/pico_unicorn.h index 0ffa5f91..636e0f7d 100644 --- a/micropython/modules/pico_unicorn/pico_unicorn.h +++ b/micropython/modules/pico_unicorn/pico_unicorn.h @@ -1,6 +1,7 @@ #include "py/runtime.h" extern const mp_obj_type_t picounicorn_type; +extern const mp_obj_type_t ModPicoGraphics_type; extern mp_obj_t picounicorn_get_width(mp_obj_t self_in); extern mp_obj_t picounicorn_get_height(mp_obj_t self_in); @@ -10,4 +11,6 @@ extern mp_obj_t picounicorn_make_new(const mp_obj_type_t *type, size_t n_args, s extern mp_obj_t picounicorn_set_pixel(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picounicorn_set_pixel_value(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picounicorn_clear(mp_obj_t self_in); -extern mp_obj_t picounicorn_is_pressed(mp_obj_t self_in, mp_obj_t button_obj); \ No newline at end of file +extern mp_obj_t picounicorn_is_pressed(mp_obj_t self_in, mp_obj_t button_obj); + +extern mp_obj_t picounicorn_update(mp_obj_t self_in, mp_obj_t graphics_in); \ No newline at end of file diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index c11dda68..534c04b2 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -152,6 +152,7 @@ STATIC const mp_map_elem_t picographics_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_256X64), MP_ROM_INT(DISPLAY_INTERSTATE75_256X64) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_INKY_FRAME_7), MP_ROM_INT(DISPLAY_INKY_FRAME_7) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_COSMIC_UNICORN), MP_ROM_INT(DISPLAY_COSMIC_UNICORN) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_UNICORN_PACK), MP_ROM_INT(DISPLAY_UNICORN_PACK) }, { MP_ROM_QSTR(MP_QSTR_PEN_1BIT), MP_ROM_INT(PEN_1BIT) }, { MP_ROM_QSTR(MP_QSTR_PEN_P4), MP_ROM_INT(PEN_P4) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index f49494b4..24de1cad 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -210,6 +210,13 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height, if(rotate == -1) rotate = (int)Rotation::ROTATE_0; if(pen_type == -1) pen_type = PEN_RGB888; break; + case DISPLAY_UNICORN_PACK: + width = 16; + height = 7; + bus_type = BUS_PIO; + if(rotate == -1) rotate = (int)Rotation::ROTATE_0; + if(pen_type == -1) pen_type = PEN_RGB888; + break; default: return false; } @@ -331,17 +338,17 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size } else if (display == DISPLAY_INKY_PACK) { self->display = m_new_class(UC8151, width, height, (Rotation)rotate, spi_bus); - - } else if (display == DISPLAY_GALACTIC_UNICORN) { - self->display = m_new_class(DisplayDriver, width, height, (Rotation)rotate); } else if (display == DISPLAY_GFX_PACK) { self->display = m_new_class(ST7567, width, height, spi_bus); - } else if (display == DISPLAY_INTERSTATE75_32X32 || display == DISPLAY_INTERSTATE75_64X64 || display == DISPLAY_INTERSTATE75_64X32) { - self->display = m_new_class(DisplayDriver, width, height, (Rotation)rotate); - - } else if (display == DISPLAY_COSMIC_UNICORN) { + } else if (display == DISPLAY_INTERSTATE75_32X32 + || display == DISPLAY_INTERSTATE75_64X64 + || display == DISPLAY_INTERSTATE75_64X32 + || display == DISPLAY_GALACTIC_UNICORN + || display == DISPLAY_COSMIC_UNICORN + || display == DISPLAY_UNICORN_PACK) { + // Create a dummy display driver self->display = m_new_class(DisplayDriver, width, height, (Rotation)rotate); } else { diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index 665c307a..a0f3e78f 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -25,7 +25,8 @@ enum PicoGraphicsDisplay { DISPLAY_INTERSTATE75_192X64, DISPLAY_INTERSTATE75_256X64, DISPLAY_INKY_FRAME_7, - DISPLAY_COSMIC_UNICORN + DISPLAY_COSMIC_UNICORN, + DISPLAY_UNICORN_PACK }; enum PicoGraphicsPenType { From b83bdbf198e2c5629d77d2e3c79e5c6370d6e6d5 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 16 Mar 2023 13:33:17 +0000 Subject: [PATCH 19/23] MicroPython: Pico W parity with Pico build. --- micropython/modules/micropython-common.cmake | 33 ++++++++++++----- micropython/modules/micropython-picow.cmake | 39 +------------------- 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/micropython/modules/micropython-common.cmake b/micropython/modules/micropython-common.cmake index c33d36d2..04fac22f 100644 --- a/micropython/modules/micropython-common.cmake +++ b/micropython/modules/micropython-common.cmake @@ -1,31 +1,43 @@ +# Essential include(pimoroni_i2c/micropython) include(pimoroni_bus/micropython) +# Pico Graphics Essential +include(hershey_fonts/micropython) +include(bitmap_fonts/micropython) +include(picographics/micropython) + +# Pico Graphics Extra +include(jpegdec/micropython) +include(qrcode/micropython/micropython) + +# Sensors & Breakouts include(micropython-common-breakouts) +# Packs & Bases +include(pico_unicorn/micropython) include(pico_scroll/micropython) include(pico_rgb_keypad/micropython) -include(pico_unicorn/micropython) include(pico_wireless/micropython) include(pico_explorer/micropython) -include(hershey_fonts/micropython) -include(bitmap_fonts/micropython) - +# LEDs & Matrices include(plasma/micropython) include(hub75/micropython) + +# Servos & Motors include(pwm/micropython) include(servo/micropython) include(encoder/micropython) include(motor/micropython) -include(qrcode/micropython/micropython) + +# Utility include(adcfft/micropython) -include(pcf85063a/micropython) - -include(picographics/micropython) -include(jpegdec/micropython) -include(galactic_unicorn/micropython) +# RTC (Badger 2040W, Enviro) +if(PICO_BOARD STREQUAL "pico_w") + include(pcf85063a/micropython) +endif() include(modules_py/modules_py) @@ -37,4 +49,5 @@ if(PICO_BOARD STREQUAL "pico_w") copy_module(inventor.py) endif() +# Must call `enable_ulab()` to enable include(micropython-common-ulab) \ No newline at end of file diff --git a/micropython/modules/micropython-picow.cmake b/micropython/modules/micropython-picow.cmake index 0e5621a4..4f7e7280 100644 --- a/micropython/modules/micropython-picow.cmake +++ b/micropython/modules/micropython-picow.cmake @@ -7,41 +7,4 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) -# Essential -include(pimoroni_i2c/micropython) -include(pimoroni_bus/micropython) - -# Pico Graphics Essential -include(hershey_fonts/micropython) -include(bitmap_fonts/micropython) -include(picographics/micropython) - -# Pico Graphics Extra -include(jpegdec/micropython) -include(qrcode/micropython/micropython) - -# Sensors & Breakouts -include(micropython-common-breakouts) -include(pcf85063a/micropython) - -# Utility -include(adcfft/micropython) - -# LEDs & Matrices -include(plasma/micropython) -include(hub75/micropython) - -# Packs -include(pico_unicorn/micropython) -include(pico_scroll/micropython) -include(pico_rgb_keypad/micropython) - -# Servos & Motors -include(pwm/micropython) -include(servo/micropython) -include(encoder/micropython) -include(motor/micropython) - -# include(micropython-common) - -include(modules_py/modules_py) \ No newline at end of file +include(micropython-common) From 1b0b783a2f61c08e2fa247cd893a1cc344b682ea Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 16 Mar 2023 16:59:31 +0000 Subject: [PATCH 20/23] Pico Scroll: Add support for PicoGraphics. --- libraries/pico_scroll/pico_scroll.cmake | 2 +- libraries/pico_scroll/pico_scroll.cpp | 57 +++++++++++++++++++ libraries/pico_scroll/pico_scroll.hpp | 5 +- micropython/modules/pico_scroll/pico_scroll.c | 8 ++- .../modules/pico_scroll/pico_scroll.cpp | 25 +++++++- micropython/modules/pico_scroll/pico_scroll.h | 5 +- .../modules/picographics/picographics.c | 1 + .../modules/picographics/picographics.cpp | 10 +++- .../modules/picographics/picographics.h | 3 +- 9 files changed, 107 insertions(+), 9 deletions(-) diff --git a/libraries/pico_scroll/pico_scroll.cmake b/libraries/pico_scroll/pico_scroll.cmake index 3b42f97d..dbbfc94d 100644 --- a/libraries/pico_scroll/pico_scroll.cmake +++ b/libraries/pico_scroll/pico_scroll.cmake @@ -11,4 +11,4 @@ target_sources(pico_scroll INTERFACE target_include_directories(pico_scroll INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(pico_scroll INTERFACE pico_stdlib hardware_i2c) \ No newline at end of file +target_link_libraries(pico_scroll INTERFACE pico_stdlib pico_graphics hardware_i2c) \ No newline at end of file diff --git a/libraries/pico_scroll/pico_scroll.cpp b/libraries/pico_scroll/pico_scroll.cpp index 9522d4d5..1d3a99cb 100644 --- a/libraries/pico_scroll/pico_scroll.cpp +++ b/libraries/pico_scroll/pico_scroll.cpp @@ -171,4 +171,61 @@ namespace pimoroni { memcpy(&buffer[1], data, len); i2c_write_blocking(i2c0, DEFAULT_ADDRESS, buffer, len + 1, true); } + + void PicoScroll::update(PicoGraphics *graphics) { + if(graphics->pen_type == PicoGraphics::PEN_RGB888) { + uint32_t *p = (uint32_t *)graphics->frame_buffer; + + for(int y = 0; y < HEIGHT; y++) { + for(int x = 0; x < WIDTH; x++) { + uint32_t col = *p; + uint8_t r = (col & 0xff0000) >> 16; + uint8_t g = (col & 0x00ff00) >> 8; + uint8_t b = (col & 0x0000ff) >> 0; + p++; + + set_pixel(x, y, (r + g + b) / 3); + } + } + + update(); + } + else if(graphics->pen_type == PicoGraphics::PEN_RGB565) { + uint16_t *p = (uint16_t *)graphics->frame_buffer; + for(int y = 0; y < HEIGHT; y++) { + for(int x = 0; x < WIDTH; x++) { + uint16_t col = __builtin_bswap16(*p); + uint8_t r = (col & 0b1111100000000000) >> 8; + uint8_t g = (col & 0b0000011111100000) >> 3; + uint8_t b = (col & 0b0000000000011111) << 3; + p++; + + set_pixel(x, y, (r + g + b) / 3); + } + } + + update(); + } + else if(graphics->pen_type == PicoGraphics::PEN_P8 || graphics->pen_type == PicoGraphics::PEN_P4) { + int offset = 0; + graphics->frame_convert(PicoGraphics::PEN_RGB888, [this, offset](void *data, size_t length) mutable { + uint32_t *p = (uint32_t *)data; + for(auto i = 0u; i < length / 4; i++) { + int x = offset % WIDTH; + int y = offset / WIDTH; + + uint32_t col = *p; + uint8_t r = (col & 0xff0000) >> 16; + uint8_t g = (col & 0x00ff00) >> 8; + uint8_t b = (col & 0x0000ff) >> 0; + + set_pixel(x, y, (r + g + b) / 3); + offset++; + p++; + } + }); + + update(); + } + } } \ No newline at end of file diff --git a/libraries/pico_scroll/pico_scroll.hpp b/libraries/pico_scroll/pico_scroll.hpp index a7142fb2..dfa2c7b6 100644 --- a/libraries/pico_scroll/pico_scroll.hpp +++ b/libraries/pico_scroll/pico_scroll.hpp @@ -1,6 +1,8 @@ -#include #pragma once +#include +#include "pico_graphics.hpp" + namespace pimoroni { class PicoScroll { @@ -36,6 +38,7 @@ namespace pimoroni { void clear(); bool is_pressed(uint8_t button); + void update(PicoGraphics *graphics); private: void i2c_write(uint8_t reg, const char *data, uint8_t len); }; diff --git a/micropython/modules/pico_scroll/pico_scroll.c b/micropython/modules/pico_scroll/pico_scroll.c index eae44483..e18fa8eb 100644 --- a/micropython/modules/pico_scroll/pico_scroll.c +++ b/micropython/modules/pico_scroll/pico_scroll.c @@ -18,7 +18,7 @@ enum buttons STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll___del___obj, picoscroll___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_get_width_obj, picoscroll_get_width); STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_get_height_obj, picoscroll_get_height); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_update_obj, picoscroll_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_show_obj, picoscroll_show); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_set_pixel_obj, 4, 4, picoscroll_set_pixel); STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoscroll_set_pixels_obj, picoscroll_set_pixels); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_show_text_obj, 4, 4, picoscroll_show_text); @@ -26,13 +26,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_scroll_text_obj, 4, 4, pic STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_show_bitmap_1d_obj, 4, 4, picoscroll_show_bitmap_1d); STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_clear_obj, picoscroll_clear); STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoscroll_is_pressed_obj, picoscroll_is_pressed); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoscroll_update_obj, picoscroll_update); /* Class Methods */ STATIC const mp_rom_map_elem_t picoscroll_locals[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&picoscroll___del___obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&picoscroll___del___obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picoscroll_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&picoscroll_show_obj) }, { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picoscroll_get_width_obj) }, { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picoscroll_get_height_obj) }, - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picoscroll_update_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&picoscroll_set_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pixels), MP_ROM_PTR(&picoscroll_set_pixels_obj) }, { MP_ROM_QSTR(MP_QSTR_show_text), MP_ROM_PTR(&picoscroll_show_text_obj) }, diff --git a/micropython/modules/pico_scroll/pico_scroll.cpp b/micropython/modules/pico_scroll/pico_scroll.cpp index 7e4d2800..3effcd6f 100644 --- a/micropython/modules/pico_scroll/pico_scroll.cpp +++ b/micropython/modules/pico_scroll/pico_scroll.cpp @@ -15,6 +15,8 @@ PicoScroll *scroll = nullptr; extern "C" { #include "pico_scroll.h" +#include "micropython/modules/pimoroni_i2c/pimoroni_i2c.h" +#include "py/builtin.h" #define BUFFER_TOO_SMALL_MSG "bytearray too small: len(image) < width * height." #define INCORRECT_SIZE_MSG "Scroll height wrong: > 8 pixels." @@ -24,6 +26,17 @@ typedef struct _PicoScroll_obj_t { PicoScroll* scroll; } PicoScroll_obj_t; +// from picographics/picographics.cpp +// used to support accepting a PicoGraphics class +typedef struct _ModPicoGraphics_obj_t { + mp_obj_base_t base; + PicoGraphics *graphics; + DisplayDriver *display; + void *spritedata; + void *buffer; + _PimoroniI2C_obj_t *i2c; +} ModPicoGraphics_obj_t; + mp_obj_t picoscroll_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { _PicoScroll_obj_t *self = nullptr; @@ -52,7 +65,7 @@ mp_obj_t picoscroll_get_height(mp_obj_t self_in) { return mp_obj_new_int(PicoScroll::HEIGHT); } -mp_obj_t picoscroll_update(mp_obj_t self_in) { +mp_obj_t picoscroll_show(mp_obj_t self_in) { PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); self->scroll->update(); return mp_const_none; @@ -207,4 +220,14 @@ mp_obj_t picoscroll_is_pressed(mp_obj_t self_in, mp_obj_t button_obj) { return buttonPressed ? mp_const_true : mp_const_false; } + +mp_obj_t picoscroll_update(mp_obj_t self_in, mp_obj_t graphics_in) { + PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t); + ModPicoGraphics_obj_t *picographics = MP_OBJ_TO_PTR2(graphics_in, ModPicoGraphics_obj_t); + + if(picographics->base.type == &ModPicoGraphics_type) { + self->scroll->update(picographics->graphics); + } + return mp_const_none; +} } diff --git a/micropython/modules/pico_scroll/pico_scroll.h b/micropython/modules/pico_scroll/pico_scroll.h index e841f0cd..f5c9ac9a 100644 --- a/micropython/modules/pico_scroll/pico_scroll.h +++ b/micropython/modules/pico_scroll/pico_scroll.h @@ -3,13 +3,14 @@ #include "py/objstr.h" extern const mp_obj_type_t PicoScroll_type; +extern const mp_obj_type_t ModPicoGraphics_type; // Declare the functions we'll make available in Python extern mp_obj_t picoscroll_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); extern mp_obj_t picoscroll___del__(mp_obj_t self_in); extern mp_obj_t picoscroll_get_width(mp_obj_t self_in); extern mp_obj_t picoscroll_get_height(mp_obj_t self_in); -extern mp_obj_t picoscroll_update(mp_obj_t self_in); +extern mp_obj_t picoscroll_show(mp_obj_t self_in); extern mp_obj_t picoscroll_set_pixel(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picoscroll_set_pixels(mp_obj_t self_in, mp_obj_t image_obj); extern mp_obj_t picoscroll_show_text(mp_uint_t n_args, const mp_obj_t *args); @@ -17,3 +18,5 @@ extern mp_obj_t picoscroll_scroll_text(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picoscroll_show_bitmap_1d(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picoscroll_clear(mp_obj_t self_in); extern mp_obj_t picoscroll_is_pressed(mp_obj_t self_in, mp_obj_t button_obj); + +extern mp_obj_t picoscroll_update(mp_obj_t self_in, mp_obj_t graphics_in); \ No newline at end of file diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 534c04b2..ed034dce 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -153,6 +153,7 @@ STATIC const mp_map_elem_t picographics_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DISPLAY_INKY_FRAME_7), MP_ROM_INT(DISPLAY_INKY_FRAME_7) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_COSMIC_UNICORN), MP_ROM_INT(DISPLAY_COSMIC_UNICORN) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_UNICORN_PACK), MP_ROM_INT(DISPLAY_UNICORN_PACK) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_SCROLL_PACK), MP_ROM_INT(DISPLAY_SCROLL_PACK) }, { MP_ROM_QSTR(MP_QSTR_PEN_1BIT), MP_ROM_INT(PEN_1BIT) }, { MP_ROM_QSTR(MP_QSTR_PEN_P4), MP_ROM_INT(PEN_P4) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 24de1cad..989f1e32 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -217,6 +217,13 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height, if(rotate == -1) rotate = (int)Rotation::ROTATE_0; if(pen_type == -1) pen_type = PEN_RGB888; break; + case DISPLAY_SCROLL_PACK: + width = 17; + height = 7; + bus_type = BUS_PIO; + if(rotate == -1) rotate = (int)Rotation::ROTATE_0; + if(pen_type == -1) pen_type = PEN_RGB888; + break; default: return false; } @@ -347,7 +354,8 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size || display == DISPLAY_INTERSTATE75_64X32 || display == DISPLAY_GALACTIC_UNICORN || display == DISPLAY_COSMIC_UNICORN - || display == DISPLAY_UNICORN_PACK) { + || display == DISPLAY_UNICORN_PACK + || display == DISPLAY_SCROLL_PACK) { // Create a dummy display driver self->display = m_new_class(DisplayDriver, width, height, (Rotation)rotate); diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index a0f3e78f..e5ea8cf3 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -26,7 +26,8 @@ enum PicoGraphicsDisplay { DISPLAY_INTERSTATE75_256X64, DISPLAY_INKY_FRAME_7, DISPLAY_COSMIC_UNICORN, - DISPLAY_UNICORN_PACK + DISPLAY_UNICORN_PACK, + DISPLAY_SCROLL_PACK }; enum PicoGraphicsPenType { From f9b46ba3a718cf0efcd9145dd2022ef6a53a3237 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 16 Mar 2023 17:34:52 +0000 Subject: [PATCH 21/23] Pico Scroll: PicoGraphics scrolling text example. --- .../pico_scroll/picographics_scroll_text.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 micropython/examples/pico_scroll/picographics_scroll_text.py diff --git a/micropython/examples/pico_scroll/picographics_scroll_text.py b/micropython/examples/pico_scroll/picographics_scroll_text.py new file mode 100644 index 00000000..e7936e80 --- /dev/null +++ b/micropython/examples/pico_scroll/picographics_scroll_text.py @@ -0,0 +1,24 @@ +from picographics import PicoGraphics, DISPLAY_SCROLL_PACK, PEN_P8 +from picoscroll import PicoScroll +import time + +TEXT = "Hello World" + +# By default P8 has a greyscale palette +graphics = PicoGraphics(DISPLAY_SCROLL_PACK, pen_type=PEN_P8) +scroll = PicoScroll() + +t = scroll.get_width() + +wrap = -graphics.measure_text(TEXT, scale=0) + +while True: + graphics.set_pen(0) + graphics.clear() + graphics.set_pen(255) + graphics.text(TEXT, t, 0, scale=1) + scroll.update(graphics) + t -= 1 + time.sleep(0.1) + if t <= wrap: + t = scroll.get_width() From bb004e03a6839044870a8bae1af13922473a8a82 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 17 Mar 2023 11:18:43 +0000 Subject: [PATCH 22/23] Badger: Deprecate firmware builds. Remove builds for Badger 2040 and Badger 2040 W, these now live at: https://github.com/pimoroni/badger2040/ --- .github/workflows/micropython-badger2040.yml | 172 ------------------ .github/workflows/micropython-badger2040w.yml | 164 ----------------- 2 files changed, 336 deletions(-) delete mode 100644 .github/workflows/micropython-badger2040.yml delete mode 100644 .github/workflows/micropython-badger2040w.yml diff --git a/.github/workflows/micropython-badger2040.yml b/.github/workflows/micropython-badger2040.yml deleted file mode 100644 index 58c4a1be..00000000 --- a/.github/workflows/micropython-badger2040.yml +++ /dev/null @@ -1,172 +0,0 @@ -name: MicroPython for Badger2040 - -on: - push: - pull_request: - release: - types: [created] - -env: - MICROPYTHON_VERSION: 294098d28e2bad0ac0aad0d72595d11a82798096 - BOARD_TYPE: PIMORONI_BADGER2040 - # MicroPython version will be contained in github.event.release.tag_name for releases - RELEASE_FILE: pimoroni-badger2040-${{github.event.release.tag_name || github.sha}}-micropython - -jobs: - deps: - runs-on: ubuntu-20.04 - name: Dependencies - steps: - - name: Workspace Cache - id: cache - uses: actions/cache@v3 - with: - path: ${{runner.workspace}} - key: workspace-micropython-${{env.MICROPYTHON_VERSION}} - restore-keys: | - workspace-micropython-${{env.MICROPYTHON_VERSION}} - - # Check out MicroPython - - name: Checkout MicroPython - if: steps.cache.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: micropython/micropython - ref: ${{env.MICROPYTHON_VERSION}} - submodules: false # MicroPython submodules are hideously broken - path: micropython - - - name: Fetch base MicroPython submodules - if: steps.cache.outputs.cache-hit != 'true' - shell: bash - working-directory: micropython - run: git submodule update --init - - - name: Fetch Pico SDK submodules - if: steps.cache.outputs.cache-hit != 'true' - shell: bash - working-directory: micropython/lib/pico-sdk - run: git submodule update --init - - - name: Build mpy-cross - if: steps.cache.outputs.cache-hit != 'true' - shell: bash - working-directory: micropython/mpy-cross - run: make - - build: - needs: deps - name: Build Badger 2040 - runs-on: ubuntu-20.04 - - steps: - - name: Compiler Cache - uses: actions/cache@v3 - with: - path: /home/runner/.ccache - key: ccache-micropython-badger2040-${{github.ref}}-${{github.sha}} - restore-keys: | - ccache-micropython-badger2040-${{github.ref}} - ccache-micropython-badger2040- - - - name: Workspace Cache - uses: actions/cache@v3 - with: - path: ${{runner.workspace}} - key: workspace-micropython-${{env.MICROPYTHON_VERSION}} - restore-keys: | - workspace-micropython-${{env.MICROPYTHON_VERSION}} - - - uses: actions/checkout@v3 - with: - submodules: true - path: pimoroni-pico-${{ github.sha }} - - - name: "HACK: MicroPython Board Fixups" - shell: bash - working-directory: micropython/ports/rp2 - run: | - ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board/board-fixup.sh badger2040 ${{env.BOARD_TYPE}} ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board - - # Linux deps - - name: Install Compiler & CCache - if: runner.os == 'Linux' - run: | - sudo apt update && sudo apt install ccache gcc-arm-none-eabi - python3 -m pip install pillow - - # Build without BadgerOS - - name: Configure MicroPython (No BadgerOS) - shell: bash - working-directory: micropython/ports/rp2 - run: | - cmake -S . -B build-${{env.BOARD_TYPE}}-without-badger-os -DBADGER2040_NO_MODULES=1 -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/badger2040-micropython.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - - - name: Build MicroPython (No BadgerOS) - shell: bash - working-directory: micropython/ports/rp2 - run: | - ccache --zero-stats || true - cmake --build build-${{env.BOARD_TYPE}}-without-badger-os -j 2 - ccache --show-stats || true - - - name: Rename .uf2 for artifact (No BadgerOS) - shell: bash - working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os - run: | - cp firmware.uf2 ${{env.RELEASE_FILE}}-without-badger-os.uf2 - - - name: Store .uf2 as artifact (No BadgerOS) - uses: actions/upload-artifact@v3 - with: - name: ${{env.RELEASE_FILE}}-without-badger-os.uf2 - path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2 - - - name: Upload .uf2 (No BadgerOS) - if: github.event_name == 'release' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - with: - asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2 - upload_url: ${{github.event.release.upload_url}} - asset_name: ${{env.RELEASE_FILE}}-without-badger-os.uf2 - asset_content_type: application/octet-stream - - # Build with BadgerOS - - name: Configure MicroPython - shell: bash - working-directory: micropython/ports/rp2 - run: | - cmake -S . -B build-${{env.BOARD_TYPE}} -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/badger2040-micropython.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - - - name: Build MicroPython - shell: bash - working-directory: micropython/ports/rp2 - run: | - ccache --zero-stats || true - cmake --build build-${{env.BOARD_TYPE}} -j 2 - ccache --show-stats || true - - - name: Rename .uf2 for artifact - shell: bash - working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}} - run: | - cp firmware.uf2 ${{env.RELEASE_FILE}}.uf2 - - - name: Store .uf2 as artifact - uses: actions/upload-artifact@v3 - with: - name: ${{env.RELEASE_FILE}}.uf2 - path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 - - - name: Upload .uf2 - if: github.event_name == 'release' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - with: - asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 - upload_url: ${{github.event.release.upload_url}} - asset_name: ${{env.RELEASE_FILE}}.uf2 - asset_content_type: application/octet-stream diff --git a/.github/workflows/micropython-badger2040w.yml b/.github/workflows/micropython-badger2040w.yml deleted file mode 100644 index f17b9b26..00000000 --- a/.github/workflows/micropython-badger2040w.yml +++ /dev/null @@ -1,164 +0,0 @@ -name: MicroPython for Badger2040W - -on: - push: - pull_request: - release: - types: [created] - -env: - MICROPYTHON_VERSION: 294098d28e2bad0ac0aad0d72595d11a82798096 - BOARD_TYPE: PIMORONI_BADGER2040W - # MicroPython version will be contained in github.event.release.tag_name for releases - RELEASE_FILE: pimoroni-badger2040w-${{github.event.release.tag_name || github.sha}}-micropython - -jobs: - deps: - runs-on: ubuntu-20.04 - name: Dependencies - steps: - - name: Workspace Cache - id: cache - uses: actions/cache@v3 - with: - path: ${{runner.workspace}} - key: workspace-micropython-${{env.MICROPYTHON_VERSION}} - restore-keys: | - workspace-micropython-${{env.MICROPYTHON_VERSION}} - - # Check out MicroPython - - name: Checkout MicroPython - if: steps.cache.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: micropython/micropython - ref: ${{env.MICROPYTHON_VERSION}} - submodules: false # MicroPython submodules are hideously broken - path: micropython - - - name: Fetch base MicroPython submodules - if: steps.cache.outputs.cache-hit != 'true' - shell: bash - working-directory: micropython - run: git submodule update --init - - - name: Fetch Pico SDK submodules - if: steps.cache.outputs.cache-hit != 'true' - shell: bash - working-directory: micropython/lib/pico-sdk - run: git submodule update --init - - - name: Build mpy-cross - if: steps.cache.outputs.cache-hit != 'true' - shell: bash - working-directory: micropython/mpy-cross - run: make - - build: - needs: deps - name: Build Badger 2040W - runs-on: ubuntu-20.04 - - steps: - - name: Compiler Cache - uses: actions/cache@v3 - with: - path: /home/runner/.ccache - key: ccache-micropython-badger2040w-${{github.ref}}-${{github.sha}} - restore-keys: | - ccache-micropython-badger2040w-${{github.ref}} - ccache-micropython-badger2040w- - - - name: Workspace Cache - uses: actions/cache@v3 - with: - path: ${{runner.workspace}} - key: workspace-micropython-${{env.MICROPYTHON_VERSION}} - restore-keys: | - workspace-micropython-${{env.MICROPYTHON_VERSION}} - - - uses: actions/checkout@v3 - with: - submodules: true - path: pimoroni-pico-${{ github.sha }} - - # Check out dir2u2f - - uses: actions/checkout@v3 - with: - repository: gadgetoid/dir2uf2 - ref: v0.0.1 - path: dir2uf2 - - - name: "HACK: MicroPython Board Fixups" - shell: bash - working-directory: micropython/ports/rp2 - run: | - ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board/board-fixup.sh badger2040w ${{env.BOARD_TYPE}} ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board - - # Linux deps - - name: Install Compiler & CCache - if: runner.os == 'Linux' - run: | - sudo apt update && sudo apt install ccache gcc-arm-none-eabi - python3 -m pip install pillow - - # Build firmware - - name: Configure MicroPython - shell: bash - working-directory: micropython/ports/rp2 - run: | - cmake -S . -B build-${{env.BOARD_TYPE}} -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/micropython-badger2040w.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - - - name: Build MicroPython - shell: bash - working-directory: micropython/ports/rp2 - run: | - ccache --zero-stats || true - cmake --build build-${{env.BOARD_TYPE}} -j 2 - ccache --show-stats || true - - - name: Rename .uf2 for artifact - shell: bash - working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}} - run: | - cp firmware.uf2 ${{env.RELEASE_FILE}}.uf2 - - - name: Append Filesystem - shell: bash - run: | - python3 -m pip install littlefs-python - ./dir2uf2/dir2uf2 --append-to micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 --manifest pimoroni-pico-${{ github.sha }}/micropython/examples/badger2040w/uf2-manifest.txt --filename with-examples.uf2 pimoroni-pico-${{ github.sha }}/micropython/examples/badger2040w/ - - - name: Store .uf2 as artifact - uses: actions/upload-artifact@v3 - with: - name: ${{env.RELEASE_FILE}}.uf2 - path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 - - - name: Store .uf2 + examples as artifact - uses: actions/upload-artifact@v3 - with: - name: ${{env.RELEASE_FILE}}-with-examples.uf2 - path: ${{env.RELEASE_FILE}}-with-examples.uf2 - - - name: Upload .uf2 - if: github.event_name == 'release' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - with: - asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 - upload_url: ${{github.event.release.upload_url}} - asset_name: ${{env.RELEASE_FILE}}.uf2 - asset_content_type: application/octet-stream - - - name: Upload .uf2 + examples - if: github.event_name == 'release' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - with: - asset_path: ${{env.RELEASE_FILE}}-with-examples.uf2 - upload_url: ${{github.event.release.upload_url}} - asset_name: ${{env.RELEASE_FILE}}-with-examples.uf2 - asset_content_type: application/octet-stream From 587588dca5ad74920b47023f23f3a2a0784e9407 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 17 Mar 2023 11:21:39 +0000 Subject: [PATCH 23/23] CI: Bump MicroPython to 05bb260. Changes: https://github.com/micropython/micropython/compare/294098d28e2bad0ac0aad0d72595d11a82798096...05bb26010e4a466a82cfed179f8d8d0b406a78ca --- .github/workflows/micropython-picow.yml | 2 +- .github/workflows/micropython.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/micropython-picow.yml b/.github/workflows/micropython-picow.yml index c06d4b1c..80b45322 100644 --- a/.github/workflows/micropython-picow.yml +++ b/.github/workflows/micropython-picow.yml @@ -7,7 +7,7 @@ on: types: [created] env: - MICROPYTHON_VERSION: 294098d28e2bad0ac0aad0d72595d11a82798096 + MICROPYTHON_VERSION: 05bb26010e4a466a82cfed179f8d8d0b406a78ca jobs: deps: diff --git a/.github/workflows/micropython.yml b/.github/workflows/micropython.yml index fac13f74..a1be2c49 100644 --- a/.github/workflows/micropython.yml +++ b/.github/workflows/micropython.yml @@ -7,7 +7,7 @@ on: types: [created] env: - MICROPYTHON_VERSION: 294098d28e2bad0ac0aad0d72595d11a82798096 + MICROPYTHON_VERSION: 05bb26010e4a466a82cfed179f8d8d0b406a78ca jobs: deps: