From 7f5546f29a9da27293b1ae2cdaad82cfe1cda4d9 Mon Sep 17 00:00:00 2001 From: Jonathan Williamson Date: Wed, 25 May 2022 10:44:14 +0100 Subject: [PATCH 01/84] Tufty2040: Initial screen bringup. --- drivers/st7789/st7789.cpp | 33 ++++- drivers/st7789/st7789.hpp | 93 ++++++++----- examples/CMakeLists.txt | 1 + examples/tufty2040/CMakeLists.txt | 1 + examples/tufty2040/tufty2040_drawing.cmake | 14 ++ examples/tufty2040/tufty2040_drawing.cpp | 137 ++++++++++++++++++++ libraries/CMakeLists.txt | 1 + libraries/generic_st7789/generic_st7789.hpp | 8 ++ libraries/tufty2040/CMakeLists.txt | 1 + libraries/tufty2040/tufty2040.cmake | 11 ++ libraries/tufty2040/tufty2040.cpp | 7 + libraries/tufty2040/tufty2040.hpp | 60 +++++++++ 12 files changed, 330 insertions(+), 37 deletions(-) create mode 100644 examples/tufty2040/CMakeLists.txt create mode 100644 examples/tufty2040/tufty2040_drawing.cmake create mode 100644 examples/tufty2040/tufty2040_drawing.cpp create mode 100644 libraries/tufty2040/CMakeLists.txt create mode 100644 libraries/tufty2040/tufty2040.cmake create mode 100644 libraries/tufty2040/tufty2040.cpp create mode 100644 libraries/tufty2040/tufty2040.hpp diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 0c0e2969..0c49a89b 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -173,26 +173,47 @@ namespace pimoroni { } uint ST7789::get_sck() const { - return sck; + return wr_sck; } uint ST7789::get_mosi() const { - return mosi; + return d0; } uint ST7789::get_bl() const { return bl; } - void ST7789::command(uint8_t command, size_t len, const char *data) { - gpio_put(cs, 0); + void ST7789::write_blocking_parallel(const uint8_t *src, size_t len) { + uint32_t mask = 0xff << d0; + while(len--) { + gpio_put(wr_sck, false); + uint8_t v = *src++; + gpio_put_masked(mask, v << d0); + asm("nop;"); + gpio_put(wr_sck, true); + asm("nop;"); + } + } + void ST7789::command(uint8_t command, size_t len, const char *data) { gpio_put(dc, 0); // command mode - spi_write_blocking(spi, &command, 1); + + gpio_put(cs, 0); + + if(spi) { + spi_write_blocking(spi, &command, 1); + } else { + write_blocking_parallel(&command, 1); + } if(data) { gpio_put(dc, 1); // data mode - spi_write_blocking(spi, (const uint8_t*)data, len); + if(spi) { + spi_write_blocking(spi, (const uint8_t*)data, len); + } else { + write_blocking_parallel((const uint8_t*)data, len); + } } gpio_put(cs, 1); diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index e2bc7cc7..522924f1 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -23,8 +23,9 @@ namespace pimoroni { // interface pins with our standard defaults where appropriate uint cs; uint dc; - uint sck; - uint mosi; + uint wr_sck; + uint rd_sck = PIN_UNUSED; + uint d0; uint bl; uint vsync = PIN_UNUSED; // only available on some products @@ -37,46 +38,58 @@ namespace pimoroni { // frame buffer where pixel data is stored uint16_t *frame_buffer; + // Parallel init + ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer, + uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) : + spi(nullptr), + width(width), height(height), round(false), + cs(cs), dc(dc), wr_sck(wr_sck), rd_sck(rd_sck), d0(d0), bl(bl), frame_buffer(frame_buffer) { + + gpio_set_function(cs, GPIO_FUNC_SIO); + gpio_set_dir(cs, GPIO_OUT); + + gpio_set_function(dc, GPIO_FUNC_SIO); + gpio_set_dir(dc, GPIO_OUT); + + gpio_set_function(wr_sck, GPIO_FUNC_SIO); + gpio_set_dir(wr_sck, GPIO_OUT); + + gpio_set_function(rd_sck, GPIO_FUNC_SIO); + gpio_set_dir(rd_sck, GPIO_OUT); + + for(auto i = 0u; i < 8; i++) { + gpio_set_function(d0 + i, GPIO_FUNC_SIO); + gpio_set_dir(d0 + i, GPIO_OUT); + } + + gpio_put(rd_sck, 1); + + common_init(); + } + + // Serial init ST7789(uint16_t width, uint16_t height, bool round, uint16_t *frame_buffer, spi_inst_t *spi, uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) : spi(spi), width(width), height(height), round(round), - cs(cs), dc(dc), sck(sck), mosi(mosi), bl(bl), frame_buffer(frame_buffer) { + cs(cs), dc(dc), wr_sck(sck), d0(mosi), bl(bl), frame_buffer(frame_buffer) { - if(!this->frame_buffer) { - this->frame_buffer = new uint16_t[width * height]; - } + // configure spi interface and pins + spi_init(spi, SPI_BAUD); - // configure spi interface and pins - spi_init(spi, SPI_BAUD); + gpio_set_function(dc, GPIO_FUNC_SIO); + gpio_set_dir(dc, GPIO_OUT); - gpio_set_function(dc, GPIO_FUNC_SIO); - gpio_set_dir(dc, GPIO_OUT); + gpio_set_function(cs, GPIO_FUNC_SIO); + gpio_set_dir(cs, GPIO_OUT); - gpio_set_function(cs, GPIO_FUNC_SIO); - gpio_set_dir(cs, GPIO_OUT); + gpio_set_function(wr_sck, GPIO_FUNC_SPI); + gpio_set_function(d0, GPIO_FUNC_SPI); - gpio_set_function(sck, GPIO_FUNC_SPI); - gpio_set_function(mosi, GPIO_FUNC_SPI); + common_init(); + } - // if a backlight pin is provided then set it up for - // pwm control - if(bl != PIN_UNUSED) { - pwm_config cfg = pwm_get_default_config(); - pwm_set_wrap(pwm_gpio_to_slice_num(bl), 65535); - pwm_init(pwm_gpio_to_slice_num(bl), &cfg, true); - gpio_set_function(bl, GPIO_FUNC_PWM); - set_backlight(0); // Turn backlight off initially to avoid nasty surprises - } - - } - - - //-------------------------------------------------- - // Methods - //-------------------------------------------------- - public: void init(); void configure_display(bool rotate180); @@ -115,6 +128,24 @@ namespace pimoroni { } return PIN_UNUSED; }; + + private: + void write_blocking_parallel(const uint8_t *src, size_t len); + void common_init() { + if(!this->frame_buffer) { + this->frame_buffer = new uint16_t[width * height]; + } + + // if a backlight pin is provided then set it up for + // pwm control + if(bl != PIN_UNUSED) { + pwm_config cfg = pwm_get_default_config(); + pwm_set_wrap(pwm_gpio_to_slice_num(bl), 65535); + pwm_init(pwm_gpio_to_slice_num(bl), &cfg, true); + gpio_set_function(bl, GPIO_FUNC_PWM); + set_backlight(0); // Turn backlight off initially to avoid nasty surprises + } + } }; } diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 8e45b4d8..f9675d27 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -44,6 +44,7 @@ add_subdirectory(pico_wireless) add_subdirectory(plasma2040) add_subdirectory(badger2040) +add_subdirectory(tufty2040) add_subdirectory(interstate75) add_subdirectory(servo2040) add_subdirectory(motor2040) diff --git a/examples/tufty2040/CMakeLists.txt b/examples/tufty2040/CMakeLists.txt new file mode 100644 index 00000000..282ad558 --- /dev/null +++ b/examples/tufty2040/CMakeLists.txt @@ -0,0 +1 @@ +include(tufty2040_drawing.cmake) diff --git a/examples/tufty2040/tufty2040_drawing.cmake b/examples/tufty2040/tufty2040_drawing.cmake new file mode 100644 index 00000000..f918ea3f --- /dev/null +++ b/examples/tufty2040/tufty2040_drawing.cmake @@ -0,0 +1,14 @@ +set(OUTPUT_NAME tufty2040_drawing) +add_executable(${OUTPUT_NAME} tufty2040_drawing.cpp) + +target_link_libraries(${OUTPUT_NAME} + tufty2040 + hardware_spi + generic_st7789 + button +) + +# enable usb output +pico_enable_stdio_usb(${OUTPUT_NAME} 1) + +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/tufty2040/tufty2040_drawing.cpp b/examples/tufty2040/tufty2040_drawing.cpp new file mode 100644 index 00000000..687df518 --- /dev/null +++ b/examples/tufty2040/tufty2040_drawing.cpp @@ -0,0 +1,137 @@ +#include "pico/stdlib.h" +#include +#include +#include +#include +#include "pico/time.h" +#include "pico/platform.h" + +#include "common/pimoroni_common.hpp" +#include "generic_st7789.hpp" +#include "tufty2040.hpp" +#include "button.hpp" + +using namespace pimoroni; + +Tufty2040 tufty; + +uint16_t buffer[Tufty2040::WIDTH * Tufty2040::HEIGHT]; + + static const uint8_t LCD_CS = 10; + static const uint8_t LCD_DC = 11; + static const uint8_t LCD_WR = 12; + static const uint8_t LCD_RD = 13; + static const uint8_t LCD_D0 = 14; + + + +// Swap WIDTH and HEIGHT to rotate 90 degrees +ST7789Generic pico_display( + Tufty2040::WIDTH, Tufty2040::HEIGHT, + buffer, + Tufty2040::LCD_CS, Tufty2040::LCD_DC, Tufty2040::LCD_WR, Tufty2040::LCD_RD, Tufty2040::LCD_D0, + Tufty2040::BACKLIGHT +); + +Button button_a(Tufty2040::A); +Button button_b(Tufty2040::B); +Button button_c(Tufty2040::C); +Button button_up(Tufty2040::UP); +Button button_down(Tufty2040::DOWN); + +uint32_t time() { + absolute_time_t t = get_absolute_time(); + return to_ms_since_boot(t); +} + +// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel +// Outputs are rgb in the range 0-255 for each channel +void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { + float i = floor(h * 6.0f); + float f = h * 6.0f - i; + v *= 255.0f; + uint8_t p = v * (1.0f - s); + uint8_t q = v * (1.0f - f * s); + uint8_t t = v * (1.0f - (1.0f - f) * s); + + switch (int(i) % 6) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } +} + +int main() { + pico_display.set_backlight(255); + pico_display.configure_display(true); // Rotate 180 + + struct pt { + float x; + float y; + uint8_t r; + float dx; + float dy; + uint16_t pen; + }; + + std::vector shapes; + for(int i = 0; i < 100; i++) { + pt shape; + shape.x = rand() % pico_display.bounds.w; + shape.y = rand() % pico_display.bounds.h; + shape.r = (rand() % 10) + 3; + shape.dx = float(rand() % 255) / 64.0f; + shape.dy = float(rand() % 255) / 64.0f; + shape.pen = pico_display.create_pen(rand() % 255, rand() % 255, rand() % 255); + shapes.push_back(shape); + } + + Point text_location(0, 0); + uint8_t i = 0; + + while(true) { + + pico_display.set_pen(120, 40, 60); + pico_display.clear(); + + for(auto &shape : shapes) { + shape.x += shape.dx; + shape.y += shape.dy; + if((shape.x - shape.r) < 0) { + shape.dx *= -1; + shape.x = shape.r; + } + if((shape.x + shape.r) >= pico_display.bounds.w) { + shape.dx *= -1; + shape.x = pico_display.bounds.w - shape.r; + } + if((shape.y - shape.r) < 0) { + shape.dy *= -1; + shape.y = shape.r; + } + if((shape.y + shape.r) >= pico_display.bounds.h) { + shape.dy *= -1; + shape.y = pico_display.bounds.h - shape.r; + } + + pico_display.set_pen(shape.pen); + pico_display.circle(Point(shape.x, shape.y), shape.r); + + } + + + pico_display.set_pen(255, 255, 255); + pico_display.text("Hello World", text_location, 320); + + // update screen + pico_display.update(); + + i+=10; + tufty.led(i); + } + + return 0; +} diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 0304d153..47f1031c 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -29,6 +29,7 @@ add_subdirectory(pico_rgb_keypad) add_subdirectory(pico_wireless) add_subdirectory(plasma2040) add_subdirectory(badger2040) +add_subdirectory(tufty2040) add_subdirectory(servo2040) add_subdirectory(motor2040) add_subdirectory(adcfft) diff --git a/libraries/generic_st7789/generic_st7789.hpp b/libraries/generic_st7789/generic_st7789.hpp index fd7e61d0..f68aaa9c 100644 --- a/libraries/generic_st7789/generic_st7789.hpp +++ b/libraries/generic_st7789/generic_st7789.hpp @@ -33,6 +33,14 @@ namespace pimoroni { this->st7789.init(); }; + ST7789Generic(uint16_t width, uint16_t height, uint16_t *frame_buffer, + uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) : + PicoGraphics(width, height, frame_buffer), + st7789(width, height, frame_buffer, cs, dc, wr_sck, rd_sck, d0, bl) { + this->frame_buffer = st7789.frame_buffer; + this->st7789.init(); + }; + spi_inst_t* get_spi() const; int get_cs() const; int get_dc() const; diff --git a/libraries/tufty2040/CMakeLists.txt b/libraries/tufty2040/CMakeLists.txt new file mode 100644 index 00000000..8f727a06 --- /dev/null +++ b/libraries/tufty2040/CMakeLists.txt @@ -0,0 +1 @@ +include(tufty2040.cmake) \ No newline at end of file diff --git a/libraries/tufty2040/tufty2040.cmake b/libraries/tufty2040/tufty2040.cmake new file mode 100644 index 00000000..ecc4dccb --- /dev/null +++ b/libraries/tufty2040/tufty2040.cmake @@ -0,0 +1,11 @@ +set(LIB_NAME tufty2040) +add_library(${LIB_NAME} INTERFACE) + +target_sources(${LIB_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +) + +target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_pwm) diff --git a/libraries/tufty2040/tufty2040.cpp b/libraries/tufty2040/tufty2040.cpp new file mode 100644 index 00000000..c32350c6 --- /dev/null +++ b/libraries/tufty2040/tufty2040.cpp @@ -0,0 +1,7 @@ +#include +#include + +#include "tufty2040.hpp" + +namespace pimoroni { +} \ No newline at end of file diff --git a/libraries/tufty2040/tufty2040.hpp b/libraries/tufty2040/tufty2040.hpp new file mode 100644 index 00000000..dca2283f --- /dev/null +++ b/libraries/tufty2040/tufty2040.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +#include "hardware/gpio.h" // Workaround SDK bug - https://github.com/raspberrypi/pico-sdk/issues/3 +#include "hardware/pwm.h" + +namespace pimoroni { + + class Tufty2040 { + public: + static const int WIDTH = 320; + static const int HEIGHT = 240; + static const uint8_t A = 7; + static const uint8_t B = 8; + static const uint8_t C = 9; + static const uint8_t Y = 15; + static const uint8_t UP = 22; + static const uint8_t DOWN = 6; + static const uint8_t LED = 25; + static const uint8_t BACKLIGHT = 2; + + + static const uint8_t LCD_CS = 10; + static const uint8_t LCD_DC = 11; + static const uint8_t LCD_WR = 12; + static const uint8_t LCD_RD = 13; + static const uint8_t LCD_D0 = 14; + + public: + Tufty2040() { + + gpio_set_function(LCD_D0 + 0, GPIO_FUNC_SIO); gpio_set_dir(LCD_D0 + 0, true); + gpio_set_function(LCD_D0 + 1, GPIO_FUNC_SIO); gpio_set_dir(LCD_D0 + 1, true); + gpio_set_function(LCD_D0 + 2, GPIO_FUNC_SIO); gpio_set_dir(LCD_D0 + 2, true); + gpio_set_function(LCD_D0 + 3, GPIO_FUNC_SIO); gpio_set_dir(LCD_D0 + 3, true); + gpio_set_function(LCD_D0 + 4, GPIO_FUNC_SIO); gpio_set_dir(LCD_D0 + 4, true); + gpio_set_function(LCD_D0 + 5, GPIO_FUNC_SIO); gpio_set_dir(LCD_D0 + 5, true); + gpio_set_function(LCD_D0 + 6, GPIO_FUNC_SIO); gpio_set_dir(LCD_D0 + 6, true); + gpio_set_function(LCD_D0 + 7, GPIO_FUNC_SIO); gpio_set_dir(LCD_D0 + 7, true); + + // led control pin + pwm_config cfg = pwm_get_default_config(); + pwm_set_wrap(pwm_gpio_to_slice_num(LED), 65535); + pwm_init(pwm_gpio_to_slice_num(LED), &cfg, true); + gpio_set_function(LED, GPIO_FUNC_PWM); + led(0); + } + + void led(uint8_t brightness) { + // set the led brightness from 1 to 256 with gamma correction + float gamma = 2.8; + uint16_t v = (uint16_t)(pow((float)(brightness) / 256.0f, gamma) * 65535.0f + 0.5f); + pwm_set_gpio_level(LED, v); + } + + }; + +} From b42425b000b0c50f0c987aa61f0669788943d466 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 25 May 2022 12:25:47 +0100 Subject: [PATCH 02/84] Tufty2040: MicroPython bindings for ST7789Parallel. --- micropython/modules/st7789/st7789.c | 9 +++ micropython/modules/st7789/st7789.cpp | 91 ++++++++++++++++++++++----- micropython/modules/st7789/st7789.h | 2 + 3 files changed, 88 insertions(+), 14 deletions(-) diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index 783831f2..fcd64a95 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -46,10 +46,19 @@ const mp_obj_type_t GenericST7789_type = { .locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict, }; +const mp_obj_type_t GenericST7789Parallel_type = { + { &mp_type_type }, + .name = MP_QSTR_st7789, + .print = GenericST7789_print, + .make_new = GenericST7789Parallel_make_new, + .locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict, +}; + /***** Module Globals *****/ STATIC const mp_map_elem_t st7789_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) }, { MP_OBJ_NEW_QSTR(MP_QSTR_ST7789), (mp_obj_t)&GenericST7789_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ST7789Parallel), (mp_obj_t)&GenericST7789Parallel_type }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_st7789_globals, st7789_globals_table); diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 7d6f0a27..a7602a67 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -13,6 +13,7 @@ extern "C" { typedef struct _GenericST7789_obj_t { mp_obj_base_t base; ST7789Generic *st7789; + bool parallel; uint16_t *buffer; } GenericST7789_obj_t; @@ -21,27 +22,31 @@ void GenericST7789_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin (void)kind; //Unused input parameter GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - mp_print_str(print, "ST7789("); + if(self->parallel) { + mp_print_str(print, "ST7789Parallel()"); + } else { + mp_print_str(print, "ST7789("); - mp_print_str(print, "spi = "); - mp_obj_print_helper(print, mp_obj_new_int((self->st7789->get_spi() == spi0) ? 0 : 1), PRINT_REPR); + mp_print_str(print, "spi = "); + mp_obj_print_helper(print, mp_obj_new_int((self->st7789->get_spi() == spi0) ? 0 : 1), PRINT_REPR); - mp_print_str(print, ", cs = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_cs()), PRINT_REPR); + mp_print_str(print, ", cs = "); + mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_cs()), PRINT_REPR); - mp_print_str(print, ", dc = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_dc()), PRINT_REPR); + mp_print_str(print, ", dc = "); + mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_dc()), PRINT_REPR); - mp_print_str(print, ", sck = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_sck()), PRINT_REPR); + mp_print_str(print, ", sck = "); + mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_sck()), PRINT_REPR); - mp_print_str(print, ", mosi = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_mosi()), PRINT_REPR); + mp_print_str(print, ", mosi = "); + mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_mosi()), PRINT_REPR); - mp_print_str(print, ", bl = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_bl()), PRINT_REPR); + mp_print_str(print, ", bl = "); + mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_bl()), PRINT_REPR); - mp_print_str(print, ")"); + mp_print_str(print, ")"); + } } /***** Constructor *****/ @@ -70,6 +75,7 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t self = m_new_obj(GenericST7789_obj_t); self->base.type = &GenericST7789_type; + self->parallel = false; bool rotate180 = args[ARG_rotate180].u_obj == mp_const_true; bool round = args[ARG_round].u_obj == mp_const_true; @@ -127,6 +133,63 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t return MP_OBJ_FROM_PTR(self); } +mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + GenericST7789_obj_t *self = nullptr; + + enum { ARG_width, ARG_height, ARG_cs, ARG_dc, ARG_wr_sck, ARG_rd_sck, ARG_d0, ARG_bl, ARG_rotate180, ARG_buffer }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_cs, MP_ARG_INT, {.u_int = 10} }, + { MP_QSTR_dc, MP_ARG_INT, {.u_int = 11} }, + { MP_QSTR_wr_sck, MP_ARG_INT, {.u_int = 12} }, + { MP_QSTR_rd_sck, MP_ARG_INT, {.u_int = 13} }, + { MP_QSTR_d0, MP_ARG_INT, {.u_int = 14} }, + + { MP_QSTR_bl, MP_ARG_INT, {.u_int = 2} }, + { MP_QSTR_rotate180, MP_ARG_OBJ, {.u_obj = mp_const_false} }, + { MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + self = m_new_obj(GenericST7789_obj_t); + self->base.type = &GenericST7789_type; + self->parallel = true; + + bool rotate180 = args[ARG_rotate180].u_obj == mp_const_true; + int width = args[ARG_width].u_int; + int height = args[ARG_height].u_int; + + if (args[ARG_buffer].u_obj != mp_const_none) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); + self->buffer = (uint16_t *)bufinfo.buf; + if(bufinfo.len < (size_t)(width * height * 2)) { + mp_raise_ValueError("Supplied buffer is too small!"); + } + } else { + self->buffer = m_new(uint16_t, width * height); + } + + int cs = args[ARG_cs].u_int; + int dc = args[ARG_dc].u_int; + int wr_sck = args[ARG_wr_sck].u_int; + int rd_sck = args[ARG_rd_sck].u_int; + int d0 = args[ARG_d0].u_int; + int bl = args[ARG_bl].u_int; + + self->st7789 = m_new_class(ST7789Generic, width, height, self->buffer, + cs, dc, wr_sck, rd_sck, d0, bl); + if (rotate180) { + self->st7789->configure_display(true); + } + + return MP_OBJ_FROM_PTR(self); +} + /***** Methods *****/ mp_obj_t GenericST7789_update(mp_obj_t self_in) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h index ecbdba10..c72a9e4a 100644 --- a/micropython/modules/st7789/st7789.h +++ b/micropython/modules/st7789/st7789.h @@ -8,6 +8,8 @@ extern const mp_obj_type_t GenericST7789_type; /***** Extern of Class Methods *****/ extern void GenericST7789_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); extern mp_obj_t GenericST7789_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 GenericST7789Parallel_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 GenericST7789_update(mp_obj_t self_in); extern mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); From 446db105f9486caa915bdbda90b4ad3e25d50883 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 25 May 2022 17:21:27 +0100 Subject: [PATCH 03/84] Tufty2040: JPEG Decode --- micropython/modules/jpegdec/JPEGDEC.h | 262 ++ micropython/modules/jpegdec/jpeg.c | 3487 +++++++++++++++++ micropython/modules/jpegdec/jpegdec.c | 121 + micropython/modules/jpegdec/micropython.cmake | 18 + micropython/modules/micropython-common.cmake | 3 +- 5 files changed, 3890 insertions(+), 1 deletion(-) create mode 100644 micropython/modules/jpegdec/JPEGDEC.h create mode 100644 micropython/modules/jpegdec/jpeg.c create mode 100644 micropython/modules/jpegdec/jpegdec.c create mode 100644 micropython/modules/jpegdec/micropython.cmake diff --git a/micropython/modules/jpegdec/JPEGDEC.h b/micropython/modules/jpegdec/JPEGDEC.h new file mode 100644 index 00000000..38c92a3a --- /dev/null +++ b/micropython/modules/jpegdec/JPEGDEC.h @@ -0,0 +1,262 @@ +// +// Copyright 2020 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +// +#ifndef __JPEGDEC__ +#define __JPEGDEC__ +#if defined( __MACH__ ) || defined( __LINUX__ ) || defined( __MCUXPRESSO ) || defined( PICO_BUILD ) +#include +#include +#include +#include +#else +#include +#if !defined(HAL_ESP32_HAL_H_) && defined(__has_include) && __has_include() +#include +#endif +#endif +#ifndef PROGMEM +#define memcpy_P memcpy +#define PROGMEM +#endif +// +// JPEG Decoder +// Written by Larry Bank +// Copyright (c) 2020 BitBank Software, Inc. +// +// Designed to decode baseline JPEG images (8 or 24-bpp) +// using less than 22K of RAM +// + +/* Defines and variables */ +#define FILE_HIGHWATER 1536 +#define JPEG_FILE_BUF_SIZE 2048 +#define HUFF_TABLEN 273 +#define HUFF11SIZE (1<<11) +#define DC_TABLE_SIZE 1024 +#define DCTSIZE 64 +#define MAX_MCU_COUNT 6 +#define MAX_COMPS_IN_SCAN 4 +#define MAX_BUFFERED_PIXELS 2048 + +// Decoder options +#define JPEG_AUTO_ROTATE 1 +#define JPEG_SCALE_HALF 2 +#define JPEG_SCALE_QUARTER 4 +#define JPEG_SCALE_EIGHTH 8 +#define JPEG_LE_PIXELS 16 +#define JPEG_EXIF_THUMBNAIL 32 +#define JPEG_LUMA_ONLY 64 + +#define MCU0 (DCTSIZE * 0) +#define MCU1 (DCTSIZE * 1) +#define MCU2 (DCTSIZE * 2) +#define MCU3 (DCTSIZE * 3) +#define MCU4 (DCTSIZE * 4) +#define MCU5 (DCTSIZE * 5) + +// Pixel types (defaults to little endian RGB565) +enum { + RGB565_LITTLE_ENDIAN = 0, + RGB565_BIG_ENDIAN, + EIGHT_BIT_GRAYSCALE, + FOUR_BIT_DITHERED, + TWO_BIT_DITHERED, + ONE_BIT_DITHERED, + INVALID_PIXEL_TYPE +}; + +enum { + JPEG_MEM_RAM=0, + JPEG_MEM_FLASH +}; + +// Error codes returned by getLastError() +enum { + JPEG_SUCCESS = 0, + JPEG_INVALID_PARAMETER, + JPEG_DECODE_ERROR, + JPEG_UNSUPPORTED_FEATURE, + JPEG_INVALID_FILE +}; + +typedef struct buffered_bits +{ +unsigned char *pBuf; // buffer pointer +uint32_t ulBits; // buffered bits +uint32_t ulBitOff; // current bit offset +} BUFFERED_BITS; + +typedef struct jpeg_file_tag +{ + int32_t iPos; // current file position + int32_t iSize; // file size + uint8_t *pData; // memory file pointer + void * fHandle; // class pointer to File/SdFat or whatever you want +} JPEGFILE; + +typedef struct jpeg_draw_tag +{ + int x, y; // upper left corner of current MCU + int iWidth, iHeight; // size of this MCU + int iBpp; // bit depth of the pixels (8 or 16) + uint16_t *pPixels; // 16-bit pixels +} JPEGDRAW; + +// Callback function prototypes +typedef int32_t (JPEG_READ_CALLBACK)(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen); +typedef int32_t (JPEG_SEEK_CALLBACK)(JPEGFILE *pFile, int32_t iPosition); +typedef int (JPEG_DRAW_CALLBACK)(JPEGDRAW *pDraw); +typedef void * (JPEG_OPEN_CALLBACK)(const char *szFilename, int32_t *pFileSize); +typedef void (JPEG_CLOSE_CALLBACK)(void *pHandle); + +/* JPEG color component info */ +typedef struct _jpegcompinfo +{ +// These values are fixed over the whole image +// For compression, they must be supplied by the user interface +// for decompression, they are read from the SOF marker. +unsigned char component_needed; /* do we need the value of this component? */ +unsigned char component_id; /* identifier for this component (0..255) */ +unsigned char component_index; /* its index in SOF or cinfo->comp_info[] */ +//unsigned char h_samp_factor; /* horizontal sampling factor (1..4) */ +//unsigned char v_samp_factor; /* vertical sampling factor (1..4) */ +unsigned char quant_tbl_no; /* quantization table selector (0..3) */ +// These values may vary between scans +// For compression, they must be supplied by the user interface +// for decompression, they are read from the SOS marker. +unsigned char dc_tbl_no; /* DC entropy table selector (0..3) */ +unsigned char ac_tbl_no; /* AC entropy table selector (0..3) */ +// These values are computed during compression or decompression startup +//int true_comp_width; /* component's image width in samples */ +//int true_comp_height; /* component's image height in samples */ +// the above are the logical dimensions of the downsampled image +// These values are computed before starting a scan of the component +//int MCU_width; /* number of blocks per MCU, horizontally */ +//int MCU_height; /* number of blocks per MCU, vertically */ +//int MCU_blocks; /* MCU_width * MCU_height */ +//int downsampled_width; /* image width in samples, after expansion */ +//int downsampled_height; /* image height in samples, after expansion */ +// the above are the true_comp_xxx values rounded up to multiples of +// the MCU dimensions; these are the working dimensions of the array +// as it is passed through the DCT or IDCT step. NOTE: these values +// differ depending on whether the component is interleaved or not!! +// This flag is used only for decompression. In cases where some of the +// components will be ignored (eg grayscale output from YCbCr image), +// we can skip IDCT etc. computations for the unused components. +} JPEGCOMPINFO; + +// +// our private structure to hold a JPEG image decode state +// +typedef struct jpeg_image_tag +{ + int iWidth, iHeight; // image size + int iThumbWidth, iThumbHeight; // thumbnail size (if present) + int iThumbData; // offset to image data + int iXOffset, iYOffset; // placement on the display + uint8_t ucBpp, ucSubSample, ucHuffTableUsed; + uint8_t ucMode, ucOrientation, ucHasThumb, b11Bit; + uint8_t ucComponentsInScan, cApproxBitsLow, cApproxBitsHigh; + uint8_t iScanStart, iScanEnd, ucFF, ucNumComponents; + uint8_t ucACTable, ucDCTable, ucMaxACCol, ucMaxACRow; + uint8_t ucMemType, ucPixelType; + int iEXIF; // Offset to EXIF 'TIFF' file + int iError; + int iOptions; + int iVLCOff; // current VLC data offset + int iVLCSize; // current quantity of data in the VLC buffer + int iResInterval, iResCount; // restart interval + int iMaxMCUs; // max MCUs of pixels per JPEGDraw call + JPEG_READ_CALLBACK *pfnRead; + JPEG_SEEK_CALLBACK *pfnSeek; + JPEG_DRAW_CALLBACK *pfnDraw; + JPEG_OPEN_CALLBACK *pfnOpen; + JPEG_CLOSE_CALLBACK *pfnClose; + JPEGCOMPINFO JPCI[MAX_COMPS_IN_SCAN]; /* Max color components */ + JPEGFILE JPEGFile; + BUFFERED_BITS bb; + uint8_t *pDitherBuffer; // provided externally to do Floyd-Steinberg dithering + uint16_t usPixels[MAX_BUFFERED_PIXELS]; + int16_t sMCUs[DCTSIZE * MAX_MCU_COUNT]; // 4:2:0 needs 6 DCT blocks per MCU + int16_t sQuantTable[DCTSIZE*4]; // quantization tables + uint8_t ucFileBuf[JPEG_FILE_BUF_SIZE]; // holds temp data and pixel stack + uint8_t ucHuffDC[DC_TABLE_SIZE * 2]; // up to 2 'short' tables + uint16_t usHuffAC[HUFF11SIZE * 2]; +} JPEGIMAGE; + +#ifdef __cplusplus +#if defined(__has_include) && __has_include() +#include "FS.h" +#endif +#define JPEG_STATIC static +// +// The JPEGDEC class wraps portable C code which does the actual work +// +class JPEGDEC +{ + public: + int openRAM(uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw); + int openFLASH(uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw); + int open(const char *szFilename, JPEG_OPEN_CALLBACK *pfnOpen, JPEG_CLOSE_CALLBACK *pfnClose, JPEG_READ_CALLBACK *pfnRead, JPEG_SEEK_CALLBACK *pfnSeek, JPEG_DRAW_CALLBACK *pfnDraw); +#ifdef FS_H + int open(File &file, JPEG_DRAW_CALLBACK *pfnDraw); +#endif + void close(); + int decode(int x, int y, int iOptions); + int decodeDither(uint8_t *pDither, int iOptions); + int getOrientation(); + int getWidth(); + int getHeight(); + int getBpp(); + int getSubSample(); + int hasThumb(); + int getThumbWidth(); + int getThumbHeight(); + int getLastError(); + void setPixelType(int iType); // defaults to little endian + void setMaxOutputSize(int iMaxMCUs); + + private: + JPEGIMAGE _jpeg; +}; +#else +#define JPEG_STATIC +int JPEG_openRAM(JPEGIMAGE *pJPEG, uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw); +int JPEG_openFile(JPEGIMAGE *pJPEG, const char *szFilename, JPEG_DRAW_CALLBACK *pfnDraw); +int JPEG_getWidth(JPEGIMAGE *pJPEG); +int JPEG_getHeight(JPEGIMAGE *pJPEG); +int JPEG_decode(JPEGIMAGE *pJPEG, int x, int y, int iOptions); +int JPEG_decodeDither(JPEGIMAGE *pJPEG, uint8_t *pDither, int iOptions); +void JPEG_close(JPEGIMAGE *pJPEG); +int JPEG_getLastError(JPEGIMAGE *pJPEG); +int JPEG_getOrientation(JPEGIMAGE *pJPEG); +int JPEG_getBpp(JPEGIMAGE *pJPEG); +int JPEG_getSubSample(JPEGIMAGE *pJPEG); +int JPEG_hasThumb(JPEGIMAGE *pJPEG); +int JPEG_getThumbWidth(JPEGIMAGE *pJPEG); +int JPEG_getThumbHeight(JPEGIMAGE *pJPEG); +int JPEG_getLastError(JPEGIMAGE *pJPEG); +void JPEG_setPixelType(JPEGIMAGE *pJPEG, int iType); // defaults to little endian +void JPEG_setMaxOutputSize(JPEGIMAGE *pJPEG, int iMaxMCUs); +#endif // __cplusplus + +// Due to unaligned memory causing an exception, we have to do these macros the slow way +#define INTELSHORT(p) ((*p) + (*(p+1)<<8)) +#define INTELLONG(p) ((*p) + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24)) +#define MOTOSHORT(p) (((*(p))<<8) + (*(p+1))) +#define MOTOLONG(p) (((*p)<<24) + ((*(p+1))<<16) + ((*(p+2))<<8) + (*(p+3))) + +// Must be a 32-bit target processor +#define REGISTER_WIDTH 32 + +#endif // __JPEGDEC__ diff --git a/micropython/modules/jpegdec/jpeg.c b/micropython/modules/jpegdec/jpeg.c new file mode 100644 index 00000000..6618a35c --- /dev/null +++ b/micropython/modules/jpegdec/jpeg.c @@ -0,0 +1,3487 @@ +// +// JPEG Decoder +// +// written by Larry Bank +// bitbank@pobox.com +// Arduino port started 8/2/2020 +// Original JPEG code written 26+ years ago :) +// The goal of this code is to decode baseline JPEG images +// using no more than 18K of RAM (if sent directly to an LCD display) +// +// Copyright 2020 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +// +#include "JPEGDEC.h" + +#if defined(ARM_MATH_CM4) || defined(ARM_MATH_CM7) +#define HAS_SIMD +#endif + +// forward references +static int JPEGInit(JPEGIMAGE *pJPEG); +static int JPEGParseInfo(JPEGIMAGE *pPage, int bExtractThumb); +static void JPEGGetMoreData(JPEGIMAGE *pPage); +static int DecodeJPEG(JPEGIMAGE *pImage); +static int32_t readRAM(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen); +static int32_t seekMem(JPEGFILE *pFile, int32_t iPosition); +static int32_t readFile(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen); +static int32_t seekFile(JPEGFILE *pFile, int32_t iPosition); +static void closeFile(void *handle); +static void JPEGDither(JPEGIMAGE *pJPEG, int iWidth, int iHeight); +/* JPEG tables */ +// zigzag ordering of DCT coefficients +static const unsigned char cZigZag[64] = {0,1,5,6,14,15,27,28, + 2,4,7,13,16,26,29,42, + 3,8,12,17,25,30,41,43, + 9,11,18,24,31,40,44,53, + 10,19,23,32,39,45,52,54, + 20,22,33,38,46,51,55,60, + 21,34,37,47,50,56,59,61, + 35,36,48,49,57,58,62,63}; + +// un-zigzag ordering +static const unsigned char cZigZag2[64] = {0,1,8,16,9,2,3,10, + 17,24,32,25,18,11,4,5, + 12,19,26,33,40,48,41,34, + 27,20,13,6,7,14,21,28, + 35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51, + 58,59,52,45,38,31,39,46, + 53,60,61,54,47,55,62,63}; + +// For AA&N IDCT method, multipliers are equal to quantization +// coefficients scaled by scalefactor[row]*scalefactor[col], where +// scalefactor[0] = 1 +// scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 +// For integer operation, the multiplier table is to be scaled by +// IFAST_SCALE_BITS. +static const int iScaleBits[64] = {16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247}; +// +// Range clip and shift for RGB565 output +// input value is 0 to 255, then another 256 for overflow to FF, then 512 more for negative values wrapping around +// Trims a few instructions off the final output stage +// +static const uint8_t ucRangeTable[] = {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, + 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, + 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, + 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, + 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, + 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f}; + +// +// Convert 8-bit grayscale into RGB565 +// +static const uint16_t usGrayTo565[] = {0x0000,0x0000,0x0000,0x0000,0x0020,0x0020,0x0020,0x0020, // 0 + 0x0841,0x0841,0x0841,0x0841,0x0861,0x0861,0x0861,0x0861, + 0x1082,0x1082,0x1082,0x1082,0x10a2,0x10a2,0x10a2,0x10a2, + 0x18c3,0x18c3,0x18c3,0x18c3,0x18e3,0x18e3,0x18e3,0x18e3, + 0x2104,0x2104,0x2104,0x2104,0x2124,0x2124,0x2124,0x2124, + 0x2945,0x2945,0x2945,0x2945,0x2965,0x2965,0x2965,0x2965, + 0x3186,0x3186,0x3186,0x3186,0x31a6,0x31a6,0x31a6,0x31a6, + 0x39c7,0x39c7,0x39c7,0x39c7,0x39e7,0x39e7,0x39e7,0x39e7, + 0x4208,0x4208,0x4208,0x4208,0x4228,0x4228,0x4228,0x4228, + 0x4a49,0x4a49,0x4a49,0x4a49,0x4a69,0x4a69,0x4a69,0x4a69, + 0x528a,0x528a,0x528a,0x528a,0x52aa,0x52aa,0x52aa,0x52aa, + 0x5acb,0x5acb,0x5acb,0x5acb,0x5aeb,0x5aeb,0x5aeb,0x5aeb, + 0x630c,0x630c,0x630c,0x630c,0x632c,0x632c,0x632c,0x632c, + 0x6b4d,0x6b4d,0x6b4d,0x6b4d,0x6b6d,0x6b6d,0x6b6d,0x6b6d, + 0x738e,0x738e,0x738e,0x738e,0x73ae,0x73ae,0x73ae,0x73ae, + 0x7bcf,0x7bcf,0x7bcf,0x7bcf,0x7bef,0x7bef,0x7bef,0x7bef, + 0x8410,0x8410,0x8410,0x8410,0x8430,0x8430,0x8430,0x8430, + 0x8c51,0x8c51,0x8c51,0x8c51,0x8c71,0x8c71,0x8c71,0x8c71, + 0x9492,0x9492,0x9492,0x9492,0x94b2,0x94b2,0x94b2,0x94b2, + 0x9cd3,0x9cd3,0x9cd3,0x9cd3,0x9cf3,0x9cf3,0x9cf3,0x9cf3, + 0xa514,0xa514,0xa514,0xa514,0xa534,0xa534,0xa534,0xa534, + 0xad55,0xad55,0xad55,0xad55,0xad75,0xad75,0xad75,0xad75, + 0xb596,0xb596,0xb596,0xb596,0xb5b6,0xb5b6,0xb5b6,0xb5b6, + 0xbdd7,0xbdd7,0xbdd7,0xbdd7,0xbdf7,0xbdf7,0xbdf7,0xbdf7, + 0xc618,0xc618,0xc618,0xc618,0xc638,0xc638,0xc638,0xc638, + 0xce59,0xce59,0xce59,0xce59,0xce79,0xce79,0xce79,0xce79, + 0xd69a,0xd69a,0xd69a,0xd69a,0xd6ba,0xd6ba,0xd6ba,0xd6ba, + 0xdedb,0xdedb,0xdedb,0xdedb,0xdefb,0xdefb,0xdefb,0xdefb, + 0xe71c,0xe71c,0xe71c,0xe71c,0xe73c,0xe73c,0xe73c,0xe73c, + 0xef5d,0xef5d,0xef5d,0xef5d,0xef7d,0xef7d,0xef7d,0xef7d, + 0xf79e,0xf79e,0xf79e,0xf79e,0xf7be,0xf7be,0xf7be,0xf7be, + 0xffdf,0xffdf,0xffdf,0xffdf,0xffff,0xffff,0xffff,0xffff}; +// +// Clip and convert red value into 5-bits for RGB565 +// +static const uint16_t usRangeTableR[] = {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // 0 + 0x0800,0x0800,0x0800,0x0800,0x0800,0x0800,0x0800,0x0800, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800, + 0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, + 0x2800,0x2800,0x2800,0x2800,0x2800,0x2800,0x2800,0x2800, + 0x3000,0x3000,0x3000,0x3000,0x3000,0x3000,0x3000,0x3000, + 0x3800,0x3800,0x3800,0x3800,0x3800,0x3800,0x3800,0x3800, + 0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, + 0x4800,0x4800,0x4800,0x4800,0x4800,0x4800,0x4800,0x4800, + 0x5000,0x5000,0x5000,0x5000,0x5000,0x5000,0x5000,0x5000, + 0x5800,0x5800,0x5800,0x5800,0x5800,0x5800,0x5800,0x5800, + 0x6000,0x6000,0x6000,0x6000,0x6000,0x6000,0x6000,0x6000, + 0x6800,0x6800,0x6800,0x6800,0x6800,0x6800,0x6800,0x6800, + 0x7000,0x7000,0x7000,0x7000,0x7000,0x7000,0x7000,0x7000, + 0x7800,0x7800,0x7800,0x7800,0x7800,0x7800,0x7800,0x7800, + 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, + 0x8800,0x8800,0x8800,0x8800,0x8800,0x8800,0x8800,0x8800, + 0x9000,0x9000,0x9000,0x9000,0x9000,0x9000,0x9000,0x9000, + 0x9800,0x9800,0x9800,0x9800,0x9800,0x9800,0x9800,0x9800, + 0xa000,0xa000,0xa000,0xa000,0xa000,0xa000,0xa000,0xa000, + 0xa800,0xa800,0xa800,0xa800,0xa800,0xa800,0xa800,0xa800, + 0xb000,0xb000,0xb000,0xb000,0xb000,0xb000,0xb000,0xb000, + 0xb800,0xb800,0xb800,0xb800,0xb800,0xb800,0xb800,0xb800, + 0xc000,0xc000,0xc000,0xc000,0xc000,0xc000,0xc000,0xc000, + 0xc800,0xc800,0xc800,0xc800,0xc800,0xc800,0xc800,0xc800, + 0xd000,0xd000,0xd000,0xd000,0xd000,0xd000,0xd000,0xd000, + 0xd800,0xd800,0xd800,0xd800,0xd800,0xd800,0xd800,0xd800, + 0xe000,0xe000,0xe000,0xe000,0xe000,0xe000,0xe000,0xe000, + 0xe800,0xe800,0xe800,0xe800,0xe800,0xe800,0xe800,0xe800, + 0xf000,0xf000,0xf000,0xf000,0xf000,0xf000,0xf000,0xf000, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, // 256 + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 512 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 768 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +// +// Clip and convert green value into 5-bits for RGB565 +// +static const uint16_t usRangeTableG[] = {0x0000,0x0000,0x0000,0x0000,0x0020,0x0020,0x0020,0x0020, // 0 + 0x0040,0x0040,0x0040,0x0040,0x0060,0x0060,0x0060,0x0060, + 0x0080,0x0080,0x0080,0x0080,0x00a0,0x00a0,0x00a0,0x00a0, + 0x00c0,0x00c0,0x00c0,0x00c0,0x00e0,0x00e0,0x00e0,0x00e0, + 0x0100,0x0100,0x0100,0x0100,0x0120,0x0120,0x0120,0x0120, + 0x0140,0x0140,0x0140,0x0140,0x0160,0x0160,0x0160,0x0160, + 0x0180,0x0180,0x0180,0x0180,0x01a0,0x01a0,0x01a0,0x01a0, + 0x01c0,0x01c0,0x01c0,0x01c0,0x01e0,0x01e0,0x01e0,0x01e0, + 0x0200,0x0200,0x0200,0x0200,0x0220,0x0220,0x0220,0x0220, + 0x0240,0x0240,0x0240,0x0240,0x0260,0x0260,0x0260,0x0260, + 0x0280,0x0280,0x0280,0x0280,0x02a0,0x02a0,0x02a0,0x02a0, + 0x02c0,0x02c0,0x02c0,0x02c0,0x02e0,0x02e0,0x02e0,0x02e0, + 0x0300,0x0300,0x0300,0x0300,0x0320,0x0320,0x0320,0x0320, + 0x0340,0x0340,0x0340,0x0340,0x0360,0x0360,0x0360,0x0360, + 0x0380,0x0380,0x0380,0x0380,0x03a0,0x03a0,0x03a0,0x03a0, + 0x03c0,0x03c0,0x03c0,0x03c0,0x03e0,0x03e0,0x03e0,0x03e0, + 0x0400,0x0400,0x0400,0x0400,0x0420,0x0420,0x0420,0x0420, + 0x0440,0x0440,0x0440,0x0440,0x0460,0x0460,0x0460,0x0460, + 0x0480,0x0480,0x0480,0x0480,0x04a0,0x04a0,0x04a0,0x04a0, + 0x04c0,0x04c0,0x04c0,0x04c0,0x04e0,0x04e0,0x04e0,0x04e0, + 0x0500,0x0500,0x0500,0x0500,0x0520,0x0520,0x0520,0x0520, + 0x0540,0x0540,0x0540,0x0540,0x0560,0x0560,0x0560,0x0560, + 0x0580,0x0580,0x0580,0x0580,0x05a0,0x05a0,0x05a0,0x05a0, + 0x05c0,0x05c0,0x05c0,0x05c0,0x05e0,0x05e0,0x05e0,0x05e0, + 0x0600,0x0600,0x0600,0x0600,0x0620,0x0620,0x0620,0x0620, + 0x0640,0x0640,0x0640,0x0640,0x0660,0x0660,0x0660,0x0660, + 0x0680,0x0680,0x0680,0x0680,0x06a0,0x06a0,0x06a0,0x06a0, + 0x06c0,0x06c0,0x06c0,0x06c0,0x06e0,0x06e0,0x06e0,0x06e0, + 0x0700,0x0700,0x0700,0x0700,0x0720,0x0720,0x0720,0x0720, + 0x0740,0x0740,0x0740,0x0740,0x0760,0x0760,0x0760,0x0760, + 0x0780,0x0780,0x0780,0x0780,0x07a0,0x07a0,0x07a0,0x07a0, + 0x07c0,0x07c0,0x07c0,0x07c0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, // 256 + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 512 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 768 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +// +// Clip and convert blue value into 5-bits for RGB565 +// +static const uint16_t usRangeTableB[] = {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // 0 + 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001, + 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004, + 0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007, + 0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x000a,0x000a,0x000a,0x000a,0x000a,0x000a,0x000a,0x000a, + 0x000b,0x000b,0x000b,0x000b,0x000b,0x000b,0x000b,0x000b, + 0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000e,0x000e,0x000e,0x000e,0x000e,0x000e,0x000e,0x000e, + 0x000f,0x000f,0x000f,0x000f,0x000f,0x000f,0x000f,0x000f, + 0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0012,0x0012,0x0012,0x0012,0x0012,0x0012,0x0012,0x0012, + 0x0013,0x0013,0x0013,0x0013,0x0013,0x0013,0x0013,0x0013, + 0x0014,0x0014,0x0014,0x0014,0x0014,0x0014,0x0014,0x0014, + 0x0015,0x0015,0x0015,0x0015,0x0015,0x0015,0x0015,0x0015, + 0x0016,0x0016,0x0016,0x0016,0x0016,0x0016,0x0016,0x0016, + 0x0017,0x0017,0x0017,0x0017,0x0017,0x0017,0x0017,0x0017, + 0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018, + 0x0019,0x0019,0x0019,0x0019,0x0019,0x0019,0x0019,0x0019, + 0x001a,0x001a,0x001a,0x001a,0x001a,0x001a,0x001a,0x001a, + 0x001b,0x001b,0x001b,0x001b,0x001b,0x001b,0x001b,0x001b, + 0x001c,0x001c,0x001c,0x001c,0x001c,0x001c,0x001c,0x001c, + 0x001d,0x001d,0x001d,0x001d,0x001d,0x001d,0x001d,0x001d, + 0x001e,0x001e,0x001e,0x001e,0x001e,0x001e,0x001e,0x001e, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, // 256 + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 512 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 768 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +#if defined (__MACH__) || defined( __LINUX__ ) || defined( __MCUXPRESSO ) || defined( PICO_BUILD ) +// +// API for C +// + +// +// Memory initialization +// +int JPEG_openRAM(JPEGIMAGE *pJPEG, uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(pJPEG, 0, sizeof(JPEGIMAGE)); + pJPEG->ucMemType = JPEG_MEM_RAM; + pJPEG->pfnRead = readRAM; + pJPEG->pfnSeek = seekMem; + pJPEG->pfnDraw = pfnDraw; + pJPEG->pfnOpen = NULL; + pJPEG->pfnClose = NULL; + pJPEG->JPEGFile.iSize = iDataSize; + pJPEG->JPEGFile.pData = pData; + pJPEG->iMaxMCUs = 1000; // set to an unnaturally high value to start + return JPEGInit(pJPEG); +} /* JPEG_openRAM() */ +// +// File initialization +// +/* +int JPEG_openFile(JPEGIMAGE *pJPEG, const char *szFilename, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(pJPEG, 0, sizeof(JPEGIMAGE)); + pJPEG->ucMemType = JPEG_MEM_RAM; + pJPEG->pfnRead = readFile; + pJPEG->pfnSeek = seekFile; + pJPEG->pfnDraw = pfnDraw; + pJPEG->pfnOpen = NULL; + pJPEG->pfnClose = closeFile; + pJPEG->iMaxMCUs = 1000; // set to an unnaturally high value to start + pJPEG->JPEGFile.fHandle = fopen(szFilename, "r+b"); + if (pJPEG->JPEGFile.fHandle == NULL) + return 0; + fseek((FILE *)pJPEG->JPEGFile.fHandle, 0, SEEK_END); + pJPEG->JPEGFile.iSize = (int)ftell((FILE *)pJPEG->JPEGFile.fHandle); + fseek((FILE *)pJPEG->JPEGFile.fHandle, 0, SEEK_SET); + return JPEGInit(pJPEG); +} *//* JPEG_openFile() */ + +int JPEG_getLastError(JPEGIMAGE *pJPEG) +{ + return pJPEG->iError; +} /* JPEG_getLastError() */ + +int JPEG_getWidth(JPEGIMAGE *pJPEG) +{ + return pJPEG->iWidth; +} /* JPEG_getWidth() */ + +int JPEG_getHeight(JPEGIMAGE *pJPEG) +{ + return pJPEG->iHeight; +} /* JPEG_getHeight() */ + +int JPEG_getOrientation(JPEGIMAGE *pJPEG) +{ + return (int)pJPEG->ucOrientation; +} /* JPEG_getOrientation() */ + +int JPEG_getBpp(JPEGIMAGE *pJPEG) +{ + return (int)pJPEG->ucBpp; +} /* JPEG_getBpp() */ +int JPEG_getSubSample(JPEGIMAGE *pJPEG) +{ + return (int)pJPEG->ucSubSample; +} /* JPEG_getSubSample() */ +int JPEG_hasThumb(JPEGIMAGE *pJPEG) +{ + return (int)pJPEG->ucHasThumb; +} /* JPEG_hasThumb() */ +int JPEG_getThumbWidth(JPEGIMAGE *pJPEG) +{ + return pJPEG->iThumbWidth; +} /* JPEG_getThumbWidth() */ +int JPEG_getThumbHeight(JPEGIMAGE *pJPEG) +{ + return pJPEG->iThumbHeight; +} /* JPEG_getThumbHeight() */ +void JPEG_setPixelType(JPEGIMAGE *pJPEG, int iType) +{ + pJPEG->ucPixelType = (uint8_t)iType; +} /* JPEG_setPixelType() */ +void JPEG_setMaxOutputSize(JPEGIMAGE *pJPEG, int iMaxMCUs) +{ + if (iMaxMCUs < 1) + iMaxMCUs = 1; // don't allow invalid value + pJPEG->iMaxMCUs = iMaxMCUs; +} /* JPEG_setMaxOutputSize() */ + +int JPEG_decode(JPEGIMAGE *pJPEG, int x, int y, int iOptions) +{ + pJPEG->iXOffset = x; + pJPEG->iYOffset = y; + pJPEG->iOptions = iOptions; + return DecodeJPEG(pJPEG); +} /* JPEG_decode() */ + +int JPEG_decodeDither(JPEGIMAGE *pJPEG, uint8_t *pDither, int iOptions) +{ + pJPEG->iOptions = iOptions; + pJPEG->pDitherBuffer = pDither; + return DecodeJPEG(pJPEG); +} /* JPEG_decodeDither() */ + +void JPEG_close(JPEGIMAGE *pJPEG) +{ + if (pJPEG->pfnClose) + (*pJPEG->pfnClose)(pJPEG->JPEGFile.fHandle); +} /* JPEG_close() */ + +#endif // !__cplusplus +// +// Helper functions for memory based images +// +static int32_t readRAM(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen) +{ + int32_t iBytesRead; + + iBytesRead = iLen; + if ((pFile->iSize - pFile->iPos) < iLen) + iBytesRead = pFile->iSize - pFile->iPos; + if (iBytesRead <= 0) + return 0; + memcpy(pBuf, &pFile->pData[pFile->iPos], iBytesRead); + pFile->iPos += iBytesRead; + return iBytesRead; +} /* readRAM() */ + +static int32_t readFLASH(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen) +{ + int32_t iBytesRead; + + iBytesRead = iLen; + if ((pFile->iSize - pFile->iPos) < iLen) + iBytesRead = pFile->iSize - pFile->iPos; + if (iBytesRead <= 0) + return 0; + memcpy_P(pBuf, &pFile->pData[pFile->iPos], iBytesRead); + pFile->iPos += iBytesRead; + return iBytesRead; +} /* readFLASH() */ + +static int32_t seekMem(JPEGFILE *pFile, int32_t iPosition) +{ + if (iPosition < 0) iPosition = 0; + else if (iPosition >= pFile->iSize) iPosition = pFile->iSize-1; + pFile->iPos = iPosition; + return iPosition; +} /* seekMem() */ + +#if defined (__MACH__) || defined( __LINUX__ ) || defined( __MCUXPRESSO ) || defined( PICO_BUILD ) + +static void closeFile(void *handle) +{ + fclose((FILE *)handle); +} /* closeFile() */ + +static int32_t seekFile(JPEGFILE *pFile, int32_t iPosition) +{ + if (iPosition < 0) iPosition = 0; + else if (iPosition >= pFile->iSize) iPosition = pFile->iSize-1; + pFile->iPos = iPosition; + fseek((FILE *)pFile->fHandle, iPosition, SEEK_SET); + return iPosition; +} /* seekFile() */ + +static int32_t readFile(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen) +{ + int32_t iBytesRead; + + iBytesRead = iLen; + if ((pFile->iSize - pFile->iPos) < iLen) + iBytesRead = pFile->iSize - pFile->iPos; + if (iBytesRead <= 0) + return 0; + iBytesRead = (int)fread(pBuf, 1, iBytesRead, (FILE *)pFile->fHandle); + pFile->iPos += iBytesRead; + return iBytesRead; +} /* readFile() */ + +#endif // __LINUX__ +// +// The following functions are written in plain C and have no +// 3rd party dependencies, not even the C runtime library +// +// +// Initialize a JPEG file and callback access from a file on SD or memory +// returns 1 for success, 0 for failure +// Fills in the basic image info fields of the JPEGIMAGE structure +// +static int JPEGInit(JPEGIMAGE *pJPEG) +{ + return JPEGParseInfo(pJPEG, 0); // gather info for image +} /* JPEGInit() */ +// +// Unpack the Huffman tables +// +static int JPEGGetHuffTables(uint8_t *pBuf, int iLen, JPEGIMAGE *pJPEG) +{ + int i, j, iOffset, iTableOffset; + uint8_t ucTable, *pHuffVals; + + iOffset = 0; + pHuffVals = (uint8_t *)pJPEG->usPixels; // temp holding area to save RAM + while (iLen > 17) // while there are tables to copy (we may have combined more than 1 table together) + { + ucTable = pBuf[iOffset++]; // get table index + if (ucTable & 0x10) // convert AC offset of 0x10 into offset of 4 + ucTable ^= 0x14; + pJPEG->ucHuffTableUsed |= (1 << ucTable); // mark this table as being defined + if (ucTable <= 7) // tables are 0-3, AC+DC + { + iTableOffset = ucTable * HUFF_TABLEN; + j = 0; // total bits + for (i=0; i<16; i++) + { + j += pBuf[iOffset]; + pHuffVals[iTableOffset+i] = pBuf[iOffset++]; + } + iLen -= 17; // subtract length of bit lengths + if (j == 0 || j > 256 || j > iLen) // bogus bit lengths + { + return -1; + } + iTableOffset += 16; + for (i=0; ib11Bit = 1; // indicate we're using the bigger A/C decode tables + // first do DC components (up to 4 tables of 12-bit codes) + // we can save time and memory for the DC codes by knowing that there exist short codes (<= 6 bits) + // and long codes (>6 bits, but the first 5 bits are 1's). This allows us to create 2 tables: a 6-bit and 7 or 8-bit + // to handle any DC codes + iMaxLength = 12; // assume DC codes can be 12-bits + iMaxMask = 0x7f; // lower 7 bits after truncate 5 leading 1's + if (pJPEG->ucMode == 0xc3) // create 13-bit tables for lossless mode + { + iMaxLength = 13; + iMaxMask = 0xff; + } + for (iTable = 0; iTable < 2; iTable++) + { + if (pJPEG->ucHuffTableUsed & (1<huffdcFast[iTable] = (int *)PILIOAlloc(0x180); // short table = 128 bytes, long table = 256 bytes + pucShort = (unsigned char *)&pJPEG->ucHuffDC[iTable*DC_TABLE_SIZE]; + // pJPEG->huffdc[iTable] = pJPEG->huffdcFast[iTable] + 0x20; // 0x20 longs = 128 bytes + pucLong = (unsigned char *)&pJPEG->ucHuffDC[iTable*DC_TABLE_SIZE + 128]; + pBits = &pJPEG->ucHuffVals[iTable * HUFF_TABLEN]; + p = pBits; + p += 16; // point to bit data + cc = 0; // start with a code of 0 + for (iBitNum = 1; iBitNum <= 16; iBitNum++) + { + iLen = *pBits++; // get number of codes for this bit length + if (iBitNum > iMaxLength && iLen > 0) // we can't handle codes longer a certain length + { + return -1; + } + while (iLen) + { + // if (iBitNum > 6) // do long table + if ((cc >> (iBitNum-5)) == 0x1f) // first 5 bits are 1 - use long table + { + count = iMaxLength - iBitNum; + codestart = cc << count; + pucTable = &pucLong[codestart & iMaxMask]; // use lower 7/8 bits of code + } + else // do short table + { + count = 6 - iBitNum; + if (count < 0) + return -1; // DEBUG - something went wrong + codestart = cc << count; + pucTable = &pucShort[codestart]; + } + ucCode = *p++; // get actual huffman code + if (ucCode == 16 && pJPEG->ucMode == 0xc3) // lossless mode + { + // in lossless mode, this code won't fit in 4 bits, so save it's length in the next slot + ucCode = 255; + pucLong[256] = (unsigned char)iBitNum; + } + // does precalculating the DC value save time on ARM? +#ifndef USE_ARM_ASM + if (ucCode != 0 && (ucCode + iBitNum) <= 6 && pJPEG->ucMode != 0xc2) // we can fit the magnitude value in the code lookup (not for progressive) + { + int k, iLoop; + unsigned char ucCoeff; + unsigned char *d = &pucTable[512]; + unsigned char ucMag = ucCode; + ucCode |= ((iBitNum+ucCode) << 4); // add magnitude bits to length + repeat = 1<ucHuffTableUsed & (1<<(iTable+4))) // if this table is defined + { + pBits = &pJPEG->ucHuffVals[(iTable+4) * HUFF_TABLEN]; + p = pBits; + p += 16; // point to bit data + pShort = &pJPEG->usHuffAC[iTable*HUFF11SIZE]; + pLong = &pJPEG->usHuffAC[iTable*HUFF11SIZE + 1024]; // long codes start here + cc = 0; // start with a code of 0 + // construct the decode table + for (iBitNum = 1; iBitNum <= 16; iBitNum++) + { + iLen = *pBits++; // get number of codes for this bit length + while (iLen) + { + if ((cc >> (iBitNum-4)) == 0xf) // first 4 bits are 1 - use long table + { + count = 16 - iBitNum; + codestart = cc << count; + pTable = &pLong[codestart & 0xfff]; // use lower 12 bits of code + } + else + { + count = 12 - iBitNum; + if (count < 0) // a 13-bit? code - that doesn't fit our optimized scheme, see if we can do a bigger table version + { + return -1; // DEBUG - fatal error, we currently don't support it + } + codestart = cc << count; + pTable = &pShort[codestart]; // 11 bits or shorter + } + code = *p++; // get actual huffman code + if (bThumbnail && code != 0) // add "extra" bits to code length since we skip these codes + { + // get rid of extra bits in code and add increment (1) for AC index + code = ((iBitNum+(code & 0xf)) << 8) | ((code >> 4)+1); + } + else + { + code |= (iBitNum << 8); + } + if (count) // do it as dwords to save time + { + repeat = 1 << (count-1); // store as dwords (/2) + ul = code | (code << 16); + pLongTable = (uint32_t *)pTable; + for (j=0; jusPixels; + for (j=0; j<4; j++) + { + if (pJPEG->ucHuffTableUsed & (1 << j)) + iTablesUsed++; + } + // first do DC components (up to 4 tables of 12-bit codes) + // we can save time and memory for the DC codes by knowing that there exist short codes (<= 6 bits) + // and long codes (>6 bits, but the first 5 bits are 1's). This allows us to create 2 tables: a 6-bit and 7 or 8-bit + // to handle any DC codes + iMaxLength = 12; // assume DC codes can be 12-bits + iMaxMask = 0x7f; // lower 7 bits after truncate 5 leading 1's + for (iTable = 0; iTable < 4; iTable++) + { + if (pJPEG->ucHuffTableUsed & (1 << iTable)) + { + // pJPEG->huffdcFast[iTable] = (int *)PILIOAlloc(0x180); // short table = 128 bytes, long table = 256 bytes + pucShort = &pJPEG->ucHuffDC[iTable*DC_TABLE_SIZE]; + // pJPEG->huffdc[iTable] = pJPEG->huffdcFast[iTable] + 0x20; // 0x20 longs = 128 bytes + pucLong = &pJPEG->ucHuffDC[iTable*DC_TABLE_SIZE + 128]; + pBits = &pHuffVals[iTable * HUFF_TABLEN]; + p = pBits; + p += 16; // point to bit data + cc = 0; // start with a code of 0 + for (iBitNum = 1; iBitNum <= 16; iBitNum++) + { + iLen = *pBits++; // get number of codes for this bit length + if (iBitNum > iMaxLength && iLen > 0) // we can't handle codes longer a certain length + { + return 0; + } + while (iLen) + { + // if (iBitNum > 6) // do long table + if ((cc >> (iBitNum-5)) == 0x1f) // first 5 bits are 1 - use long table + { + count = iMaxLength - iBitNum; + codestart = cc << count; + pucTable = &pucLong[codestart & iMaxMask]; // use lower 7/8 bits of code + } + else // do short table + { + count = 6 - iBitNum; + if (count < 0) + return 0; // DEBUG - something went wrong + codestart = cc << count; + pucTable = &pucShort[codestart]; + } + ucCode = *p++; // get actual huffman code + // does precalculating the DC value save time on ARM? +#ifndef USE_ARM_ASM + if (ucCode != 0 && (ucCode + iBitNum) <= 6 && pJPEG->ucMode != 0xc2) // we can fit the magnitude value in the code lookup (not for progressive) + { + int k, iLoop; + unsigned char ucCoeff; + unsigned char *d = &pucTable[512]; + unsigned char ucMag = ucCode; + ucCode |= ((iBitNum+ucCode) << 4); // add magnitude bits to length + repeat = 1<ucHuffTableUsed & (1 << (iTable+4))) // if this table is defined + { + pBits = &pHuffVals[(iTable+4) * HUFF_TABLEN]; + p = pBits; + p += 16; // point to bit data + pShort = &pJPEG->usHuffAC[iTable*HUFF11SIZE]; + pLong = &pJPEG->usHuffAC[iTable*HUFF11SIZE + 1024]; + cc = 0; // start with a code of 0 + // construct the decode table + for (iBitNum = 1; iBitNum <= 16; iBitNum++) + { + iLen = *pBits++; // get number of codes for this bit length + while (iLen) + { + if ((cc >> (iBitNum-6)) == 0x3f) // first 6 bits are 1 - use long table + { + count = 16 - iBitNum; + codestart = cc << count; + pTable = &pLong[codestart & 0x3ff]; // use lower 10 bits of code + } + else + { + count = 10 - iBitNum; + if (count < 0) // an 11/12-bit? code - that doesn't fit our optimized scheme, see if we can do a bigger table version + { + if (count == -1 && iTablesUsed <= 4) // we need to create "slow" tables + { // DEBUG +// j = JPEGMakeHuffTables_Slow(pJPEG, bThumbnail); + return 0; + } + else + return 0; // DEBUG - fatal error, more than 2 big tables we currently don't support + } + codestart = cc << count; + pTable = &pShort[codestart]; // 10 bits or shorter + } + code = *p++; // get actual huffman code + if (bThumbnail && code != 0) // add "extra" bits to code length since we skip these codes + { + // get rid of extra bits in code and add increment (1) for AC index + code = ((iBitNum+(code & 0xf)) << 8) | ((code >> 4)+1); + } +#ifdef BOGUS // precalculating the AC coeff makes it run slightly slower + else if ((code & 0xf) != 0 && (code + iBitNum) <= 10) // we can fit the magnitude value + huffman code in a single read + { + int k, iLoop; + unsigned short usCoeff; + unsigned short *d = &pTable[4096]; // use unused table slots 2+3 for extra coeff data + unsigned char ucMag = (unsigned char)(code & 0xf); + code |= ((iBitNum + (code & 0xf)) << 8); // add magnitude bits to length + repeat = 1< 1) + { + iType = 4; + } + switch (iType) + { + case 3: /* Short */ + i = TIFFSHORT(p+8, bMotorola); + break; + case 4: /* Long */ + case 7: // undefined (treat it as a long since it's usually a multibyte buffer) + i = TIFFLONG(p+8, bMotorola); + break; + case 6: // signed byte + i = (signed char)p[8]; + break; + case 2: /* ASCII */ + case 5: /* Unsigned Rational */ + case 10: /* Signed Rational */ + i = TIFFLONG(p+8, bMotorola); + break; + default: /* to suppress compiler warning */ + i = 0; + break; + } + return i; + +} /* TIFFVALUE() */ +static void GetTIFFInfo(JPEGIMAGE *pPage, int bMotorola, int iOffset) +{ + int iTag, iTagCount, i; + uint8_t *cBuf = pPage->ucFileBuf; + + iTagCount = TIFFSHORT(&cBuf[iOffset], bMotorola); /* Number of tags in this dir */ + if (iTagCount < 1 || iTagCount > 256) // invalid tag count + return; /* Bad header info */ + /*--- Search the TIFF tags ---*/ + for (i=0; iucOrientation = TIFFVALUE(p, bMotorola); + } + else if (iTag == 256) // width of thumbnail + { + pPage->iThumbWidth = TIFFVALUE(p, bMotorola); + } + else if (iTag == 257) // height of thumbnail + { + pPage->iThumbHeight = TIFFVALUE(p, bMotorola); + } + else if (iTag == 513) // offset to JPEG data + { + pPage->iThumbData = TIFFVALUE(p, bMotorola); + } + } +} /* GetTIFFInfo() */ + +static int JPEGGetSOS(JPEGIMAGE *pJPEG, int *iOff) +{ + int16_t sLen; + int iOffset = *iOff; + int i, j; + uint8_t uc,c,cc; + uint8_t *buf = pJPEG->ucFileBuf; + + sLen = MOTOSHORT(&buf[iOffset]); + iOffset += 2; + + // Assume no components in this scan + for (i=0; i<4; i++) + pJPEG->JPCI[i].component_needed = 0; + + uc = buf[iOffset++]; // get number of components + pJPEG->ucComponentsInScan = uc; + sLen -= 3; + if (uc < 1 || uc > MAX_COMPS_IN_SCAN || sLen != (uc*2+3)) // check length of data packet + return 1; // error + for (i=0; iJPCI[j].component_id == cc) + break; + } + if (j == 4) // error, not found + return 1; + if ((c & 0xf) > 3 || (c & 0xf0) > 0x30) + return 1; // bogus table numbers + pJPEG->JPCI[j].dc_tbl_no = c >> 4; + pJPEG->JPCI[j].ac_tbl_no = c & 0xf; + pJPEG->JPCI[j].component_needed = 1; // mark this component as being included in the scan + } + pJPEG->iScanStart = buf[iOffset++]; // Get the scan start (or lossless predictor) for this scan + pJPEG->iScanEnd = buf[iOffset++]; // Get the scan end for this scan + c = buf[iOffset++]; // successive approximation bits + pJPEG->cApproxBitsLow = c & 0xf; // also point transform in lossless mode + pJPEG->cApproxBitsHigh = c >> 4; + + *iOff = iOffset; + return 0; + +} /* JPEGGetSOS() */ +// +// Remove markers from the data stream to allow faster decode +// Stuffed zeros and restart interval markers aren't needed to properly decode +// the data, but they make reading VLC data slower, so I pull them out first +// +static int JPEGFilter(uint8_t *pBuf, uint8_t *d, int iLen, uint8_t *bFF) +{ + // since we have the entire jpeg buffer in memory already, we can just change it in place + unsigned char c, *s, *pEnd, *pStart; + + pStart = d; + s = pBuf; + pEnd = &s[iLen-1]; // stop just shy of the end to not miss a final marker/stuffed 0 + if (*bFF) // last byte was a FF, check the next one + { + if (s[0] == 0) // stuffed 0, keep the FF + *d++ = 0xff; + s++; + *bFF = 0; + } + while (s < pEnd) + { + c = *d++ = *s++; + if (c == 0xff) // marker or stuffed zeros? + { + if (s[0] != 0) // it's a marker, skip both + { + d--; + } + s++; // for stuffed 0's, store the FF, skip the 00 + } + } + if (s == pEnd) // need to test the last byte + { + c = s[0]; + if (c == 0xff) // last byte is FF, take care of it next time through + *bFF = 1; // take care of it next time through + else + *d++ = c; // nope, just store it + } + return (int)(d-pStart); // filtered output length +} /* JPEGFilter() */ +// +// Read and filter more VLC data for decoding +// +static void JPEGGetMoreData(JPEGIMAGE *pPage) +{ + int iDelta = pPage->iVLCSize - pPage->iVLCOff; +// printf("Getting more data...size=%d, off=%d\n", pPage->iVLCSize, pPage->iVLCOff); + // move any existing data down + if (iDelta >= (JPEG_FILE_BUF_SIZE-64) || iDelta < 0) + return; // buffer is already full; no need to read more data + if (pPage->iVLCOff != 0) + { + memcpy(pPage->ucFileBuf, &pPage->ucFileBuf[pPage->iVLCOff], pPage->iVLCSize - pPage->iVLCOff); + pPage->iVLCSize -= pPage->iVLCOff; + pPage->iVLCOff = 0; + pPage->bb.pBuf = pPage->ucFileBuf; // reset VLC source pointer too + } + if (pPage->JPEGFile.iPos < pPage->JPEGFile.iSize && pPage->iVLCSize < JPEG_FILE_BUF_SIZE-64) + { + int i; + // Try to read enough to fill the buffer + i = (*pPage->pfnRead)(&pPage->JPEGFile, &pPage->ucFileBuf[pPage->iVLCSize], JPEG_FILE_BUF_SIZE - pPage->iVLCSize); // max length we can read + // Filter out the markers + pPage->iVLCSize += JPEGFilter(&pPage->ucFileBuf[pPage->iVLCSize], &pPage->ucFileBuf[pPage->iVLCSize], i, &pPage->ucFF); + } +} /* JPEGGetMoreData() */ + +// +// Parse the JPEG header, gather necessary info to decode the image +// Returns 1 for success, 0 for failure +// +static int JPEGParseInfo(JPEGIMAGE *pPage, int bExtractThumb) +{ + int iBytesRead; + int i, iOffset, iTableOffset; + uint8_t ucTable, *s = pPage->ucFileBuf; + uint16_t usMarker, usLen = 0; + int iFilePos = 0; + + if (bExtractThumb) // seek to the start of the thumbnail image + { + iFilePos = pPage->iThumbData; + (*pPage->pfnSeek)(&pPage->JPEGFile, iFilePos); + } + iBytesRead = (*pPage->pfnRead)(&pPage->JPEGFile, s, JPEG_FILE_BUF_SIZE); + if (iBytesRead < 256) // a JPEG file this tiny? probably bad + { + pPage->iError = JPEG_INVALID_FILE; + return 0; + } + iFilePos += iBytesRead; + if (MOTOSHORT(pPage->ucFileBuf) != 0xffd8) + { + pPage->iError = JPEG_INVALID_FILE; + return 0; // not a JPEG file + } + iOffset = 2; /* Start at offset of first marker */ + usMarker = 0; /* Search for SOFx (start of frame) marker */ + while (usMarker != 0xffda && iOffset < pPage->JPEGFile.iSize) + { + if (iOffset >= JPEG_FILE_BUF_SIZE/2) // too close to the end, read more data + { + // Do we need to seek first? + if (iOffset >= JPEG_FILE_BUF_SIZE) + { + iFilePos += (iOffset - iBytesRead); + iOffset = 0; + (*pPage->pfnSeek)(&pPage->JPEGFile, iFilePos); + iBytesRead = 0; // throw away any old data + } + // move existing bytes down + if (iOffset) + { + memcpy(pPage->ucFileBuf, &pPage->ucFileBuf[iOffset], iBytesRead - iOffset); + iBytesRead -= iOffset; + iOffset = 0; + } + i = (*pPage->pfnRead)(&pPage->JPEGFile, &pPage->ucFileBuf[iBytesRead], JPEG_FILE_BUF_SIZE-iBytesRead); + iFilePos += i; + iBytesRead += i; + } + usMarker = MOTOSHORT(&s[iOffset]); + iOffset += 2; + usLen = MOTOSHORT(&s[iOffset]); // marker length + + if (usMarker < 0xffc0 || usMarker == 0xffff) // invalid marker, could be generated by "Arles Image Web Page Creator" or Accusoft + { + iOffset++; + continue; // skip 1 byte and try to resync + } + switch (usMarker) + { + case 0xffc1: + case 0xffc2: + case 0xffc3: + pPage->iError = JPEG_UNSUPPORTED_FEATURE; + return 0; // currently unsupported modes + + case 0xffe1: // App1 (EXIF?) + if (s[iOffset+2] == 'E' && s[iOffset+3] == 'x' && (s[iOffset+8] == 'M' || s[iOffset+8] == 'I')) // the EXIF data we want + { + int bMotorola, IFD, iTagCount; + pPage->iEXIF = iFilePos - iBytesRead + iOffset + 8; // start of TIFF file + // Get the orientation value (if present) + bMotorola = (s[iOffset+8] == 'M'); + IFD = TIFFLONG(&s[iOffset+12], bMotorola); + iTagCount = TIFFSHORT(&s[iOffset+16], bMotorola); + GetTIFFInfo(pPage, bMotorola, IFD+iOffset+8); + // The second IFD defines the thumbnail (if present) + if (iTagCount >= 1 && iTagCount < 32) // valid number of tags for EXIF data 'page' + { + // point to next IFD + IFD += (12 * iTagCount) + 2; + IFD = TIFFLONG(&s[IFD + iOffset + 8], bMotorola); + if (IFD != 0) // Thumbnail present? + { + pPage->ucHasThumb = 1; + GetTIFFInfo(pPage, bMotorola, IFD+iOffset+8); // info for second 'page' of TIFF + pPage->iThumbData += iOffset + 8; // absolute offset in the file + } + } + } + break; + case 0xffc0: // SOFx - start of frame + pPage->ucMode = (uint8_t)usMarker; + pPage->ucBpp = s[iOffset+2]; // bits per sample + pPage->iHeight = MOTOSHORT(&s[iOffset+3]); + pPage->iWidth = MOTOSHORT(&s[iOffset+5]); + pPage->ucNumComponents = s[iOffset+7]; + pPage->ucBpp = pPage->ucBpp * pPage->ucNumComponents; /* Bpp = number of components * bits per sample */ + if (pPage->ucNumComponents == 1) + pPage->ucSubSample = 0; // use this to differentiate from color 1:1 + else + { + usLen -= 8; + iOffset += 8; +// pPage->ucSubSample = s[iOffset+9]; // subsampling option for the second color component + for (i=0; iucNumComponents; i++) + { + uint8_t ucSamp; + pPage->JPCI[i].component_id = s[iOffset++]; + pPage->JPCI[i].component_index = (unsigned char)i; + ucSamp = s[iOffset++]; // get the h+v sampling factor + if (i == 0) // Y component? + pPage->ucSubSample = ucSamp; +// pPage->JPCI[i].h_samp_factor = ucSamp >> 4; +// pPage->JPCI[i].v_samp_factor = ucSamp & 0xf; + pPage->JPCI[i].quant_tbl_no = s[iOffset++]; // quantization table number + usLen -= 3; + } + } + break; + case 0xffdd: // Restart Interval + if (usLen == 4) + pPage->iResInterval = MOTOSHORT(&s[iOffset+2]); + break; + case 0xffc4: /* M_DHT */ // get Huffman tables + iOffset += 2; // skip length + usLen -= 2; // subtract length length + if (JPEGGetHuffTables(&s[iOffset], usLen, pPage) != 0) // bad tables? + { + pPage->iError = JPEG_DECODE_ERROR; + return 0; // error + } + break; + case 0xffdb: /* M_DQT */ + /* Get the quantization tables */ + /* first byte has PPPPNNNN where P = precision and N = table number 0-3 */ + iOffset += 2; // skip length + usLen -= 2; // subtract length length + while (usLen > 0) + { + ucTable = s[iOffset++]; // table number + if ((ucTable & 0xf) > 3) // invalid table number + { + pPage->iError = JPEG_DECODE_ERROR; + return 0; + } + iTableOffset = (ucTable & 0xf) * DCTSIZE; + if (ucTable & 0xf0) // if word precision + { + for (i=0; isQuantTable[i+iTableOffset] = MOTOSHORT(&s[iOffset]); + iOffset += 2; + } + usLen -= (DCTSIZE*2 + 1); + } + else // byte precision + { + for (i=0; isQuantTable[i+iTableOffset] = (unsigned short)s[iOffset++]; + } + usLen -= (DCTSIZE + 1); + } + } + break; + } // switch on JPEG marker + iOffset += usLen; + } // while + if (usMarker == 0xffda) // start of image + { + if (pPage->ucBpp != 8) // need to match up table IDs + { + iOffset -= usLen; + JPEGGetSOS(pPage, &iOffset); // get Start-Of-Scan info for decoding + } + if (!JPEGMakeHuffTables(pPage, 0)) //int bThumbnail) DEBUG + { + pPage->iError = JPEG_UNSUPPORTED_FEATURE; + return 0; + } + // Now the offset points to the start of compressed data + i = JPEGFilter(&pPage->ucFileBuf[iOffset], pPage->ucFileBuf, iBytesRead-iOffset, &pPage->ucFF); + pPage->iVLCOff = 0; + pPage->iVLCSize = i; + JPEGGetMoreData(pPage); // read more VLC data + return 1; + } + pPage->iError = JPEG_DECODE_ERROR; + return 0; +} /* JPEGParseInfo() */ +// +// Fix and reorder the quantization table for faster decoding.* +// +static void JPEGFixQuantD(JPEGIMAGE *pJPEG) +{ + int iTable, iTableOffset; + signed short sTemp[DCTSIZE]; + int i; + uint16_t *p; + + for (iTable=0; iTableucNumComponents; iTable++) + { + iTableOffset = iTable * DCTSIZE; + p = (uint16_t *)&pJPEG->sQuantTable[iTableOffset]; + for (i=0; isQuantTable[iTableOffset], sTemp, DCTSIZE*sizeof(short)); // copy back to original spot + + // Prescale for DCT multiplication + p = (uint16_t *)&pJPEG->sQuantTable[iTableOffset]; + for (i=0; i> 12); + } + } +} /* JPEGFixQuantD() */ +// +// Decode the 64 coefficients of the current DCT block +// +static int JPEGDecodeMCU(JPEGIMAGE *pJPEG, int iMCU, int *iDCPredictor) +{ + uint32_t ulCode, ulTemp; + uint8_t *pZig; + signed char cCoeff; + unsigned short *pFast; + unsigned char ucHuff, *pucFast; + uint32_t usHuff; // this prevents an unnecessary & 65535 for shorts + uint32_t ulBitOff, ulBits; // local copies to allow compiler to use register vars + uint8_t *pBuf, *pEnd, *pEnd2; + signed short *pMCU = &pJPEG->sMCUs[iMCU]; + uint8_t ucMaxACCol, ucMaxACRow; + + #define MIN_DCT_THRESHOLD 8 + + ulBitOff = pJPEG->bb.ulBitOff; + ulBits = pJPEG->bb.ulBits; + pBuf = pJPEG->bb.pBuf; + + pZig = (unsigned char *)&cZigZag2[1]; + pEnd = (unsigned char *)&cZigZag2[64]; + + if (ulBitOff > (REGISTER_WIDTH-17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + if (pJPEG->iOptions & (JPEG_SCALE_QUARTER | JPEG_SCALE_EIGHTH)) // reduced size DCT + { + pMCU[1] = pMCU[8] = pMCU[9] = 0; + pEnd2 = (uint8_t *)&cZigZag2[5]; // we only need to store the 4 elements we care about + } + else + { + memset(pMCU, 0, 64*sizeof(short)); // pre-fill with zero since we may skip coefficients + pEnd2 = (uint8_t *)&cZigZag2[64]; + } + ucMaxACCol = ucMaxACRow = 0; + pZig = (unsigned char *)&cZigZag2[1]; + pEnd = (unsigned char *)&cZigZag2[64]; + + // get the DC component + pucFast = &pJPEG->ucHuffDC[pJPEG->ucDCTable * DC_TABLE_SIZE]; + ulCode = (ulBits >> (REGISTER_WIDTH - 12 - ulBitOff)) & 0xfff; // get as lower 12 bits + if (ulCode >= 0xf80) // it's a long code + ulCode = (ulCode & 0xff); // point to long table and trim to 7-bits + 0x80 offset into long table + else + ulCode >>= 6; // it's a short code, use first 6 bits only + ucHuff = pucFast[ulCode]; + cCoeff = (signed char)pucFast[ulCode+512]; // get pre-calculated extra bits for "small" values + if (ucHuff == 0) // invalid code + return -1; + ulBitOff += (ucHuff >> 4); // add the Huffman length + ucHuff &= 0xf; // get the actual code (SSSS) + if (ucHuff) // if there is a change to the DC value + { // get the 'extra' bits + if (cCoeff) + { + (*iDCPredictor) += cCoeff; + } + else + { + if (ulBitOff > (REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + ulCode = ulBits << ulBitOff; + ulTemp = ~(uint32_t)(((int32_t)ulCode)>>31); // slide sign bit across other 31 bits + ulCode >>= (REGISTER_WIDTH - ucHuff); + ulCode -= ulTemp>>(REGISTER_WIDTH-ucHuff); + ulBitOff += ucHuff; // add bit length + (*iDCPredictor) += (int)ulCode; + } + } + pMCU[0] = (short)*iDCPredictor; // store in MCU[0] + // Now get the other 63 AC coefficients + pFast = &pJPEG->usHuffAC[pJPEG->ucACTable * HUFF11SIZE]; + if (pJPEG->b11Bit) // 11-bit "slow" tables used + { +// if (pJPEG->pHuffACFast == pJPEG->huffacFast[1]) // second table +// pFast = &pJPEG->ucAltHuff[0]; + while (pZig < pEnd) + { + if (ulBitOff >(REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + ulCode = (ulBits >> (REGISTER_WIDTH - 16 - ulBitOff)) & 0xffff; // get as lower 16 bits + if (ulCode >= 0xf000) // first 4 bits = 1, use long table + ulCode = (ulCode & 0x1fff); + else + ulCode >>= 4; // use lower 12 bits (short table) + usHuff = pFast[ulCode]; + if (usHuff == 0) // invalid code + return -1; + ulBitOff += (usHuff >> 8); // add length + usHuff &= 0xff; // get code (RRRR/SSSS) + if (usHuff == 0) // no more AC components + { + goto mcu_done; + } + if (ulBitOff > (REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + pZig += (usHuff >> 4); // get the skip amount (RRRR) + usHuff &= 0xf; // get (SSSS) - extra length + if (pZig < pEnd && usHuff) // && piHisto) + { + ulCode = ulBits << ulBitOff; + ulTemp = ~(uint32_t) (((int32_t) ulCode) >> (REGISTER_WIDTH-1)); // slide sign bit across other 63 bits + ulCode >>= (REGISTER_WIDTH - usHuff); + ulCode -= ulTemp >> (REGISTER_WIDTH - usHuff); + ucMaxACCol |= 1<<(*pZig & 7); // keep track of occupied columns + if (*pZig >= 0x20) // if more than 4 rows used in a col, mark it + ucMaxACRow |= 1<<(*pZig & 7); // keep track of the max AC term row + pMCU[*pZig] = (signed short)ulCode; // store AC coefficient (already reordered) + } + ulBitOff += usHuff; // add (SSSS) extra length + pZig++; + } // while + } + else // 10-bit "fast" tables used + { + while (pZig < pEnd) + { + if (ulBitOff >(REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + ulCode = (ulBits >> (REGISTER_WIDTH - 16 - ulBitOff)) & 0xffff; // get as lower 16 bits + if (ulCode >= 0xfc00) // first 6 bits = 1, use long table + ulCode = (ulCode & 0x7ff); // (ulCode & 0x3ff) + 0x400; + else + ulCode >>= 6; // use lower 10 bits (short table) + usHuff = pFast[ulCode]; + if (usHuff == 0) // invalid code + return -1; + ulBitOff += (usHuff >> 8); // add length + usHuff &= 0xff; // get code (RRRR/SSSS) + if (usHuff == 0) // no more AC components + { + goto mcu_done; + } + if (ulBitOff >(REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + pZig += (usHuff >> 4); // get the skip amount (RRRR) + usHuff &= 0xf; // get (SSSS) - extra length + if (pZig < pEnd2 && usHuff) + { + ulCode = ulBits << ulBitOff; + ulTemp = ~(uint32_t) (((int32_t) ulCode) >> (REGISTER_WIDTH-1)); // slide sign bit across other 63 bits + ulCode >>= (REGISTER_WIDTH - usHuff); + ulCode -= ulTemp >> (REGISTER_WIDTH - usHuff); + ucMaxACCol |= 1<<(*pZig & 7); // keep track of occupied columns + if (*pZig >= 0x20) // if more than 4 rows used in a col, mark it + ucMaxACRow |= 1<<(*pZig & 7); // keep track of the max AC term row + pMCU[*pZig] = (signed short)ulCode; // store AC coefficient (already reordered) + } + ulBitOff += usHuff; // add (SSSS) extra length + pZig++; + } // while + } // 10-bit tables +mcu_done: + pJPEG->bb.pBuf = pBuf; + pJPEG->iVLCOff = (int)(pBuf - pJPEG->ucFileBuf); + pJPEG->bb.ulBitOff = ulBitOff; + pJPEG->bb.ulBits = ulBits; + pJPEG->ucMaxACCol = ucMaxACCol; + pJPEG->ucMaxACRow = ucMaxACRow; // DEBUG + return 0; +} /* JPEGDecodeMCU() */ +// +// Inverse DCT +// +static void JPEGIDCT(JPEGIMAGE *pJPEG, int iMCUOffset, int iQuantTable, int iACFlags) +{ + int iRow; + unsigned char ucColMask; + int iCol; + signed int tmp6,tmp7,tmp10,tmp11,tmp12,tmp13; + signed int z5,z10,z11,z12,z13; + signed int tmp0,tmp1,tmp2,tmp3,tmp4,tmp5; + signed short *pQuant; + unsigned char *pOutput; + unsigned char ucMaxACRow, ucMaxACCol; + int16_t *pMCUSrc = &pJPEG->sMCUs[iMCUOffset]; + + ucMaxACRow = (unsigned char)(iACFlags >> 8); + ucMaxACCol = iACFlags & 0xff; + + // my shortcut method appears to violate patent 20020080052 + // but the patent is invalidated by prior art: + // http://netilium.org/~mad/dtj/DTJ/DTJK04/ + pQuant = &pJPEG->sQuantTable[iQuantTable * DCTSIZE]; + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) // special case + { + /* Column 0 */ + tmp4 = pMCUSrc[0] * pQuant[0]; + tmp5 = pMCUSrc[8] * pQuant[8]; + tmp0 = tmp4 + tmp5; + tmp2 = tmp4 - tmp5; + /* Column 1 */ + tmp4 = pMCUSrc[1] * pQuant[1]; + tmp5 = pMCUSrc[9] * pQuant[9]; + tmp1 = tmp4 + tmp5; + tmp3 = tmp4 - tmp5; + /* Pass 2: process 2 rows, store into output array. */ + /* Row 0 */ + pOutput = (unsigned char *)pMCUSrc; // store output pixels back into MCU + pOutput[0] = ucRangeTable[(((tmp0 + tmp1)>>5) & 0x3ff)]; + pOutput[1] = ucRangeTable[(((tmp0 - tmp1)>>5) & 0x3ff)]; + /* Row 1 */ + pOutput[2] = ucRangeTable[(((tmp2 + tmp3)>>5) & 0x3ff)]; + pOutput[3] = ucRangeTable[(((tmp2 - tmp3)>>5) & 0x3ff)]; + return; + } + // do columns first + ucColMask = ucMaxACCol | 1; // column 0 must always be calculated + for (iCol = 0; iCol < 8 && ucColMask; iCol++) + { + if (ucColMask & (1<>8); // used to be 362 - 1 (256) + tmp0 = tmp10 + tmp1; + tmp3 = tmp10 - tmp1; + tmp1 = tmp10 + tmp12; + tmp2 = tmp10 - tmp12; + // odd part + tmp4 = pMCUSrc[iCol+8] * pQuant[iCol+8]; // get 1st row + tmp5 = pMCUSrc[iCol+24]; + if (tmp5) // this value is usually 0 + { + tmp5 *= pQuant[iCol+24]; // get 3rd row + tmp7 = tmp4 + tmp5; + tmp11 = (((tmp4 - tmp5) * 362) >> 8); // 362>>8 = 1.414213562 + z5 = (((tmp4-tmp5) * 473) >> 8); // 473>>8 = 1.8477 + tmp12 = ((-tmp5 * -669)>>8) + z5; // -669>>8 = -2.6131259 + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp10 = ((tmp4 * 277)>>8) - z5; // 277>>8 = 1.08239 + tmp4 = tmp10 + tmp5; + } + else // simpler case when we only have 1 odd row to calculate + { + tmp7 = tmp4; + tmp5 = (145*tmp4) >> 8; + tmp6 = (217*tmp4) >> 8; + tmp4 = (-51*tmp4) >> 8; + } + pMCUSrc[iCol] = (short)(tmp0 + tmp7); // row0 + pMCUSrc[iCol+8] = (short)(tmp1 + tmp6); // row 1 + pMCUSrc[iCol+16] = (short)(tmp2 + tmp5); // row 2 + pMCUSrc[iCol+24] = (short)(tmp3 - tmp4); // row 3 + pMCUSrc[iCol+32] = (short)(tmp3 + tmp4); // row 4 + pMCUSrc[iCol+40] = (short)(tmp2 - tmp5); // row 5 + pMCUSrc[iCol+48] = (short)(tmp1 - tmp6); // row 6 + pMCUSrc[iCol+56] = (short)(tmp0 - tmp7); // row 7 + } + else // need to do full column calculation + { + // even part + tmp0 = pMCUSrc[iCol] * pQuant[iCol]; + tmp2 = pMCUSrc[iCol+32]; // get 4th row + if (tmp2) // 4th row is most likely 0 + { + tmp2 = tmp2 * pQuant[iCol+32]; + tmp10 = tmp0 + tmp2; + tmp11 = tmp0 - tmp2; + } + else + { + tmp10 = tmp11 = tmp0; + } + tmp1 = pMCUSrc[iCol+16] * pQuant[iCol+16]; // get 2nd row + tmp3 = pMCUSrc[iCol+48]; // get 6th row + if (tmp3) // 6th row is most likely 0 + { + tmp3 = tmp3 * pQuant[iCol+48]; + tmp13 = tmp1 + tmp3; + tmp12 = (((tmp1 - tmp3) * 362) >> 8) - tmp13; // 362>>8 = 1.414213562 + } + else + { + tmp13 = tmp1; + tmp12 = ((tmp1*362)>>8) - tmp1; + } + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + // odd part + tmp5 = pMCUSrc[iCol+24] * pQuant[iCol+24]; // get 3rd row + tmp6 = pMCUSrc[iCol+40]; // get 5th row + if (tmp6) // very likely that row 5 = 0 + { + tmp6 = tmp6 * pQuant[iCol+40]; + z13 = tmp6 + tmp5; + z10 = tmp6 - tmp5; + } + else + { + z13 = tmp5; + z10 = -tmp5; + } + tmp4 = pMCUSrc[iCol+8] * pQuant[iCol+8]; // get 1st row + tmp7 = pMCUSrc[iCol+56]; // get 7th row + if (tmp7) // very likely that row 7 = 0 + { + tmp7 = tmp7 * pQuant[iCol+56]; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + } + else + { + z11 = z12 = tmp4; + } + tmp7 = z11 + z13; + tmp11 = (((z11 - z13) * 362) >> 8); // 362>>8 = 1.414213562 + z5 = (((z10 + z12) * 473) >> 8); // 473>>8 = 1.8477 + tmp12 = ((z10 * -669)>>8) + z5; // -669>>8 = -2.6131259 + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp10 = ((z12 * 277)>>8) - z5; // 277>>8 = 1.08239 + tmp4 = tmp10 + tmp5; + pMCUSrc[iCol] = (short)(tmp0 + tmp7); // row0 + pMCUSrc[iCol+8] = (short)(tmp1 + tmp6); // row 1 + pMCUSrc[iCol+16] = (short)(tmp2 + tmp5); // row 2 + pMCUSrc[iCol+24] = (short)(tmp3 - tmp4); // row 3 + pMCUSrc[iCol+32] = (short)(tmp3 + tmp4); // row 4 + pMCUSrc[iCol+40] = (short)(tmp2 - tmp5); // row 5 + pMCUSrc[iCol+48] = (short)(tmp1 - tmp6); // row 6 + pMCUSrc[iCol+56] = (short)(tmp0 - tmp7); // row 7 + } // full calculation needed + } // if column has data in it + } // for each column + // now do rows + pOutput = (unsigned char *)pMCUSrc; // store output pixels back into MCU + for (iRow=0; iRow<64; iRow+=8) // all rows must be calculated + { + // even part + if (ucMaxACCol < 0x10) // quick and dirty calculation (right 4 columns are all 0's) + { + if (ucMaxACCol < 0x04) // very likely case (1 or 2 columns occupied) + { + // even part + tmp0 = tmp1 = tmp2 = tmp3 = pMCUSrc[iRow+0]; + // odd part + tmp7 = pMCUSrc[iRow+1]; + tmp6 = (tmp7 * 217)>>8; // * 0.8477 + tmp5 = (tmp7 * 145)>>8; // * 0.5663 + tmp4 = -((tmp7 * 51)>>8); // * -0.199 + } + else + { + tmp10 = pMCUSrc[iRow+0]; + tmp13 = pMCUSrc[iRow+2]; + tmp12 = ((tmp13 * 106)>>8); // 2-6 * 1.414 + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp10 + tmp12; + tmp2 = tmp10 - tmp12; + // odd part + z13 = pMCUSrc[iRow+3]; + z11 = pMCUSrc[iRow+1]; + tmp7 = z11 + z13; + tmp11 = ((z11 - z13)*362)>>8; // * 1.414 + z5 = ((z11 - z13)*473)>>8; // * 1.8477 + tmp10 = ((z11*277)>>8) - z5; // * 1.08239 + tmp12 = ((z13*669)>>8) + z5; // * 2.61312 + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + } + } + else // need to do the full calculation + { + tmp10 = pMCUSrc[iRow+0] + pMCUSrc[iRow+4]; + tmp11 = pMCUSrc[iRow+0] - pMCUSrc[iRow+4]; + tmp13 = pMCUSrc[iRow+2] + pMCUSrc[iRow+6]; + tmp12 = (((pMCUSrc[iRow+2] - pMCUSrc[iRow+6]) * 362)>>8) - tmp13; // 2-6 * 1.414 + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + // odd part + z13 = pMCUSrc[iRow+5] + pMCUSrc[iRow+3]; + z10 = pMCUSrc[iRow+5] - pMCUSrc[iRow+3]; + z11 = pMCUSrc[iRow+1] + pMCUSrc[iRow+7]; + z12 = pMCUSrc[iRow+1] - pMCUSrc[iRow+7]; + tmp7 = z11 + z13; + tmp11 = ((z11 - z13)*362)>>8; // * 1.414 + z5 = ((z10 + z12)*473)>>8; // * 1.8477 + tmp10 = ((z12*277)>>8) - z5; // * 1.08239 + tmp12 = ((z10*-669)>>8) + z5; // * 2.61312 + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + } + // final output stage - scale down and range limit + pOutput[0] = ucRangeTable[(((tmp0 + tmp7)>>5) & 0x3ff)]; + pOutput[1] = ucRangeTable[(((tmp1 + tmp6)>>5) & 0x3ff)]; + pOutput[2] = ucRangeTable[(((tmp2 + tmp5)>>5) & 0x3ff)]; + pOutput[3] = ucRangeTable[(((tmp3 - tmp4)>>5) & 0x3ff)]; + pOutput[4] = ucRangeTable[(((tmp3 + tmp4)>>5) & 0x3ff)]; + pOutput[5] = ucRangeTable[(((tmp2 - tmp5)>>5) & 0x3ff)]; + pOutput[6] = ucRangeTable[(((tmp1 - tmp6)>>5) & 0x3ff)]; + pOutput[7] = ucRangeTable[(((tmp0 - tmp7)>>5) & 0x3ff)]; + pOutput += 8; + } // for each row +} /* JPEGIDCT() */ +static void JPEGPutMCU8BitGray(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + int i, j, xcount, ycount; + uint8_t *pDest, *pSrc = (uint8_t *)&pJPEG->sMCUs[0]; + + if (pJPEG->pDitherBuffer) + pDest = &pJPEG->pDitherBuffer[x]; + else + pDest = (uint8_t *)&pJPEG->usPixels[x/2]; + + if (pJPEG->ucSubSample <= 0x11) // single Y + { + if (pJPEG->iOptions & JPEG_SCALE_HALF) // special handling of 1/2 size (pixel averaging) + { + int pix; + for (i=0; i<4; i++) + { + for (j=0; j<4; j++) + { + pix = (pSrc[0] + pSrc[1] + pSrc[8] + pSrc[9] + 2) >> 2; // average 2x2 block + pDest[j] = (uint8_t)pix; + pSrc += 2; + } + pSrc += 8; // skip extra line + pDest += iPitch; + } + return; + } + xcount = ycount = 8; // debug + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + xcount = ycount = 2; + else if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + xcount = ycount = 1; + for (i=0; iucSubSample == 0x21) // stacked horizontally + { + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + // only 2 pixels emitted + pDest[0] = pSrc[0]; + pDest[1] = pSrc[128]; + return; + } /* 1/8 */ + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (i=0; i<4; i++) + { + for (j=0; j<4; j++) + { + int pix; + pix = (pSrc[j*2] + pSrc[j*2+1] + pSrc[j*2 + 8] + pSrc[j*2 + 9] + 2) >> 2; + pDest[j] = (uint8_t)pix; + pix = (pSrc[j*2 + 128] + pSrc[j*2+129] + pSrc[j*2 + 136] + pSrc[j*2 + 137] + 2) >> 2; + pDest[j+4] = (uint8_t)pix; + } + pSrc += 16; + pDest += iPitch; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { + // each MCU contributes a 2x2 block + pDest[0] = pSrc[0]; // Y0 + pDest[1] = pSrc[1]; + pDest[iPitch] = pSrc[2]; + pDest[iPitch+1] = pSrc[3]; + + pDest[2] = pSrc[128]; // Y` + pDest[3] = pSrc[129]; + pDest[iPitch+2] = pSrc[130]; + pDest[iPitch+3] = pSrc[131]; + return; + } + for (i=0; i<8; i++) + { + for (j=0; j<8; j++) + { + pDest[j] = pSrc[j]; + pDest[j+8] = pSrc[128 + j]; + } + pSrc += 8; + pDest += iPitch; + } + } // 0x21 + if (pJPEG->ucSubSample == 0x12) // stacked vertically + { + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + // only 2 pixels emitted + pDest[0] = pSrc[0]; + pDest[iPitch] = pSrc[128]; + return; + } /* 1/8 */ + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (i=0; i<4; i++) + { + for (j=0; j<4; j++) + { + int pix; + pix = (pSrc[j*2] + pSrc[j*2+1] + pSrc[j*2 + 8] + pSrc[j*2 + 9] + 2) >> 2; + pDest[j] = (uint8_t)pix; + pix = (pSrc[j*2 + 128] + pSrc[j*2+129] + pSrc[j*2 + 136] + pSrc[j*2 + 137] + 2) >> 2; + pDest[4*iPitch+j] = (uint8_t)pix; + } + pSrc += 16; + pDest += iPitch; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { + // each MCU contributes a 2x2 block + pDest[0] = pSrc[0]; // Y0 + pDest[1] = pSrc[1]; + pDest[iPitch] = pSrc[2]; + pDest[iPitch+1] = pSrc[3]; + + pDest[iPitch*2] = pSrc[128]; // Y` + pDest[iPitch*2+1] = pSrc[129]; + pDest[iPitch*3] = pSrc[130]; + pDest[iPitch*3+1] = pSrc[131]; + return; + } + for (i=0; i<8; i++) + { + for (j=0; j<8; j++) + { + pDest[j] = pSrc[j]; + pDest[8*iPitch + j] = pSrc[128 + j]; + } + pSrc += 8; + pDest += iPitch; + } + } // 0x12 + if (pJPEG->ucSubSample == 0x22) + { + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + // each MCU contributes 1 pixel + pDest[0] = pSrc[0]; // Y0 + pDest[1] = pSrc[128]; // Y1 + pDest[iPitch] = pSrc[256]; // Y2 + pDest[iPitch + 1] = pSrc[384]; // Y3 + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { + // each MCU contributes 2x2 pixels + pDest[0] = pSrc[0]; // Y0 + pDest[1] = pSrc[1]; + pDest[iPitch] = pSrc[2]; + pDest[iPitch+1] = pSrc[3]; + + pDest[2] = pSrc[128]; // Y1 + pDest[3] = pSrc[129]; + pDest[iPitch+2] = pSrc[130]; + pDest[iPitch+3] = pSrc[131]; + + pDest[iPitch*2] = pSrc[256]; // Y2 + pDest[iPitch*2+1] = pSrc[257]; + pDest[iPitch*3] = pSrc[258]; + pDest[iPitch*3+1] = pSrc[259]; + + pDest[iPitch*2+2] = pSrc[384]; // Y3 + pDest[iPitch*2+3] = pSrc[385]; + pDest[iPitch*3+2] = pSrc[386]; + pDest[iPitch*3+3] = pSrc[387]; + return; + } + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (i=0; i<4; i++) + { + for (j=0; j<4; j++) + { + int pix; + pix = (pSrc[j*2] + pSrc[j*2+1] + pSrc[j*2 + 8] + pSrc[j*2 + 9] + 2) >> 2; + pDest[j] = (uint8_t)pix; // Y0 + pix = (pSrc[j*2+128] + pSrc[j*2+129] + pSrc[j*2 + 136] + pSrc[j*2 + 137] + 2) >> 2; + pDest[j+4] = (uint8_t)pix; // Y1 + pix = (pSrc[j*2+256] + pSrc[j*2+257] + pSrc[j*2 + 264] + pSrc[j*2 + 265] + 2) >> 2; + pDest[iPitch*4 + j] = (uint8_t)pix; // Y2 + pix = (pSrc[j*2+384] + pSrc[j*2+385] + pSrc[j*2 + 392] + pSrc[j*2 + 393] + 2) >> 2; + pDest[iPitch*4 + j + 4] = (uint8_t)pix; // Y3 + } + pSrc += 16; + pDest += iPitch; + } + return; + } + for (i=0; i<8; i++) + { + for (j=0; j<8; j++) + { + pDest[j] = pSrc[j]; // Y0 + pDest[j+8] = pSrc[j+128]; // Y1 + pDest[iPitch*8 + j] = pSrc[j+256]; // Y2 + pDest[iPitch*8 + j + 8] = pSrc[j + 384]; // Y3 + } + pSrc += 8; + pDest += iPitch; + } + } // 0x22 +} /* JPEGMPutMCU8BitGray() */ + +static void JPEGPutMCUGray(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + uint16_t *usDest = (uint16_t *)&pJPEG->usPixels[x]; + int i, j, xcount, ycount; + uint8_t *pSrc = (uint8_t *)&pJPEG->sMCUs[0]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) // special handling of 1/2 size (pixel averaging) + { + int pix; + for (i=0; i<4; i++) + { + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + for (j=0; j<4; j++) + { + pix = (pSrc[0] + pSrc[1] + pSrc[8] + pSrc[9] + 2) >> 2; // average 2x2 block + usDest[j] = usGrayTo565[pix]; + pSrc += 2; + } + } + else + { + for (j=0; j<4; j++) + { + pix = (pSrc[0] + pSrc[1] + pSrc[8] + pSrc[9] + 2) >> 2; // average 2x2 block + usDest[j] = __builtin_bswap16(usGrayTo565[pix]); + pSrc += 2; + } + } + pSrc += 8; // skip extra line + usDest += iPitch; + } + return; + } + xcount = ycount = 8; // debug + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + xcount = ycount = 2; + else if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + xcount = ycount = 1; + for (i=0; iucPixelType == RGB565_LITTLE_ENDIAN) + { + for (j=0; j> 14; // G + ulPixel = __USAT16(ulPixel, 6) << 5; // range limit to 6 bits + ulTmp = __SMLAD(7258, ulCbCr, iY) >> 15; // Blue + ulTmp = __USAT16(ulTmp, 5); // range limit to 5 bits + ulPixel |= ulTmp; // now we have G + B + ulTmp = __SMLAD(5742, ulCbCr >> 16, iY) >> 15; // Red + ulTmp = __USAT16(ulTmp, 5); // range limit to 5 bits + ulPixel |= (ulTmp << 11); // now we have R + G + B + pDest[0] = (uint16_t)ulPixel; +#else + int iCBB, iCBG, iCRG, iCRR; + unsigned short usPixel; + + iCBB = 7258 * (iCb-0x80); + iCBG = -1409 * (iCb-0x80); + iCRG = -2925 * (iCr-0x80); + iCRR = 5742 * (iCr-0x80); + usPixel = usRangeTableB[((iCBB + iY) >> 12) & 0x3ff]; // blue pixel + usPixel |= usRangeTableG[((iCBG + iCRG + iY) >> 12) & 0x3ff]; // green pixel + usPixel |= usRangeTableR[((iCRR + iY) >> 12) & 0x3ff]; // red pixel + pDest[0] = usPixel; +#endif +} /* JPEGPixelLE() */ + +static void JPEGPixelBE(uint16_t *pDest, int iY, int iCb, int iCr) +{ + int iCBB, iCBG, iCRG, iCRR; + unsigned short usPixel; + + iCBB = 7258 * (iCb-0x80); + iCBG = -1409 * (iCb-0x80); + iCRG = -2925 * (iCr-0x80); + iCRR = 5742 * (iCr-0x80); + usPixel = usRangeTableB[((iCBB + iY) >> 12) & 0x3ff]; // blue pixel + usPixel |= usRangeTableG[((iCBG + iCRG + iY) >> 12) & 0x3ff]; // green pixel + usPixel |= usRangeTableR[((iCRR + iY) >> 12) & 0x3ff]; // red pixel + pDest[0] = __builtin_bswap16(usPixel); +} /* JPEGPixelBE() */ + +static void JPEGPixel2LE(uint16_t *pDest, int iY1, int iY2, int iCb, int iCr) +{ + uint32_t ulPixel1, ulPixel2; +// +// Cortex-M4/M7 has some SIMD instructions which can shave a few cycles +// off of this function (e.g. Teensy, Arduino Nano 33 BLE, Portenta, etc) +// +#ifdef HAS_SIMD + uint32_t ulCbCr = (iCb | (iCr << 16)); + uint32_t ulTmp2, ulTmp = -1409 | (-2925 << 16); // for green calc + ulCbCr = __SSUB16(ulCbCr, 0x00800080); // dual 16-bit subtraction + ulPixel1 = __SMLAD(ulCbCr, ulTmp, iY1) >> 14; // G for pixel 1 + ulPixel2 = __SMLAD(ulCbCr, ulTmp, iY2) >> 14; // G for pixel 2 + ulPixel1 |= (ulPixel2 << 16); + ulPixel1 = __USAT16(ulPixel1, 6) << 5; // range limit both to 6 bits + ulTmp = __SMLAD(7258, ulCbCr, iY1) >> 15; // Blue 1 + ulTmp2 = __SMLAD(7258, ulCbCr, iY2) >> 15; // Blue 2 + ulTmp = __USAT16(ulTmp | (ulTmp2 << 16), 5); // range limit both to 5 bits + ulPixel1 |= ulTmp; // now we have G + B + ulTmp = __SMLAD(5742, ulCbCr >> 16, iY1) >> 15; // Red 1 + ulTmp2 = __SMLAD(5742, ulCbCr >> 16, iY2) >> 15; // Red 2 + ulTmp = __USAT16(ulTmp | (ulTmp2 << 16), 5); // range limit both to 5 bits + ulPixel1 |= (ulTmp << 11); // now we have R + G + B + *(uint32_t *)&pDest[0] = ulPixel1; +#else + int iCBB, iCBG, iCRG, iCRR; + iCBB = 7258 * (iCb-0x80); + iCBG = -1409 * (iCb-0x80); + iCRG = -2925 * (iCr-0x80); + iCRR = 5742 * (iCr-0x80); + ulPixel1 = usRangeTableB[((iCBB + iY1) >> 12) & 0x3ff]; // blue pixel + ulPixel1 |= usRangeTableG[((iCBG + iCRG + iY1) >> 12) & 0x3ff]; // green pixel + ulPixel1 |= usRangeTableR[((iCRR + iY1) >> 12) & 0x3ff]; // red pixel + + ulPixel2 = usRangeTableB[((iCBB + iY2) >> 12) & 0x3ff]; // blue pixel + ulPixel2 |= usRangeTableG[((iCBG + iCRG + iY2) >> 12) & 0x3ff]; // green pixel + ulPixel2 |= usRangeTableR[((iCRR + iY2) >> 12) & 0x3ff]; // red pixel + *(uint32_t *)&pDest[0] = (ulPixel1 | (ulPixel2<<16)); +#endif +} /* JPEGPixel2LE() */ + +static void JPEGPixel2BE(uint16_t *pDest, int iY1, int iY2, int iCb, int iCr) +{ + int iCBB, iCBG, iCRG, iCRR; + uint32_t ulPixel1, ulPixel2; + + iCBB = 7258 * (iCb-0x80); + iCBG = -1409 * (iCb-0x80); + iCRG = -2925 * (iCr-0x80); + iCRR = 5742 * (iCr-0x80); + ulPixel1 = usRangeTableB[((iCBB + iY1) >> 12) & 0x3ff]; // blue pixel + ulPixel1 |= usRangeTableG[((iCBG + iCRG + iY1) >> 12) & 0x3ff]; // green pixel + ulPixel1 |= usRangeTableR[((iCRR + iY1) >> 12) & 0x3ff]; // red pixel + + ulPixel2 = usRangeTableB[((iCBB + iY2) >> 12) & 0x3ff]; // blue pixel + ulPixel2 |= usRangeTableG[((iCBG + iCRG + iY2) >> 12) & 0x3ff]; // green pixel + ulPixel2 |= usRangeTableR[((iCRR + iY2) >> 12) & 0x3ff]; // red pixel + *(uint32_t *)&pDest[0] = __builtin_bswap16(ulPixel1) | (__builtin_bswap16(ulPixel2)<<16); +} /* JPEGPixel2BE() */ + +static void JPEGPutMCU11(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + int iCr, iCb; + signed int Y; + int iCol; + int iRow; + uint8_t *pY, *pCr, *pCb; + uint16_t *pOutput = &pJPEG->usPixels[x]; + + pY = (unsigned char *)&pJPEG->sMCUs[0*DCTSIZE]; + pCb = (unsigned char *)&pJPEG->sMCUs[1*DCTSIZE]; + pCr = (unsigned char *)&pJPEG->sMCUs[2*DCTSIZE]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (iRow=0; iRow<4; iRow++) // up to 8 rows to do + { + for (iCol=0; iCol<4; iCol++) // up to 4x2 cols to do + { + iCr = (pCr[0] + pCr[1] + pCr[8] + pCr[9] + 2) >> 2; + iCb = (pCb[0] + pCb[1] + pCb[8] + pCb[9] + 2) >> 2; + Y = (pY[0] + pY[1] + pY[8] + pY[9]) << 10; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol, Y, iCb, iCr); + else + JPEGPixelBE(pOutput+iCol, Y, iCb, iCr); + pCr += 2; + pCb += 2; + pY += 2; + } // for col + pCr += 8; + pCb += 8; + pY += 8; + pOutput += iPitch; + } // for row + return; + } + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) // special case for 1/8 scaling + { + // only 4 pixels to draw, so no looping needed + iCr = pCr[0]; + iCb = pCb[0]; + Y = (int)(pY[0]) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput, Y, iCb, iCr); + else + JPEGPixelBE(pOutput, Y, iCb, iCr); + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) // special case for 1/4 scaling + { + // only 4 pixels to draw, so no looping needed + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput+1, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput+iPitch, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput+1+iPitch, Y, iCb, iCr); + } + else + { + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput+1, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput+iPitch, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput+1+iPitch, Y, iCb, iCr); + } + return; + } + for (iRow=0; iRow<8; iRow++) // up to 8 rows to do + { + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + for (iCol=0; iCol<8; iCol++) // up to 4x2 cols to do + { + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput+iCol, Y, iCb, iCr); + } // for col + } + else + { + for (iCol=0; iCol<8; iCol++) // up to 4x2 cols to do + { + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput+iCol, Y, iCb, iCr); + } // for col + } + pOutput += iPitch; + } // for row +} /* JPEGPutMCU11() */ + +static void JPEGPutMCU22(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + uint32_t Cr,Cb; + signed int Y1, Y2, Y3, Y4; + int iRow, iCol, iXCount1, iXCount2, iYCount; + unsigned char *pY, *pCr, *pCb; + int bUseOdd1, bUseOdd2; // special case where 24bpp odd sized image can clobber first column + uint16_t *pOutput = &pJPEG->usPixels[x]; + + pY = (unsigned char *)&pJPEG->sMCUs[0*DCTSIZE]; + pCb = (unsigned char *)&pJPEG->sMCUs[4*DCTSIZE]; + pCr = (unsigned char *)&pJPEG->sMCUs[5*DCTSIZE]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) // special handling of 1/2 size (pixel averaging) + { + for (iRow=0; iRow<4; iRow++) // 16x16 becomes 8x8 of 2x2 pixels + { + for (iCol=0; iCol<4; iCol++) + { + Y1 = (pY[iCol*2] + pY[iCol*2+1] + pY[iCol*2+8] + pY[iCol*2+9]) << 10; + Cb = pCb[iCol]; + Cr = pCr[iCol]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol, Y1, Cb, Cr); // top left + else + JPEGPixelBE(pOutput+iCol, Y1, Cb, Cr); + Y1 = (pY[iCol*2+(DCTSIZE*2)] + pY[iCol*2+1+(DCTSIZE*2)] + pY[iCol*2+8+(DCTSIZE*2)] + pY[iCol*2+9+(DCTSIZE*2)]) << 10; + Cb = pCb[iCol+4]; + Cr = pCr[iCol+4]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+4, Y1, Cb, Cr); // top right + else + JPEGPixelBE(pOutput+iCol+4, Y1, Cb, Cr); + Y1 = (pY[iCol*2+(DCTSIZE*4)] + pY[iCol*2+1+(DCTSIZE*4)] + pY[iCol*2+8+(DCTSIZE*4)] + pY[iCol*2+9+(DCTSIZE*4)]) << 10; + Cb = pCb[iCol+32]; + Cr = pCr[iCol+32]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+iPitch*4, Y1, Cb, Cr); // bottom left + else + JPEGPixelBE(pOutput+iCol+iPitch*4, Y1, Cb, Cr); + Y1 = (pY[iCol*2+(DCTSIZE*6)] + pY[iCol*2+1+(DCTSIZE*6)] + pY[iCol*2+8+(DCTSIZE*6)] + pY[iCol*2+9+(DCTSIZE*6)]) << 10; + Cb = pCb[iCol+32+4]; + Cr = pCr[iCol+32+4]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+4+iPitch*4, Y1, Cb, Cr); // bottom right + else + JPEGPixelBE(pOutput+iCol+4+iPitch*4, Y1, Cb, Cr); + } + pY += 16; + pCb += 8; + pCr += 8; + pOutput += iPitch; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + Y1 = pY[0] << 12; // scale to level of conversion table + Cb = pCb[0]; + Cr = pCr[0]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput, Y1, Cb, Cr); + // top right block + Y1 = pY[DCTSIZE*2] << 12; // scale to level of conversion table + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput + 1, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput + 1, Y1, Cb, Cr); + // bottom left block + Y1 = pY[DCTSIZE*4] << 12; // scale to level of conversion table + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iPitch, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput+iPitch, Y1, Cb, Cr); + // bottom right block + Y1 = pY[DCTSIZE*6] << 12; // scale to level of conversion table + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+ 1 + iPitch, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput+ 1 + iPitch, Y1, Cb, Cr); + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) // special case of 1/4 + { + for (iRow=0; iRow<2; iRow++) + { + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + for (iCol=0; iCol<2; iCol++) + { + // top left block + Y1 = pY[iCol] << 12; // scale to level of conversion table + Cb = pCb[0]; + Cr = pCr[0]; + JPEGPixelLE(pOutput + iCol, Y1, Cb, Cr); + // top right block + Y1 = pY[iCol+(DCTSIZE*2)] << 12; // scale to level of conversion table + Cb = pCb[1]; + Cr = pCr[1]; + JPEGPixelLE(pOutput + 2+iCol, Y1, Cb, Cr); + // bottom left block + Y1 = pY[iCol+DCTSIZE*4] << 12; // scale to level of conversion table + Cb = pCb[2]; + Cr = pCr[2]; + JPEGPixelLE(pOutput+iPitch*2 + iCol, Y1, Cb, Cr); + // bottom right block + Y1 = pY[iCol+DCTSIZE*6] << 12; // scale to level of conversion table + Cb = pCb[3]; + Cr = pCr[3]; + JPEGPixelLE(pOutput+iPitch*2 + 2+iCol, Y1, Cb, Cr); + } // for each column + } + else + { + for (iCol=0; iCol<2; iCol++) + { + // top left block + Y1 = pY[iCol] << 12; // scale to level of conversion table + Cb = pCb[0]; + Cr = pCr[0]; + JPEGPixelBE(pOutput + iCol, Y1, Cb, Cr); + // top right block + Y1 = pY[iCol+(DCTSIZE*2)] << 12; // scale to level of conversion table + Cb = pCb[1]; + Cr = pCr[1]; + JPEGPixelBE(pOutput + 2+iCol, Y1, Cb, Cr); + // bottom left block + Y1 = pY[iCol+DCTSIZE*4] << 12; // scale to level of conversion table + Cb = pCb[2]; + Cr = pCr[2]; + JPEGPixelBE(pOutput+iPitch*2 + iCol, Y1, Cb, Cr); + // bottom right block + Y1 = pY[iCol+DCTSIZE*6] << 12; // scale to level of conversion table + Cb = pCb[3]; + Cr = pCr[3]; + JPEGPixelBE(pOutput+iPitch*2 + 2+iCol, Y1, Cb, Cr); + } // for each column + } + pY += 2; // skip 1 line of source pixels + pOutput += iPitch; + } + return; + } + /* Convert YCC pixels into RGB pixels and store in output image */ + iYCount = 4; + bUseOdd1 = bUseOdd2 = 1; // assume odd column can be used + if ((x+15) >= pJPEG->iWidth) + { + iCol = (((pJPEG->iWidth & 15)+1) >> 1); + if (iCol >= 4) + { + iXCount1 = 4; + iXCount2 = iCol-4; + if (pJPEG->iWidth & 1 && (iXCount2 * 2) + 8 + (x * 16) > pJPEG->iWidth) + bUseOdd2 = 0; + } + else + { + iXCount1 = iCol; + iXCount2 = 0; + if (pJPEG->iWidth & 1 && (iXCount1 * 2) + (x * 16) > pJPEG->iWidth) + bUseOdd1 = 0; + } + } + else + iXCount1 = iXCount2 = 4; + for (iRow=0; iRowucPixelType == RGB565_LITTLE_ENDIAN) + { + if (bUseOdd1 || iCol != (iXCount1-1)) // only render if it won't go off the right edge + { + JPEGPixel2LE(pOutput + (iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2LE(pOutput+iPitch + (iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelLE(pOutput + (iCol<<1), Y1, Cb, Cr); + JPEGPixelLE(pOutput+iPitch + (iCol<<1), Y3, Cb, Cr); + } + } + else + { + if (bUseOdd1 || iCol != (iXCount1-1)) // only render if it won't go off the right edge + { + JPEGPixel2BE(pOutput + (iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2BE(pOutput+iPitch + (iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + (iCol<<1), Y1, Cb, Cr); + JPEGPixelBE(pOutput+iPitch + (iCol<<1), Y3, Cb, Cr); + } + } + // for top right block + if (iCol < iXCount2) + { + Y1 = pY[iCol*2+DCTSIZE*2]; + Y2 = pY[iCol*2+1+DCTSIZE*2]; + Y3 = pY[iCol*2+8+DCTSIZE*2]; + Y4 = pY[iCol*2+9+DCTSIZE*2]; + Y1 <<= 12; // scale to level of conversion table + Y2 <<= 12; + Y3 <<= 12; + Y4 <<= 12; + Cb = pCb[iCol+4]; + Cr = pCr[iCol+4]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + if (bUseOdd2 || iCol != (iXCount2-1)) // only render if it won't go off the right edge + { + JPEGPixel2LE(pOutput + 8+(iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2LE(pOutput+iPitch + 8+(iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelLE(pOutput+ 8+(iCol<<1), Y1, Cb, Cr); + JPEGPixelLE(pOutput+iPitch+ 8+(iCol<<1), Y3, Cb, Cr); + } + } + else + { + if (bUseOdd2 || iCol != (iXCount2-1)) // only render if it won't go off the right edge + { + JPEGPixel2BE(pOutput + 8+(iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2BE(pOutput+iPitch + 8+(iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput+ 8+(iCol<<1), Y1, Cb, Cr); + JPEGPixelBE(pOutput+iPitch+ 8+(iCol<<1), Y3, Cb, Cr); + } + } + } + // for bottom left block + Y1 = pY[iCol*2+DCTSIZE*4]; + Y2 = pY[iCol*2+1+DCTSIZE*4]; + Y3 = pY[iCol*2+8+DCTSIZE*4]; + Y4 = pY[iCol*2+9+DCTSIZE*4]; + Y1 <<= 12; // scale to level of conversion table + Y2 <<= 12; + Y3 <<= 12; + Y4 <<= 12; + Cb = pCb[iCol+32]; + Cr = pCr[iCol+32]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + if (bUseOdd1 || iCol != (iXCount1-1)) // only render if it won't go off the right edge + { + JPEGPixel2LE(pOutput+iPitch*8+ (iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2LE(pOutput+iPitch*9+ (iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelLE(pOutput+iPitch*8+ (iCol<<1), Y1, Cb, Cr); + JPEGPixelLE(pOutput+iPitch*9+ (iCol<<1), Y3, Cb, Cr); + } + } + else + { + if (bUseOdd1 || iCol != (iXCount1-1)) // only render if it won't go off the right edge + { + JPEGPixel2BE(pOutput+iPitch*8+ (iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2BE(pOutput+iPitch*9+ (iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput+iPitch*8+ (iCol<<1), Y1, Cb, Cr); + JPEGPixelBE(pOutput+iPitch*9+ (iCol<<1), Y3, Cb, Cr); + } + } + // for bottom right block + if (iCol < iXCount2) + { + Y1 = pY[iCol*2+DCTSIZE*6]; + Y2 = pY[iCol*2+1+DCTSIZE*6]; + Y3 = pY[iCol*2+8+DCTSIZE*6]; + Y4 = pY[iCol*2+9+DCTSIZE*6]; + Y1 <<= 12; // scale to level of conversion table + Y2 <<= 12; + Y3 <<= 12; + Y4 <<= 12; + Cb = pCb[iCol+36]; + Cr = pCr[iCol+36]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + if (bUseOdd2 || iCol != (iXCount2-1)) // only render if it won't go off the right edge + { + JPEGPixel2LE(pOutput+iPitch*8+ 8+(iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2LE(pOutput+iPitch*9+ 8+(iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelLE(pOutput+iPitch*8+ 8+(iCol<<1), Y1, Cb, Cr); + JPEGPixelLE(pOutput+iPitch*9+ 8+(iCol<<1), Y3, Cb, Cr); + } + } + else + { + if (bUseOdd2 || iCol != (iXCount2-1)) // only render if it won't go off the right edge + { + JPEGPixel2BE(pOutput+iPitch*8+ 8+(iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2BE(pOutput+iPitch*9+ 8+(iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput+iPitch*8+ 8+(iCol<<1), Y1, Cb, Cr); + JPEGPixelBE(pOutput+iPitch*9+ 8+(iCol<<1), Y3, Cb, Cr); + } + } + } + } // for each column + pY += 16; // skip to next line of source pixels + pCb += 8; + pCr += 8; + pOutput += iPitch*2; + } +} /* JPEGPutMCU22() */ + +static void JPEGPutMCU12(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + uint32_t Cr,Cb; + signed int Y1, Y2; + int iRow, iCol, iXCount, iYCount; + uint8_t *pY, *pCr, *pCb; + uint16_t *pOutput = &pJPEG->usPixels[x]; + + pY = (uint8_t *)&pJPEG->sMCUs[0*DCTSIZE]; + pCb = (uint8_t *)&pJPEG->sMCUs[2*DCTSIZE]; + pCr = (uint8_t *)&pJPEG->sMCUs[3*DCTSIZE]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (iRow=0; iRow<4; iRow++) + { + for (iCol=0; iCol<4; iCol++) + { + Y1 = (pY[0] + pY[1] + pY[8] + pY[9]) << 10; + Cb = (pCb[0] + pCb[1] + 1) >> 1; + Cr = (pCr[0] + pCr[1] + 1) >> 1; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput+iCol, Y1, Cb, Cr); + Y1 = (pY[DCTSIZE*2] + pY[DCTSIZE*2+1] + pY[DCTSIZE*2+8] + pY[DCTSIZE*2+9]) << 10; + Cb = (pCb[32] + pCb[33] + 1) >> 1; + Cr = (pCr[32] + pCr[33] + 1) >> 1; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+iPitch, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput+iCol+iPitch, Y1, Cb, Cr); + pCb += 2; + pCr += 2; + pY += 2; + } + pY += 8; + pOutput += iPitch*2; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + Y1 = pY[0] << 12; + Y2 = pY[DCTSIZE*2] << 12; + Cb = pCb[0]; + Cr = pCr[0]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput, Y1, Cb, Cr); + JPEGPixelLE(pOutput + iPitch, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput, Y1, Cb, Cr); + JPEGPixelBE(pOutput + iPitch, Y2, Cb, Cr); + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { // draw a 2x4 block + Y1 = pY[0] << 12; + Y2 = pY[2] << 12; + Cb = pCb[0]; + Cr = pCr[0]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput, Y1, Cb, Cr); + JPEGPixelLE(pOutput + iPitch, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput, Y1, Cb, Cr); + JPEGPixelBE(pOutput + iPitch, Y2, Cb, Cr); + } + Y1 = pY[1] << 12; + Y2 = pY[3] << 12; + Cb = pCb[1]; + Cr = pCr[1]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput + 1, Y1, Cb, Cr); + JPEGPixelLE(pOutput + 1 + iPitch, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + 1, Y1, Cb, Cr); + JPEGPixelBE(pOutput + 1 + iPitch, Y2, Cb, Cr); + } + pY += DCTSIZE*2; // next Y block below + Y1 = pY[0] << 12; + Y2 = pY[2] << 12; + Cb = pCb[2]; + Cr = pCr[2]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput + iPitch*2, Y1, Cb, Cr); + JPEGPixelLE(pOutput + iPitch*3, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + iPitch*2, Y1, Cb, Cr); + JPEGPixelBE(pOutput + iPitch*3, Y2, Cb, Cr); + } + Y1 = pY[1] << 12; + Y2 = pY[3] << 12; + Cb = pCb[3]; + Cr = pCr[3]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput + 1 + iPitch*2, Y1, Cb, Cr); + JPEGPixelLE(pOutput + 1 + iPitch*3, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + 1 + iPitch*2, Y1, Cb, Cr); + JPEGPixelBE(pOutput + 1 + iPitch*3, Y2, Cb, Cr); + } + return; + } + /* Convert YCC pixels into RGB pixels and store in output image */ + iYCount = 16; + iXCount = 8; + for (iRow=0; iRowucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput + iCol, Y1, Cb, Cr); + JPEGPixelLE(pOutput + iPitch + iCol, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + iCol, Y1, Cb, Cr); + JPEGPixelBE(pOutput + iPitch + iCol, Y2, Cb, Cr); + } + } + pY += 16; // skip to next 2 lines of source pixels + if (iRow == 6) // next MCU block, skip ahead to correct spot + pY += (128-64); + pCb += 8; + pCr += 8; + pOutput += iPitch*2; // next 2 lines of dest pixels + } +} /* JPEGPutMCU12() */ +static void JPEGPutMCU21(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + int iCr, iCb; + signed int Y1, Y2; + int iCol; + int iRow; + uint8_t *pY, *pCr, *pCb; + uint16_t *pOutput = &pJPEG->usPixels[x]; + + pY = (uint8_t *)&pJPEG->sMCUs[0*DCTSIZE]; + pCb = (uint8_t *)&pJPEG->sMCUs[2*DCTSIZE]; + pCr = (uint8_t *)&pJPEG->sMCUs[3*DCTSIZE]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (iRow=0; iRow<4; iRow++) + { + for (iCol=0; iCol<4; iCol++) + { // left block + iCr = (pCr[0] + pCr[8] + 1) >> 1; + iCb = (pCb[0] + pCb[8] + 1) >> 1; + Y1 = (signed int)(pY[0] + pY[1] + pY[8] + pY[9]) << 10; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol, Y1, iCb, iCr); + else + JPEGPixelBE(pOutput+iCol, Y1, iCb, iCr); + // right block + iCr = (pCr[4] + pCr[12] + 1) >> 1; + iCb = (pCb[4] + pCb[12] + 1) >> 1; + Y1 = (signed int)(pY[128] + pY[129] + pY[136] + pY[137]) << 10; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+4, Y1, iCb, iCr); + else + JPEGPixelBE(pOutput+iCol+4, Y1, iCb, iCr); + pCb++; + pCr++; + pY += 2; + } + pCb += 12; + pCr += 12; + pY += 8; + pOutput += iPitch; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { // draw 2 pixels + iCr = pCr[0]; + iCb = pCb[0]; + Y1 = (signed int)(pY[0]) << 12; + Y2 = (signed int)(pY[DCTSIZE*2]) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput, Y1, Y2, iCb, iCr); + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { // draw 4x2 pixels + // top left + iCr = pCr[0]; + iCb = pCb[0]; + Y1 = (signed int)(pY[0]) << 12; + Y2 = (signed int)(pY[1]) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput, Y1, Y2, iCb, iCr); + // top right + iCr = pCr[1]; + iCb = pCb[1]; + Y1 = (signed int)pY[DCTSIZE*2] << 12; + Y2 = (signed int)pY[DCTSIZE*2+1] << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + 2, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + 2, Y1, Y2, iCb, iCr); + // bottom left + iCr = pCr[2]; + iCb = pCb[2]; + Y1 = (signed int)(pY[2]) << 12; + Y2 = (signed int)(pY[3]) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + iPitch, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + iPitch, Y1, Y2, iCb, iCr); + // bottom right + iCr = pCr[3]; + iCb = pCb[3]; + Y1 = (signed int)pY[DCTSIZE*2+2] << 12; + Y2 = (signed int)pY[DCTSIZE*2+3] << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + iPitch + 2, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + iPitch + 2, Y1, Y2, iCb, iCr); + return; + } + /* Convert YCC pixels into RGB pixels and store in output image */ + for (iRow=0; iRow<8; iRow++) // up to 8 rows to do + { + for (iCol=0; iCol<4; iCol++) // up to 4x2 cols to do + { // left block + iCr = *pCr++; + iCb = *pCb++; + Y1 = (signed int)(*pY++) << 12; + Y2 = (signed int)(*pY++) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + iCol*2, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + iCol*2, Y1, Y2, iCb, iCr); + // right block + iCr = pCr[3]; + iCb = pCb[3]; + Y1 = (signed int)pY[126] << 12; + Y2 = (signed int)pY[127] << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + 8 + iCol*2, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + 8 + iCol*2, Y1, Y2, iCb, iCr); + } // for col + pCb += 4; + pCr += 4; + pOutput += iPitch; + } // for row +} /* JPEGPutMCU21() */ + +// Dither the 8-bit gray pixels into 1, 2, or 4-bit gray +static void JPEGDither(JPEGIMAGE *pJPEG, int iWidth, int iHeight) +{ +int x, y, xmask=0, iDestPitch=0; +int32_t cNew, lFErr, v=0, h; +int32_t e1,e2,e3,e4; +uint8_t cOut, ucPixelType; // forward errors for gray +uint8_t *pSrc, *pDest, *errors, *pErrors=NULL, *d, *pPixels; // destination 8bpp image +uint8_t pixelmask=0, shift=0; + + ucPixelType = pJPEG->ucPixelType; + errors = (uint8_t *)pJPEG->usPixels; // plenty of space here + errors[0] = errors[1] = errors[2] = 0; + pDest = pSrc = pJPEG->pDitherBuffer; // write the new pixels over the original + switch (ucPixelType) + { + case FOUR_BIT_DITHERED: + iDestPitch = (iWidth+1)/2; + pixelmask = 0xf0; + shift = 4; + xmask = 1; + break; + case TWO_BIT_DITHERED: + iDestPitch = (iWidth+3)/4; + pixelmask = 0xc0; + shift = 2; + xmask = 3; + break; + case ONE_BIT_DITHERED: + iDestPitch = (iWidth+7)/8; + pixelmask = 0x80; + shift = 1; + xmask = 7; + break; + } + for (y=0; y 255) cNew = 255; // clip to uint8_t + cOut <<= shift; // pack new pixels into a byte + cOut |= (cNew >> (8-shift)); // keep top N bits + if ((x & xmask) == xmask) // store it when the byte is full + { + *d++ = cOut; + cOut = 0; + } + // calculate the Floyd-Steinberg error for this pixel + v = cNew - (cNew & pixelmask); // new error for N-bit gray output (always positive) + h = v >> 1; + e1 = (7*h)>>3; // 7/16 + e2 = h - e1; // 1/16 + e3 = (5*h) >> 3; // 5/16 + e4 = h - e3; // 3/16 + // distribute error to neighbors + lFErr = e1 + pErrors[1]; + pErrors[1] = (uint8_t)e2; + pErrors[0] += e3; + pErrors[-1] += e4; + pErrors++; + } // for x + } // for y +} /* JPEGDither() */ + +// +// Decode the image +// returns 0 for error, 1 for success +// +static int DecodeJPEG(JPEGIMAGE *pJPEG) +{ + int cx, cy, x, y, mcuCX, mcuCY; + int iLum0, iLum1, iLum2, iLum3, iCr, iCb; + signed int iDCPred0, iDCPred1, iDCPred2; + int i, iQuant1, iQuant2, iQuant3, iErr; + uint8_t c; + int iMCUCount, xoff, iPitch, bThumbnail = 0; + int bContinue = 1; // early exit if the DRAW callback wants to stop + uint32_t l, *pl; + unsigned char cDCTable0, cACTable0, cDCTable1, cACTable1, cDCTable2, cACTable2; + JPEGDRAW jd; + int iMaxFill = 16, iScaleShift = 0; + + // Requested the Exif thumbnail + if (pJPEG->iOptions & JPEG_EXIF_THUMBNAIL) + { + if (pJPEG->iThumbData == 0 || pJPEG->iThumbWidth == 0) // doesn't exist + { + pJPEG->iError = JPEG_INVALID_PARAMETER; + return 0; + } + if (!JPEGParseInfo(pJPEG, 1)) // parse the embedded thumbnail file header + return 0; // something went wrong + } + // Fast downscaling options + if (pJPEG->iOptions & JPEG_SCALE_HALF) + iScaleShift = 1; + else if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { + iScaleShift = 2; + iMaxFill = 1; + } + else if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + iScaleShift = 3; + iMaxFill = 1; + bThumbnail = 1; + } + + // reorder and fix the quantization table for decoding + JPEGFixQuantD(pJPEG); + pJPEG->bb.ulBits = MOTOLONG(&pJPEG->ucFileBuf[0]); // preload first 4 bytes + pJPEG->bb.pBuf = pJPEG->ucFileBuf; + pJPEG->bb.ulBitOff = 0; + + cDCTable0 = pJPEG->JPCI[0].dc_tbl_no; + cACTable0 = pJPEG->JPCI[0].ac_tbl_no; + cDCTable1 = pJPEG->JPCI[1].dc_tbl_no; + cACTable1 = pJPEG->JPCI[1].ac_tbl_no; + cDCTable2 = pJPEG->JPCI[2].dc_tbl_no; + cACTable2 = pJPEG->JPCI[2].ac_tbl_no; + iDCPred0 = iDCPred1 = iDCPred2 = mcuCX = mcuCY = 0; + + switch (pJPEG->ucSubSample) // set up the parameters for the different subsampling options + { + case 0x00: // fake value to handle grayscale + case 0x01: // fake value to handle sRGB/CMYK + case 0x11: + cx = (pJPEG->iWidth + 7) >> 3; // number of MCU blocks + cy = (pJPEG->iHeight + 7) >> 3; + iCr = MCU1; + iCb = MCU2; + mcuCX = mcuCY = 8; + break; + case 0x12: + cx = (pJPEG->iWidth + 7) >> 3; // number of MCU blocks + cy = (pJPEG->iHeight + 15) >> 4; + iCr = MCU2; + iCb = MCU3; + mcuCX = 8; + mcuCY = 16; + break; + case 0x21: + cx = (pJPEG->iWidth + 15) >> 4; // number of MCU blocks + cy = (pJPEG->iHeight + 7) >> 3; + iCr = MCU2; + iCb = MCU3; + mcuCX = 16; + mcuCY = 8; + break; + case 0x22: + cx = (pJPEG->iWidth + 15) >> 4; // number of MCU blocks + cy = (pJPEG->iHeight + 15) >> 4; + iCr = MCU4; + iCb = MCU5; + mcuCX = mcuCY = 16; + break; + default: // to suppress compiler warning + cx = cy = 0; + iCr = iCb = 0; + break; + } + // Scale down the MCUs by the requested amount + mcuCX >>= iScaleShift; + mcuCY >>= iScaleShift; + + iQuant1 = pJPEG->sQuantTable[pJPEG->JPCI[0].quant_tbl_no*DCTSIZE]; // DC quant values + iQuant2 = pJPEG->sQuantTable[pJPEG->JPCI[1].quant_tbl_no*DCTSIZE]; + iQuant3 = pJPEG->sQuantTable[pJPEG->JPCI[2].quant_tbl_no*DCTSIZE]; + // luminance values are always in these positions + iLum0 = MCU0; + iLum1 = MCU1; + iLum2 = MCU2; + iLum3 = MCU3; + iErr = 0; + pJPEG->iResCount = pJPEG->iResInterval; + // Calculate how many MCUs we can fit in the pixel buffer to maximize LCD drawing speed + iMCUCount = MAX_BUFFERED_PIXELS / (mcuCX * mcuCY); + if (pJPEG->ucPixelType == EIGHT_BIT_GRAYSCALE) + iMCUCount *= 2; // each pixel is only 1 byte + if (iMCUCount > cx) + iMCUCount = cx; // don't go wider than the image + if (iMCUCount > pJPEG->iMaxMCUs) // did the user set an upper bound on how many pixels per JPEGDraw callback? + iMCUCount = pJPEG->iMaxMCUs; + if (pJPEG->ucPixelType > EIGHT_BIT_GRAYSCALE) // dithered, override the max MCU count + iMCUCount = cx; // do the whole row + jd.iBpp = 16; + switch (pJPEG->ucPixelType) + { + case EIGHT_BIT_GRAYSCALE: + jd.iBpp = 8; + break; + case FOUR_BIT_DITHERED: + jd.iBpp = 4; + break; + case TWO_BIT_DITHERED: + jd.iBpp = 2; + break; + case ONE_BIT_DITHERED: + jd.iBpp = 1; + break; + } + if (pJPEG->ucPixelType > EIGHT_BIT_GRAYSCALE) + jd.pPixels = (uint16_t *)pJPEG->pDitherBuffer; + else + jd.pPixels = pJPEG->usPixels; + jd.iHeight = mcuCY; + jd.y = pJPEG->iYOffset; + for (y = 0; y < cy && bContinue && iErr == 0; y++, jd.y += mcuCY) + { + jd.x = pJPEG->iXOffset; + xoff = 0; // start of new LCD output group + iPitch = iMCUCount * mcuCX; // pixels per line of LCD buffer + for (x = 0; x < cx && bContinue && iErr == 0; x++) + { + pJPEG->ucACTable = cACTable0; + pJPEG->ucDCTable = cDCTable0; + // do the first luminance component + iErr = JPEGDecodeMCU(pJPEG, iLum0, &iDCPred0); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + pl = (uint32_t *)&pJPEG->sMCUs[iLum0]; + c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + for (i = 0; iJPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // first quantization table + } + // do the second luminance component + if (pJPEG->ucSubSample > 0x11) // subsampling + { + iErr |= JPEGDecodeMCU(pJPEG, iLum1, &iDCPred0); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iLum1]; + for (i = 0; iJPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // first quantization table + } + if (pJPEG->ucSubSample == 0x22) + { + iErr |= JPEGDecodeMCU(pJPEG, iLum2, &iDCPred0); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iLum2]; + for (i = 0; iJPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // first quantization table + } + iErr |= JPEGDecodeMCU(pJPEG, iLum3, &iDCPred0); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iLum3]; + for (i = 0; iJPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // first quantization table + } + } // if 2:2 subsampling + } // if subsampling used + if (pJPEG->ucSubSample && pJPEG->ucNumComponents == 3) // if color (not CMYK) + { + // first chroma + pJPEG->ucACTable = cACTable1; + pJPEG->ucDCTable = cDCTable1; + iErr |= JPEGDecodeMCU(pJPEG, iCr, &iDCPred1); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred1 * iQuant2) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iCr]; + for (i = 0; iJPCI[1].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // second quantization table + } + // second chroma + pJPEG->ucACTable = cACTable2; + pJPEG->ucDCTable = cDCTable2; + iErr |= JPEGDecodeMCU(pJPEG, iCb, &iDCPred2); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred2 * iQuant3) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iCb]; + for (i = 0; iJPCI[2].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); + } + } // if color components present + if (pJPEG->ucPixelType >= EIGHT_BIT_GRAYSCALE) + { + JPEGPutMCU8BitGray(pJPEG, xoff, iPitch); + } + else + { + switch (pJPEG->ucSubSample) + { + case 0x00: // grayscale + JPEGPutMCUGray(pJPEG, xoff, iPitch); + break; + case 0x11: + JPEGPutMCU11(pJPEG, xoff, iPitch); + break; + case 0x12: + JPEGPutMCU12(pJPEG, xoff, iPitch); + break; + case 0x21: + JPEGPutMCU21(pJPEG, xoff, iPitch); + break; + case 0x22: + JPEGPutMCU22(pJPEG, xoff, iPitch); + break; + } // switch on color option + } + xoff += mcuCX; + if (xoff == iPitch || x == cx-1) // time to draw + { + xoff = 0; + jd.iWidth = iPitch; // width of each LCD block group + if (pJPEG->ucPixelType > EIGHT_BIT_GRAYSCALE) // dither to 4/2/1 bits + JPEGDither(pJPEG, cx * mcuCX, mcuCY); + if ((jd.y - pJPEG->iYOffset + mcuCY) > (pJPEG->iHeight>>iScaleShift)) { // last row needs to be trimmed + jd.iHeight = (pJPEG->iHeight>>iScaleShift) - (jd.y - pJPEG->iYOffset); + } + bContinue = (*pJPEG->pfnDraw)(&jd); + jd.x += iPitch; + if ((cx - 1 - x) < iMCUCount) // change pitch for the last set of MCUs on this row + iPitch = (cx - 1 - x) * mcuCX; + } + if (pJPEG->iResInterval) + { + if (--pJPEG->iResCount == 0) + { + pJPEG->iResCount = pJPEG->iResInterval; + iDCPred0 = iDCPred1 = iDCPred2 = 0; // reset DC predictors + if (pJPEG->bb.ulBitOff & 7) // need to start at the next even byte + { + pJPEG->bb.ulBitOff += (8 - (pJPEG->bb.ulBitOff & 7)); // new restart interval starts on byte boundary + } + } // if restart interval needs to reset + } // if there is a restart interval + // See if we need to feed it more data + if (pJPEG->iVLCOff >= FILE_HIGHWATER) + JPEGGetMoreData(pJPEG); // need more 'filtered' VLC data + } // for x + } // for y + if (iErr != 0) + pJPEG->iError = JPEG_DECODE_ERROR; + return (iErr == 0); +} /* DecodeJPEG() */ diff --git a/micropython/modules/jpegdec/jpegdec.c b/micropython/modules/jpegdec/jpegdec.c new file mode 100644 index 00000000..1b24bddf --- /dev/null +++ b/micropython/modules/jpegdec/jpegdec.c @@ -0,0 +1,121 @@ +#include "py/runtime.h" +#include "py/objstr.h" +#include "JPEGDEC.h" + +const mp_obj_type_t JPEG_type; + +typedef struct _JPEG_obj_t { + mp_obj_base_t base; + JPEGIMAGE *jpeg; + mp_obj_t callback; +} _JPEG_obj_t; + +mp_obj_t current_callback = mp_const_none; + +int JPEGDraw(JPEGDRAW *pDraw) { + for(int y = 0; y < pDraw->iHeight; y++) { + for(int x = 0; x < pDraw->iWidth; x++) { + int i = y * pDraw->iWidth + x; + mp_obj_t args[] = { + mp_obj_new_int(pDraw->x + x), + mp_obj_new_int(pDraw->y + y), + mp_obj_new_int(pDraw->pPixels[i]) + }; + mp_call_function_n_kw(current_callback, MP_ARRAY_SIZE(args), 0, args); + } + } + return 1; +} + +STATIC mp_obj_t _JPEG_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { + ARG_callback + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _JPEG_obj_t *self = m_new_obj_with_finaliser(_JPEG_obj_t); + self->base.type = &JPEG_type; + self->jpeg = m_new(JPEGIMAGE, 1); + self->callback = args[ARG_callback].u_obj; + return self; +} + +STATIC mp_obj_t _JPEG_del(mp_obj_t self_in) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); + m_del(JPEGIMAGE, self->jpeg, 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_del_obj, _JPEG_del); + +// open_RAM +STATIC mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + int result = JPEG_openRAM(self->jpeg, bufinfo.buf, bufinfo.len, JPEGDraw); + JPEG_setPixelType(self->jpeg, RGB565_BIG_ENDIAN); + return result == 1 ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(JPEG_openRAM_obj, _JPEG_openRAM); + +// decode +STATIC mp_obj_t _JPEG_decode(mp_obj_t self_in, mp_obj_t flags) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); + int x = 0; + int y = 0; + int f = mp_obj_get_int(flags); + current_callback = self->callback; + return JPEG_decode(self->jpeg, x, y, f) == 1 ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(JPEG_decode_obj, _JPEG_decode); + +// get_width +STATIC mp_obj_t _JPEG_getWidth(mp_obj_t self_in) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(JPEG_getWidth(self->jpeg)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_getWidth_obj, _JPEG_getWidth); + +// get_height +STATIC mp_obj_t _JPEG_getHeight(mp_obj_t self_in) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(JPEG_getHeight(self->jpeg)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_getHeight_obj, _JPEG_getHeight); + +// class +STATIC const mp_rom_map_elem_t JPEG_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&JPEG_del_obj) }, + { MP_ROM_QSTR(MP_QSTR_open_RAM), MP_ROM_PTR(&JPEG_openRAM_obj) }, + { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&JPEG_decode_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&JPEG_getWidth_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&JPEG_getHeight_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&JPEG_getHeight_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(JPEG_locals_dict, JPEG_locals_dict_table); + +const mp_obj_type_t JPEG_type = { + { &mp_type_type }, + .name = MP_QSTR_jpegdec, + //.print = _JPEG_print, + .make_new = _JPEG_make_new, + .locals_dict = (mp_obj_dict_t*)&JPEG_locals_dict, +}; + +// module +STATIC const mp_map_elem_t JPEG_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_jpegdec) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_JPEG), (mp_obj_t)&JPEG_type }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_JPEG_globals, JPEG_globals_table); + +const mp_obj_module_t JPEG_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_JPEG_globals, +}; +MP_REGISTER_MODULE(MP_QSTR_jpegdec, JPEG_user_cmodule, MODULE_JPEGDEC_ENABLED); \ No newline at end of file diff --git a/micropython/modules/jpegdec/micropython.cmake b/micropython/modules/jpegdec/micropython.cmake new file mode 100644 index 00000000..feaa331a --- /dev/null +++ b/micropython/modules/jpegdec/micropython.cmake @@ -0,0 +1,18 @@ +add_library(usermod_jpegdec INTERFACE) + +target_sources(usermod_jpegdec INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/jpegdec.c + ${CMAKE_CURRENT_LIST_DIR}/jpeg.c +) + +target_include_directories(usermod_jpegdec INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_jpegdec INTERFACE + MODULE_JPEGDEC_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_jpegdec) + +set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/jpeg.c PROPERTIES COMPILE_FLAGS "-Wno-error=unused-function") diff --git a/micropython/modules/micropython-common.cmake b/micropython/modules/micropython-common.cmake index 7146283f..345c741a 100644 --- a/micropython/modules/micropython-common.cmake +++ b/micropython/modules/micropython-common.cmake @@ -39,9 +39,10 @@ include(encoder/micropython) include(motor/micropython) include(qrcode/micropython/micropython) include(adcfft/micropython) +include(pcf85063a/micropython) include(st7789/micropython) -include(pcf85063a/micropython) +include(jpegdec/micropython) include(modules_py/modules_py) From 7abe4aae7fef803f3ce82214060f6db71596f4bb Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 25 May 2022 17:22:20 +0100 Subject: [PATCH 04/84] ST7789: Experimental 8bit framebuffer. --- drivers/st7789/st7789.cpp | 22 ++++++++++-- drivers/st7789/st7789.hpp | 10 +++--- libraries/generic_st7789/generic_st7789.cpp | 2 +- libraries/generic_st7789/generic_st7789.hpp | 16 ++++----- libraries/pico_explorer/pico_explorer.cpp | 4 +-- libraries/pico_explorer/pico_explorer.hpp | 4 +-- libraries/pico_graphics/pico_graphics.cpp | 19 ++++++++-- libraries/pico_graphics/pico_graphics.hpp | 22 +++++++++--- .../modules/pico_explorer/pico_explorer.cpp | 2 +- micropython/modules/st7789/st7789.cpp | 36 ++++++++++++------- 10 files changed, 97 insertions(+), 40 deletions(-) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 0c49a89b..eb23f7e1 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -88,7 +88,7 @@ namespace pimoroni { configure_display(false); if(bl != PIN_UNUSED) { - update(); // Send the new buffer to the display to clear any previous content + //update(); // Send the new buffer to the display to clear any previous content sleep_ms(50); // Wait for the update to apply set_backlight(255); // Turn backlight on now surprises have passed } @@ -219,8 +219,24 @@ namespace pimoroni { gpio_put(cs, 1); } - void ST7789::update() { - command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); + void ST7789::update(uint16_t *palette) { + //command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); + command(reg::RAMWR); + uint16_t row[width]; + gpio_put(dc, 1); // data mode + gpio_put(cs, 0); + for(auto y = 0u; y < height; y++) { + for(auto x = 0u; x < width; x++) { + auto i = y * width + x; + row[x] = palette[frame_buffer[i]]; + } + if(spi) { + spi_write_blocking(spi, (const uint8_t*)row, width * sizeof(uint16_t)); + } else { + write_blocking_parallel((const uint8_t*)row, width * sizeof(uint16_t)); + } + } + gpio_put(cs, 1); } void ST7789::set_backlight(uint8_t brightness) { diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index 522924f1..d74d65b4 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -36,10 +36,10 @@ namespace pimoroni { public: // frame buffer where pixel data is stored - uint16_t *frame_buffer; + uint8_t *frame_buffer; // Parallel init - ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer, + ST7789(uint16_t width, uint16_t height, uint8_t *frame_buffer, uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) : spi(nullptr), width(width), height(height), round(false), @@ -68,7 +68,7 @@ namespace pimoroni { } // Serial init - ST7789(uint16_t width, uint16_t height, bool round, uint16_t *frame_buffer, + ST7789(uint16_t width, uint16_t height, bool round, uint8_t *frame_buffer, spi_inst_t *spi, uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) : spi(spi), @@ -101,7 +101,7 @@ namespace pimoroni { uint get_bl() const; void command(uint8_t command, size_t len = 0, const char *data = NULL); - void update(); + void update(uint16_t *palette); void set_backlight(uint8_t brightness); void flip(); @@ -133,7 +133,7 @@ namespace pimoroni { void write_blocking_parallel(const uint8_t *src, size_t len); void common_init() { if(!this->frame_buffer) { - this->frame_buffer = new uint16_t[width * height]; + this->frame_buffer = new uint8_t[width * height]; } // if a backlight pin is provided then set it up for diff --git a/libraries/generic_st7789/generic_st7789.cpp b/libraries/generic_st7789/generic_st7789.cpp index 44bd6b97..d0dc2d98 100644 --- a/libraries/generic_st7789/generic_st7789.cpp +++ b/libraries/generic_st7789/generic_st7789.cpp @@ -30,7 +30,7 @@ namespace pimoroni { } void ST7789Generic::update() { - st7789.update(); + st7789.update(palette); } void ST7789Generic::flip() { diff --git a/libraries/generic_st7789/generic_st7789.hpp b/libraries/generic_st7789/generic_st7789.hpp index f68aaa9c..e1157ee9 100644 --- a/libraries/generic_st7789/generic_st7789.hpp +++ b/libraries/generic_st7789/generic_st7789.hpp @@ -10,34 +10,34 @@ namespace pimoroni { ST7789 st7789; public: - ST7789Generic(uint16_t width, uint16_t height, bool round=false, uint16_t *frame_buffer=nullptr) : + ST7789Generic(uint16_t width, uint16_t height, bool round=false, uint8_t *frame_buffer=nullptr) : PicoGraphics(width, height, frame_buffer), st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { - this->frame_buffer = st7789.frame_buffer; + this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); }; - ST7789Generic(uint16_t width, uint16_t height, bool round, uint16_t *frame_buffer, BG_SPI_SLOT slot) : + ST7789Generic(uint16_t width, uint16_t height, bool round, uint8_t *frame_buffer, BG_SPI_SLOT slot) : PicoGraphics(width, height, frame_buffer), st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, st7789.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, st7789.get_slot_bl(slot)) { - this->frame_buffer = st7789.frame_buffer; + this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); }; - ST7789Generic(uint16_t width, uint16_t height, bool round, uint16_t *frame_buffer, + ST7789Generic(uint16_t width, uint16_t height, bool round, uint8_t *frame_buffer, spi_inst_t *spi, uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) : PicoGraphics(width, height, frame_buffer), st7789(width, height, round, frame_buffer, spi, cs, dc, sck, mosi, bl) { - this->frame_buffer = st7789.frame_buffer; + this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); }; - ST7789Generic(uint16_t width, uint16_t height, uint16_t *frame_buffer, + ST7789Generic(uint16_t width, uint16_t height, uint8_t *frame_buffer, uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) : PicoGraphics(width, height, frame_buffer), st7789(width, height, frame_buffer, cs, dc, wr_sck, rd_sck, d0, bl) { - this->frame_buffer = st7789.frame_buffer; + this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); }; diff --git a/libraries/pico_explorer/pico_explorer.cpp b/libraries/pico_explorer/pico_explorer.cpp index 3cba4710..a29b9ae2 100644 --- a/libraries/pico_explorer/pico_explorer.cpp +++ b/libraries/pico_explorer/pico_explorer.cpp @@ -14,7 +14,7 @@ const uint8_t MOTOR2P = 11; namespace pimoroni { - PicoExplorer::PicoExplorer(uint16_t *buf) + PicoExplorer::PicoExplorer(uint8_t *buf) : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, PIMORONI_SPI_DEFAULT_INSTANCE, screen.get_slot_cs(PICO_EXPLORER_ONBOARD), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, screen.get_slot_bl(PICO_EXPLORER_ONBOARD)) { __fb = buf; @@ -52,7 +52,7 @@ namespace pimoroni { } void PicoExplorer::update() { - screen.update(); + screen.update(palette); } bool PicoExplorer::is_pressed(uint8_t button) { diff --git a/libraries/pico_explorer/pico_explorer.hpp b/libraries/pico_explorer/pico_explorer.hpp index 3c5217ee..ab0504b3 100644 --- a/libraries/pico_explorer/pico_explorer.hpp +++ b/libraries/pico_explorer/pico_explorer.hpp @@ -34,13 +34,13 @@ namespace pimoroni { static const uint GP6 = 6; static const uint GP7 = 7; - uint16_t *__fb; + uint8_t *__fb; private: ST7789 screen; int8_t audio_pin = -1; public: - PicoExplorer(uint16_t *buf); + PicoExplorer(uint8_t *buf); void init(); void update(); diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 17e09937..cd28831d 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -1,8 +1,8 @@ #include "pico_graphics.hpp" namespace pimoroni { - PicoGraphics::PicoGraphics(uint16_t width, uint16_t height, uint16_t *frame_buffer) - : frame_buffer(frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { + PicoGraphics::PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) + : frame_buffer((Pen *)frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { set_font(&font6); }; @@ -18,6 +18,21 @@ namespace pimoroni { pen = p; } + void PicoGraphics::set_pen_raw(uint16_t p) { + for(auto i=0u; i < palette_ptr; i++) { + if(palette[i] == p) { + pen = i; + return; + }; + } + + if(palette_ptr < 256) { + palette[palette_ptr] = p; + pen = palette_ptr; + palette_ptr += 1; + } + } + void PicoGraphics::set_clip(const Rect &r) { clip = bounds.intersection(r); } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index a80857cf..87c7cd41 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -10,7 +10,7 @@ // supports only 16-bit (565) RGB framebuffers namespace pimoroni { - typedef uint16_t Pen; + typedef uint8_t Pen; struct Rect; @@ -45,7 +45,7 @@ namespace pimoroni { class PicoGraphics { public: - uint16_t *frame_buffer; + Pen *frame_buffer; Rect bounds; Rect clip; @@ -54,18 +54,32 @@ namespace pimoroni { const bitmap::font_t *font; + uint16_t palette[256]; + uint16_t palette_ptr = 0; + public: - PicoGraphics(uint16_t width, uint16_t height, uint16_t *frame_buffer); + PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer); void set_font(const bitmap::font_t *font); void set_pen(uint8_t r, uint8_t g, uint8_t b); void set_pen(Pen p); + void set_pen_raw(uint16_t p); constexpr Pen create_pen(uint8_t r, uint8_t g, uint8_t b) { uint16_t p = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | ((b & 0b11111000) >> 3); - return __builtin_bswap16(p); + p = __builtin_bswap16(p); + + for(auto i=0u; i < palette_ptr; i++) { + if(palette[i] == p) return i; + } + + if(palette_ptr < 256) { + palette[palette_ptr] = p; + palette_ptr += 1; + } + return palette_ptr - 1; }; void set_clip(const Rect &r); diff --git a/micropython/modules/pico_explorer/pico_explorer.cpp b/micropython/modules/pico_explorer/pico_explorer.cpp index 1e0e8815..81de8865 100644 --- a/micropython/modules/pico_explorer/pico_explorer.cpp +++ b/micropython/modules/pico_explorer/pico_explorer.cpp @@ -27,7 +27,7 @@ mp_obj_t picoexplorer_init(mp_obj_t buf_obj) { } // Create a new display pointing to the newly provided buffer - explorer = new PicoExplorer((uint16_t *)bufinfo.buf); + explorer = new PicoExplorer((uint8_t *)bufinfo.buf); explorer->init(); return mp_const_none; diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index a7602a67..891f52b0 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -14,7 +14,7 @@ typedef struct _GenericST7789_obj_t { mp_obj_base_t base; ST7789Generic *st7789; bool parallel; - uint16_t *buffer; + uint8_t *buffer; } GenericST7789_obj_t; /***** Print *****/ @@ -85,12 +85,12 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t if (args[ARG_buffer].u_obj != mp_const_none) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - self->buffer = (uint16_t *)bufinfo.buf; - if(bufinfo.len < (size_t)(width * height * 2)) { + self->buffer = (uint8_t *)bufinfo.buf; + if(bufinfo.len < (size_t)(width * height)) { mp_raise_ValueError("Supplied buffer is too small!"); } } else { - self->buffer = m_new(uint16_t, width * height); + self->buffer = m_new(uint8_t, width * height); } if(args[ARG_slot].u_int != -1) { @@ -166,12 +166,12 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args if (args[ARG_buffer].u_obj != mp_const_none) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - self->buffer = (uint16_t *)bufinfo.buf; - if(bufinfo.len < (size_t)(width * height * 2)) { + self->buffer = (uint8_t *)bufinfo.buf; + if(bufinfo.len < (size_t)(width * height)) { mp_raise_ValueError("Supplied buffer is too small!"); } } else { - self->buffer = m_new(uint16_t, width * height); + self->buffer = m_new(uint8_t, width * height); } int cs = args[ARG_cs].u_int; @@ -187,6 +187,8 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args self->st7789->configure_display(true); } + mp_printf(&mp_plat_print, "ST7789Generic - %lu\n", sizeof(ST7789Generic)); + return MP_OBJ_FROM_PTR(self); } @@ -223,10 +225,11 @@ mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { if(n_args <= 2) { - enum { ARG_self, ARG_pen }; + enum { ARG_self, ARG_pen, ARG_raw }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_raw, MP_ARG_OBJ, { .u_obj = mp_const_false } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -236,10 +239,19 @@ mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t int pen = args[ARG_pen].u_int; - if(pen < 0 || pen > 0xffff) - mp_raise_ValueError("p is not a valid pen."); - else - self->st7789->set_pen(pen); + if (args[ARG_raw].u_obj == mp_const_false) { + if(pen < 0 || pen > 0xff) { + mp_raise_ValueError("p is not a valid pen."); + } else { + self->st7789->set_pen(pen); + } + } else { + if(pen < 0 || pen > 0xffff) { + mp_raise_ValueError("p is not a valid pen."); + } else { + self->st7789->set_pen_raw(pen); + } + } } else { enum { ARG_self, ARG_r, ARG_g, ARG_b }; From 51ad7edb099966490aaaf8e74b6cf152d2bea734 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 26 May 2022 11:51:15 +0100 Subject: [PATCH 05/84] Prefer RGB332, add palette management functions --- drivers/st7789/st7789.cpp | 10 ++++- drivers/st7789/st7789.hpp | 7 +-- libraries/generic_st7789/generic_st7789.hpp | 8 ++-- libraries/pico_display/pico_display.cpp | 4 +- libraries/pico_display/pico_display.hpp | 6 +-- libraries/pico_display_2/pico_display_2.cpp | 4 +- libraries/pico_display_2/pico_display_2.hpp | 6 +-- libraries/pico_explorer/pico_explorer.cpp | 2 +- libraries/pico_explorer/pico_explorer.hpp | 4 +- libraries/pico_graphics/pico_graphics.cpp | 37 ++++++++++----- libraries/pico_graphics/pico_graphics.hpp | 45 +++++++++++++------ .../modules/pico_display/pico_display.cpp | 2 +- .../modules/pico_display_2/pico_display_2.cpp | 2 +- micropython/modules/st7789/st7789.c | 8 +++- micropython/modules/st7789/st7789.cpp | 39 +++++++++------- micropython/modules/st7789/st7789.h | 2 + 16 files changed, 117 insertions(+), 69 deletions(-) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index eb23f7e1..089f1cd4 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -219,8 +219,13 @@ namespace pimoroni { gpio_put(cs, 1); } + // Native 16-bit framebuffer update + void ST7789::update() { + command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); + } + + // 8-bit framebuffer with palette conversion update void ST7789::update(uint16_t *palette) { - //command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); command(reg::RAMWR); uint16_t row[width]; gpio_put(dc, 1); // data mode @@ -228,8 +233,9 @@ namespace pimoroni { for(auto y = 0u; y < height; y++) { for(auto x = 0u; x < width; x++) { auto i = y * width + x; - row[x] = palette[frame_buffer[i]]; + row[x] = palette[((uint8_t *)frame_buffer)[i]]; } + // TODO: Add DMA->SPI / PIO while we prep the next row if(spi) { spi_write_blocking(spi, (const uint8_t*)row, width * sizeof(uint16_t)); } else { diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index d74d65b4..df15d747 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -36,10 +36,10 @@ namespace pimoroni { public: // frame buffer where pixel data is stored - uint8_t *frame_buffer; + void *frame_buffer; // Parallel init - ST7789(uint16_t width, uint16_t height, uint8_t *frame_buffer, + ST7789(uint16_t width, uint16_t height, void *frame_buffer, uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) : spi(nullptr), width(width), height(height), round(false), @@ -68,7 +68,7 @@ namespace pimoroni { } // Serial init - ST7789(uint16_t width, uint16_t height, bool round, uint8_t *frame_buffer, + ST7789(uint16_t width, uint16_t height, bool round, void *frame_buffer, spi_inst_t *spi, uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) : spi(spi), @@ -101,6 +101,7 @@ namespace pimoroni { uint get_bl() const; void command(uint8_t command, size_t len = 0, const char *data = NULL); + void update(); void update(uint16_t *palette); void set_backlight(uint8_t brightness); void flip(); diff --git a/libraries/generic_st7789/generic_st7789.hpp b/libraries/generic_st7789/generic_st7789.hpp index e1157ee9..4ccebd0a 100644 --- a/libraries/generic_st7789/generic_st7789.hpp +++ b/libraries/generic_st7789/generic_st7789.hpp @@ -10,21 +10,21 @@ namespace pimoroni { ST7789 st7789; public: - ST7789Generic(uint16_t width, uint16_t height, bool round=false, uint8_t *frame_buffer=nullptr) : + ST7789Generic(uint16_t width, uint16_t height, bool round=false, void *frame_buffer=nullptr) : PicoGraphics(width, height, frame_buffer), st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); }; - ST7789Generic(uint16_t width, uint16_t height, bool round, uint8_t *frame_buffer, BG_SPI_SLOT slot) : + ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer, BG_SPI_SLOT slot) : PicoGraphics(width, height, frame_buffer), st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, st7789.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, st7789.get_slot_bl(slot)) { this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); }; - ST7789Generic(uint16_t width, uint16_t height, bool round, uint8_t *frame_buffer, + ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer, spi_inst_t *spi, uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) : PicoGraphics(width, height, frame_buffer), @@ -33,7 +33,7 @@ namespace pimoroni { this->st7789.init(); }; - ST7789Generic(uint16_t width, uint16_t height, uint8_t *frame_buffer, + ST7789Generic(uint16_t width, uint16_t height, void *frame_buffer, uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) : PicoGraphics(width, height, frame_buffer), st7789(width, height, frame_buffer, cs, dc, wr_sck, rd_sck, d0, bl) { diff --git a/libraries/pico_display/pico_display.cpp b/libraries/pico_display/pico_display.cpp index d8d6ac2f..4b5cee47 100644 --- a/libraries/pico_display/pico_display.cpp +++ b/libraries/pico_display/pico_display.cpp @@ -8,13 +8,13 @@ namespace pimoroni { - PicoDisplay::PicoDisplay(uint16_t *buf) + PicoDisplay::PicoDisplay(void *buf) : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { __fb = buf; } - PicoDisplay::PicoDisplay(uint16_t *buf, int width, int height) + PicoDisplay::PicoDisplay(void *buf, int width, int height) : PicoGraphics(width, height, buf), screen(width, height, false, buf, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { __fb = buf; diff --git a/libraries/pico_display/pico_display.hpp b/libraries/pico_display/pico_display.hpp index 17bb65a6..fea52674 100644 --- a/libraries/pico_display/pico_display.hpp +++ b/libraries/pico_display/pico_display.hpp @@ -19,13 +19,13 @@ namespace pimoroni { static const uint8_t LED_G = 7; static const uint8_t LED_B = 8; - uint16_t *__fb; + void *__fb; private: ST7789 screen; public: - PicoDisplay(uint16_t *buf); - PicoDisplay(uint16_t *buf, int width, int height); + PicoDisplay(void *buf); + PicoDisplay(void *buf, int width, int height); void init(); void update(); diff --git a/libraries/pico_display_2/pico_display_2.cpp b/libraries/pico_display_2/pico_display_2.cpp index 4738433f..969df230 100644 --- a/libraries/pico_display_2/pico_display_2.cpp +++ b/libraries/pico_display_2/pico_display_2.cpp @@ -8,13 +8,13 @@ namespace pimoroni { - PicoDisplay2::PicoDisplay2(uint16_t *buf) + PicoDisplay2::PicoDisplay2(void *buf) : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { __fb = buf; } - PicoDisplay2::PicoDisplay2(uint16_t *buf, int width, int height) + PicoDisplay2::PicoDisplay2(void *buf, int width, int height) : PicoGraphics(width, height, buf), screen(width, height, false, buf, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { __fb = buf; diff --git a/libraries/pico_display_2/pico_display_2.hpp b/libraries/pico_display_2/pico_display_2.hpp index 67ceb52c..769b983f 100644 --- a/libraries/pico_display_2/pico_display_2.hpp +++ b/libraries/pico_display_2/pico_display_2.hpp @@ -19,13 +19,13 @@ namespace pimoroni { static const uint8_t LED_G = 7; static const uint8_t LED_B = 8; - uint16_t *__fb; + void *__fb; private: ST7789 screen; public: - PicoDisplay2(uint16_t *buf); - PicoDisplay2(uint16_t *buf, int width, int height); + PicoDisplay2(void *buf); + PicoDisplay2(void *buf, int width, int height); void init(); void update(); diff --git a/libraries/pico_explorer/pico_explorer.cpp b/libraries/pico_explorer/pico_explorer.cpp index a29b9ae2..946935a2 100644 --- a/libraries/pico_explorer/pico_explorer.cpp +++ b/libraries/pico_explorer/pico_explorer.cpp @@ -14,7 +14,7 @@ const uint8_t MOTOR2P = 11; namespace pimoroni { - PicoExplorer::PicoExplorer(uint8_t *buf) + PicoExplorer::PicoExplorer(void *buf) : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, PIMORONI_SPI_DEFAULT_INSTANCE, screen.get_slot_cs(PICO_EXPLORER_ONBOARD), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, screen.get_slot_bl(PICO_EXPLORER_ONBOARD)) { __fb = buf; diff --git a/libraries/pico_explorer/pico_explorer.hpp b/libraries/pico_explorer/pico_explorer.hpp index ab0504b3..13933204 100644 --- a/libraries/pico_explorer/pico_explorer.hpp +++ b/libraries/pico_explorer/pico_explorer.hpp @@ -34,13 +34,13 @@ namespace pimoroni { static const uint GP6 = 6; static const uint GP7 = 7; - uint8_t *__fb; + void *__fb; private: ST7789 screen; int8_t audio_pin = -1; public: - PicoExplorer(uint8_t *buf); + PicoExplorer(void *buf); void init(); void update(); diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index cd28831d..d5e62871 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -4,6 +4,7 @@ namespace pimoroni { PicoGraphics::PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) : frame_buffer((Pen *)frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { set_font(&font6); + default_palette(); }; void PicoGraphics::set_font(const bitmap::font_t *font){ @@ -11,28 +12,36 @@ namespace pimoroni { } void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) { - pen = create_pen(r, g, b); + pen = put_palette(create_pen_rgb332(r, g, b)); } void PicoGraphics::set_pen(Pen p) { pen = p; } - void PicoGraphics::set_pen_raw(uint16_t p) { - for(auto i=0u; i < palette_ptr; i++) { - if(palette[i] == p) { - pen = i; - return; - }; - } + uint16_t PicoGraphics::get_palette(uint8_t i) { + return palette[i]; + } - if(palette_ptr < 256) { - palette[palette_ptr] = p; - pen = palette_ptr; - palette_ptr += 1; + void PicoGraphics::put_palette(uint16_t p, uint8_t i) { + palette[i] = p; + if (i > palette_entries) { + palette_entries = i; } } + uint8_t PicoGraphics::put_palette(uint16_t p) { + for(auto i=0u; i < palette_entries; i++) { + if(palette[i] == p) return i; + } + + if(palette_entries < 256) { + palette[palette_entries] = p; + palette_entries += 1; + } + return palette_entries - 1; + }; + void PicoGraphics::set_clip(const Rect &r) { clip = bounds.intersection(r); } @@ -136,6 +145,10 @@ namespace pimoroni { }, t, p.x, p.y, wrap, scale); } + void PicoGraphics::measure_text(const std::string &t, uint8_t scale) { + bitmap::measure_text(font, t, scale); + } + int32_t orient2d(Point p1, Point p2, Point p3) { return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x); } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 87c7cd41..c7af8f1b 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -55,32 +55,48 @@ namespace pimoroni { const bitmap::font_t *font; uint16_t palette[256]; - uint16_t palette_ptr = 0; + uint16_t palette_entries = 0; public: PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer); void set_font(const bitmap::font_t *font); void set_pen(uint8_t r, uint8_t g, uint8_t b); void set_pen(Pen p); - void set_pen_raw(uint16_t p); - constexpr Pen create_pen(uint8_t r, uint8_t g, uint8_t b) { + constexpr uint16_t create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) { uint16_t p = ((r & 0b11111000) << 8) | - ((g & 0b11111100) << 3) | - ((b & 0b11111000) >> 3); + ((g & 0b11111100) << 3) | + ((b & 0b11111000) >> 3); - p = __builtin_bswap16(p); + return __builtin_bswap16(p); + } + + constexpr uint16_t create_pen_rgb332(uint8_t r, uint8_t g, uint8_t b) { + uint16_t p = ((r & 0b11100000) << 8) | + ((g & 0b11100000) << 3) | + ((b & 0b11000000) >> 3); - for(auto i=0u; i < palette_ptr; i++) { - if(palette[i] == p) return i; + return __builtin_bswap16(p); + } + + Pen create_pen(uint8_t r, uint8_t g, uint8_t b) { + return put_palette(create_pen_rgb332(r, g, b)); + } + + void flush_palette() { + palette_entries = 0; + } + + void default_palette() { + for (auto i = 0u; i < 255; i++) { + palette[i] = i; } + palette_entries = 255; + } - if(palette_ptr < 256) { - palette[palette_ptr] = p; - palette_ptr += 1; - } - return palette_ptr - 1; - }; + uint8_t put_palette(uint16_t p); + uint16_t get_palette(uint8_t i); + void put_palette(uint16_t p, uint8_t i); void set_clip(const Rect &r); void remove_clip(); @@ -96,6 +112,7 @@ namespace pimoroni { void circle(const Point &p, int32_t r); void character(const char c, const Point &p, uint8_t scale = 2); void text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale = 2); + void measure_text(const std::string &t, uint8_t scale = 2); 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/pico_display/pico_display.cpp b/micropython/modules/pico_display/pico_display.cpp index c6b7650d..985ba4a4 100644 --- a/micropython/modules/pico_display/pico_display.cpp +++ b/micropython/modules/pico_display/pico_display.cpp @@ -27,7 +27,7 @@ mp_obj_t picodisplay_init(mp_obj_t buf_obj) { } // Create a new display pointing to the newly provided buffer - display = new PicoDisplay((uint16_t *)bufinfo.buf); + display = new PicoDisplay(bufinfo.buf); display->init(); return mp_const_none; diff --git a/micropython/modules/pico_display_2/pico_display_2.cpp b/micropython/modules/pico_display_2/pico_display_2.cpp index f33eb065..831407f4 100644 --- a/micropython/modules/pico_display_2/pico_display_2.cpp +++ b/micropython/modules/pico_display_2/pico_display_2.cpp @@ -27,7 +27,7 @@ mp_obj_t picodisplay2_init(mp_obj_t buf_obj) { } // Create a new display pointing to the newly provided buffer - display2 = new PicoDisplay2((uint16_t *)bufinfo.buf); + display2 = new PicoDisplay2(bufinfo.buf); display2->init(); return mp_const_none; diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index fcd64a95..dd6a80ab 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -1,6 +1,8 @@ #include "st7789.h" MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_update_obj, GenericST7789_update); +MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_flush_palette_obj, GenericST7789_flush_palette); +MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_default_palette_obj, GenericST7789_default_palette); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_backlight_obj, 1, GenericST7789_set_backlight); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_pen_obj, 1, GenericST7789_set_pen); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_create_pen_obj, 1, GenericST7789_create_pen); @@ -19,13 +21,15 @@ MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_line_obj, 1, GenericST7789_line); STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&GenericST7789_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush_palette), MP_ROM_PTR(&GenericST7789_flush_palette_obj) }, + { MP_ROM_QSTR(MP_QSTR_default_palette), MP_ROM_PTR(&GenericST7789_default_palette_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) }, { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&GenericST7789_set_clip_obj) }, { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&GenericST7789_remove_clip_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&GenericST7789_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&GenericST7789_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&GenericST7789_pixel_span_obj) }, { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&GenericST7789_rectangle_obj) }, { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&GenericST7789_circle_obj) }, diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 891f52b0..cfd1df07 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -14,7 +14,7 @@ typedef struct _GenericST7789_obj_t { mp_obj_base_t base; ST7789Generic *st7789; bool parallel; - uint8_t *buffer; + void *buffer; } GenericST7789_obj_t; /***** Print *****/ @@ -85,12 +85,12 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t if (args[ARG_buffer].u_obj != mp_const_none) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - self->buffer = (uint8_t *)bufinfo.buf; - if(bufinfo.len < (size_t)(width * height)) { + self->buffer = bufinfo.buf; + if(bufinfo.len < (size_t)(width * height * sizeof(Pen))) { mp_raise_ValueError("Supplied buffer is too small!"); } } else { - self->buffer = m_new(uint8_t, width * height); + self->buffer = m_new(uint8_t, width * height * sizeof(Pen)); } if(args[ARG_slot].u_int != -1) { @@ -200,6 +200,20 @@ mp_obj_t GenericST7789_update(mp_obj_t self_in) { return mp_const_none; } +mp_obj_t GenericST7789_flush_palette(mp_obj_t self_in) { + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); + self->st7789->flush_palette(); + + return mp_const_none; +} + +mp_obj_t GenericST7789_default_palette(mp_obj_t self_in) { + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); + self->st7789->default_palette(); + + return mp_const_none; +} + mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_self, ARG_brightness }; static const mp_arg_t allowed_args[] = { @@ -225,11 +239,10 @@ mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { if(n_args <= 2) { - enum { ARG_self, ARG_pen, ARG_raw }; + enum { ARG_self, ARG_pen }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_raw, MP_ARG_OBJ, { .u_obj = mp_const_false } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -239,18 +252,10 @@ mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t int pen = args[ARG_pen].u_int; - if (args[ARG_raw].u_obj == mp_const_false) { - if(pen < 0 || pen > 0xff) { - mp_raise_ValueError("p is not a valid pen."); - } else { - self->st7789->set_pen(pen); - } + if(pen < 0 || pen > 0xff) { + mp_raise_ValueError("p is not a valid pen."); } else { - if(pen < 0 || pen > 0xffff) { - mp_raise_ValueError("p is not a valid pen."); - } else { - self->st7789->set_pen_raw(pen); - } + self->st7789->set_pen(pen); } } else { diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h index c72a9e4a..1d822556 100644 --- a/micropython/modules/st7789/st7789.h +++ b/micropython/modules/st7789/st7789.h @@ -11,6 +11,8 @@ extern mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, extern mp_obj_t GenericST7789Parallel_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 GenericST7789_update(mp_obj_t self_in); +extern mp_obj_t GenericST7789_flush_palette(mp_obj_t self_in); +extern mp_obj_t GenericST7789_default_palette(mp_obj_t self_in); extern mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); From 3f9f28c60b6ffcc946fadd61a8491b69457b0129 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 26 May 2022 12:47:06 +0100 Subject: [PATCH 06/84] Add measure_text, fixed default palette init --- libraries/pico_graphics/pico_graphics.cpp | 4 +-- libraries/pico_graphics/pico_graphics.hpp | 5 +-- micropython/modules/st7789/st7789.c | 2 ++ micropython/modules/st7789/st7789.cpp | 39 ++++++++++++++++++----- micropython/modules/st7789/st7789.h | 1 + 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index d5e62871..3c948002 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -145,8 +145,8 @@ namespace pimoroni { }, t, p.x, p.y, wrap, scale); } - void PicoGraphics::measure_text(const std::string &t, uint8_t scale) { - bitmap::measure_text(font, t, scale); + int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) { + return bitmap::measure_text(font, t, scale); } int32_t orient2d(Point p1, Point p2, Point p3) { diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index c7af8f1b..d8ef0ef8 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -89,7 +89,8 @@ namespace pimoroni { void default_palette() { for (auto i = 0u; i < 255; i++) { - palette[i] = i; + palette[i] = ((i & 0b11100000) << 8) | ((i & 0b00011100) << 6) | ((i & 0b00000011) << 3); + palette[i] = __builtin_bswap16(palette[i]); } palette_entries = 255; } @@ -112,7 +113,7 @@ namespace pimoroni { void circle(const Point &p, int32_t r); void character(const char c, const Point &p, uint8_t scale = 2); void text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale = 2); - void measure_text(const std::string &t, uint8_t scale = 2); + int32_t measure_text(const std::string &t, uint8_t scale = 2); 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/st7789/st7789.c b/micropython/modules/st7789/st7789.c index dd6a80ab..882d0fdd 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -15,6 +15,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_rectangle_obj, 1, GenericST7789_rectang MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_circle_obj, 1, GenericST7789_circle); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_character_obj, 1, GenericST7789_character); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_text_obj, 1, GenericST7789_text); +MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_measure_text_obj, 1, GenericST7789_measure_text); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_polygon_obj, 2, GenericST7789_polygon); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_triangle_obj, 1, GenericST7789_triangle); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_line_obj, 1, GenericST7789_line); @@ -35,6 +36,7 @@ STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&GenericST7789_circle_obj) }, { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&GenericST7789_character_obj) }, { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&GenericST7789_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_measure_text), MP_ROM_PTR(&GenericST7789_measure_text_obj) }, { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&GenericST7789_polygon_obj) }, { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&GenericST7789_triangle_obj) }, { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&GenericST7789_line_obj) }, diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index cfd1df07..5692439a 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -511,17 +511,40 @@ mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k self->st7789->text(t, Point(x, y), wrap, scale); } - else if(mp_obj_is_float(text_obj)) { - mp_raise_TypeError("can't convert 'float' object to str implicitly"); + else { + mp_raise_TypeError("text: string required"); } - else if(mp_obj_is_int(text_obj)) { - mp_raise_TypeError("can't convert 'int' object to str implicitly"); - } - else if(mp_obj_is_bool(text_obj)) { - mp_raise_TypeError("can't convert 'bool' object to str implicitly"); + + return mp_const_none; +} + +mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_text, ARG_scale }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); + + mp_obj_t text_obj = args[ARG_text].u_obj; + if(mp_obj_is_str_or_bytes(text_obj)) { + GET_STR_DATA_LEN(text_obj, str, str_len); + + std::string t((const char*)str); + + int scale = args[ARG_scale].u_int; + + int width = self->st7789->measure_text(t, scale); + + return mp_obj_new_int(width); } else { - mp_raise_TypeError("can't convert object to str implicitly"); + mp_raise_TypeError("text: string required"); } return mp_const_none; diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h index 1d822556..39a467ef 100644 --- a/micropython/modules/st7789/st7789.h +++ b/micropython/modules/st7789/st7789.h @@ -26,6 +26,7 @@ extern mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *pos_args, extern mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); \ No newline at end of file From 73f73a0ac5e3892ba3f2ee1f587a9691dcb67284 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 26 May 2022 13:13:45 +0100 Subject: [PATCH 07/84] Make colour truncation from 565 to 332 optional --- libraries/pico_graphics/pico_graphics.cpp | 4 ++-- libraries/pico_graphics/pico_graphics.hpp | 6 +++--- micropython/modules/st7789/st7789.cpp | 16 +++++++++------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 3c948002..8c1382ce 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -11,8 +11,8 @@ namespace pimoroni { this->font = font; } - void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) { - pen = put_palette(create_pen_rgb332(r, g, b)); + void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b, bool truncate) { + pen = put_palette(truncate ? create_pen_rgb332(r, g, b) : create_pen_rgb565(r, g, b)); } void PicoGraphics::set_pen(Pen p) { diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index d8ef0ef8..89166da4 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -60,7 +60,7 @@ namespace pimoroni { public: PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer); void set_font(const bitmap::font_t *font); - void set_pen(uint8_t r, uint8_t g, uint8_t b); + void set_pen(uint8_t r, uint8_t g, uint8_t b, bool truncate=true); void set_pen(Pen p); constexpr uint16_t create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) { @@ -79,8 +79,8 @@ namespace pimoroni { return __builtin_bswap16(p); } - Pen create_pen(uint8_t r, uint8_t g, uint8_t b) { - return put_palette(create_pen_rgb332(r, g, b)); + Pen create_pen(uint8_t r, uint8_t g, uint8_t b, bool truncate=true) { + return put_palette(truncate ? create_pen_rgb332(r, g, b) : create_pen_rgb565(r, g, b)); } void flush_palette() { diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 5692439a..bae133c9 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -259,12 +259,13 @@ mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t } } else { - enum { ARG_self, ARG_r, ARG_g, ARG_b }; + enum { ARG_self, ARG_r, ARG_g, ARG_b, ARG_truncate }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_truncate, MP_ARG_OBJ, { .u_obj = mp_const_true } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -275,6 +276,7 @@ mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t int r = args[ARG_r].u_int; int g = args[ARG_g].u_int; int b = args[ARG_b].u_int; + bool t = args[ARG_truncate].u_obj == mp_const_true; if(r < 0 || r > 255) mp_raise_ValueError("r out of range. Expected 0 to 255"); @@ -283,21 +285,20 @@ mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t else if(b < 0 || b > 255) mp_raise_ValueError("b out of range. Expected 0 to 255"); else - self->st7789->set_pen(r, g, b); + self->st7789->set_pen(r, g, b, t); } return mp_const_none; } mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - int pen = 0; - - enum { ARG_self, ARG_r, ARG_g, ARG_b }; + enum { ARG_self, ARG_r, ARG_g, ARG_b, ARG_truncate }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_truncate, MP_ARG_OBJ, { .u_obj = mp_const_true } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -308,6 +309,7 @@ mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_ma int r = args[ARG_r].u_int; int g = args[ARG_g].u_int; int b = args[ARG_b].u_int; + bool t = args[ARG_truncate].u_obj == mp_const_true; if(r < 0 || r > 255) mp_raise_ValueError("r out of range. Expected 0 to 255"); @@ -316,9 +318,9 @@ mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_ma else if(b < 0 || b > 255) mp_raise_ValueError("b out of range. Expected 0 to 255"); else - pen = self->st7789->create_pen(r, g, b); + return mp_obj_new_int(self->st7789->create_pen(r, g, b, t)); - return mp_obj_new_int(pen); + return mp_const_none; } mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { From 1cd58ed2985b9a8b3e574d1c7d452336d7831b1f Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 26 May 2022 13:19:42 +0100 Subject: [PATCH 08/84] Remove debug print --- micropython/modules/st7789/st7789.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index bae133c9..ff8e8662 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -187,8 +187,6 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args self->st7789->configure_display(true); } - mp_printf(&mp_plat_print, "ST7789Generic - %lu\n", sizeof(ST7789Generic)); - return MP_OBJ_FROM_PTR(self); } From ef6179e77d6f914917e4d8cffbf52678d123c070 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 27 May 2022 16:52:43 +0100 Subject: [PATCH 09/84] ST7789/PicoGraphics: Refactor & make modes more explicit. --- drivers/st7735/st7735.cpp | 22 +- drivers/st7735/st7735.hpp | 11 +- examples/breakout_colourlcd160x80/demo.cpp | 13 +- examples/breakout_colourlcd240x240/demo.cpp | 12 +- examples/breakout_roundlcd/demo.cpp | 10 +- examples/pico_display/demo.cpp | 13 +- examples/pico_display_2/demo.cpp | 7 +- examples/pico_explorer/demo.cpp | 37 +-- examples/pico_explorer/text_demo.cpp | 7 +- .../breakout_colourlcd160x80.cpp | 8 +- .../breakout_colourlcd160x80.hpp | 8 +- libraries/generic_st7789/generic_st7789.hpp | 8 + libraries/pico_graphics/pico_graphics.cpp | 75 +++++-- libraries/pico_graphics/pico_graphics.hpp | 40 ++-- .../breakout_colourlcd160x80.cpp | 59 ++--- micropython/modules/micropython-common.cmake | 1 - micropython/modules/st7789/micropython.cmake | 8 +- micropython/modules/st7789/st7789.c | 46 +++- micropython/modules/st7789/st7789.cpp | 212 +++++++----------- micropython/modules/st7789/st7789.h | 25 ++- 20 files changed, 340 insertions(+), 282 deletions(-) diff --git a/drivers/st7735/st7735.cpp b/drivers/st7735/st7735.cpp index 52cd714d..c3ed0aa6 100644 --- a/drivers/st7735/st7735.cpp +++ b/drivers/st7735/st7735.cpp @@ -195,8 +195,26 @@ namespace pimoroni { gpio_put(cs, 1); } - void ST7735::update(bool dont_block) { - ST7735::command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); + // Native 16-bit framebuffer update + void ST7735::update() { + command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); + } + + // 8-bit framebuffer with palette conversion update + void ST7735::update(uint16_t *palette) { + command(reg::RAMWR); + uint16_t row[width]; + gpio_put(dc, 1); // data mode + gpio_put(cs, 0); + for(auto y = 0u; y < height; y++) { + for(auto x = 0u; x < width; x++) { + auto i = y * width + x; + row[x] = palette[((uint8_t *)frame_buffer)[i]]; + } + // TODO: Add DMA->SPI / PIO while we prep the next row + spi_write_blocking(spi, (const uint8_t*)row, width * sizeof(uint16_t)); + } + gpio_put(cs, 1); } void ST7735::set_backlight(uint8_t brightness) { diff --git a/drivers/st7735/st7735.hpp b/drivers/st7735/st7735.hpp index e4f8c327..75c739c3 100644 --- a/drivers/st7735/st7735.hpp +++ b/drivers/st7735/st7735.hpp @@ -32,7 +32,7 @@ namespace pimoroni { public: // frame buffer where pixel data is stored - uint16_t *frame_buffer; + void *frame_buffer; private: spi_inst_t *spi = spi0; @@ -58,7 +58,7 @@ namespace pimoroni { // Constructors/Destructor //-------------------------------------------------- public: - ST7735(uint16_t width, uint16_t height, uint16_t *frame_buffer, BG_SPI_SLOT slot) : + ST7735(uint16_t width, uint16_t height, void *frame_buffer, BG_SPI_SLOT slot) : width(width), height(height), frame_buffer(frame_buffer) { switch(slot) { case PICO_EXPLORER_ONBOARD: // Don't read too much into this, the case is just here to avoid a compile error @@ -76,10 +76,10 @@ namespace pimoroni { } } - ST7735(uint16_t width, uint16_t height, uint16_t *frame_buffer) : + ST7735(uint16_t width, uint16_t height, void *frame_buffer) : width(width), height(height), frame_buffer(frame_buffer) {} - ST7735(uint16_t width, uint16_t height, uint16_t *frame_buffer, + ST7735(uint16_t width, uint16_t height, void *frame_buffer, spi_inst_t *spi, uint8_t cs, uint8_t dc, uint8_t sck, uint8_t mosi, uint8_t miso = -1, uint8_t bl = -1) : width(width), height(height), frame_buffer(frame_buffer), @@ -100,7 +100,8 @@ namespace pimoroni { int get_bl() const; void command(uint8_t command, size_t len = 0, const char *data = NULL); - void update(bool dont_block = false); + void update(); + void update(uint16_t *palette); void set_backlight(uint8_t brightness); }; diff --git a/examples/breakout_colourlcd160x80/demo.cpp b/examples/breakout_colourlcd160x80/demo.cpp index cb4a06ca..f2757536 100644 --- a/examples/breakout_colourlcd160x80/demo.cpp +++ b/examples/breakout_colourlcd160x80/demo.cpp @@ -5,20 +5,23 @@ using namespace pimoroni; -uint16_t buffer[BreakoutColourLCD160x80::WIDTH * BreakoutColourLCD160x80::HEIGHT]; -BreakoutColourLCD160x80 lcd(buffer); +uint8_t buffer[BreakoutColourLCD160x80::WIDTH * BreakoutColourLCD160x80::HEIGHT]; +BreakoutColourLCD160x80 lcd((void *)buffer); int main() { lcd.init(); lcd.set_backlight(255); + // Delete the default palette and allow us to create up to 256 of our own RGB565 colours + lcd.set_palette_mode(BreakoutColourLCD160x80::PaletteModeUSER); + struct pt { float x; float y; uint8_t r; float dx; float dy; - uint16_t pen; + Pen pen; }; std::vector shapes; @@ -33,8 +36,10 @@ int main() { shapes.push_back(shape); } + uint8_t bg = lcd.create_pen(120, 40, 60); + while(true) { - lcd.set_pen(120, 40, 60); + lcd.set_pen(bg); lcd.clear(); for(auto &shape : shapes) { diff --git a/examples/breakout_colourlcd240x240/demo.cpp b/examples/breakout_colourlcd240x240/demo.cpp index 3ab5f8c7..2fd5ca6b 100644 --- a/examples/breakout_colourlcd240x240/demo.cpp +++ b/examples/breakout_colourlcd240x240/demo.cpp @@ -14,13 +14,16 @@ int main() { //lcd.configure_display(false); lcd.set_backlight(255); + // Delete the default palette and allow us to create up to 256 of our own RGB565 colours + lcd.set_palette_mode(ST7789Generic::PaletteModeUSER); + struct pt { float x; float y; uint8_t r; float dx; float dy; - uint16_t pen; + Pen pen; }; std::vector shapes; @@ -37,8 +40,11 @@ int main() { shapes.push_back(shape); } + Pen BG = lcd.create_pen(120, 40, 60); + Pen WHITE = lcd.create_pen(255, 255, 255); + while(true) { - lcd.set_pen(120, 40, 60); + lcd.set_pen(BG); lcd.clear(); for(auto &shape : shapes) { @@ -53,7 +59,7 @@ int main() { lcd.circle(Point(shape.x, shape.y), shape.r); } - lcd.set_pen(255, 255, 255); + lcd.set_pen(WHITE); lcd.text("Hello World", Point(0, 0), 240); // update screen diff --git a/examples/breakout_roundlcd/demo.cpp b/examples/breakout_roundlcd/demo.cpp index 9c8880eb..14edf18a 100644 --- a/examples/breakout_roundlcd/demo.cpp +++ b/examples/breakout_roundlcd/demo.cpp @@ -43,17 +43,23 @@ Pen from_hsv(float h, float s, float v) { int main() { display.set_backlight(255); + // Delete the default palette and allow us to create up to 256 of our own RGB565 colours + // display.set_palette_mode(ST7789Generic::PaletteModeUSER); + uint32_t steps = 70; float angle_step = 0.5f; + Pen BLACK = display.create_pen(0, 0, 0); + Pen WHITE = display.create_pen(255, 255, 255); + while(1) { absolute_time_t at = get_absolute_time(); uint64_t t = to_us_since_boot(at) / 100000; float angle = (t % 360) * M_PI / 180.0f; - display.set_pen(0, 0, 0); + display.set_pen(BLACK); display.clear(); - display.set_pen(255, 255, 255); + display.set_pen(WHITE); for(auto step = 0u; step < steps; step++) { auto distance = RADIUS / steps * step; diff --git a/examples/pico_display/demo.cpp b/examples/pico_display/demo.cpp index 85c31082..34a69d2f 100644 --- a/examples/pico_display/demo.cpp +++ b/examples/pico_display/demo.cpp @@ -43,8 +43,13 @@ int main() { } uint32_t i = 0; + Pen BG = pico_display.create_pen(120, 40, 60); + Pen YELLOW = pico_display.create_pen(255, 255, 0); + Pen TEAL = pico_display.create_pen(0, 255, 255); + Pen WHITE = pico_display.create_pen(255, 255, 255); + while(true) { - pico_display.set_pen(120, 40, 60); + pico_display.set_pen(BG); pico_display.clear(); for(auto &shape : shapes) { @@ -72,14 +77,14 @@ int main() { poly.push_back(Point(50, 85)); poly.push_back(Point(30, 45)); - pico_display.set_pen(255, 255, 0); + pico_display.set_pen(YELLOW); //pico_display.pixel(Point(0, 0)); pico_display.polygon(poly); - pico_display.set_pen(0, 255, 255); + pico_display.set_pen(TEAL); pico_display.triangle(Point(50, 50), Point(130, 80), Point(80, 110)); - pico_display.set_pen(255, 255, 255); + pico_display.set_pen(WHITE); pico_display.line(Point(50, 50), Point(120, 80)); pico_display.line(Point(20, 20), Point(120, 20)); pico_display.line(Point(20, 20), Point(20, 120)); diff --git a/examples/pico_display_2/demo.cpp b/examples/pico_display_2/demo.cpp index f1a06a38..b39fa4b2 100644 --- a/examples/pico_display_2/demo.cpp +++ b/examples/pico_display_2/demo.cpp @@ -69,6 +69,9 @@ int main() { Point text_location(0, 0); + Pen BG = pico_display.create_pen(120, 40, 60); + Pen WHITE = pico_display.create_pen(255, 255, 255); + while(true) { if(button_a.raw()) text_location.x -= 1; if(button_b.raw()) text_location.x += 1; @@ -76,7 +79,7 @@ int main() { if(button_x.raw()) text_location.y -= 1; if(button_y.raw()) text_location.y += 1; - pico_display.set_pen(120, 40, 60); + pico_display.set_pen(BG); pico_display.clear(); for(auto &shape : shapes) { @@ -112,7 +115,7 @@ int main() { led.set_rgb(r, g, b); - pico_display.set_pen(255, 255, 255); + pico_display.set_pen(WHITE); pico_display.text("Hello World", text_location, 320); // update screen diff --git a/examples/pico_explorer/demo.cpp b/examples/pico_explorer/demo.cpp index 6e7cbbf7..f7e72914 100644 --- a/examples/pico_explorer/demo.cpp +++ b/examples/pico_explorer/demo.cpp @@ -81,9 +81,14 @@ int main() { pico_explorer.set_audio_pin(pico_explorer.GP0); + Pen BG = pico_explorer.create_pen(120, 40, 60); + Pen WHITE = pico_explorer.create_pen(255, 255, 255); + Pen BOX = pico_explorer.create_pen(55, 65, 75); + Pen PURPLE = pico_explorer.create_pen(255, 0, 255); + uint32_t i = 0; while(true) { - pico_explorer.set_pen(120, 40, 60); + pico_explorer.set_pen(BG); pico_explorer.clear(); for(auto &shape : shapes) { @@ -99,21 +104,21 @@ int main() { } float rv = pico_explorer.get_adc(pico_explorer.ADC0); - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.circle(Point(rv * 140 + 50, 110), 20); - pico_explorer.set_pen(rv * 255, 0, 0); + pico_explorer.set_pen(pico_explorer.create_pen(rv * 255, 0, 0)); pico_explorer.circle(Point(rv * 140 + 50, 110), 15); float gv = pico_explorer.get_adc(pico_explorer.ADC1); - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.circle(Point(gv * 140 + 50, 160), 20); - pico_explorer.set_pen(0, gv * 255, 0); + pico_explorer.set_pen(pico_explorer.create_pen(0, gv * 255, 0)); pico_explorer.circle(Point(gv * 140 + 50, 160), 15); float bv = pico_explorer.get_adc(pico_explorer.ADC2); - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.circle(Point(bv * 140 + 50, 210), 20); - pico_explorer.set_pen(0, 0, bv * 255); + pico_explorer.set_pen(pico_explorer.create_pen(0, 0, bv * 255)); pico_explorer.circle(Point(bv * 140 + 50, 210), 15); pico_explorer.set_motor(pico_explorer.MOTOR1, pico_explorer.FORWARD, bv); @@ -122,32 +127,32 @@ int main() { pico_explorer.set_tone(440, 0.5); if(pico_explorer.is_pressed(pico_explorer.A)) { - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.character('A', Point(120, 180), 5); } if(pico_explorer.is_pressed(pico_explorer.B)) { - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.character('B', Point(120, 180), 5); } if(pico_explorer.is_pressed(pico_explorer.X)) { - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.character('X', Point(120, 180), 5); } if(pico_explorer.is_pressed(pico_explorer.Y)) { - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.character('Y', Point(120, 180), 5); } float tyoff = cos(i / 20.0f) * 50.0f - 50.0f; Rect text_box(10, 10, 150, 150); - pico_explorer.set_pen(55, 65, 75); + pico_explorer.set_pen(BOX); pico_explorer.rectangle(text_box); text_box.deflate(10); pico_explorer.set_clip(text_box); - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.text("This is a test of some text data that should wrap nicely onto multiple lines which is dead useful like.", Point(text_box.x, text_box.y + tyoff), 100); float xoff = sin(i / 20.0f) * 50.0f; @@ -169,16 +174,16 @@ int main() { pico_explorer.remove_clip(); - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.text("x: " + std::to_string(int(msa301.get_axis(msa301.X, 16) * 100)), Point(10, 190), 100); pico_explorer.text("y: " + std::to_string(int(msa301.get_axis(msa301.Y, 16) * 100)), Point(10, 205), 100); pico_explorer.text("z: " + std::to_string(int(msa301.get_axis(msa301.Z, 16) * 100)), Point(10, 220), 100); uint16_t xpos = (msa301.get_axis(msa301.X, 16) * 120) + 120; uint16_t ypos = (msa301.get_axis(msa301.Z, 16) * 120) + 120; - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.circle(Point(xpos, ypos), 20); - pico_explorer.set_pen(255, 0, 255); + pico_explorer.set_pen(PURPLE); pico_explorer.circle(Point(xpos, ypos), 15); diff --git a/examples/pico_explorer/text_demo.cpp b/examples/pico_explorer/text_demo.cpp index 971b8883..6aa0ff79 100644 --- a/examples/pico_explorer/text_demo.cpp +++ b/examples/pico_explorer/text_demo.cpp @@ -21,12 +21,15 @@ int main() { pico_explorer.set_font(&font8); msa301.init(); + Pen BG = pico_explorer.create_pen(120, 40, 60); + Pen WHITE = pico_explorer.create_pen(255, 255, 255); + uint32_t i = 0; while(true) { - pico_explorer.set_pen(120, 40, 60); + pico_explorer.set_pen(BG); pico_explorer.clear(); - pico_explorer.set_pen(255, 255, 255); + pico_explorer.set_pen(WHITE); pico_explorer.set_font(&font6); pico_explorer.text("6x6: The quick, brown fox jumps over the lazy dog! UPPER. lower.", Point(10, 10), 220); pico_explorer.text("0123456789 !$%^&*()", Point(10, 70), 220); diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp index bfa71ff4..393e04e2 100644 --- a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp +++ b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp @@ -2,18 +2,18 @@ namespace pimoroni { - BreakoutColourLCD160x80::BreakoutColourLCD160x80(uint16_t *buf) + BreakoutColourLCD160x80::BreakoutColourLCD160x80(void *buf) : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf) { __fb = buf; } - BreakoutColourLCD160x80::BreakoutColourLCD160x80(uint16_t *buf, spi_inst_t *spi, + BreakoutColourLCD160x80::BreakoutColourLCD160x80(void *buf, spi_inst_t *spi, uint cs, uint dc, uint sck, uint mosi, uint miso, uint bl) : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, spi, cs, dc, sck, mosi, miso, bl) { __fb = buf; } - BreakoutColourLCD160x80::BreakoutColourLCD160x80(uint16_t *buf, BG_SPI_SLOT slot) + BreakoutColourLCD160x80::BreakoutColourLCD160x80(void *buf, BG_SPI_SLOT slot) : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, slot) { __fb = buf; } @@ -48,7 +48,7 @@ namespace pimoroni { } void BreakoutColourLCD160x80::update() { - screen.update(); + screen.update(palette); } void BreakoutColourLCD160x80::set_backlight(uint8_t brightness) { diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp index 8db78425..13582bf1 100644 --- a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp +++ b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp @@ -18,7 +18,7 @@ namespace pimoroni { // Variables //-------------------------------------------------- public: - uint16_t *__fb; + void *__fb; private: ST7735 screen; @@ -27,10 +27,10 @@ namespace pimoroni { // Constructors/Destructor //-------------------------------------------------- public: - BreakoutColourLCD160x80(uint16_t *buf); - BreakoutColourLCD160x80(uint16_t *buf, spi_inst_t *spi, + BreakoutColourLCD160x80(void *buf); + BreakoutColourLCD160x80(void *buf, spi_inst_t *spi, uint cs, uint dc, uint sck, uint mosi, uint miso = PIN_UNUSED, uint bl = PIN_UNUSED); - BreakoutColourLCD160x80(uint16_t *buf, BG_SPI_SLOT slot); + BreakoutColourLCD160x80(void *buf, BG_SPI_SLOT slot); //-------------------------------------------------- diff --git a/libraries/generic_st7789/generic_st7789.hpp b/libraries/generic_st7789/generic_st7789.hpp index 4ccebd0a..3de609dd 100644 --- a/libraries/generic_st7789/generic_st7789.hpp +++ b/libraries/generic_st7789/generic_st7789.hpp @@ -15,6 +15,7 @@ namespace pimoroni { st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); + this->st7789.update(palette); }; ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer, BG_SPI_SLOT slot) : @@ -22,6 +23,7 @@ namespace pimoroni { st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, st7789.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, st7789.get_slot_bl(slot)) { this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); + this->st7789.update(palette); }; ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer, @@ -31,6 +33,7 @@ namespace pimoroni { st7789(width, height, round, frame_buffer, spi, cs, dc, sck, mosi, bl) { this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); + this->st7789.update(palette); }; ST7789Generic(uint16_t width, uint16_t height, void *frame_buffer, @@ -39,6 +42,7 @@ namespace pimoroni { st7789(width, height, frame_buffer, cs, dc, wr_sck, rd_sck, d0, bl) { this->frame_buffer = (Pen *)st7789.frame_buffer; this->st7789.init(); + this->st7789.update(palette); }; spi_inst_t* get_spi() const; @@ -52,6 +56,10 @@ namespace pimoroni { [[deprecated("Use configure_display(true) instead.")]] void flip(); void set_backlight(uint8_t brightness); void configure_display(bool rotate180); + void set_framebuffer(void* frame_buffer) { + this->frame_buffer = (Pen *)frame_buffer; + st7789.frame_buffer = frame_buffer; + } }; } diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 8c1382ce..62dd91a2 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -4,43 +4,74 @@ namespace pimoroni { PicoGraphics::PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) : frame_buffer((Pen *)frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { set_font(&font6); - default_palette(); + set_palette_mode(PaletteModeRGB332); }; void PicoGraphics::set_font(const bitmap::font_t *font){ this->font = font; } - void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b, bool truncate) { - pen = put_palette(truncate ? create_pen_rgb332(r, g, b) : create_pen_rgb565(r, g, b)); - } - void PicoGraphics::set_pen(Pen p) { pen = p; } - uint16_t PicoGraphics::get_palette(uint8_t i) { - return palette[i]; - } - - void PicoGraphics::put_palette(uint16_t p, uint8_t i) { - palette[i] = p; - if (i > palette_entries) { - palette_entries = i; + void PicoGraphics::set_palette_mode(PaletteMode mode) { + palette_mode = mode; + if(mode == PaletteModeRGB332) { + rgb332_palette(); + } else { + empty_palette(); } } - uint8_t PicoGraphics::put_palette(uint16_t p) { - for(auto i=0u; i < palette_entries; i++) { - if(palette[i] == p) return i; - } + int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) { + RGB565 c = palette_mode == PaletteModeRGB332 ? create_pen_rgb332(r, g, b) : create_pen_rgb565(r, g, b); + int result = search_palette(c); - if(palette_entries < 256) { - palette[palette_entries] = p; - palette_entries += 1; + if (result == -1 && palette_mode == PaletteModeUSER) { + result = put_palette(create_pen_rgb565(r, g, b)); } - return palette_entries - 1; - }; + + return result; + } + + int PicoGraphics::search_palette(RGB565 c) { + for(auto i = 0u; i < 256; i++) { + if(palette_status[i] && palette[i] == c) return i; + } + return -1; + } + + int PicoGraphics::put_palette(RGB565 c) { + for(auto i = 0u; i < 256; i++) { + if(!palette_status[i]) { + palette[i] = c; + palette_status[i] = true; + return i; + } + } + return -1; + } + + void PicoGraphics::set_palette(uint8_t i, uint16_t c) { + palette[i] = c; + palette_status[i] = true; + } + + void PicoGraphics::empty_palette() { + for (auto i = 0u; i < 255; i++) { + palette[i] = 0; + palette_status[i] = false; + } + } + + void PicoGraphics::rgb332_palette() { + for (auto i = 0u; i < 255; i++) { + palette[i] = ((i & 0b11100000) << 8) | ((i & 0b00011100) << 6) | ((i & 0b00000011) << 3); + palette[i] = __builtin_bswap16(palette[i]); + palette_status[i] = true; + } + } void PicoGraphics::set_clip(const Rect &r) { clip = bounds.intersection(r); diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 89166da4..dbda0324 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -11,6 +11,7 @@ namespace pimoroni { typedef uint8_t Pen; + typedef uint16_t RGB565; struct Rect; @@ -55,15 +56,22 @@ namespace pimoroni { const bitmap::font_t *font; uint16_t palette[256]; - uint16_t palette_entries = 0; + bool palette_status[256]; + + enum PaletteMode { + PaletteModeRGB332 = 0, + PaletteModeUSER = 1 + }; + + PaletteMode palette_mode = PaletteModeRGB332; public: PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer); void set_font(const bitmap::font_t *font); - void set_pen(uint8_t r, uint8_t g, uint8_t b, bool truncate=true); void set_pen(Pen p); + void set_palette_mode(PaletteMode mode); - constexpr uint16_t create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) { + static constexpr RGB565 create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) { uint16_t p = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | ((b & 0b11111000) >> 3); @@ -71,7 +79,7 @@ namespace pimoroni { return __builtin_bswap16(p); } - constexpr uint16_t create_pen_rgb332(uint8_t r, uint8_t g, uint8_t b) { + static constexpr RGB565 create_pen_rgb332(uint8_t r, uint8_t g, uint8_t b) { uint16_t p = ((r & 0b11100000) << 8) | ((g & 0b11100000) << 3) | ((b & 0b11000000) >> 3); @@ -79,25 +87,15 @@ namespace pimoroni { return __builtin_bswap16(p); } - Pen create_pen(uint8_t r, uint8_t g, uint8_t b, bool truncate=true) { - return put_palette(truncate ? create_pen_rgb332(r, g, b) : create_pen_rgb565(r, g, b)); - } + int create_pen(uint8_t r, uint8_t g, uint8_t b); - void flush_palette() { - palette_entries = 0; - } + void empty_palette(); + void rgb332_palette(); - void default_palette() { - for (auto i = 0u; i < 255; i++) { - palette[i] = ((i & 0b11100000) << 8) | ((i & 0b00011100) << 6) | ((i & 0b00000011) << 3); - palette[i] = __builtin_bswap16(palette[i]); - } - palette_entries = 255; - } - - uint8_t put_palette(uint16_t p); - uint16_t get_palette(uint8_t i); - void put_palette(uint16_t p, uint8_t i); + int search_palette(RGB565 c); + int get_palette(uint8_t i); + void set_palette(uint8_t i, RGB565 c); + int put_palette(RGB565 c); void set_clip(const Rect &r); void remove_clip(); diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp index f598b636..f51f5f50 100644 --- a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp +++ b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp @@ -64,7 +64,7 @@ mp_obj_t BreakoutColourLCD160x80_make_new(const mp_obj_type_t *type, size_t n_ar mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - self->breakout = m_new_class(BreakoutColourLCD160x80, (uint16_t *)bufinfo.buf, (BG_SPI_SLOT)slot); + self->breakout = m_new_class(BreakoutColourLCD160x80, bufinfo.buf, (BG_SPI_SLOT)slot); } else { mp_raise_ValueError("slot not a valid value. Expected 0 to 1"); @@ -113,7 +113,7 @@ mp_obj_t BreakoutColourLCD160x80_make_new(const mp_obj_type_t *type, size_t n_ar self->base.type = &breakout_colourlcd160x80_BreakoutColourLCD160x80_type; spi_inst_t *spi = (spi_id == 0) ? spi0 : spi1; - self->breakout = m_new_class(BreakoutColourLCD160x80, (uint16_t *)bufinfo.buf, spi, + self->breakout = m_new_class(BreakoutColourLCD160x80, bufinfo.buf, spi, args[ARG_cs].u_int, args[ARG_dc].u_int, sck, mosi, PIN_UNUSED, args[ARG_bl].u_int); } @@ -154,52 +154,23 @@ mp_obj_t BreakoutColourLCD160x80_set_backlight(size_t n_args, const mp_obj_t *po mp_obj_t BreakoutColourLCD160x80_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - if(n_args <= 2) { - enum { ARG_self, ARG_pen }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT }, - }; + enum { ARG_self, ARG_pen }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT }, + }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - int pen = args[ARG_pen].u_int; + int pen = args[ARG_pen].u_int; - if(pen < 0 || pen > 0xffff) - mp_raise_ValueError("p is not a valid pen."); - else - self->breakout->set_pen(pen); - } - else { - enum { ARG_self, ARG_r, ARG_g, ARG_b }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - - int r = args[ARG_r].u_int; - int g = args[ARG_g].u_int; - int b = args[ARG_b].u_int; - - 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 - self->breakout->set_pen(r, g, b); - } + if(pen < 0 || pen > 0xffff) + mp_raise_ValueError("p is not a valid pen."); + else + self->breakout->set_pen(pen); return mp_const_none; } diff --git a/micropython/modules/micropython-common.cmake b/micropython/modules/micropython-common.cmake index 345c741a..29097097 100644 --- a/micropython/modules/micropython-common.cmake +++ b/micropython/modules/micropython-common.cmake @@ -26,7 +26,6 @@ include(breakout_vl53l5cx/micropython) include(pico_scroll/micropython) include(pico_rgb_keypad/micropython) include(pico_unicorn/micropython) -include(pico_explorer/micropython) include(pico_wireless/micropython) include(bitmap_fonts/micropython) diff --git a/micropython/modules/st7789/micropython.cmake b/micropython/modules/st7789/micropython.cmake index 0da1fa86..4d7714b3 100644 --- a/micropython/modules/st7789/micropython.cmake +++ b/micropython/modules/st7789/micropython.cmake @@ -19,4 +19,10 @@ target_compile_definitions(usermod_${MOD_NAME} INTERFACE -DMODULE_${MOD_NAME_UPPER}_ENABLED=1 ) -target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) \ No newline at end of file +target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) + +set_source_files_properties( + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + PROPERTIES COMPILE_FLAGS + "-Wno-discarded-qualifiers" +) \ No newline at end of file diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index 882d0fdd..7881aad1 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -1,15 +1,27 @@ #include "st7789.h" +// Module functions +STATIC MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_module_RGB332_obj, GenericST7789_module_RGB332); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_module_RGB565_obj, GenericST7789_module_RGB565); + +// Class Methods MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_update_obj, GenericST7789_update); -MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_flush_palette_obj, GenericST7789_flush_palette); -MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_default_palette_obj, GenericST7789_default_palette); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_backlight_obj, 1, GenericST7789_set_backlight); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_pen_obj, 1, GenericST7789_set_pen); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_create_pen_obj, 1, GenericST7789_create_pen); +MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_backlight_obj, GenericST7789_set_backlight); +MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_framebuffer_obj, GenericST7789_set_framebuffer); + +// Palette management +MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_palette_mode_obj, GenericST7789_set_palette_mode); +MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_set_palette_obj, GenericST7789_set_palette); + +// Pen +MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_pen_obj, GenericST7789_set_pen); +MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_create_pen_obj, 3, GenericST7789_create_pen); + +// Primitives MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_clip_obj, 1, GenericST7789_set_clip); MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_remove_clip_obj, GenericST7789_remove_clip); MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_clear_obj, GenericST7789_clear); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_pixel_obj, 1, GenericST7789_pixel); +MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_pixel_obj, GenericST7789_pixel); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_pixel_span_obj, 1, GenericST7789_pixel_span); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_rectangle_obj, 1, GenericST7789_rectangle); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_circle_obj, 1, GenericST7789_circle); @@ -21,11 +33,13 @@ MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_triangle_obj, 1, GenericST7789_triangle MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_line_obj, 1, GenericST7789_line); STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) }, { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&GenericST7789_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_flush_palette), MP_ROM_PTR(&GenericST7789_flush_palette_obj) }, - { MP_ROM_QSTR(MP_QSTR_default_palette), MP_ROM_PTR(&GenericST7789_default_palette_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_palette_mode), MP_ROM_PTR(&GenericST7789_set_palette_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_palette), MP_ROM_PTR(&GenericST7789_set_palette_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) }, { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&GenericST7789_set_clip_obj) }, @@ -40,6 +54,8 @@ STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&GenericST7789_polygon_obj) }, { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&GenericST7789_triangle_obj) }, { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&GenericST7789_line_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_framebuffer), MP_ROM_PTR(&GenericST7789_set_framebuffer_obj) }, }; STATIC MP_DEFINE_CONST_DICT(GenericST7789_locals_dict, GenericST7789_locals_dict_table); @@ -62,9 +78,15 @@ const mp_obj_type_t GenericST7789Parallel_type = { /***** Module Globals *****/ STATIC const mp_map_elem_t st7789_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ST7789), (mp_obj_t)&GenericST7789_type }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ST7789Parallel), (mp_obj_t)&GenericST7789Parallel_type }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) }, + { MP_ROM_QSTR(MP_QSTR_ST7789), (mp_obj_t)&GenericST7789_type }, + { MP_ROM_QSTR(MP_QSTR_ST7789Parallel), (mp_obj_t)&GenericST7789Parallel_type }, + + { MP_ROM_QSTR(MP_QSTR_RGB332), MP_ROM_PTR(&GenericST7789_module_RGB332_obj) }, + { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&GenericST7789_module_RGB565_obj) }, + + { MP_ROM_QSTR(MP_QSTR_PALETTE_RGB332), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_PALETTE_USER), MP_ROM_INT(1) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_st7789_globals, st7789_globals_table); diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index ff8e8662..43430009 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -166,7 +166,7 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args if (args[ARG_buffer].u_obj != mp_const_none) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - self->buffer = (uint8_t *)bufinfo.buf; + self->buffer = bufinfo.buf; if(bufinfo.len < (size_t)(width * height)) { mp_raise_ValueError("Supplied buffer is too small!"); } @@ -191,6 +191,23 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args } /***** Methods *****/ +mp_obj_t GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) { + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); + + if (framebuffer == mp_const_none) { + m_del(uint8_t, self->buffer, self->st7789->bounds.w * self->st7789->bounds.h); + self->buffer = nullptr; + self->st7789->set_framebuffer(nullptr); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(framebuffer, &bufinfo, MP_BUFFER_RW); + self->buffer = bufinfo.buf; + self->st7789->set_framebuffer(self->buffer); + } + + return mp_const_none; +} + mp_obj_t GenericST7789_update(mp_obj_t self_in) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); self->st7789->update(); @@ -198,105 +215,69 @@ mp_obj_t GenericST7789_update(mp_obj_t self_in) { return mp_const_none; } -mp_obj_t GenericST7789_flush_palette(mp_obj_t self_in) { +mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - self->st7789->flush_palette(); - return mp_const_none; -} + float b = mp_obj_get_float(brightness); -mp_obj_t GenericST7789_default_palette(mp_obj_t self_in) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - self->st7789->default_palette(); - - return mp_const_none; -} - -mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_brightness }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_brightness, MP_ARG_REQUIRED | MP_ARG_OBJ }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); - - float brightness = mp_obj_get_float(args[ARG_brightness].u_obj); - - if(brightness < 0 || brightness > 1.0f) + if(b < 0 || b > 1.0f) mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); else - self->st7789->set_backlight((uint8_t)(brightness * 255.0f)); + self->st7789->set_backlight((uint8_t)(b * 255.0f)); return mp_const_none; } -mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { + return mp_obj_new_int(ST7789Generic::create_pen_rgb332( + mp_obj_get_int(r), + mp_obj_get_int(g), + mp_obj_get_int(b) + )); +} - if(n_args <= 2) { - enum { ARG_self, ARG_pen }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT }, - }; +mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { + return mp_obj_new_int(ST7789Generic::create_pen_rgb565( + mp_obj_get_int(r), + mp_obj_get_int(g), + mp_obj_get_int(b) + )); +} - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); +mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen) { + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); + self->st7789->set_pen(mp_obj_get_int(pen) & 0xff); - int pen = args[ARG_pen].u_int; + return mp_const_none; +} - if(pen < 0 || pen > 0xff) { - mp_raise_ValueError("p is not a valid pen."); - } else { - self->st7789->set_pen(pen); - } - } - else { - enum { ARG_self, ARG_r, ARG_g, ARG_b, ARG_truncate }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_truncate, MP_ARG_OBJ, { .u_obj = mp_const_true } }, - }; +mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode) { + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + self->st7789->set_palette_mode((ST7789Generic::PaletteMode)mp_obj_get_int(mode)); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); + return mp_const_none; +} - int r = args[ARG_r].u_int; - int g = args[ARG_g].u_int; - int b = args[ARG_b].u_int; - bool t = args[ARG_truncate].u_obj == mp_const_true; +mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t colour) { + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - 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 - self->st7789->set_pen(r, g, b, t); - } + self->st7789->set_palette( + mp_obj_get_int(index) & 0xff, + mp_obj_get_int(colour) & 0xffff + ); return mp_const_none; } mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_r, ARG_g, ARG_b, ARG_truncate }; + enum { ARG_self, ARG_r, ARG_g, ARG_b }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_truncate, MP_ARG_OBJ, { .u_obj = mp_const_true } }, + { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT } }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -304,21 +285,17 @@ mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_ma GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); - int r = args[ARG_r].u_int; - int g = args[ARG_g].u_int; - int b = args[ARG_b].u_int; - bool t = args[ARG_truncate].u_obj == mp_const_true; + int result = self->st7789->create_pen( + args[ARG_r].u_int & 0xff, + args[ARG_g].u_int & 0xff, + args[ARG_b].u_int & 0xff + ); - 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 - return mp_obj_new_int(self->st7789->create_pen(r, g, b, t)); + if (result == -1) { + mp_raise_ValueError("create_pen failed. No space in palette!"); + } - return mp_const_none; + return mp_obj_new_int(result); } mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -361,24 +338,13 @@ mp_obj_t GenericST7789_clear(mp_obj_t self_in) { return mp_const_none; } -mp_obj_t GenericST7789_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, - }; +mp_obj_t GenericST7789_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y) { + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - - Point p(x, y); - self->st7789->pixel(p); + self->st7789->pixel(Point( + mp_obj_get_int(x), + mp_obj_get_int(y) + )); return mp_const_none; } @@ -499,21 +465,19 @@ mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); mp_obj_t text_obj = args[ARG_text].u_obj; - if(mp_obj_is_str_or_bytes(text_obj)) { - GET_STR_DATA_LEN(text_obj, str, str_len); - std::string t((const char*)str); + if(!mp_obj_is_str_or_bytes(text_obj)) mp_raise_TypeError("text: string required"); - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int wrap = args[ARG_wrap].u_int; - int scale = args[ARG_scale].u_int; + GET_STR_DATA_LEN(text_obj, str, str_len); - self->st7789->text(t, Point(x, y), wrap, scale); - } - else { - mp_raise_TypeError("text: string required"); - } + std::string t((const char*)str); + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + int wrap = args[ARG_wrap].u_int; + int scale = args[ARG_scale].u_int; + + self->st7789->text(t, Point(x, y), wrap, scale); return mp_const_none; } @@ -532,20 +496,18 @@ mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_ GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); mp_obj_t text_obj = args[ARG_text].u_obj; - if(mp_obj_is_str_or_bytes(text_obj)) { - GET_STR_DATA_LEN(text_obj, str, str_len); - std::string t((const char*)str); + if(!mp_obj_is_str_or_bytes(text_obj)) mp_raise_TypeError("text: string required"); - int scale = args[ARG_scale].u_int; + GET_STR_DATA_LEN(text_obj, str, str_len); - int width = self->st7789->measure_text(t, scale); + std::string t((const char*)str); - return mp_obj_new_int(width); - } - else { - mp_raise_TypeError("text: string required"); - } + int scale = args[ARG_scale].u_int; + + int width = self->st7789->measure_text(t, scale); + + return mp_obj_new_int(width); return mp_const_none; } diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h index 39a467ef..97ea6e9a 100644 --- a/micropython/modules/st7789/st7789.h +++ b/micropython/modules/st7789/st7789.h @@ -1,26 +1,35 @@ -// Include MicroPython API. #include "py/runtime.h" #include "py/objstr.h" -/***** Extern of Class Definition *****/ +// Type extern const mp_obj_type_t GenericST7789_type; -/***** Extern of Class Methods *****/ +// Module functions +extern mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b); +extern mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); + +// Class methods extern void GenericST7789_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); extern mp_obj_t GenericST7789_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 GenericST7789Parallel_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 GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); extern mp_obj_t GenericST7789_update(mp_obj_t self_in); -extern mp_obj_t GenericST7789_flush_palette(mp_obj_t self_in); -extern mp_obj_t GenericST7789_default_palette(mp_obj_t self_in); -extern mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness); -extern mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +// Palette management +extern mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode); +extern mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t colour); + +// Pen +extern mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen); extern mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +// Primitives extern mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_remove_clip(mp_obj_t self_in); extern mp_obj_t GenericST7789_clear(mp_obj_t self_in); -extern mp_obj_t GenericST7789_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t GenericST7789_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y); extern mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); From a483b2aad40b8017f80db8dc0fa4cfda2fa857cc Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 01:00:56 +0100 Subject: [PATCH 10/84] ST7789/PicoGraphics: Refactor for init & rotation. --- common/pimoroni_bus.cmake | 11 + common/pimoroni_bus.cpp | 15 ++ common/pimoroni_bus.hpp | 26 ++ common/pimoroni_common.hpp | 7 + drivers/st7789/st7789.cmake | 2 +- drivers/st7789/st7789.cpp | 60 ++--- drivers/st7789/st7789.hpp | 90 +++---- libraries/generic_st7789/generic_st7789.cmake | 2 +- libraries/generic_st7789/generic_st7789.cpp | 32 --- libraries/generic_st7789/generic_st7789.hpp | 49 ++-- libraries/pico_graphics/pico_graphics.hpp | 7 + .../{demo.py => colourlcd240x240_demo.py} | 11 +- .../modules/pimoroni_bus/micropython.cmake | 19 ++ micropython/modules/st7789/st7789.c | 22 +- micropython/modules/st7789/st7789.cpp | 224 +++++++++++------- micropython/modules/st7789/st7789.h | 9 +- 16 files changed, 324 insertions(+), 262 deletions(-) create mode 100644 common/pimoroni_bus.cmake create mode 100644 common/pimoroni_bus.cpp create mode 100644 common/pimoroni_bus.hpp rename micropython/examples/breakout_colourlcd240x240/{demo.py => colourlcd240x240_demo.py} (80%) create mode 100644 micropython/modules/pimoroni_bus/micropython.cmake diff --git a/common/pimoroni_bus.cmake b/common/pimoroni_bus.cmake new file mode 100644 index 00000000..fb24b56e --- /dev/null +++ b/common/pimoroni_bus.cmake @@ -0,0 +1,11 @@ +set(LIB_NAME pimoroni_bus) +add_library(${LIB_NAME} INTERFACE) + +target_sources(${LIB_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +) + +target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_spi) diff --git a/common/pimoroni_bus.cpp b/common/pimoroni_bus.cpp new file mode 100644 index 00000000..794ba973 --- /dev/null +++ b/common/pimoroni_bus.cpp @@ -0,0 +1,15 @@ +#include "pimoroni_bus.hpp" + +namespace pimoroni { + SPIPins get_spi_pins(BG_SPI_SLOT slot) { + switch(slot) { + case PICO_EXPLORER_ONBOARD: + return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, PIN_UNUSED}; + case BG_SPI_FRONT: + return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, SPI_BG_FRONT_PWM}; + case BG_SPI_BACK: + return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_BACK_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, SPI_BG_BACK_PWM}; + } + return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, SPI_BG_FRONT_PWM}; + }; +} \ No newline at end of file diff --git a/common/pimoroni_bus.hpp b/common/pimoroni_bus.hpp new file mode 100644 index 00000000..eafecc19 --- /dev/null +++ b/common/pimoroni_bus.hpp @@ -0,0 +1,26 @@ +#pragma once +#include "pimoroni_common.hpp" +#include "hardware/gpio.h" +#include "hardware/spi.h" + +namespace pimoroni { + struct SPIPins { + spi_inst_t *spi; + uint cs; + uint sck; + uint mosi; + uint miso; + uint bl; + }; + + struct ParallelPins { + uint cs; + uint dc; + uint wr_sck; + uint rd_sck; + uint d0; + uint bl; + }; + + SPIPins get_spi_pins(BG_SPI_SLOT slot); +} \ No newline at end of file diff --git a/common/pimoroni_common.hpp b/common/pimoroni_common.hpp index 03b64f1f..90c949b2 100644 --- a/common/pimoroni_common.hpp +++ b/common/pimoroni_common.hpp @@ -53,6 +53,13 @@ namespace pimoroni { INTERSTATE_75, SERVO_2040 }; + + enum Rotation { + ROTATE_0 = 0, + ROTATE_90 = 90, + ROTATE_180 = 180, + ROTATE_270 = 270 + }; enum Polarity { ACTIVE_LOW = 0, diff --git a/drivers/st7789/st7789.cmake b/drivers/st7789/st7789.cmake index 5dbf4c8b..80420fef 100644 --- a/drivers/st7789/st7789.cmake +++ b/drivers/st7789/st7789.cmake @@ -9,4 +9,4 @@ target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) target_include_directories(st7789 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma) +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 089f1cd4..32068544 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -70,8 +70,7 @@ namespace pimoroni { command(reg::GMCTRN1, 14, "\xD0\x04\x0C\x11\x13\x2C\x3F\x44\x51\x2F\x1F\x1F\x20\x23"); } - if((width == 320 && height == 240) - || (width == 240 && height == 320)) { + if(width == 320 && height == 240) { command(reg::GCTRL, 1, "\x35"); command(reg::VCOMS, 1, "\x1f"); command(0xd6, 1, "\xa1"); // ??? @@ -85,7 +84,7 @@ namespace pimoroni { sleep_ms(100); - configure_display(false); + configure_display(rotation); if(bl != PIN_UNUSED) { //update(); // Send the new buffer to the display to clear any previous content @@ -94,9 +93,15 @@ namespace pimoroni { } } - void ST7789::configure_display(bool rotate180) { + void ST7789::configure_display(Rotation rotate) { + + bool rotate180 = rotate == ROTATE_180 || rotate == ROTATE_90; + + if(rotate == ROTATE_90 || rotate == ROTATE_270) { + std::swap(width, height); + } + // 240x240 Square and Round LCD Breakouts - // TODO: How can we support 90 degree rotations here? if(width == 240 && height == 240) { caset[0] = 0; caset[1] = 239; @@ -108,6 +113,7 @@ namespace pimoroni { raset[1] = rotate180 ? 329 : 239; } madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0; + if (rotate == ROTATE_90) madctl |= MADCTL::SWAP_XY; madctl |= MADCTL::HORIZ_ORDER; } @@ -160,30 +166,6 @@ namespace pimoroni { command(reg::MADCTL, 1, (char *)&madctl); } - spi_inst_t* ST7789::get_spi() const { - return spi; - } - - uint ST7789::get_cs() const { - return cs; - } - - uint ST7789::get_dc() const { - return dc; - } - - uint ST7789::get_sck() const { - return wr_sck; - } - - uint ST7789::get_mosi() const { - return d0; - } - - uint ST7789::get_bl() const { - return bl; - } - void ST7789::write_blocking_parallel(const uint8_t *src, size_t len) { uint32_t mask = 0xff << d0; while(len--) { @@ -226,10 +208,21 @@ namespace pimoroni { // 8-bit framebuffer with palette conversion update void ST7789::update(uint16_t *palette) { - command(reg::RAMWR); + uint8_t command = reg::RAMWR; uint16_t row[width]; - gpio_put(dc, 1); // data mode + + gpio_put(dc, 0); // command mode + gpio_put(cs, 0); + + if(spi) { + spi_write_blocking(spi, &command, 1); + } else { + write_blocking_parallel(&command, 1); + } + + gpio_put(dc, 1); // data mode + for(auto y = 0u; y < height; y++) { for(auto x = 0u; x < width; x++) { auto i = y * width + x; @@ -242,6 +235,7 @@ namespace pimoroni { write_blocking_parallel((const uint8_t*)row, width * sizeof(uint16_t)); } } + gpio_put(cs, 1); } @@ -252,8 +246,4 @@ namespace pimoroni { uint16_t value = (uint16_t)(pow((float)(brightness) / 255.0f, gamma) * 65535.0f + 0.5f); pwm_set_gpio_level(bl, value); } - - void ST7789::flip(){ - configure_display(true); - } } diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index df15d747..1effcb41 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -3,22 +3,28 @@ #include "hardware/spi.h" #include "hardware/gpio.h" #include "hardware/pwm.h" -#include "../../common/pimoroni_common.hpp" +#include "common/pimoroni_common.hpp" +#include "common/pimoroni_bus.hpp" + +#include namespace pimoroni { class ST7789 { spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE; + + public: + // screen properties + uint16_t width; + uint16_t height; + Rotation rotation; + bool round; //-------------------------------------------------- // Variables //-------------------------------------------------- private: - // screen properties - uint16_t width; - uint16_t height; - bool round; // interface pins with our standard defaults where appropriate uint cs; @@ -35,22 +41,16 @@ namespace pimoroni { public: + // frame buffer where pixel data is stored void *frame_buffer; // Parallel init - ST7789(uint16_t width, uint16_t height, void *frame_buffer, - uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) : + ST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins pins) : spi(nullptr), - width(width), height(height), round(false), - cs(cs), dc(dc), wr_sck(wr_sck), rd_sck(rd_sck), d0(d0), bl(bl), frame_buffer(frame_buffer) { + width(width), height(height), rotation(rotation), round(false), + cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl), frame_buffer(frame_buffer) { - gpio_set_function(cs, GPIO_FUNC_SIO); - gpio_set_dir(cs, GPIO_OUT); - - gpio_set_function(dc, GPIO_FUNC_SIO); - gpio_set_dir(dc, GPIO_OUT); - gpio_set_function(wr_sck, GPIO_FUNC_SIO); gpio_set_dir(wr_sck, GPIO_OUT); @@ -68,22 +68,14 @@ namespace pimoroni { } // Serial init - ST7789(uint16_t width, uint16_t height, bool round, void *frame_buffer, - spi_inst_t *spi, - uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) : - spi(spi), - width(width), height(height), round(round), - cs(cs), dc(dc), wr_sck(sck), d0(mosi), bl(bl), frame_buffer(frame_buffer) { + ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins pins) : + spi(pins.spi), + width(width), height(height), rotation(rotation), round(round), + cs(pins.cs), dc(pins.miso), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl), frame_buffer(frame_buffer) { // configure spi interface and pins spi_init(spi, SPI_BAUD); - gpio_set_function(dc, GPIO_FUNC_SIO); - gpio_set_dir(dc, GPIO_OUT); - - gpio_set_function(cs, GPIO_FUNC_SIO); - gpio_set_dir(cs, GPIO_OUT); - gpio_set_function(wr_sck, GPIO_FUNC_SPI); gpio_set_function(d0, GPIO_FUNC_SPI); @@ -91,52 +83,26 @@ namespace pimoroni { } void init(); - void configure_display(bool rotate180); - - spi_inst_t* get_spi() const; - uint get_cs() const; - uint get_dc() const; - uint get_sck() const; - uint get_mosi() const; - uint get_bl() const; - void command(uint8_t command, size_t len = 0, const char *data = NULL); + void set_backlight(uint8_t brightness); + void update(); void update(uint16_t *palette); - void set_backlight(uint8_t brightness); - void flip(); - - static uint get_slot_cs(BG_SPI_SLOT slot) { - switch(slot) { - case PICO_EXPLORER_ONBOARD: - return SPI_BG_FRONT_CS; - case BG_SPI_FRONT: - return SPI_BG_FRONT_CS; - case BG_SPI_BACK: - return SPI_BG_BACK_CS; - } - return PIN_UNUSED; - }; - - static uint get_slot_bl(BG_SPI_SLOT slot) { - switch(slot) { - case PICO_EXPLORER_ONBOARD: - return PIN_UNUSED; - case BG_SPI_FRONT: - return SPI_BG_FRONT_PWM; - case BG_SPI_BACK: - return SPI_BG_BACK_PWM; - } - return PIN_UNUSED; - }; private: + void configure_display(Rotation rotate); void write_blocking_parallel(const uint8_t *src, size_t len); void common_init() { if(!this->frame_buffer) { this->frame_buffer = new uint8_t[width * height]; } + gpio_set_function(dc, GPIO_FUNC_SIO); + gpio_set_dir(dc, GPIO_OUT); + + gpio_set_function(cs, GPIO_FUNC_SIO); + gpio_set_dir(cs, GPIO_OUT); + // if a backlight pin is provided then set it up for // pwm control if(bl != PIN_UNUSED) { diff --git a/libraries/generic_st7789/generic_st7789.cmake b/libraries/generic_st7789/generic_st7789.cmake index f25f5797..25a98272 100644 --- a/libraries/generic_st7789/generic_st7789.cmake +++ b/libraries/generic_st7789/generic_st7789.cmake @@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma st7789 pico_graphics) \ No newline at end of file +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma pimoroni_bus st7789 pico_graphics) \ No newline at end of file diff --git a/libraries/generic_st7789/generic_st7789.cpp b/libraries/generic_st7789/generic_st7789.cpp index d0dc2d98..7bb09a4b 100644 --- a/libraries/generic_st7789/generic_st7789.cpp +++ b/libraries/generic_st7789/generic_st7789.cpp @@ -5,43 +5,11 @@ namespace pimoroni { - spi_inst_t* ST7789Generic::get_spi() const { - return st7789.get_spi(); - } - - int ST7789Generic::get_cs() const { - return st7789.get_cs(); - } - - int ST7789Generic::get_dc() const { - return st7789.get_dc(); - } - - int ST7789Generic::get_sck() const { - return st7789.get_sck(); - } - - int ST7789Generic::get_mosi() const { - return st7789.get_mosi(); - } - - int ST7789Generic::get_bl() const { - return st7789.get_bl(); - } - void ST7789Generic::update() { st7789.update(palette); } - void ST7789Generic::flip() { - st7789.configure_display(true); - } - void ST7789Generic::set_backlight(uint8_t brightness) { st7789.set_backlight(brightness); } - - void ST7789Generic::configure_display(bool rotate180) { - st7789.configure_display(rotate180); - } } diff --git a/libraries/generic_st7789/generic_st7789.hpp b/libraries/generic_st7789/generic_st7789.hpp index 3de609dd..857027bb 100644 --- a/libraries/generic_st7789/generic_st7789.hpp +++ b/libraries/generic_st7789/generic_st7789.hpp @@ -2,6 +2,7 @@ #include "drivers/st7789/st7789.hpp" #include "libraries/pico_graphics/pico_graphics.hpp" +#include "common/pimoroni_bus.hpp" namespace pimoroni { @@ -10,50 +11,32 @@ namespace pimoroni { ST7789 st7789; public: - ST7789Generic(uint16_t width, uint16_t height, bool round=false, void *frame_buffer=nullptr) : + ST7789Generic(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) : PicoGraphics(width, height, frame_buffer), - st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { - this->frame_buffer = (Pen *)st7789.frame_buffer; - this->st7789.init(); - this->st7789.update(palette); + st7789(width, height, rotation, round, frame_buffer, get_spi_pins(BG_SPI_FRONT)) { + common_init(); }; - ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer, BG_SPI_SLOT slot) : + ST7789Generic(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) : PicoGraphics(width, height, frame_buffer), - st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, st7789.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, st7789.get_slot_bl(slot)) { - this->frame_buffer = (Pen *)st7789.frame_buffer; - this->st7789.init(); - this->st7789.update(palette); + st7789(width, height, rotation, round, frame_buffer, bus_pins) { + common_init(); }; - ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer, - spi_inst_t *spi, - uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) : + ST7789Generic(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) : PicoGraphics(width, height, frame_buffer), - st7789(width, height, round, frame_buffer, spi, cs, dc, sck, mosi, bl) { - this->frame_buffer = (Pen *)st7789.frame_buffer; - this->st7789.init(); - this->st7789.update(palette); + st7789(width, height, rotation, frame_buffer, bus_pins) { + common_init(); }; - ST7789Generic(uint16_t width, uint16_t height, void *frame_buffer, - uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) : - PicoGraphics(width, height, frame_buffer), - st7789(width, height, frame_buffer, cs, dc, wr_sck, rd_sck, d0, bl) { - this->frame_buffer = (Pen *)st7789.frame_buffer; - this->st7789.init(); - this->st7789.update(palette); - }; - - spi_inst_t* get_spi() const; - int get_cs() const; - int get_dc() const; - int get_sck() const; - int get_mosi() const; - int get_bl() const; + void common_init() { + this->frame_buffer = (Pen *)st7789.frame_buffer; + this->st7789.init(); + this->set_dimensions(this->st7789.width, this->st7789.height); + this->st7789.update(palette); + } void update(); - [[deprecated("Use configure_display(true) instead.")]] void flip(); void set_backlight(uint8_t brightness); void configure_display(bool rotate180); void set_framebuffer(void* frame_buffer) { diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index dbda0324..f9fba09e 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -87,6 +87,13 @@ namespace pimoroni { return __builtin_bswap16(p); } + void set_dimensions(int width, int height) { + bounds.w = width; + bounds.h = height; + clip.w = width; + clip.h = height; + } + int create_pen(uint8_t r, uint8_t g, uint8_t b); void empty_palette(); diff --git a/micropython/examples/breakout_colourlcd240x240/demo.py b/micropython/examples/breakout_colourlcd240x240/colourlcd240x240_demo.py similarity index 80% rename from micropython/examples/breakout_colourlcd240x240/demo.py rename to micropython/examples/breakout_colourlcd240x240/colourlcd240x240_demo.py index 90ae788c..fcf64c4b 100644 --- a/micropython/examples/breakout_colourlcd240x240/demo.py +++ b/micropython/examples/breakout_colourlcd240x240/colourlcd240x240_demo.py @@ -1,11 +1,15 @@ import time import random -from st7789 import ST7789 +from st7789 import ST7789, PALETTE_USER WIDTH, HEIGHT = 240, 240 display = ST7789(WIDTH, HEIGHT, round=False) +# We're creating 100 balls with their own individual colour and 1 BG colour +# for a total of 101 colours, which will all fit in the 256 entry palette! +display.set_palette_mode(PALETTE_USER) + display.set_backlight(1.0) @@ -33,9 +37,11 @@ for i in range(0, 100): display.create_pen(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), ) ) + +BG = display.create_pen(40, 40, 40) while True: - display.set_pen(40, 40, 40) + display.set_pen(BG) display.clear() for ball in balls: @@ -58,3 +64,4 @@ while True: display.update() time.sleep(0.01) + diff --git a/micropython/modules/pimoroni_bus/micropython.cmake b/micropython/modules/pimoroni_bus/micropython.cmake new file mode 100644 index 00000000..c9eb1aba --- /dev/null +++ b/micropython/modules/pimoroni_bus/micropython.cmake @@ -0,0 +1,19 @@ +set(MOD_NAME pimoroni_bus) +string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) +add_library(usermod_${MOD_NAME} INTERFACE) + +target_sources(usermod_${MOD_NAME} INTERFACE + #${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + #${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../common/pimoroni_bus.cpp +) + +target_include_directories(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_${MOD_NAME} INTERFACE + MODULE_${MOD_NAME_UPPER}_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) \ No newline at end of file diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index 7881aad1..86092b31 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -32,6 +32,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_polygon_obj, 2, GenericST7789_polygon); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_triangle_obj, 1, GenericST7789_triangle); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_line_obj, 1, GenericST7789_line); +// Utility +MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_get_bounds_obj, GenericST7789_get_bounds); + STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&GenericST7789_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) }, @@ -55,6 +58,7 @@ STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&GenericST7789_triangle_obj) }, { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&GenericST7789_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_bounds), MP_ROM_PTR(&GenericST7789_get_bounds_obj) }, { MP_ROM_QSTR(MP_QSTR_set_framebuffer), MP_ROM_PTR(&GenericST7789_set_framebuffer_obj) }, }; STATIC MP_DEFINE_CONST_DICT(GenericST7789_locals_dict, GenericST7789_locals_dict_table); @@ -63,7 +67,6 @@ STATIC MP_DEFINE_CONST_DICT(GenericST7789_locals_dict, GenericST7789_locals_dict const mp_obj_type_t GenericST7789_type = { { &mp_type_type }, .name = MP_QSTR_st7789, - .print = GenericST7789_print, .make_new = GenericST7789_make_new, .locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict, }; @@ -71,22 +74,37 @@ const mp_obj_type_t GenericST7789_type = { const mp_obj_type_t GenericST7789Parallel_type = { { &mp_type_type }, .name = MP_QSTR_st7789, - .print = GenericST7789_print, .make_new = GenericST7789Parallel_make_new, .locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict, }; +const mp_obj_type_t GenericST7789SPI_type = { + { &mp_type_type }, + .name = MP_QSTR_st7789, + .make_new = GenericST7789SPI_make_new, + .locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict, +}; + /***** Module Globals *****/ STATIC const mp_map_elem_t st7789_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) }, { MP_ROM_QSTR(MP_QSTR_ST7789), (mp_obj_t)&GenericST7789_type }, { MP_ROM_QSTR(MP_QSTR_ST7789Parallel), (mp_obj_t)&GenericST7789Parallel_type }, + { MP_ROM_QSTR(MP_QSTR_ST7789SPI), (mp_obj_t)&GenericST7789Parallel_type }, { MP_ROM_QSTR(MP_QSTR_RGB332), MP_ROM_PTR(&GenericST7789_module_RGB332_obj) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&GenericST7789_module_RGB565_obj) }, { MP_ROM_QSTR(MP_QSTR_PALETTE_RGB332), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_PALETTE_USER), MP_ROM_INT(1) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_240X240), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_ROUND_LCD_240X240), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY_2), MP_ROM_INT(3) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_EXPLORER), MP_ROM_INT(4) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_TUFTY_2040), MP_ROM_INT(5) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_ENVIRO_PLUS), MP_ROM_INT(6) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_st7789_globals, st7789_globals_table); diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 43430009..9042de7e 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -1,4 +1,6 @@ #include "libraries/generic_st7789/generic_st7789.hpp" +#include "common/pimoroni_common.hpp" +#include "common/pimoroni_bus.hpp" #include "micropython/modules/util.hpp" @@ -9,57 +11,101 @@ using namespace pimoroni; extern "C" { #include "st7789.h" -/***** Variables Struct *****/ +enum ST7789Display { + DISPLAY_LCD_240X240=0, + DISPLAY_ROUND_LCD_240X240, + DISPLAY_PICO_DISPLAY, + DISPLAY_PICO_DISPLAY_2, + DISPLAY_PICO_EXPLORER, + DISPLAY_TUFTY_2040, + DISPLAY_ENVIRO_PLUS +}; + typedef struct _GenericST7789_obj_t { mp_obj_base_t base; ST7789Generic *st7789; - bool parallel; void *buffer; } GenericST7789_obj_t; -/***** Print *****/ -void GenericST7789_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - (void)kind; //Unused input parameter - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - - if(self->parallel) { - mp_print_str(print, "ST7789Parallel()"); - } else { - mp_print_str(print, "ST7789("); - - mp_print_str(print, "spi = "); - mp_obj_print_helper(print, mp_obj_new_int((self->st7789->get_spi() == spi0) ? 0 : 1), PRINT_REPR); - - mp_print_str(print, ", cs = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_cs()), PRINT_REPR); - - mp_print_str(print, ", dc = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_dc()), PRINT_REPR); - - mp_print_str(print, ", sck = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_sck()), PRINT_REPR); - - mp_print_str(print, ", mosi = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_mosi()), PRINT_REPR); - - mp_print_str(print, ", bl = "); - mp_obj_print_helper(print, mp_obj_new_int(self->st7789->get_bl()), PRINT_REPR); - - mp_print_str(print, ")"); - } -} - -/***** Constructor *****/ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { GenericST7789_obj_t *self = nullptr; - enum { ARG_width, ARG_height, ARG_round, ARG_rotate180, ARG_slot, ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; + enum { ARG_display, ARG_rotate, ARG_slot, ARG_buffer }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_display, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_rotate, MP_ARG_INT, { .u_int = Rotation::ROTATE_0 } }, + { MP_QSTR_slot, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + self = m_new_obj(GenericST7789_obj_t); + self->base.type = &GenericST7789_type; + + Rotation rotate = (Rotation)args[ARG_rotate].u_int; + bool round = false; + int width = 0; + int height = 0; + + ST7789Display display = (ST7789Display)args[ARG_display].u_int; + + switch(display) { + case DISPLAY_PICO_DISPLAY: + width = 240; + height = 135; + break; + case DISPLAY_PICO_DISPLAY_2: + case DISPLAY_TUFTY_2040: + width = 320; + height = 240; + break; + case DISPLAY_PICO_EXPLORER: + case DISPLAY_LCD_240X240: + case DISPLAY_ENVIRO_PLUS: + width = 240; + height = 240; + break; + case DISPLAY_ROUND_LCD_240X240: + width = 240; + height = 240; + round = true; + break; + } + + if (args[ARG_buffer].u_obj != mp_const_none) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); + self->buffer = bufinfo.buf; + if(bufinfo.len < (size_t)(width * height * sizeof(Pen))) { + mp_raise_ValueError("Supplied buffer is too small!"); + } + } else { + self->buffer = m_new(uint8_t, width * height * sizeof(Pen)); + } + + + if (display == DISPLAY_TUFTY_2040) { + self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); + } else { + BG_SPI_SLOT slot = (BG_SPI_SLOT)args[ARG_slot].u_int; + self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, get_spi_pins(slot)); + } + + return MP_OBJ_FROM_PTR(self); +} + +mp_obj_t GenericST7789SPI_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + GenericST7789_obj_t *self = nullptr; + + enum { ARG_width, ARG_height, ARG_rotate, ARG_round, ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; static const mp_arg_t allowed_args[] = { { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_rotate, MP_ARG_INT, {.u_int = Rotation::ROTATE_0} }, { MP_QSTR_round, MP_ARG_OBJ, {.u_obj = mp_const_false} }, - { MP_QSTR_rotate180, MP_ARG_OBJ, {.u_obj = mp_const_false} }, - { MP_QSTR_slot, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_spi, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_cs, MP_ARG_INT, {.u_int = pimoroni::SPI_BG_FRONT_CS} }, @@ -75,10 +121,9 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t self = m_new_obj(GenericST7789_obj_t); self->base.type = &GenericST7789_type; - self->parallel = false; - bool rotate180 = args[ARG_rotate180].u_obj == mp_const_true; bool round = args[ARG_round].u_obj == mp_const_true; + Rotation rotate = (Rotation)args[ARG_rotate].u_int; int width = args[ARG_width].u_int; int height = args[ARG_height].u_int; @@ -93,50 +138,42 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t self->buffer = m_new(uint8_t, width * height * sizeof(Pen)); } - if(args[ARG_slot].u_int != -1) { - BG_SPI_SLOT slot = (BG_SPI_SLOT)args[ARG_slot].u_int; - self->st7789 = m_new_class(ST7789Generic, width, height, round, self->buffer, slot); - if (rotate180) { - self->st7789->configure_display(true); - } - } else { - // Get SPI bus. - int spi_id = args[ARG_spi].u_int; - int sck = args[ARG_sck].u_int; - int mosi = args[ARG_mosi].u_int; - int dc = args[ARG_dc].u_int; - int cs = args[ARG_cs].u_int; - int bl = args[ARG_bl].u_int; + int spi_id = args[ARG_spi].u_int; - if(spi_id == -1) { - spi_id = (sck >> 3) & 0b1; // If no spi specified, choose the one for the given SCK pin - } - if(spi_id < 0 || spi_id > 1) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id); - } + // Get SPI bus. + SPIPins bus_pins = { + nullptr, + (uint)args[ARG_cs].u_int, + (uint)args[ARG_sck].u_int, + (uint)args[ARG_mosi].u_int, + (uint)args[ARG_dc].u_int, + args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int + }; - if(!IS_VALID_SCK(spi_id, sck)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin")); - } - - if(!IS_VALID_MOSI(spi_id, mosi)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin")); - } - spi_inst_t *spi = (spi_id == 0) ? spi0 : spi1; - self->st7789 = m_new_class(ST7789Generic, width, height, round, self->buffer, - spi, cs, dc, sck, mosi, bl); - if (rotate180) { - self->st7789->configure_display(true); - } + if(spi_id == -1) { + spi_id = (bus_pins.sck >> 3) & 0b1; // If no spi specified, choose the one for the given SCK pin } + if(spi_id < 0 || spi_id > 1) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id); + } + + if(!IS_VALID_SCK(spi_id, (int)bus_pins.sck)) { + mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin")); + } + + if(!IS_VALID_MOSI(spi_id, (int)bus_pins.mosi)) { + mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin")); + } + + bus_pins.spi = (spi_id == 0) ? spi0 : spi1; + + self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, bus_pins); return MP_OBJ_FROM_PTR(self); } mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - GenericST7789_obj_t *self = nullptr; - - enum { ARG_width, ARG_height, ARG_cs, ARG_dc, ARG_wr_sck, ARG_rd_sck, ARG_d0, ARG_bl, ARG_rotate180, ARG_buffer }; + enum { ARG_width, ARG_height, ARG_cs, ARG_dc, ARG_wr_sck, ARG_rd_sck, ARG_d0, ARG_bl, ARG_rotate, ARG_buffer }; static const mp_arg_t allowed_args[] = { { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, @@ -147,7 +184,7 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args { MP_QSTR_d0, MP_ARG_INT, {.u_int = 14} }, { MP_QSTR_bl, MP_ARG_INT, {.u_int = 2} }, - { MP_QSTR_rotate180, MP_ARG_OBJ, {.u_obj = mp_const_false} }, + { MP_QSTR_rotate, MP_ARG_INT, {.u_int = Rotation::ROTATE_0} }, { MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; @@ -155,11 +192,10 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - self = m_new_obj(GenericST7789_obj_t); + GenericST7789_obj_t *self = m_new_obj(GenericST7789_obj_t); self->base.type = &GenericST7789_type; - self->parallel = true; - bool rotate180 = args[ARG_rotate180].u_obj == mp_const_true; + Rotation rotate = (Rotation)args[ARG_rotate].u_int; int width = args[ARG_width].u_int; int height = args[ARG_height].u_int; @@ -174,18 +210,16 @@ mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args self->buffer = m_new(uint8_t, width * height); } - int cs = args[ARG_cs].u_int; - int dc = args[ARG_dc].u_int; - int wr_sck = args[ARG_wr_sck].u_int; - int rd_sck = args[ARG_rd_sck].u_int; - int d0 = args[ARG_d0].u_int; - int bl = args[ARG_bl].u_int; + ParallelPins bus_pins = { + (uint)args[ARG_cs].u_int, + (uint)args[ARG_dc].u_int, + (uint)args[ARG_wr_sck].u_int, + (uint)args[ARG_rd_sck].u_int, + (uint)args[ARG_d0].u_int, + args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int + }; - self->st7789 = m_new_class(ST7789Generic, width, height, self->buffer, - cs, dc, wr_sck, rd_sck, d0, bl); - if (rotate180) { - self->st7789->configure_display(true); - } + self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, bus_pins); return MP_OBJ_FROM_PTR(self); } @@ -208,6 +242,14 @@ mp_obj_t GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) { return mp_const_none; } +mp_obj_t GenericST7789_get_bounds(mp_obj_t self_in) { + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_int(self->st7789->bounds.w); + tuple[1] = mp_obj_new_int(self->st7789->bounds.h); + return mp_obj_new_tuple(2, tuple); +} + mp_obj_t GenericST7789_update(mp_obj_t self_in) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); self->st7789->update(); diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h index 97ea6e9a..ab1fc771 100644 --- a/micropython/modules/st7789/st7789.h +++ b/micropython/modules/st7789/st7789.h @@ -9,10 +9,9 @@ extern mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b); extern mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); // Class methods -extern void GenericST7789_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); extern mp_obj_t GenericST7789_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 GenericST7789SPI_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 GenericST7789Parallel_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 GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); extern mp_obj_t GenericST7789_update(mp_obj_t self_in); extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness); @@ -38,4 +37,8 @@ extern mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_m extern mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); \ No newline at end of file +extern mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +// Utility +extern mp_obj_t GenericST7789_get_bounds(mp_obj_t self_in); +extern mp_obj_t GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); \ No newline at end of file From 844a5af384c4779c9c2b72cea70232dd50592654 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 01:19:58 +0100 Subject: [PATCH 11/84] ST7789/PicoGraphics: Update some examples. --- .../colourlcd240x240_demo.py | 9 +++---- .../examples/pico_display/basic_qrcode.py | 24 ++++++++++-------- micropython/examples/pico_display/buttons.py | 7 ++---- micropython/examples/pico_display/demo.py | 6 ++--- micropython/examples/pico_display/rainbow.py | 19 ++++++++------ .../examples/pico_display/thermometer.py | 25 +++++++++++-------- 6 files changed, 46 insertions(+), 44 deletions(-) diff --git a/micropython/examples/breakout_colourlcd240x240/colourlcd240x240_demo.py b/micropython/examples/breakout_colourlcd240x240/colourlcd240x240_demo.py index fcf64c4b..b614cef9 100644 --- a/micropython/examples/breakout_colourlcd240x240/colourlcd240x240_demo.py +++ b/micropython/examples/breakout_colourlcd240x240/colourlcd240x240_demo.py @@ -1,10 +1,10 @@ import time import random -from st7789 import ST7789, PALETTE_USER +from st7789 import ST7789, PALETTE_USER, DISPLAY_LCD_240X240 -WIDTH, HEIGHT = 240, 240 +display = ST7789(DISPLAY_LCD_240X240, rotate=0) -display = ST7789(WIDTH, HEIGHT, round=False) +WIDTH, HEIGHT = display.get_bounds() # We're creating 100 balls with their own individual colour and 1 BG colour # for a total of 101 colours, which will all fit in the 256 entry palette! @@ -37,7 +37,7 @@ for i in range(0, 100): display.create_pen(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), ) ) - + BG = display.create_pen(40, 40, 40) while True: @@ -64,4 +64,3 @@ while True: display.update() time.sleep(0.01) - diff --git a/micropython/examples/pico_display/basic_qrcode.py b/micropython/examples/pico_display/basic_qrcode.py index 6ca46727..a689b764 100644 --- a/micropython/examples/pico_display/basic_qrcode.py +++ b/micropython/examples/pico_display/basic_qrcode.py @@ -1,12 +1,12 @@ import st7789 import qrcode -# Set the display resolution -# in most cases you can swap WIDTH weith HEIGHT for portrait mode -WIDTH, HEIGHT = 240, 135 # Pico Display -# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0 +display = st7789.ST7789(st7789.DISPLAY_PICO_DISPLAY, rotate=0) -display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False) +WIDTH, HEIGHT = display.get_bounds() + +BG = display.create_pen(0, 0, 0) +FG = display.create_pen(128, 128, 128) def measure_qr_code(size, code): @@ -17,9 +17,9 @@ def measure_qr_code(size, code): def draw_qr_code(ox, oy, size, code): size, module_size = measure_qr_code(size, code) - display.set_pen(128, 128, 128) + display.set_pen(FG) display.rectangle(ox, oy, size, size) - display.set_pen(0, 0, 0) + display.set_pen(BG) for x in range(size): for y in range(size): if code.get_module(x, y): @@ -29,14 +29,16 @@ def draw_qr_code(ox, oy, size, code): code = qrcode.QRCode() code.set_text("shop.pimoroni.com") -display.set_pen(128, 128, 128) +display.set_pen(FG) display.clear() -display.set_pen(0, 0, 0) +display.set_pen(BG) -size, module_size = measure_qr_code(HEIGHT, code) +max_size = min(WIDTH, HEIGHT) + +size, module_size = measure_qr_code(max_size, code) left = int((WIDTH // 2) - (size // 2)) top = int((HEIGHT // 2) - (size // 2)) -draw_qr_code(left, top, HEIGHT, code) +draw_qr_code(left, top, max_size, code) display.update() diff --git a/micropython/examples/pico_display/buttons.py b/micropython/examples/pico_display/buttons.py index 874ade1c..0d350f8d 100644 --- a/micropython/examples/pico_display/buttons.py +++ b/micropython/examples/pico_display/buttons.py @@ -4,14 +4,11 @@ import st7789 import utime from pimoroni import Button -# Set the display resolution -# in most cases you can swap WIDTH weith HEIGHT for portrait mode -WIDTH, HEIGHT = 240, 135 # Pico Display -# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0 -display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False) +display = st7789.ST7789(st7789.DISPLAY_PICO_DISPLAY, rotate=0) display.set_backlight(0.5) +WIDTH, HEIGHT = display.get_bounds() button_a = Button(12) button_b = Button(13) diff --git a/micropython/examples/pico_display/demo.py b/micropython/examples/pico_display/demo.py index d240c08e..305e5d4b 100644 --- a/micropython/examples/pico_display/demo.py +++ b/micropython/examples/pico_display/demo.py @@ -2,11 +2,9 @@ import time import random import st7789 -# Set the display resolution, in most cases you can flip these for portrait mode -WIDTH, HEIGHT = 240, 135 # Pico Display -# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0 +display = st7789.ST7789(st7789.DISPLAY_PICO_DISPLAY, rotate=0) -display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False) +WIDTH, HEIGHT = display.get_bounds() display.set_backlight(1.0) diff --git a/micropython/examples/pico_display/rainbow.py b/micropython/examples/pico_display/rainbow.py index 9cb1ee1b..25e45a29 100644 --- a/micropython/examples/pico_display/rainbow.py +++ b/micropython/examples/pico_display/rainbow.py @@ -4,13 +4,11 @@ import utime import st7789 from pimoroni import RGBLED -# Set the display resolution -# in most cases you can swap WIDTH weith HEIGHT for portrait mode -WIDTH, HEIGHT = 240, 135 # Pico Display -# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0 - -display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False) +display = st7789.ST7789(st7789.DISPLAY_PICO_DISPLAY, rotate=0) display.set_backlight(0.8) +display.set_palette_mode(st7789.PALETTE_USER) + +WIDTH, HEIGHT = display.get_bounds() led = RGBLED(6, 7, 8) @@ -41,13 +39,18 @@ def hsv_to_rgb(h, s, v): h = 0 +BLACK = display.create_pen(0, 0, 0) +RAINBOW = BLACK + 1 # Put RAINBOW right after BLACK in the palette + + while True: h += 1 r, g, b = [int(255 * c) for c in hsv_to_rgb(h / 360.0, 1.0, 1.0)] # rainbow magic led.set_rgb(r, g, b) # Set LED to a converted HSV value - display.set_pen(r, g, b) # Set pen to a converted HSV value + display.set_palette(RAINBOW, st7789.RGB565(r, g, b)) # Create pen with converted HSV value + display.set_pen(RAINBOW) # Set pen display.clear() # Fill the screen with the colour - display.set_pen(0, 0, 0) # Set pen to black + display.set_pen(BLACK) # Set pen to black display.text("pico disco!", 10, 10, 240, 6) # Add some text display.update() # Update the display utime.sleep(1.0 / 60) diff --git a/micropython/examples/pico_display/thermometer.py b/micropython/examples/pico_display/thermometer.py index cd07b565..ea680779 100644 --- a/micropython/examples/pico_display/thermometer.py +++ b/micropython/examples/pico_display/thermometer.py @@ -7,16 +7,18 @@ import utime import st7789 from pimoroni import RGBLED -# Set the display resolution -# in most cases you can swap WIDTH weith HEIGHT for portrait mode -WIDTH, HEIGHT = 135, 240 # Pico Display -# WIDTH, HEIGHT = 320, 240 # Pico Display 2.0 - -display = st7789.ST7789(WIDTH, HEIGHT, rotate180=False) +display = st7789.ST7789(st7789.DISPLAY_PICO_DISPLAY, rotate=0) +display.set_palette_mode(st7789.PALETTE_USER) # Set the display backlight to 50% display.set_backlight(0.5) +WIDTH, HEIGHT = display.get_bounds() + +BLACK = display.create_pen(0, 0, 0) +WHITE = display.create_pen(255, 255, 255) +TEMPERATURE = WHITE + 1 + led = RGBLED(6, 7, 8) # reads from Pico's temp sensor and converts it into a more manageable number @@ -53,7 +55,7 @@ def temperature_to_color(temp): while True: # fills the screen with black - display.set_pen(0, 0, 0) + display.set_pen(BLACK) display.clear() # the following two lines do some maths to convert the number from the temp sensor into celsius @@ -68,8 +70,9 @@ while True: i = 0 for t in temperatures: - # chooses a pen colour based on the temperature - display.set_pen(*temperature_to_color(t)) + # chooses a pen colour based on the temperature and update the palette entry + display.set_palette(TEMPERATURE, st7789.RGB565(*temperature_to_color(t))) + display.set_pen(TEMPERATURE) # draws the reading as a tall, thin rectangle display.rectangle(i, HEIGHT - (round(t) * 4), bar_width, HEIGHT) @@ -82,11 +85,11 @@ while True: led.set_rgb(*temperature_to_color(temperature)) # draws a white background for the text - display.set_pen(255, 255, 255) + display.set_pen(WHITE) display.rectangle(1, 1, 100, 25) # writes the reading as text in the white rectangle - display.set_pen(0, 0, 0) + display.set_pen(BLACK) display.text("{:.2f}".format(temperature) + "c", 3, 3, 0, 3) # time to update the display From dbd716f78fd4c06e5e3f28bfd596d728aff12ea5 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 18:08:07 +0100 Subject: [PATCH 12/84] Add Buzzer to Pimoroni module --- micropython/modules_py/pimoroni.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/micropython/modules_py/pimoroni.py b/micropython/modules_py/pimoroni.py index a92919da..75074f16 100644 --- a/micropython/modules_py/pimoroni.py +++ b/micropython/modules_py/pimoroni.py @@ -136,6 +136,10 @@ class Button: else: return self.pin.value() + @property + def is_pressed(self): + return self.raw() + class RGBLED: def __init__(self, r, g, b, invert=True): @@ -178,3 +182,17 @@ class PID: self._last_value = value return (error * self.kp) + (self._error_sum * self.ki) - (rate_error * self.kd) + + +class Buzzer: + def __init__(self, pin): + self.pwm = PWM(Pin(pin)) + + def set_tone(self, hz): + if hz is None or hz <= 8: # None or <=8 to stop + self.pwm.duty_u16(0) + return False + + self.pwm.freq(hz) + self.pwm.duty_u16(1 << 15) + return True \ No newline at end of file From c13f53092d485f702dc461f41db49651c36594d2 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 18:08:47 +0100 Subject: [PATCH 13/84] ST7789/PicoGraphics: Fix palette bugs, add reserve. --- libraries/pico_graphics/pico_graphics.cpp | 30 ++++++++++++++++------- libraries/pico_graphics/pico_graphics.hpp | 10 ++++++-- micropython/modules/st7789/st7789.c | 2 ++ micropython/modules/st7789/st7789.cpp | 14 ++++++++++- micropython/modules/st7789/st7789.h | 1 + 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 62dd91a2..340e42ab 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -37,16 +37,16 @@ namespace pimoroni { int PicoGraphics::search_palette(RGB565 c) { for(auto i = 0u; i < 256; i++) { - if(palette_status[i] && palette[i] == c) return i; + if((palette_status[i] & PaletteStatusUsed) && palette[i] == c) return i; } return -1; } int PicoGraphics::put_palette(RGB565 c) { for(auto i = 0u; i < 256; i++) { - if(!palette_status[i]) { + if(!(palette_status[i] & (PaletteStatusUsed | PaletteStatusReserved))) { palette[i] = c; - palette_status[i] = true; + palette_status[i] = PaletteStatusUsed; return i; } } @@ -55,21 +55,33 @@ namespace pimoroni { void PicoGraphics::set_palette(uint8_t i, uint16_t c) { palette[i] = c; - palette_status[i] = true; + palette_status[i] |= PaletteStatusUsed; } - void PicoGraphics::empty_palette() { - for (auto i = 0u; i < 255; i++) { + int PicoGraphics::reserve_palette() { + for (auto i = 0u; i < 256; i++) { + if (!palette_status[i]) { + palette_status[i] = PaletteStatusReserved; + return i; + } + } + return -1; + } + + void PicoGraphics::empty_palette() { + for (auto i = 0u; i < 256; i++) { palette[i] = 0; - palette_status[i] = false; + palette_status[i] = 0; } } void PicoGraphics::rgb332_palette() { - for (auto i = 0u; i < 255; i++) { + for (auto i = 0u; i < 256; i++) { + // Convert the implicit RGB332 (i) into RGB565 + // 0b11100 000 0b00011100 0b00000011 palette[i] = ((i & 0b11100000) << 8) | ((i & 0b00011100) << 6) | ((i & 0b00000011) << 3); palette[i] = __builtin_bswap16(palette[i]); - palette_status[i] = true; + palette_status[i] = PaletteStatusUsed; } } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index f9fba09e..de051668 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -55,14 +55,19 @@ namespace pimoroni { const bitmap::font_t *font; - uint16_t palette[256]; - bool palette_status[256]; + RGB565 palette[256]; + uint8_t palette_status[256]; enum PaletteMode { PaletteModeRGB332 = 0, PaletteModeUSER = 1 }; + enum PaletteStatus : uint8_t { + PaletteStatusReserved = 1, + PaletteStatusUsed = 2 + }; + PaletteMode palette_mode = PaletteModeRGB332; public: @@ -96,6 +101,7 @@ namespace pimoroni { int create_pen(uint8_t r, uint8_t g, uint8_t b); + int reserve_palette(); void empty_palette(); void rgb332_palette(); diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index 86092b31..bdfff890 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -12,6 +12,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_framebuffer_obj, GenericST7789_set_f // Palette management MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_palette_mode_obj, GenericST7789_set_palette_mode); MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_set_palette_obj, GenericST7789_set_palette); +MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_reserve_palette_obj, GenericST7789_reserve_palette); // Pen MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_pen_obj, GenericST7789_set_pen); @@ -42,6 +43,7 @@ STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_palette_mode), MP_ROM_PTR(&GenericST7789_set_palette_mode_obj) }, { MP_ROM_QSTR(MP_QSTR_set_palette), MP_ROM_PTR(&GenericST7789_set_palette_obj) }, + { MP_ROM_QSTR(MP_QSTR_reserve_palette), MP_ROM_PTR(&GenericST7789_reserve_palette_obj) }, { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) }, diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 9042de7e..25dcaa8b 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -313,6 +313,18 @@ mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t co return mp_const_none; } +mp_obj_t GenericST7789_reserve_palette(mp_obj_t self_in) { + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); + + int result = self->st7789->reserve_palette(); + + if (result == -1) { + mp_raise_ValueError("reserve_palette failed. No space in palette!"); + } + + return mp_obj_new_int(result); +} + mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_self, ARG_r, ARG_g, ARG_b }; static const mp_arg_t allowed_args[] = { @@ -334,7 +346,7 @@ mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_ma ); if (result == -1) { - mp_raise_ValueError("create_pen failed. No space in palette!"); + mp_raise_ValueError("create_pen failed. No matching colour or space in palette!"); } return mp_obj_new_int(result); diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h index ab1fc771..af025054 100644 --- a/micropython/modules/st7789/st7789.h +++ b/micropython/modules/st7789/st7789.h @@ -19,6 +19,7 @@ extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightnes // Palette management extern mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode); extern mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t colour); +extern mp_obj_t GenericST7789_reserve_palette(mp_obj_t self_in); // Pen extern mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen); From 6ace09dbc3f68997a30a025a4efb08962a516182 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 18:09:39 +0100 Subject: [PATCH 14/84] Re-renable Pico Explorer and enable Pimoroni Bus --- micropython/modules/micropython-common.cmake | 2 + .../modules/pico_explorer/micropython.cmake | 7 +- .../modules/pico_explorer/pico_explorer.c | 137 ++----- .../modules/pico_explorer/pico_explorer.cpp | 371 ------------------ .../modules/pico_explorer/pico_explorer.h | 27 +- 5 files changed, 28 insertions(+), 516 deletions(-) delete mode 100644 micropython/modules/pico_explorer/pico_explorer.cpp diff --git a/micropython/modules/micropython-common.cmake b/micropython/modules/micropython-common.cmake index 29097097..fe32f7d8 100644 --- a/micropython/modules/micropython-common.cmake +++ b/micropython/modules/micropython-common.cmake @@ -1,4 +1,5 @@ include(pimoroni_i2c/micropython) +include(pimoroni_bus/micropython) include(breakout_dotmatrix/micropython) include(breakout_encoder/micropython) @@ -27,6 +28,7 @@ include(pico_scroll/micropython) include(pico_rgb_keypad/micropython) include(pico_unicorn/micropython) include(pico_wireless/micropython) +include(pico_explorer/micropython) include(bitmap_fonts/micropython) diff --git a/micropython/modules/pico_explorer/micropython.cmake b/micropython/modules/pico_explorer/micropython.cmake index 1df96c1a..6e9dca8d 100644 --- a/micropython/modules/pico_explorer/micropython.cmake +++ b/micropython/modules/pico_explorer/micropython.cmake @@ -2,11 +2,6 @@ add_library(usermod_pico_explorer INTERFACE) target_sources(usermod_pico_explorer INTERFACE ${CMAKE_CURRENT_LIST_DIR}/pico_explorer.c - ${CMAKE_CURRENT_LIST_DIR}/pico_explorer.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_explorer/pico_explorer.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp ) target_include_directories(usermod_pico_explorer INTERFACE @@ -22,5 +17,5 @@ target_link_libraries(usermod INTERFACE usermod_pico_explorer) set_source_files_properties( ${CMAKE_CURRENT_LIST_DIR}/pico_explorer.c PROPERTIES COMPILE_FLAGS - "-Wno-discarded-qualifiers -Wno-implicit-int" + "-Wno-discarded-qualifiers" ) diff --git a/micropython/modules/pico_explorer/pico_explorer.c b/micropython/modules/pico_explorer/pico_explorer.c index 6d8e05fb..9070e817 100644 --- a/micropython/modules/pico_explorer/pico_explorer.c +++ b/micropython/modules/pico_explorer/pico_explorer.c @@ -1,131 +1,42 @@ #include "pico_explorer.h" -/***** Constants *****/ -enum buttons -{ - BUTTON_A = 0, - BUTTON_B, - BUTTON_X, - BUTTON_Y, +const mp_rom_obj_tuple_t PicoExplorer_MOTOR1_pins = { + {&mp_type_tuple}, 2, { MP_ROM_INT(9), MP_ROM_INT(8) }, }; -enum adcs -{ - ADC0 = 0, - ADC1, - ADC2, +const mp_rom_obj_tuple_t PicoExplorer_MOTOR2_pins = { + {&mp_type_tuple}, 2, { MP_ROM_INT(11), MP_ROM_INT(10) }, }; -enum motors -{ - MOTOR1 = 0, - MOTOR2, -}; - -enum motions -{ - FORWARD = 0, - REVERSE, - STOP, -}; - -enum gps -{ - GP0 = 0, - GP1, - GP2, - GP3, - GP4, - GP5, - GP6, - GP7, -}; - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// picoexplorer Module -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Module Functions *****/ -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoexplorer_init_obj, picoexplorer_init); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_get_width_obj, picoexplorer_get_width); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_get_height_obj, picoexplorer_get_height); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_update_obj, picoexplorer_update); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoexplorer_is_pressed_obj, picoexplorer_is_pressed); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoexplorer_get_adc_obj, picoexplorer_get_adc); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_set_motor_obj, 2, 3, picoexplorer_set_motor); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoexplorer_set_audio_pin_obj, picoexplorer_set_audio_pin); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_set_tone_obj, 1, 2, picoexplorer_set_tone); - -//From PicoGraphics parent class -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_set_pen_obj, 1, 3, picoexplorer_set_pen); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoexplorer_create_pen_obj, picoexplorer_create_pen); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_set_clip_obj, 4, 4, picoexplorer_set_clip); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_remove_clip_obj, picoexplorer_remove_clip); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoexplorer_clear_obj, picoexplorer_clear); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoexplorer_pixel_obj, picoexplorer_pixel); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoexplorer_pixel_span_obj, picoexplorer_pixel_span); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_rectangle_obj, 4, 4, picoexplorer_rectangle); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoexplorer_circle_obj, picoexplorer_circle); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_character_obj, 3, 4, picoexplorer_character); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoexplorer_text_obj, 4, 5, picoexplorer_text); - - -/***** Globals Table *****/ STATIC const mp_map_elem_t picoexplorer_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picoexplorer) }, - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picoexplorer_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picoexplorer_get_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picoexplorer_get_height_obj) }, - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picoexplorer_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picoexplorer_is_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_adc), MP_ROM_PTR(&picoexplorer_get_adc_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_motor), MP_ROM_PTR(&picoexplorer_set_motor_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_audio_pin), MP_ROM_PTR(&picoexplorer_set_audio_pin_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_tone), MP_ROM_PTR(&picoexplorer_set_tone_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&picoexplorer_set_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&picoexplorer_create_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&picoexplorer_set_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&picoexplorer_remove_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picoexplorer_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&picoexplorer_pixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&picoexplorer_pixel_span_obj) }, - { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&picoexplorer_rectangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&picoexplorer_circle_obj) }, - { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&picoexplorer_character_obj) }, - { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&picoexplorer_text_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) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(12) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(13) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(14) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(15) }, - { MP_ROM_QSTR(MP_QSTR_ADC0), MP_ROM_INT(ADC0) }, - { MP_ROM_QSTR(MP_QSTR_ADC1), MP_ROM_INT(ADC1) }, - { MP_ROM_QSTR(MP_QSTR_ADC2), MP_ROM_INT(ADC2) }, - { MP_ROM_QSTR(MP_QSTR_MOTOR1), MP_ROM_INT(MOTOR1) }, - { MP_ROM_QSTR(MP_QSTR_MOTOR2), MP_ROM_INT(MOTOR2) }, - { MP_ROM_QSTR(MP_QSTR_FORWARD), MP_ROM_INT(FORWARD) }, - { MP_ROM_QSTR(MP_QSTR_REVERSE), MP_ROM_INT(REVERSE) }, - { MP_ROM_QSTR(MP_QSTR_STOP), MP_ROM_INT(STOP) }, - { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_INT(GP0) }, - { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_INT(GP1) }, - { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_INT(GP2) }, - { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_INT(GP3) }, - { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_INT(GP4) }, - { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_INT(GP5) }, - { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_INT(GP6) }, - { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_INT(GP7) }, + { MP_ROM_QSTR(MP_QSTR_ADC0), MP_ROM_INT(26) }, + { MP_ROM_QSTR(MP_QSTR_ADC1), MP_ROM_INT(27) }, + { MP_ROM_QSTR(MP_QSTR_ADC2), MP_ROM_INT(28) }, + + { MP_ROM_QSTR(MP_QSTR_MOTOR_1), MP_ROM_PTR(&PicoExplorer_MOTOR1_pins) }, + { MP_ROM_QSTR(MP_QSTR_MOTOR_2), MP_ROM_PTR(&PicoExplorer_MOTOR2_pins) }, + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_INT(3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_INT(4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_INT(5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_INT(6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_INT(7) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_picoexplorer_globals, picoexplorer_globals_table); -/***** Module Definition *****/ const mp_obj_module_t picoexplorer_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_picoexplorer_globals, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -MP_REGISTER_MODULE(MP_QSTR_picoexplorer, picoexplorer_user_cmodule, MODULE_PICOEXPLORER_ENABLED); -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +MP_REGISTER_MODULE(MP_QSTR_picoexplorer, picoexplorer_user_cmodule, MODULE_PICOEXPLORER_ENABLED); \ No newline at end of file diff --git a/micropython/modules/pico_explorer/pico_explorer.cpp b/micropython/modules/pico_explorer/pico_explorer.cpp deleted file mode 100644 index 81de8865..00000000 --- a/micropython/modules/pico_explorer/pico_explorer.cpp +++ /dev/null @@ -1,371 +0,0 @@ -#include "hardware/spi.h" -#include "hardware/sync.h" -#include "pico/binary_info.h" - -#include "libraries/pico_explorer/pico_explorer.hpp" - -using namespace pimoroni; - -PicoExplorer *explorer = nullptr; - - -extern "C" { -#include "pico_explorer.h" - -#define NOT_INITIALISED_MSG "Cannot call this function, as picoexplorer is not initialised. Call picoexplorer.init() first." - -mp_obj_t picoexplorer_buf_obj; - -mp_obj_t picoexplorer_init(mp_obj_t buf_obj) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_obj, &bufinfo, MP_BUFFER_RW); - picoexplorer_buf_obj = buf_obj; - - // If a display already exists, delete it - if(explorer != nullptr) { - delete explorer; - } - - // Create a new display pointing to the newly provided buffer - explorer = new PicoExplorer((uint8_t *)bufinfo.buf); - explorer->init(); - - return mp_const_none; -} - -mp_obj_t picoexplorer_get_width() { - return mp_obj_new_int(PicoExplorer::WIDTH); -} - -mp_obj_t picoexplorer_get_height() { - return mp_obj_new_int(PicoExplorer::HEIGHT); -} - -mp_obj_t picoexplorer_update() { - if(explorer != nullptr) - explorer->update(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoexplorer_is_pressed(mp_obj_t button_obj) { - bool buttonPressed = false; - - if(explorer != nullptr) { - int buttonID = mp_obj_get_int(button_obj); - switch(buttonID) { - case 0: - buttonPressed = explorer->is_pressed(PicoExplorer::A); - break; - - case 1: - buttonPressed = explorer->is_pressed(PicoExplorer::B); - break; - - case 2: - buttonPressed = explorer->is_pressed(PicoExplorer::X); - break; - - case 3: - buttonPressed = explorer->is_pressed(PicoExplorer::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; -} - -extern mp_obj_t picoexplorer_get_adc(mp_obj_t channel_obj) { - float reading = 0.0f; - - if(explorer != nullptr) { - int channel = mp_obj_get_int(channel_obj); - if(channel < 0 || channel > 2) - mp_raise_ValueError("adc channel not valid. Expected 0 to 2"); - else - reading = explorer->get_adc(channel); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_obj_new_float(reading); -} - -extern mp_obj_t picoexplorer_set_motor(mp_uint_t n_args, const mp_obj_t *args) { - if(explorer != nullptr) { - int channel = mp_obj_get_int(args[0]); - int action = mp_obj_get_int(args[1]); - - if(channel < 0 || channel > 1) - mp_raise_ValueError("motor channel not valid. Expected 0 to 1"); - else if(action < 0 || action > 2) - mp_raise_ValueError("motor action not valid. Expected 0 to 2"); - else { - if(n_args == 3) { - float speed = mp_obj_get_float(args[2]); - explorer->set_motor(channel, action, speed); - } - else - explorer->set_motor(channel, action); - } - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -extern mp_obj_t picoexplorer_set_audio_pin(mp_obj_t pin_obj) { - if(explorer != nullptr) { - int pin = mp_obj_get_int(pin_obj); - explorer->set_audio_pin(pin); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - return mp_const_none; -} - -extern mp_obj_t picoexplorer_set_tone(mp_uint_t n_args, const mp_obj_t *args) { - if(explorer != nullptr) { - int frequency = mp_obj_get_int(args[0]); - - if(n_args == 2) { - float duty = mp_obj_get_int(args[1]); - explorer->set_tone(frequency, duty); - } - else - explorer->set_tone(frequency); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoexplorer_set_pen(mp_uint_t n_args, const mp_obj_t *args) { - if(explorer != nullptr) { - switch(n_args) { - case 1: { - int p = mp_obj_get_int(args[0]); - - if(p < 0 || p > 0xffff) - mp_raise_ValueError("p is not a valid pen."); - else - explorer->set_pen(p); - } break; - - case 3: { - int r = mp_obj_get_int(args[0]); - int g = mp_obj_get_int(args[1]); - int b = mp_obj_get_int(args[2]); - - 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 - explorer->set_pen(r, g, b); - } break; - - default: { - char *buffer; - buffer = (char*)malloc(100); - sprintf(buffer, "function takes 1 or 3 (r,g,b) positional arguments but %d were given", n_args); - mp_raise_TypeError(buffer); - free(buffer); - } break; - } - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoexplorer_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) { - int pen = 0; - - if(explorer != nullptr) { - int r = mp_obj_get_int(r_obj); - int g = mp_obj_get_int(g_obj); - int b = mp_obj_get_int(b_obj); - - 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 - pen = explorer->create_pen(r, g, b); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_obj_new_int(pen); -} - -mp_obj_t picoexplorer_set_clip(mp_uint_t n_args, const mp_obj_t *args) { - (void)n_args; //Unused input parameter, we know it's 4 - - if(explorer != nullptr) { - int x = mp_obj_get_int(args[0]); - int y = mp_obj_get_int(args[1]); - int w = mp_obj_get_int(args[2]); - int h = mp_obj_get_int(args[3]); - - Rect r(x, y, w, h); - explorer->set_clip(r); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoexplorer_remove_clip() { - if(explorer != nullptr) - explorer->remove_clip(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - return mp_const_none; -} - -mp_obj_t picoexplorer_clear() { - if(explorer != nullptr) - explorer->clear(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - return mp_const_none; -} - -mp_obj_t picoexplorer_pixel(mp_obj_t x_obj, mp_obj_t y_obj) { - if(explorer != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - - Point p(x, y); - explorer->pixel(p); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoexplorer_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj) { - if(explorer != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - int l = mp_obj_get_int(l_obj); - - Point p(x, y); - explorer->pixel_span(p, l); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoexplorer_rectangle(mp_uint_t n_args, const mp_obj_t *args) { - (void)n_args; //Unused input parameter, we know it's 4 - - if(explorer != nullptr) { - int x = mp_obj_get_int(args[0]); - int y = mp_obj_get_int(args[1]); - int w = mp_obj_get_int(args[2]); - int h = mp_obj_get_int(args[3]); - - Rect r(x, y, w, h); - explorer->rectangle(r); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoexplorer_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj) { - if(explorer != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - int r = mp_obj_get_int(r_obj); - - Point p(x, y); - explorer->circle(p, r); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoexplorer_character(mp_uint_t n_args, const mp_obj_t *args) { - if(explorer != nullptr) { - int c = mp_obj_get_int(args[0]); - int x = mp_obj_get_int(args[1]); - int y = mp_obj_get_int(args[2]); - - Point p(x, y); - if(n_args == 4) { - int scale = mp_obj_get_int(args[3]); - explorer->character((char)c, p, scale); - } - else - explorer->character((char)c, p); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picoexplorer_text(mp_uint_t n_args, const mp_obj_t *args) { - if(explorer != nullptr) { - if(mp_obj_is_str_or_bytes(args[0])) { - GET_STR_DATA_LEN(args[0], str, str_len); - - std::string t((const char*)str); - - int x = mp_obj_get_int(args[1]); - int y = mp_obj_get_int(args[2]); - int wrap = mp_obj_get_int(args[3]); - - Point p(x, y); - if(n_args == 5) { - int scale = mp_obj_get_int(args[4]); - explorer->text(t, p, wrap, scale); - } - else - explorer->text(t, p, wrap); - } - else if(mp_obj_is_float(args[0])) { - mp_raise_TypeError("can't convert 'float' object to str implicitly"); - } - else if(mp_obj_is_int(args[0])) { - mp_raise_TypeError("can't convert 'int' object to str implicitly"); - } - else if(mp_obj_is_bool(args[0])) { - mp_raise_TypeError("can't convert 'bool' object to str implicitly"); - } - else { - mp_raise_TypeError("can't convert object to str implicitly"); - } - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} -} \ No newline at end of file diff --git a/micropython/modules/pico_explorer/pico_explorer.h b/micropython/modules/pico_explorer/pico_explorer.h index c7e65605..87a476d8 100644 --- a/micropython/modules/pico_explorer/pico_explorer.h +++ b/micropython/modules/pico_explorer/pico_explorer.h @@ -1,27 +1,2 @@ -// Include MicroPython API. #include "py/runtime.h" -#include "py/objstr.h" - -// Declare the functions we'll make available in Python -extern mp_obj_t picoexplorer_init(mp_obj_t buf_obj); -extern mp_obj_t picoexplorer_get_width(); -extern mp_obj_t picoexplorer_get_height(); -extern mp_obj_t picoexplorer_update(); -extern mp_obj_t picoexplorer_is_pressed(mp_obj_t button_obj); -extern mp_obj_t picoexplorer_get_adc(mp_obj_t channel_obj); -extern mp_obj_t picoexplorer_set_motor(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picoexplorer_set_audio_pin(mp_obj_t pin_obj); -extern mp_obj_t picoexplorer_set_tone(mp_uint_t n_args, const mp_obj_t *args); - -// From PicoGraphics parent class -extern mp_obj_t picoexplorer_set_pen(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picoexplorer_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj); -extern mp_obj_t picoexplorer_set_clip(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picoexplorer_remove_clip(); -extern mp_obj_t picoexplorer_clear(); -extern mp_obj_t picoexplorer_pixel(mp_obj_t x_obj, mp_obj_t y_obj); -extern mp_obj_t picoexplorer_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj); -extern mp_obj_t picoexplorer_rectangle(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picoexplorer_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj); -extern mp_obj_t picoexplorer_character(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picoexplorer_text(mp_uint_t n_args, const mp_obj_t *args); \ No newline at end of file +#include "py/objstr.h" \ No newline at end of file From 0264dddc2cfb20d73b17119e931f6d6998a4721b Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 18:09:59 +0100 Subject: [PATCH 15/84] Pico Explorer: Update examples for Motor, Buzzer, Button, ST7789. --- micropython/examples/pico_display/rainbow.py | 2 +- .../examples/pico_explorer/balls_demo.py | 29 ++-- micropython/examples/pico_explorer/buttons.py | 69 +++++---- micropython/examples/pico_explorer/demo.py | 138 +++++++++++------- micropython/examples/pico_explorer/noise.py | 34 +++-- micropython/examples/pico_explorer/rainbow.py | 23 ++- .../examples/pico_explorer/thermometer.py | 33 +++-- .../pico_explorer/weatherstation_BME280.py | 63 ++++---- .../pico_explorer/weatherstation_BME68X.py | 63 ++++---- 9 files changed, 260 insertions(+), 194 deletions(-) diff --git a/micropython/examples/pico_display/rainbow.py b/micropython/examples/pico_display/rainbow.py index 25e45a29..d2af8d85 100644 --- a/micropython/examples/pico_display/rainbow.py +++ b/micropython/examples/pico_display/rainbow.py @@ -47,7 +47,7 @@ while True: h += 1 r, g, b = [int(255 * c) for c in hsv_to_rgb(h / 360.0, 1.0, 1.0)] # rainbow magic led.set_rgb(r, g, b) # Set LED to a converted HSV value - display.set_palette(RAINBOW, st7789.RGB565(r, g, b)) # Create pen with converted HSV value + display.set_palette(RAINBOW, st7789.RGB565(r, g, b)) # Create pen with converted HSV value display.set_pen(RAINBOW) # Set pen display.clear() # Fill the screen with the colour display.set_pen(BLACK) # Set pen to black diff --git a/micropython/examples/pico_explorer/balls_demo.py b/micropython/examples/pico_explorer/balls_demo.py index f086c03a..e87725fe 100644 --- a/micropython/examples/pico_explorer/balls_demo.py +++ b/micropython/examples/pico_explorer/balls_demo.py @@ -1,20 +1,11 @@ -# adapted from demo.py in examples/pico_display -# runs full screen on a pico explorer -# all credit to orignal author(s) - -# I just changed the import statement to import picoexplorer instaead of picodisplay - - import time import random -import picoexplorer as display +import st7789 -width = display.get_width() -height = display.get_height() +display = st7789.ST7789(st7789.DISPLAY_PICO_EXPLORER, rotate=0) +display.set_backlight(1.0) -display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565) -display.init(display_buffer) - -# display.set_backlight(1.0) +WIDTH, HEIGHT = display.get_bounds() class Ball: @@ -33,8 +24,8 @@ for i in range(0, 100): r = random.randint(0, 10) + 3 balls.append( Ball( - random.randint(r, r + (width - 2 * r)), - random.randint(r, r + (height - 2 * r)), + random.randint(r, r + (WIDTH - 2 * r)), + random.randint(r, r + (HEIGHT - 2 * r)), r, (14 - r) / 2, (14 - r) / 2, @@ -42,17 +33,19 @@ for i in range(0, 100): ) ) +BG = display.create_pen(32, 32, 64) + while True: - display.set_pen(40, 40, 40) + display.set_pen(BG) display.clear() for ball in balls: ball.x += ball.dx ball.y += ball.dy - xmax = width - ball.r + xmax = WIDTH - ball.r xmin = ball.r - ymax = height - ball.r + ymax = HEIGHT - ball.r ymin = ball.r if ball.x < xmin or ball.x > xmax: diff --git a/micropython/examples/pico_explorer/buttons.py b/micropython/examples/pico_explorer/buttons.py index d52528c7..8e49d70a 100644 --- a/micropython/examples/pico_explorer/buttons.py +++ b/micropython/examples/pico_explorer/buttons.py @@ -1,51 +1,66 @@ # This example shows you a simple, non-interrupt way of reading Pico Explorer's buttons with a loop that checks to see if buttons are pressed. -import picoexplorer as display import utime - -# Initialise display with a bytearray display buffer -buf = bytearray(display.get_width() * display.get_height() * 2) -display.init(buf) +import st7789 +import picoexplorer +from pimoroni import Button -# sets up a handy function we can call to clear the screen -def clear(): - display.set_pen(0, 0, 0) - display.clear() - display.update() +display = st7789.ST7789(st7789.DISPLAY_PICO_EXPLORER, rotate=0) +display.set_palette_mode(st7789.PALETTE_USER) +display.set_backlight(1.0) + +button_a = Button(picoexplorer.BUTTON_A) +button_b = Button(picoexplorer.BUTTON_B) +button_x = Button(picoexplorer.BUTTON_X) +button_y = Button(picoexplorer.BUTTON_Y) + +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) +TEAL = display.create_pen(0, 255, 255) +MAGENTA = display.create_pen(255, 0, 255) +YELLOW = display.create_pen(255, 255, 0) +RED = display.create_pen(255, 0, 0) while True: - if display.is_pressed(display.BUTTON_A): # if a button press is detected then... - clear() # clear to black - display.set_pen(255, 255, 255) # change the pen colour + if button_a.is_pressed: # if a button press is detected then... + display.set_pen(BLACK) # set pen to black + display.clear() # clear display to the pen colour + display.set_pen(WHITE) # change the pen colour display.text("Button A pressed", 10, 10, 240, 4) # display some text on the screen display.update() # update the display utime.sleep(1) # pause for a sec - clear() # clear to black again - elif display.is_pressed(display.BUTTON_B): - clear() - display.set_pen(0, 255, 255) + + elif button_b.is_pressed: + display.set_pen(BLACK) + display.clear() + display.set_pen(TEAL) display.text("Button B pressed", 10, 10, 240, 4) display.update() utime.sleep(1) - clear() - elif display.is_pressed(display.BUTTON_X): - clear() - display.set_pen(255, 0, 255) + + elif button_x.is_pressed: + display.set_pen(BLACK) + display.clear() + display.set_pen(MAGENTA) display.text("Button X pressed", 10, 10, 240, 4) display.update() utime.sleep(1) - clear() - elif display.is_pressed(display.BUTTON_Y): - clear() - display.set_pen(255, 255, 0) + + elif button_y.is_pressed: + display.set_pen(BLACK) + display.clear() + display.set_pen(YELLOW) display.text("Button Y pressed", 10, 10, 240, 4) display.update() utime.sleep(1) - clear() + else: - display.set_pen(255, 0, 0) + display.set_pen(BLACK) + display.clear() + display.set_pen(RED) display.text("Press any button!", 10, 10, 240, 4) display.update() + utime.sleep(0.1) # this number is how frequently the Pico checks for button presses diff --git a/micropython/examples/pico_explorer/demo.py b/micropython/examples/pico_explorer/demo.py index 75f362fe..3156091f 100644 --- a/micropython/examples/pico_explorer/demo.py +++ b/micropython/examples/pico_explorer/demo.py @@ -1,79 +1,113 @@ import time -import picoexplorer as explorer +import st7789 +from motor import Motor +import picoexplorer +from pimoroni import Button, Analog, Buzzer -width = explorer.get_width() -height = explorer.get_height() +display = st7789.ST7789(st7789.DISPLAY_PICO_EXPLORER, rotate=0) +display.set_palette_mode(st7789.PALETTE_USER) +display.set_backlight(1.0) -display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565) -explorer.init(display_buffer) -explorer.set_audio_pin(0) +adc0 = Analog(picoexplorer.ADC0) +adc1 = Analog(picoexplorer.ADC1) +adc2 = Analog(picoexplorer.ADC2) + +button_a = Button(picoexplorer.BUTTON_A) +button_b = Button(picoexplorer.BUTTON_B) +button_x = Button(picoexplorer.BUTTON_X) +button_y = Button(picoexplorer.BUTTON_Y) + +BG = display.create_pen(32, 32, 64) +WHITE = display.create_pen(255, 255, 255) + +ADC0_PEN = display.reserve_palette() +ADC1_PEN = display.reserve_palette() +ADC2_PEN = display.reserve_palette() + +MOTOR1 = Motor(picoexplorer.MOTOR_1) +MOTOR2 = Motor(picoexplorer.MOTOR_2) + +BUZZER = Buzzer(0) i = 1 while True: - explorer.set_pen(120, 40, 60) - explorer.clear() + display.set_pen(BG) + display.clear() - adc0 = int(explorer.get_adc(0) * 120) - adc1 = int(explorer.get_adc(1) * 120) - adc2 = int(explorer.get_adc(2) * 120) + # Read the ADCs + adc0v = int(adc0.read_voltage() / 3.3 * 120) + adc1v = int(adc1.read_voltage() / 3.3 * 120) + adc2v = int(adc2.read_voltage() / 3.3 * 120) - explorer.set_pen(255, 255, 255) + # Update our ADC channel palette colours + display.set_palette(ADC0_PEN, st7789.RGB565(adc0v * 2, 10, 10)) + display.set_palette(ADC1_PEN, st7789.RGB565(10, adc1v * 2, 10)) + display.set_palette(ADC2_PEN, st7789.RGB565(10, 10, adc2v * 2)) - explorer.text("ADC0:", 20, 20, 100) - explorer.text("ADC1:", 20, 40, 100) - explorer.text("ADC2:", 20, 60, 100) + # ADC labels + display.set_pen(WHITE) + display.text("ADC0:", 20, 20, 100) + display.text("ADC1:", 20, 40, 100) + display.text("ADC2:", 20, 60, 100) - explorer.set_pen(adc0 * 2, 0, 0) - explorer.circle(90 + adc0, 26, 10) + # ADC graph + display.set_pen(ADC0_PEN) + display.circle(90 + adc0v, 26, 10) - explorer.set_pen(0, adc1 * 2, 0) - explorer.circle(90 + adc1, 46, 10) + display.set_pen(ADC1_PEN) + display.circle(90 + adc1v, 46, 10) - explorer.set_pen(0, 0, adc2 * 2) - explorer.circle(90 + adc2, 66, 10) + display.set_pen(ADC2_PEN) + display.circle(90 + adc2v, 66, 10) + + # On-board A/B/X/Y buttons + if button_a.is_pressed: + display.set_pen(WHITE) + display.text("Button A pressed", 20, 110, 200) + + elif button_b.is_pressed: + display.set_pen(WHITE) + display.text("Button B pressed", 20, 110, 200) + + elif button_x.is_pressed and button_y.is_pressed: + display.set_pen(WHITE) + display.text("Buttons X and Y pressed", 20, 110, 200) + + elif button_x.is_pressed: + display.set_pen(WHITE) + display.text("Button X pressed", 20, 110, 200) + + elif button_y.is_pressed: + display.set_pen(WHITE) + display.text("Button Y pressed", 20, 110, 200) - # example for the on-board A/B/X/Y buttons - if explorer.is_pressed(explorer.BUTTON_A): - explorer.set_pen(255, 255, 255) - explorer.text("Button A pressed", 20, 110, 200) - elif explorer.is_pressed(explorer.BUTTON_B): - explorer.set_pen(255, 255, 255) - explorer.text("Button B pressed", 20, 110, 200) - elif explorer.is_pressed(explorer.BUTTON_X) and explorer.is_pressed(explorer.BUTTON_Y): - explorer.set_pen(255, 255, 255) - explorer.text("Buttons X and Y pressed", 20, 110, 200) - elif explorer.is_pressed(explorer.BUTTON_X): - explorer.set_pen(255, 255, 255) - explorer.text("Button X pressed", 20, 110, 200) - elif explorer.is_pressed(explorer.BUTTON_Y): - explorer.set_pen(255, 255, 255) - explorer.text("Button Y pressed", 20, 110, 200) else: # no button press was detected - explorer.set_pen(255, 255, 255) - explorer.text("Plug a jumper wire from GP0 to AUDIO to hear noise!", 20, 110, 200) + display.set_pen(WHITE) + display.text("Plug a jumper wire from GP0 to AUDIO to hear noise!", 20, 110, 200) - explorer.set_tone(i) + BUZZER.set_tone(i) + + # Motors + if i > 600: + display.text("Motor 1: Forwards", 20, 180, 200) + MOTOR1.full_positive() + else: + display.text("Motor 1: Backwards", 20, 180, 200) + MOTOR1.full_negative() if i > 600: - explorer.text("Motor 1: Forwards", 20, 180, 200) - explorer.set_motor(0, 0, 1) + display.text("Motor 2: Forwards", 20, 200, 200) + MOTOR2.full_positive() else: - explorer.text("Motor 1: Backwards", 20, 180, 200) - explorer.set_motor(0, 1, 1) - - if i > 600: - explorer.text("Motor 2: Forwards", 20, 200, 200) - explorer.set_motor(1, 0, 1) - else: - explorer.text("Motor 2: Backwards", 20, 200, 200) - explorer.set_motor(1, 1, 1) + display.text("Motor 2: Backwards", 20, 200, 200) + MOTOR2.full_negative() i = i + 20 if i > 1000: i = 1 - explorer.update() + display.update() time.sleep(0.01) diff --git a/micropython/examples/pico_explorer/noise.py b/micropython/examples/pico_explorer/noise.py index 8f094a3f..5db940dc 100644 --- a/micropython/examples/pico_explorer/noise.py +++ b/micropython/examples/pico_explorer/noise.py @@ -3,14 +3,20 @@ # You'll need to connect a jumper wire between GPO and AUDIO on the Explorer Base to hear noise. import utime -import picoexplorer as explorer +import st7789 +from pimoroni import Buzzer -# Set up and initialise Pico Explorer -buf = bytearray(explorer.get_width() * explorer.get_height() * 2) -explorer.init(buf) -# tells Pico Explorer which pin you'll be using for noise -explorer.set_audio_pin(0) +display = st7789.ST7789(st7789.DISPLAY_PICO_EXPLORER, rotate=0) +display.set_palette_mode(st7789.PALETTE_USER) +display.set_backlight(1.0) + +# tCreate a buzzer on pin 0 +# Don't forget t write GP0 to AUDIO! +BUZZER = Buzzer(0) + +BLACK = display.create_pen(0, 0, 0) +GREEN = display.create_pen(0, 255, 0) # this handy list converts notes into frequencies, which you can use with the explorer.set_tone function tones = { @@ -110,17 +116,17 @@ song = ["F6", "F6", "E6", "F6", "F5", "P", "F5", "P", "C6", "AS5", "A5", "C6", " def clear(): # this function clears Pico Explorer's screen to black - explorer.set_pen(0, 0, 0) - explorer.clear() - explorer.update() + display.set_pen(BLACK) + display.clear() + display.update() def playtone(frequency): # this function tells your program how to make noise - explorer.set_tone(frequency) + BUZZER.set_tone(frequency) def bequiet(): # this function tells your program how not to make noise - explorer.set_tone(-1) + BUZZER.set_tone(-1) def playsong(song): # this function plays your song @@ -130,13 +136,13 @@ def playsong(song): # this function plays your song bequiet() else: playtone(tones[song[i]]) - explorer.set_pen(0, 255, 0) # switch to green pen - explorer.rectangle(a, 240 - (int((tones[song[i]]) / 21)), 5, 240) # draw a green bar corresponding to the frequency of the note + display.set_pen(GREEN) # switch to green pen + display.rectangle(a, 240 - (int((tones[song[i]]) / 21)), 5, 240) # draw a green bar corresponding to the frequency of the note a += 7 if a >= 240: # clears the screen if the green bars reach the right hand edge clear() a = 0 - explorer.update() + display.update() utime.sleep(0.15) # change this number if you want to alter how long the notes play for bequiet() diff --git a/micropython/examples/pico_explorer/rainbow.py b/micropython/examples/pico_explorer/rainbow.py index d44bef52..dee58743 100644 --- a/micropython/examples/pico_explorer/rainbow.py +++ b/micropython/examples/pico_explorer/rainbow.py @@ -1,11 +1,19 @@ -# This example borrows a CircuitPython hsv_to_rgb function to cycle through some rainbows on Pico Explorer's screen and RGB LED . If you're into rainbows, HSV (Hue, Saturation, Value) is very useful! +# This example borrows a CircuitPython hsv_to_rgb function to cycle through some rainbows on Pico Explorer's screen. +# If you're into rainbows, HSV (Hue, Saturation, Value) is very useful! import utime -import picoexplorer as display +import st7789 -# Set up and initialise Pico Explorer -buf = bytearray(display.get_width() * display.get_height() * 2) -display.init(buf) + +display = st7789.ST7789(st7789.DISPLAY_PICO_EXPLORER, rotate=0) +display.set_palette_mode(st7789.PALETTE_USER) +display.set_backlight(1.0) + +# Create a text colour +TEXT_COLOR = display.create_pen(0, 0, 0) + +# Reserve a palette entry for our rainbow background colour +RAINBOW = display.reserve_palette() # From CPython Lib/colorsys.py @@ -37,9 +45,10 @@ h = 0 while True: h += 1 r, g, b = [int(255 * c) for c in hsv_to_rgb(h / 360.0, 1.0, 1.0)] # rainbow magic - display.set_pen(r, g, b) # Set pen to a converted HSV value + display.set_palette(RAINBOW, st7789.RGB565(r, g, b)) # Set pen to a converted HSV value + display.set_pen(RAINBOW) display.clear() # Fill the screen with the colour - display.set_pen(0, 0, 0) # Set pen to black + display.set_pen(TEXT_COLOR) display.text("pico disco!", 25, 20, 240, 6) # Add some text display.text("\\o/ \\o/ \\o/ \\o/ \\o/ \\o/ \\o/ \\o/ \\o/", 25, 120, 240, 4) # and some more text display.text("oontz oontz oontz", 25, 220, 240, 2) # and a bit more tiny text diff --git a/micropython/examples/pico_explorer/thermometer.py b/micropython/examples/pico_explorer/thermometer.py index 16c093b1..3b7b5b7c 100644 --- a/micropython/examples/pico_explorer/thermometer.py +++ b/micropython/examples/pico_explorer/thermometer.py @@ -1,20 +1,27 @@ # This example takes the temperature from the Pico's onboard temperature sensor, and displays it on Pico Explorer, along with a little pixelly graph. # It's based on the thermometer example in the "Getting Started with MicroPython on the Raspberry Pi Pico" book, which is a great read if you're a beginner! +import st7789 import machine import utime # Pico Explorer boilerplate -import picoexplorer as display -width = display.get_width() -height = display.get_height() -display_buffer = bytearray(width * height * 2) -display.init(display_buffer) +display = st7789.ST7789(st7789.DISPLAY_PICO_EXPLORER, rotate=0) +display.set_palette_mode(st7789.PALETTE_USER) +display.set_backlight(1.0) + +WIDTH, HEIGHT = display.get_bounds() # reads from Pico's temp sensor and converts it into a more manageable number sensor_temp = machine.ADC(4) conversion_factor = 3.3 / (65535) +BLACK = display.create_pen(0, 0, 0) +WHITE = display.create_pen(255, 255, 255) +RED = display.create_pen(255, 0, 0) +GREEN = display.create_pen(0, 255, 0) +BLUE = display.create_pen(0, 0, 255) + i = 0 while True: @@ -23,27 +30,27 @@ while True: temperature = round(27 - (reading - 0.706) / 0.001721) # this if statement clears the display once the graph reaches the right hand side of the display - if i >= (width + 1): + if i >= WIDTH + 1: i = 0 - display.set_pen(0, 0, 0) + display.set_pen(BLACK) display.clear() # chooses a pen colour based on the temperature - display.set_pen(0, 255, 0) + display.set_pen(GREEN) if temperature > 20: - display.set_pen(255, 0, 0) + display.set_pen(RED) if temperature < 13: - display.set_pen(0, 0, 255) + display.set_pen(BLUE) # draws the reading as a tall, thin rectangle - display.rectangle(i, height - (temperature * 6), 6, height) + display.rectangle(i, HEIGHT - (temperature * 6), 6, HEIGHT) # draws a white background for the text - display.set_pen(255, 255, 255) + display.set_pen(WHITE) display.rectangle(1, 1, 65, 33) # writes the reading as text in the white rectangle - display.set_pen(0, 0, 0) + display.set_pen(BLACK) display.text("{:.0f}".format(temperature) + "c", 3, 3, 0, 4) # time to update the display diff --git a/micropython/examples/pico_explorer/weatherstation_BME280.py b/micropython/examples/pico_explorer/weatherstation_BME280.py index d4e3ad21..3e4d67dc 100644 --- a/micropython/examples/pico_explorer/weatherstation_BME280.py +++ b/micropython/examples/pico_explorer/weatherstation_BME280.py @@ -7,68 +7,68 @@ from pimoroni_i2c import PimoroniI2C from pimoroni import PICO_EXPLORER_I2C_PINS # Pico Explorer boilerplate -import picoexplorer as display -width = display.get_width() -height = display.get_height() -display_buffer = bytearray(width * height * 2) -display.init(display_buffer) +import st7789 +display = st7789.ST7789(st7789.DISPLAY_PICO_EXPLORER, rotate=0) +display.set_palette_mode(st7789.PALETTE_USER) +display.set_backlight(1.0) i2c = PimoroniI2C(**PICO_EXPLORER_I2C_PINS) bme = BreakoutBME280(i2c) # lets set up some pen colours to make drawing easier -tempcolour = display.create_pen(255, 255, 255) # this colour will get changed in a bit -white = display.create_pen(255, 255, 255) -black = display.create_pen(0, 0, 0) -red = display.create_pen(255, 0, 0) +TEMPCOLOUR = display.reserve_palette() # this colour will get changed in a bit +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) +RED = display.create_pen(255, 0, 0) +GREY = display.create_pen(125, 125, 125) # converts the temperature into a barometer-type description and pen colour def describe_temperature(temperature): - global tempcolour + global TEMPCOLOUR if temperature < 10: description = "very cold" - tempcolour = display.create_pen(0, 255, 255) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 255, 255)) elif 10 <= temperature < 20: description = "cold" - tempcolour = display.create_pen(0, 0, 255) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 0, 255)) elif 20 <= temperature < 25: description = "temperate" - tempcolour = display.create_pen(0, 255, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 255, 0)) elif 25 <= temperature < 30: description = "warm" - tempcolour = display.create_pen(255, 255, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(255, 255, 0)) elif temperature >= 30: description = "very warm" - tempcolour = display.create_pen(255, 0, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(255, 0, 0)) else: description = "" - tempcolour = display.create_pen(0, 0, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 0, 0)) return description # comment out the function above and uncomment this one for yorkshire mode """ def describe_temperature(temperature): - global tempcolour + global TEMPCOLOUR if temperature < 10: description = "frozzed" - tempcolour = display.create_pen(0, 255, 255) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 255, 255)) elif 10 <= temperature < 20: description = "nithering" - tempcolour = display.create_pen(0, 0, 255) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 0, 255)) elif 20 <= temperature < 25: description = "fair t' middlin" - tempcolour = display.create_pen(0, 255, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 255, 0)) elif 25 <= temperature < 30: description = "chuffing warm" - tempcolour = display.create_pen(255, 255, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(255, 255, 0)) elif temperature >= 30: description = "crackin t' flags" - tempcolour = display.create_pen(255, 0, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(255, 0, 0)) else: description = "" - tempcolour = display.create_pen(0, 0, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 0, 0)) return description """ @@ -100,18 +100,21 @@ def describe_humidity(humidity): while True: + display.set_pen(BLACK) + display.clear() + # read the sensors temperature, pressure, humidity = bme.read() # pressure comes in pascals which is a reight long number, lets convert it to the more manageable hPa pressurehpa = pressure / 100 # draw a thermometer/barometer thingy - display.set_pen(125, 125, 125) + display.set_pen(GREY) display.circle(190, 190, 40) display.rectangle(180, 45, 20, 140) # switch to red to draw the 'mercury' - display.set_pen(red) + display.set_pen(RED) display.circle(190, 190, 30) thermometerheight = int(120 / 30 * temperature) if thermometerheight > 120: @@ -121,11 +124,11 @@ while True: display.rectangle(186, 50 + 120 - thermometerheight, 10, thermometerheight) # drawing the temperature text - display.set_pen(white) + display.set_pen(WHITE) display.text("temperature:", 10, 10, 240, 3) - display.set_pen(tempcolour) + display.set_pen(TEMPCOLOUR) display.text('{:.1f}'.format(temperature) + 'C', 10, 30, 240, 5) - display.set_pen(white) + display.set_pen(WHITE) display.text(describe_temperature(temperature), 10, 60, 240, 3) # and the pressure text @@ -141,7 +144,5 @@ while True: # time to update the display display.update() - # waits for 1 second and clears to black + # waits for 1 second and clears to BLACK utime.sleep(1) - display.set_pen(black) - display.clear() diff --git a/micropython/examples/pico_explorer/weatherstation_BME68X.py b/micropython/examples/pico_explorer/weatherstation_BME68X.py index 5040cb2d..19535746 100644 --- a/micropython/examples/pico_explorer/weatherstation_BME68X.py +++ b/micropython/examples/pico_explorer/weatherstation_BME68X.py @@ -7,68 +7,68 @@ from pimoroni_i2c import PimoroniI2C from pimoroni import PICO_EXPLORER_I2C_PINS # Pico Explorer boilerplate -import picoexplorer as display -width = display.get_width() -height = display.get_height() -display_buffer = bytearray(width * height * 2) -display.init(display_buffer) +import st7789 +display = st7789.ST7789(st7789.DISPLAY_PICO_EXPLORER, rotate=0) +display.set_palette_mode(st7789.PALETTE_USER) +display.set_backlight(1.0) i2c = PimoroniI2C(**PICO_EXPLORER_I2C_PINS) bme = BreakoutBME68X(i2c) # lets set up some pen colours to make drawing easier -tempcolour = display.create_pen(255, 255, 255) # this colour will get changed in a bit -white = display.create_pen(255, 255, 255) -black = display.create_pen(0, 0, 0) -red = display.create_pen(255, 0, 0) +TEMPCOLOUR = display.reserve_palette() # this colour will get changed in a bit +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) +RED = display.create_pen(255, 0, 0) +GREY = display.create_pen(125, 125, 125) # converts the temperature into a barometer-type description and pen colour def describe_temperature(temperature): - global tempcolour + global TEMPCOLOUR if temperature < 10: description = "very cold" - tempcolour = display.create_pen(0, 255, 255) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 255, 255)) elif 10 <= temperature < 20: description = "cold" - tempcolour = display.create_pen(0, 0, 255) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 0, 255)) elif 20 <= temperature < 25: description = "temperate" - tempcolour = display.create_pen(0, 255, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 255, 0)) elif 25 <= temperature < 30: description = "warm" - tempcolour = display.create_pen(255, 255, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(255, 255, 0)) elif temperature >= 30: description = "very warm" - tempcolour = display.create_pen(255, 0, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(255, 0, 0)) else: description = "" - tempcolour = display.create_pen(0, 0, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 0, 0)) return description # comment out the function above and uncomment this one for yorkshire mode """ def describe_temperature(temperature): - global tempcolour + global TEMPCOLOUR if temperature < 10: description = "frozzed" - tempcolour = display.create_pen(0, 255, 255) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 255, 255)) elif 10 <= temperature < 20: description = "nithering" - tempcolour = display.create_pen(0, 0, 255) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 0, 255)) elif 20 <= temperature < 25: description = "fair t' middlin" - tempcolour = display.create_pen(0, 255, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 255, 0)) elif 25 <= temperature < 30: description = "chuffing warm" - tempcolour = display.create_pen(255, 255, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(255, 255, 0)) elif temperature >= 30: description = "crackin t' flags" - tempcolour = display.create_pen(255, 0, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(255, 0, 0)) else: description = "" - tempcolour = display.create_pen(0, 0, 0) + display.set_palette(TEMPCOLOUR, st7789.RGB565(0, 0, 0)) return description """ @@ -100,6 +100,9 @@ def describe_humidity(humidity): while True: + display.set_pen(BLACK) + display.clear() + # read the sensors temperature, pressure, humidity, gas_resistance, status, gas_index, meas_index = bme.read() @@ -107,12 +110,12 @@ while True: pressurehpa = pressure / 100 # draw a thermometer/barometer thingy - display.set_pen(125, 125, 125) + display.set_pen(GREY) display.circle(190, 190, 40) display.rectangle(180, 45, 20, 140) # switch to red to draw the 'mercury' - display.set_pen(red) + display.set_pen(RED) display.circle(190, 190, 30) thermometerheight = int(120 / 30 * temperature) if thermometerheight > 120: @@ -122,11 +125,11 @@ while True: display.rectangle(186, 50 + 120 - thermometerheight, 10, thermometerheight) # drawing the temperature text - display.set_pen(white) + display.set_pen(WHITE) display.text("temperature:", 10, 10, 240, 3) - display.set_pen(tempcolour) + display.set_pen(TEMPCOLOUR) display.text('{:.1f}'.format(temperature) + 'C', 10, 30, 240, 5) - display.set_pen(white) + display.set_pen(WHITE) display.text(describe_temperature(temperature), 10, 60, 240, 3) # and the pressure text @@ -142,7 +145,5 @@ while True: # time to update the display display.update() - # waits for 1 second and clears to black + # waits for 1 second and clears to BLACK utime.sleep(1) - display.set_pen(black) - display.clear() From 9b8d215cd3a62b7357ac28daa362a45fdabfd81a Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 21:26:17 +0100 Subject: [PATCH 16/84] ST7789/PicoGraphics: Update C++ libs and examples. --- examples/breakout_colourlcd240x240/demo.cpp | 2 +- examples/breakout_roundlcd/demo.cpp | 2 +- examples/pico_display/demo.cpp | 6 +- examples/pico_display_2/demo.cpp | 6 +- examples/tufty2040/tufty2040_drawing.cpp | 23 +++--- .../breakout_roundlcd/breakout_roundlcd.cmake | 2 +- .../breakout_roundlcd/breakout_roundlcd.cpp | 11 +-- libraries/generic_st7789/README.md | 22 +++--- libraries/pico_display/pico_display.cpp | 8 +- libraries/pico_explorer/pico_explorer.cpp | 9 ++- libraries/pico_graphics/README.md | 75 ++++++++++++++++--- libraries/pico_graphics/pico_graphics.cpp | 7 +- libraries/pico_graphics/pico_graphics.hpp | 3 + 13 files changed, 117 insertions(+), 59 deletions(-) diff --git a/examples/breakout_colourlcd240x240/demo.cpp b/examples/breakout_colourlcd240x240/demo.cpp index 2fd5ca6b..02a0b45c 100644 --- a/examples/breakout_colourlcd240x240/demo.cpp +++ b/examples/breakout_colourlcd240x240/demo.cpp @@ -8,7 +8,7 @@ using namespace pimoroni; const int WIDTH = 240; const int HEIGHT = 240; -ST7789Generic lcd(WIDTH, HEIGHT, false, nullptr, BG_SPI_FRONT); +ST7789Generic display(WIDTH, HEIGHT, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); int main() { //lcd.configure_display(false); diff --git a/examples/breakout_roundlcd/demo.cpp b/examples/breakout_roundlcd/demo.cpp index 14edf18a..b6bb0d0f 100644 --- a/examples/breakout_roundlcd/demo.cpp +++ b/examples/breakout_roundlcd/demo.cpp @@ -14,7 +14,7 @@ using namespace pimoroni; const int WIDTH = 240; const int HEIGHT = 240; -ST7789Generic display(WIDTH, HEIGHT, true, nullptr, BG_SPI_FRONT); +ST7789Generic display(WIDTH, HEIGHT, ROTATE_0, true, nullptr, get_spi_pins(BG_SPI_FRONT)); constexpr float RADIUS = WIDTH / 2; diff --git a/examples/pico_display/demo.cpp b/examples/pico_display/demo.cpp index 34a69d2f..3c1b2aeb 100644 --- a/examples/pico_display/demo.cpp +++ b/examples/pico_display/demo.cpp @@ -9,16 +9,12 @@ using namespace pimoroni; -const bool ROTATE_180 = false; - -// Swap WIDTH and HEIGHT to rotate 90 degrees -ST7789Generic pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT); +ST7789Generic pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0); RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); int main() { - pico_display.configure_display(ROTATE_180); pico_display.set_backlight(100); struct pt { diff --git a/examples/pico_display_2/demo.cpp b/examples/pico_display_2/demo.cpp index b39fa4b2..b53f84bc 100644 --- a/examples/pico_display_2/demo.cpp +++ b/examples/pico_display_2/demo.cpp @@ -10,10 +10,7 @@ using namespace pimoroni; -const bool ROTATE_180 = false; - -// Swap WIDTH and HEIGHT to rotate 90 degrees -ST7789Generic pico_display(240, 240); +ST7789Generic pico_display(240, 240, ROTATE_0); RGBLED led(PicoDisplay2::LED_R, PicoDisplay2::LED_G, PicoDisplay2::LED_B); @@ -43,7 +40,6 @@ void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { } int main() { - pico_display.configure_display(ROTATE_180); pico_display.set_backlight(255); struct pt { diff --git a/examples/tufty2040/tufty2040_drawing.cpp b/examples/tufty2040/tufty2040_drawing.cpp index 687df518..a4bbb99a 100644 --- a/examples/tufty2040/tufty2040_drawing.cpp +++ b/examples/tufty2040/tufty2040_drawing.cpp @@ -15,22 +15,17 @@ using namespace pimoroni; Tufty2040 tufty; -uint16_t buffer[Tufty2040::WIDTH * Tufty2040::HEIGHT]; - - static const uint8_t LCD_CS = 10; - static const uint8_t LCD_DC = 11; - static const uint8_t LCD_WR = 12; - static const uint8_t LCD_RD = 13; - static const uint8_t LCD_D0 = 14; - - - // Swap WIDTH and HEIGHT to rotate 90 degrees ST7789Generic pico_display( - Tufty2040::WIDTH, Tufty2040::HEIGHT, - buffer, - Tufty2040::LCD_CS, Tufty2040::LCD_DC, Tufty2040::LCD_WR, Tufty2040::LCD_RD, Tufty2040::LCD_D0, - Tufty2040::BACKLIGHT + Tufty2040::WIDTH, Tufty2040::HEIGHT, ROTATE_0, nullptr, + ParallelPins{ + Tufty2040::LCD_CS, + Tufty2040::LCD_DC, + Tufty2040::LCD_WR, + Tufty2040::LCD_RD, + Tufty2040::LCD_D0, + Tufty2040::BACKLIGHT + } ); Button button_a(Tufty2040::A); diff --git a/libraries/breakout_roundlcd/breakout_roundlcd.cmake b/libraries/breakout_roundlcd/breakout_roundlcd.cmake index aa0d5718..b4a2c5ec 100644 --- a/libraries/breakout_roundlcd/breakout_roundlcd.cmake +++ b/libraries/breakout_roundlcd/breakout_roundlcd.cmake @@ -11,4 +11,4 @@ target_sources(${LIB_NAME} INTERFACE target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib st7789 pico_graphics) \ No newline at end of file +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib st7789 pimoroni_bus pico_graphics) \ No newline at end of file diff --git a/libraries/breakout_roundlcd/breakout_roundlcd.cpp b/libraries/breakout_roundlcd/breakout_roundlcd.cpp index d398f2cc..3684d3d2 100644 --- a/libraries/breakout_roundlcd/breakout_roundlcd.cpp +++ b/libraries/breakout_roundlcd/breakout_roundlcd.cpp @@ -3,20 +3,21 @@ namespace pimoroni { BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, true, buf, - PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { + : PicoGraphics(WIDTH, HEIGHT, buf), + screen(WIDTH, HEIGHT, ROTATE_0, true, buf, get_spi_pins(BG_SPI_FRONT)) { __fb = buf; } BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf, spi_inst_t *spi, uint cs, uint dc, uint sck, uint mosi, uint bl) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, true, buf, spi, cs, dc, sck, mosi, bl) { + : PicoGraphics(WIDTH, HEIGHT, buf), + screen(WIDTH, HEIGHT, ROTATE_0, true, buf, SPIPins{spi, cs sck, mosi, dc, bl}) { __fb = buf; } BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf, BG_SPI_SLOT slot) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, true, buf, - PIMORONI_SPI_DEFAULT_INSTANCE, screen.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, screen.get_slot_bl(slot)) { + : PicoGraphics(WIDTH, HEIGHT, buf), + screen(WIDTH, HEIGHT, ROTATE_0, true, buf, get_spi_pins(slot)) { { __fb = buf; } diff --git a/libraries/generic_st7789/README.md b/libraries/generic_st7789/README.md index 48268841..6a4fe4c6 100644 --- a/libraries/generic_st7789/README.md +++ b/libraries/generic_st7789/README.md @@ -22,12 +22,8 @@ The following example sets up Pico Display, displays some basic demo text and gr using namespace pimoroni; -const bool ROTATE_180 = false; - -uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT]; - // Swap WIDTH and HEIGHT to rotate 90 degrees -ST7789Generic pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, buffer); +ST7789Generic pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0); // RGB LED controller RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); @@ -39,12 +35,17 @@ Button button_x(PicoDisplay::X); Button button_y(PicoDisplay::Y); int main() { - pico_display.configure_display(ROTATE_180); - // set the backlight to a value between 0 and 255 // the backlight is driven via PWM and is gamma corrected by our // library to give a gorgeous linear brightness range. pico_display.set_backlight(100); + + // Create pens for the colours we want to use + // parameters are red, green, blue all between 0 and 255 + // By default these are crushed to RGB332 so only the upper bits of each are used! + int BG_COLOR = pico_display.create_pen(30, 40, 50); + int BOX_COLOR = pico_display.create_pen(10, 20, 30); + int TEXT_COLOR = pico_display.create_pen(110, 120, 130); while(true) { // detect if the A button is pressed (could be A, B, X, or Y) @@ -56,21 +57,20 @@ int main() { } // set the colour of the pen - // parameters are red, green, blue all between 0 and 255 - pico_display.set_pen(30, 40, 50); + pico_display.set_pen(BG_COLOR); // fill the screen with the current pen colour pico_display.clear(); // draw a box to put some text in - pico_display.set_pen(10, 20, 30); + pico_display.set_pen(BOX_COLOR); Rect text_rect(10, 10, 150, 150); pico_display.rectangle(text_rect); // write some text inside the box with 10 pixels of margin // automatically word wrapping text_rect.deflate(10); - pico_display.set_pen(110, 120, 130); + pico_display.set_pen(TEXT_COLOR); pico_display.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w); // now we've done our drawing let's update the screen diff --git a/libraries/pico_display/pico_display.cpp b/libraries/pico_display/pico_display.cpp index 4b5cee47..f9f635da 100644 --- a/libraries/pico_display/pico_display.cpp +++ b/libraries/pico_display/pico_display.cpp @@ -9,14 +9,14 @@ namespace pimoroni { PicoDisplay::PicoDisplay(void *buf) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, - PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { + : PicoGraphics(WIDTH, HEIGHT, buf), + screen(WIDTH, HEIGHT, ROTATE_0, false, buf, get_spi_pins(BG_SPI_FRONT)) { __fb = buf; } PicoDisplay::PicoDisplay(void *buf, int width, int height) - : PicoGraphics(width, height, buf), screen(width, height, false, buf, - PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { + : PicoGraphics(width, height, buf), + screen(width, height, ROTATE_0, false, buf, get_spi_pins(BG_SPI_FRONT)) { __fb = buf; } diff --git a/libraries/pico_explorer/pico_explorer.cpp b/libraries/pico_explorer/pico_explorer.cpp index 946935a2..ccd07c69 100644 --- a/libraries/pico_explorer/pico_explorer.cpp +++ b/libraries/pico_explorer/pico_explorer.cpp @@ -15,8 +15,8 @@ const uint8_t MOTOR2P = 11; namespace pimoroni { PicoExplorer::PicoExplorer(void *buf) - : PicoGraphics(WIDTH, HEIGHT, buf), - screen(WIDTH, HEIGHT, false, buf, PIMORONI_SPI_DEFAULT_INSTANCE, screen.get_slot_cs(PICO_EXPLORER_ONBOARD), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, screen.get_slot_bl(PICO_EXPLORER_ONBOARD)) { + : PicoGraphics(WIDTH, HEIGHT, buf), + screen(WIDTH, HEIGHT, ROTATE_0, false, buf, get_spi_pins(PICO_EXPLORER_ONBOARD)) { __fb = buf; } @@ -55,10 +55,12 @@ namespace pimoroni { screen.update(palette); } + [[deprecated("Use Button(uint pin).")]] bool PicoExplorer::is_pressed(uint8_t button) { return !gpio_get(button); } + [[deprecated("Use Analog(uint pin).")]] float PicoExplorer::get_adc(uint8_t channel) { adc_select_input(channel); // scale raw 12-bit adc value to 0 .. 1 float @@ -68,6 +70,7 @@ namespace pimoroni { return result; } + [[deprecated("Use Motor(pin_pair pins).")]] void PicoExplorer::set_motor(uint8_t channel, uint8_t action, float speed) { uint8_t p = channel == MOTOR1 ? MOTOR1P : MOTOR2P; uint8_t n = channel == MOTOR1 ? MOTOR1N : MOTOR2N; @@ -93,6 +96,7 @@ namespace pimoroni { } } + [[deprecated("Use Buzzer(uint pin).")]] void PicoExplorer::set_audio_pin(uint pin) { pwm_config tone_pwm_cfg = pwm_get_default_config(); @@ -105,6 +109,7 @@ namespace pimoroni { audio_pin = pin; } + [[deprecated("Use Buzzer(uint pin).set_tone().")]] void PicoExplorer::set_tone(uint16_t frequency, float duty) { // output a square wave, so 50% duty cycle if(audio_pin != -1) { diff --git a/libraries/pico_graphics/README.md b/libraries/pico_graphics/README.md index 0fd70c3b..e2e74f2d 100644 --- a/libraries/pico_graphics/README.md +++ b/libraries/pico_graphics/README.md @@ -19,6 +19,11 @@ It supports drawing text, primitive and individual pixels and includes basic typ - [set_pen](#set_pen) - [create_pen](#create_pen) - [set_clip & remove_clip](#set_clip--remove_clip) + - [Palette](#palette) + - [set_palette_mode](#set_palette_mode) + - [reserve_palette](#reserve_palette) + - [set_palette](#set_palette) + - [RGB565 and RGB332](#rgb565-and-rgb332) - [Pixels](#pixels) - [pixel](#pixel) - [pixel_span](#pixel_span) @@ -123,9 +128,10 @@ Would deflate our `box` to start at `11,11` and be 8x8 pixels in size. Since `rectangle` *always* draws a filled rectangle, this can be useful to add an outline of your desired thickness: ```c++ +WHITE = screen.create_pen(255, 255, 255); rect box(10, 10, 100, 100); box.inflate(1); // Inflate our box by 1px on all sides -screen.set_pen(255, 255, 255); // White outline +screen.set_pen(WHITE); // White outline screen.rectangle(box); box.deflate(1); // Return to our original box size screen.set_pen(0, 0, 0); /// Black fill @@ -157,26 +163,24 @@ TODO #### set_pen -In order to draw anything with Pico Graphics you must first set the pen to your desired colour, there are two ways to do this: +In order to draw anything with Pico Graphics you must first set the pen to your desired palette colour: ```c++ -void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b); -void PicoGraphics::set_pen(uint16_t p); +void PicoGraphics::set_pen(uint8_t p); ``` -The former uses 8-bit R, G and B values which are clipped to 5, 6 and 5 bits respectively to form a 16-bit colour. Internally it uses `create_pen`. +This value represents an index into the internal colour palette, which has 256 entries and defaults to RGB332 giving an approximation of all RGB888 colours. -The latter takes a 16-bit colour directly and is a great way to save a few cycles if you're working with a constant palette of colours. #### create_pen ```c++ -uint16_t PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b); +int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b); ``` -Create pen takes R, G and B values, clamps them to 5, 6 and 5 bits respectively and joins them into a `uint16_t` pen that represents a single 16-bit colour. +By default create pen takes R, G and B values, clamps them to 3, 3 and 2 bits respectively and returns an index in the RGB332 palette. -Creating your pens up front and storing them as `uint16_t` can speed up switching colours. +You must create pens before using them with `set_pen()` which accepts only a palette index. #### set_clip & remove_clip @@ -189,6 +193,59 @@ void PicoGraphics::remove_clip(); `remove_clip` sets the surface clipping rectangle back to the surface `bounds`. +### Palette + +By default Pico Graphics uses an `RGB332` palette and clamps all pens to their `RGB332` values so it can give you an approximate colour for every `RGB888` value you request. If you don't want to think about colours and palettes you can leave it as is. + +Alternatively `set_palette_mode()` lets you switch into an RGB565 `USER` palette which gives you up to 256 16-bit colours of your choice. + +#### set_palette_mode + +```c++ +void PicoGraphics::set_palette_mode(PALETTE_USER); +``` + +Clears the default `RGB332` palette and switches into `USER` mode. + +Pens created with `create_pen()` will use 16-bit `RGB565` resolution and you have up to 256 palette entries to use. + +```c++ +void PicoGraphics::set_palette_mode(PALETTE_RGB332); +``` + +Clears any `USER` assigned palettes and returns to `RGB332` mode. + +#### reserve_palette + +```c++ +int PicoGraphics::reserve_palette(); +``` + +Marks the first empty palette entry as reserved and return its index. + + +#### set_palette + +```c++ +void PicoGraphics::set_palette(uint8_t index, RGB565 color); +``` + +#### RGB565 and RGB332 + +```c++ +int RGB565(uint8_t r, uint8_t g, uint8_t b); +``` + +Creates and returns an RGB565 colour, using the five/six/five most significant bits of each channel in turn. + +```c++ +int RGB332(uint8_t, uint8_t g, uint8_t b); +``` + +Creates and returns an RGB565 colour, using the three/three/two most significant bits of each channel in turn. + +IE: This clips the colour to RGB332. + ### Pixels #### pixel diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 340e42ab..96f6a0e2 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -35,6 +35,11 @@ namespace pimoroni { return result; } + void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) { + int result = create_pen(r, g, b); + (void)result; + } + int PicoGraphics::search_palette(RGB565 c) { for(auto i = 0u; i < 256; i++) { if((palette_status[i] & PaletteStatusUsed) && palette[i] == c) return i; @@ -53,7 +58,7 @@ namespace pimoroni { return -1; } - void PicoGraphics::set_palette(uint8_t i, uint16_t c) { + void PicoGraphics::set_palette(uint8_t i, RGB565 c) { palette[i] = c; palette_status[i] |= PaletteStatusUsed; } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index de051668..f2ee6249 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -76,6 +76,9 @@ namespace pimoroni { void set_pen(Pen p); void set_palette_mode(PaletteMode mode); + [[deprecated("Use uint8_t create_pen(uint8_t, uint8_t, uint8_t).")]] + void set_pen(uint8_t r, uint8_t g, uint8_t b); + static constexpr RGB565 create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) { uint16_t p = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | From cf842d559ead09af09654447077976deb1ca529a Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 21:39:49 +0100 Subject: [PATCH 17/84] Badger2040: Remove deprecated modules. --- micropython/modules/badger2040-micropython.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/micropython/modules/badger2040-micropython.cmake b/micropython/modules/badger2040-micropython.cmake index 3849e2ea..5b3aae32 100644 --- a/micropython/modules/badger2040-micropython.cmake +++ b/micropython/modules/badger2040-micropython.cmake @@ -4,6 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") include(pimoroni_i2c/micropython) +include(pimoroni_bus/micropython) include(breakout_dotmatrix/micropython) include(breakout_encoder/micropython) @@ -11,7 +12,7 @@ include(breakout_ioexpander/micropython) include(breakout_ltr559/micropython) include(breakout_colourlcd160x80/micropython) include(breakout_as7262/micropython) -include(breakout_roundlcd/micropython) +#include(breakout_roundlcd/micropython) # replaced with Generic ST7789 include(breakout_rgbmatrix5x5/micropython) include(breakout_matrix11x7/micropython) include(breakout_msa301/micropython) @@ -21,7 +22,7 @@ include(breakout_potentiometer/micropython) include(breakout_rtc/micropython) include(breakout_trackball/micropython) include(breakout_sgp30/micropython) -include(breakout_colourlcd240x240/micropython) +# include(breakout_colourlcd240x240/micropython) # replaced with Generic ST7789 include(breakout_bh1745/micropython) include(breakout_bme68x/micropython) include(breakout_bme280/micropython) From 38efc7de62d6685dd211fda1043ae92ec9c73429 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 21:40:02 +0100 Subject: [PATCH 18/84] MicroPython: Fix pimoroni.py --- micropython/modules_py/pimoroni.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/micropython/modules_py/pimoroni.py b/micropython/modules_py/pimoroni.py index 75074f16..0e513e51 100644 --- a/micropython/modules_py/pimoroni.py +++ b/micropython/modules_py/pimoroni.py @@ -187,12 +187,12 @@ class PID: class Buzzer: def __init__(self, pin): self.pwm = PWM(Pin(pin)) - - def set_tone(self, hz): - if hz is None or hz <= 8: # None or <=8 to stop + + def set_tone(self, freq, duty=0.5): + if freq < 50.0: # uh... https://github.com/micropython/micropython/blob/af64c2ddbd758ab6bac0fcca94c66d89046663be/ports/rp2/machine_pwm.c#L105-L119 self.pwm.duty_u16(0) return False - self.pwm.freq(hz) - self.pwm.duty_u16(1 << 15) - return True \ No newline at end of file + self.pwm.freq(freq) + self.pwm.duty_u16(int(65535 * duty)) + return True From 13f0813d8a56d51372e2b5b17a296a1d54c0313a Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sat, 28 May 2022 23:00:43 +0100 Subject: [PATCH 19/84] ST7789/PicoDisplay: Collapse make_new into one using pimoroni_bus. --- common/pimoroni_bus.cpp | 8 +- common/pimoroni_bus.hpp | 1 + common/pimoroni_common.hpp | 1 + drivers/st7789/st7789.hpp | 2 +- .../breakout_roundlcd/breakout_roundlcd.cpp | 2 +- .../modules/pimoroni_bus/micropython.cmake | 5 +- .../modules/pimoroni_bus/pimoroni_bus.c | 37 +++++ .../modules/pimoroni_bus/pimoroni_bus.cpp | 114 ++++++++++++++ .../modules/pimoroni_bus/pimoroni_bus.h | 15 ++ micropython/modules/st7789/st7789.c | 16 -- micropython/modules/st7789/st7789.cpp | 148 ++---------------- 11 files changed, 194 insertions(+), 155 deletions(-) create mode 100644 micropython/modules/pimoroni_bus/pimoroni_bus.c create mode 100644 micropython/modules/pimoroni_bus/pimoroni_bus.cpp create mode 100644 micropython/modules/pimoroni_bus/pimoroni_bus.h diff --git a/common/pimoroni_bus.cpp b/common/pimoroni_bus.cpp index 794ba973..d6c7eac1 100644 --- a/common/pimoroni_bus.cpp +++ b/common/pimoroni_bus.cpp @@ -4,12 +4,12 @@ namespace pimoroni { SPIPins get_spi_pins(BG_SPI_SLOT slot) { switch(slot) { case PICO_EXPLORER_ONBOARD: - return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, PIN_UNUSED}; + return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, SPI_DEFAULT_DC, PIN_UNUSED}; case BG_SPI_FRONT: - return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, SPI_BG_FRONT_PWM}; + return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, SPI_DEFAULT_DC, SPI_BG_FRONT_PWM}; case BG_SPI_BACK: - return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_BACK_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, SPI_BG_BACK_PWM}; + return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_BACK_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, SPI_DEFAULT_DC, SPI_BG_BACK_PWM}; } - return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_DEFAULT_MISO, SPI_BG_FRONT_PWM}; + return {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, SPI_DEFAULT_DC, SPI_BG_FRONT_PWM}; }; } \ No newline at end of file diff --git a/common/pimoroni_bus.hpp b/common/pimoroni_bus.hpp index eafecc19..8a9d400b 100644 --- a/common/pimoroni_bus.hpp +++ b/common/pimoroni_bus.hpp @@ -10,6 +10,7 @@ namespace pimoroni { uint sck; uint mosi; uint miso; + uint dc; uint bl; }; diff --git a/common/pimoroni_common.hpp b/common/pimoroni_common.hpp index 90c949b2..6300a3ac 100644 --- a/common/pimoroni_common.hpp +++ b/common/pimoroni_common.hpp @@ -32,6 +32,7 @@ namespace pimoroni { // SPI static const unsigned int SPI_DEFAULT_MOSI = 19; static const unsigned int SPI_DEFAULT_MISO = 16; + static const unsigned int SPI_DEFAULT_DC = 16; static const unsigned int SPI_DEFAULT_SCK = 18; static const unsigned int SPI_BG_FRONT_PWM = 20; diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index 1effcb41..228dc1f1 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -71,7 +71,7 @@ namespace pimoroni { ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins pins) : spi(pins.spi), width(width), height(height), rotation(rotation), round(round), - cs(pins.cs), dc(pins.miso), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl), frame_buffer(frame_buffer) { + cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl), frame_buffer(frame_buffer) { // configure spi interface and pins spi_init(spi, SPI_BAUD); diff --git a/libraries/breakout_roundlcd/breakout_roundlcd.cpp b/libraries/breakout_roundlcd/breakout_roundlcd.cpp index 3684d3d2..c46f8cbb 100644 --- a/libraries/breakout_roundlcd/breakout_roundlcd.cpp +++ b/libraries/breakout_roundlcd/breakout_roundlcd.cpp @@ -11,7 +11,7 @@ namespace pimoroni { BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf, spi_inst_t *spi, uint cs, uint dc, uint sck, uint mosi, uint bl) : PicoGraphics(WIDTH, HEIGHT, buf), - screen(WIDTH, HEIGHT, ROTATE_0, true, buf, SPIPins{spi, cs sck, mosi, dc, bl}) { + screen(WIDTH, HEIGHT, ROTATE_0, true, buf, SPIPins{spi, cs sck, mosi, PIN_UNUSED, dc, bl}) { __fb = buf; } diff --git a/micropython/modules/pimoroni_bus/micropython.cmake b/micropython/modules/pimoroni_bus/micropython.cmake index c9eb1aba..eec58f1a 100644 --- a/micropython/modules/pimoroni_bus/micropython.cmake +++ b/micropython/modules/pimoroni_bus/micropython.cmake @@ -3,13 +3,14 @@ string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) add_library(usermod_${MOD_NAME} INTERFACE) target_sources(usermod_${MOD_NAME} INTERFACE - #${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c - #${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../common/pimoroni_bus.cpp ) target_include_directories(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/../../../common/ ) target_compile_definitions(usermod_${MOD_NAME} INTERFACE diff --git a/micropython/modules/pimoroni_bus/pimoroni_bus.c b/micropython/modules/pimoroni_bus/pimoroni_bus.c new file mode 100644 index 00000000..8a608ba1 --- /dev/null +++ b/micropython/modules/pimoroni_bus/pimoroni_bus.c @@ -0,0 +1,37 @@ +#include "pimoroni_bus.h" + +const mp_obj_type_t SPISlot_type = { + { &mp_type_type }, + .name = MP_QSTR_SPISlot, + .print = PimoroniBus_print, + .make_new = SPISlot_make_new +}; + +const mp_obj_type_t SPIPins_type = { + { &mp_type_type }, + .name = MP_QSTR_SPIBus, + .print = PimoroniBus_print, + .make_new = SPIPins_make_new +}; + +const mp_obj_type_t ParallelPins_type = { + { &mp_type_type }, + .name = MP_QSTR_ParallelBus, + .print = PimoroniBus_print, + .make_new = ParallelPins_make_new +}; + +STATIC const mp_map_elem_t pimoroni_bus_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pimoroni_bus) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SPIBus), (mp_obj_t)&SPIPins_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SPISlot), (mp_obj_t)&SPISlot_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ParallelBus), (mp_obj_t)&ParallelPins_type }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_pimoroni_bus_globals, pimoroni_bus_globals_table); + +const mp_obj_module_t pimoroni_bus_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_pimoroni_bus_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_pimoroni_bus, pimoroni_bus_user_cmodule, MODULE_PIMORONI_BUS_ENABLED); \ No newline at end of file diff --git a/micropython/modules/pimoroni_bus/pimoroni_bus.cpp b/micropython/modules/pimoroni_bus/pimoroni_bus.cpp new file mode 100644 index 00000000..170fd72e --- /dev/null +++ b/micropython/modules/pimoroni_bus/pimoroni_bus.cpp @@ -0,0 +1,114 @@ +#include "common/pimoroni_bus.hpp" +#include "micropython/modules/util.hpp" +#include + +using namespace pimoroni; + +extern "C" { +#include "pimoroni_bus.h" +#include "py/mperrno.h" + +void PimoroniBus_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + _PimoroniBus_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PimoroniBus_obj_t); + if(self->base.type == &SPIPins_type) { + mp_print_str(print, "SPIBus()"); + } else { + mp_print_str(print, "ParallelBus()"); + } + (void)kind; +} + +mp_obj_t SPIPins_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_cs, MP_ARG_INT, {.u_int = SPI_BG_FRONT_CS} }, + { MP_QSTR_dc, MP_ARG_INT, {.u_int = SPI_DEFAULT_MISO} }, + { MP_QSTR_sck, MP_ARG_INT, {.u_int = SPI_DEFAULT_SCK} }, + { MP_QSTR_mosi, MP_ARG_INT, {.u_int = SPI_DEFAULT_MOSI} }, + { MP_QSTR_bl, MP_ARG_INT, {.u_int = SPI_BG_FRONT_PWM} }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _PimoroniBus_obj_t *self = m_new_obj(_PimoroniBus_obj_t); + self->base.type = &SPIPins_type; + self->pins = m_new(SPIPins, 1); + + SPIPins *pins = (SPIPins *)self->pins; + + pins->spi = ((args[ARG_sck].u_int >> 3) & 0b1) == 0 ? spi0 : spi1; + pins->cs = (uint)args[ARG_cs].u_int; + pins->sck = (uint)args[ARG_sck].u_int; + pins->mosi = (uint)args[ARG_mosi].u_int; + pins->miso = PIN_UNUSED; + pins->dc = (uint)args[ARG_dc].u_int; + pins->bl = args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int; + + return MP_OBJ_FROM_PTR(self); +} + +mp_obj_t SPISlot_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_slot }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_slot, MP_ARG_INT | MP_ARG_REQUIRED }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _PimoroniBus_obj_t *self = m_new_obj(_PimoroniBus_obj_t); + self->base.type = &SPIPins_type; + //self->pins = m_new(SPIPins, 1); + + //SPIPins *pins = (SPIPins *)self->pins; + + SPIPins slot_pins = get_spi_pins((BG_SPI_SLOT)args[ARG_slot].u_int); + + self->pins = new(m_new(SPIPins, 1)) SPIPins(slot_pins); + + /* pins->spi = slot_pins.spi; + pins->cs = slot_pins.cs; + pins->sck = slot_pins.sck; + pins->mosi = slot_pins.mosi; + pins->miso = slot_pins.miso; + pins->dc = slot_pins.dc; + pins->bl = slot_pins.bl;*/ + + return MP_OBJ_FROM_PTR(self); +} + +mp_obj_t ParallelPins_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_cs, ARG_dc, ARG_wr_sck, ARG_rd_sck, ARG_d0, ARG_bl }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_cs, MP_ARG_INT, {.u_int = 10} }, + { MP_QSTR_dc, MP_ARG_INT, {.u_int = 11} }, + { MP_QSTR_wr_sck, MP_ARG_INT, {.u_int = 12} }, + { MP_QSTR_rd_sck, MP_ARG_INT, {.u_int = 13} }, + { MP_QSTR_d0, MP_ARG_INT, {.u_int = 14} }, + { MP_QSTR_bl, MP_ARG_INT, {.u_int = 2} }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _PimoroniBus_obj_t *self = m_new_obj(_PimoroniBus_obj_t); + self->base.type = &ParallelPins_type; + self->pins = m_new(ParallelPins, 1); + + ParallelPins *pins = (ParallelPins *)self->pins; + + pins->cs = (uint)args[ARG_cs].u_int; + pins->dc = (uint)args[ARG_dc].u_int; + pins->wr_sck = (uint)args[ARG_wr_sck].u_int; + pins->rd_sck = (uint)args[ARG_rd_sck].u_int; + pins->d0 = (uint)args[ARG_d0].u_int; + pins->bl = args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int; + + return MP_OBJ_FROM_PTR(self); +} + +} \ No newline at end of file diff --git a/micropython/modules/pimoroni_bus/pimoroni_bus.h b/micropython/modules/pimoroni_bus/pimoroni_bus.h new file mode 100644 index 00000000..1ab4413b --- /dev/null +++ b/micropython/modules/pimoroni_bus/pimoroni_bus.h @@ -0,0 +1,15 @@ +#include "py/runtime.h" +#include "hardware/spi.h" + +extern const mp_obj_type_t SPIPins_type; +extern const mp_obj_type_t ParallelPins_type; + +typedef struct _PimoroniBus_obj_t { + mp_obj_base_t base; + void *pins; +} _PimoroniBus_obj_t; + +extern void PimoroniBus_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +extern mp_obj_t SPIPins_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 SPISlot_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 ParallelPins_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); \ No newline at end of file diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index bdfff890..243cf10b 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -73,26 +73,10 @@ const mp_obj_type_t GenericST7789_type = { .locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict, }; -const mp_obj_type_t GenericST7789Parallel_type = { - { &mp_type_type }, - .name = MP_QSTR_st7789, - .make_new = GenericST7789Parallel_make_new, - .locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict, -}; - -const mp_obj_type_t GenericST7789SPI_type = { - { &mp_type_type }, - .name = MP_QSTR_st7789, - .make_new = GenericST7789SPI_make_new, - .locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict, -}; - /***** Module Globals *****/ STATIC const mp_map_elem_t st7789_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) }, { MP_ROM_QSTR(MP_QSTR_ST7789), (mp_obj_t)&GenericST7789_type }, - { MP_ROM_QSTR(MP_QSTR_ST7789Parallel), (mp_obj_t)&GenericST7789Parallel_type }, - { MP_ROM_QSTR(MP_QSTR_ST7789SPI), (mp_obj_t)&GenericST7789Parallel_type }, { MP_ROM_QSTR(MP_QSTR_RGB332), MP_ROM_PTR(&GenericST7789_module_RGB332_obj) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&GenericST7789_module_RGB565_obj) }, diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 25dcaa8b..0e7efb34 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -10,6 +10,7 @@ using namespace pimoroni; extern "C" { #include "st7789.h" +#include "micropython/modules/pimoroni_bus/pimoroni_bus.h" enum ST7789Display { DISPLAY_LCD_240X240=0, @@ -30,11 +31,11 @@ typedef struct _GenericST7789_obj_t { mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { GenericST7789_obj_t *self = nullptr; - enum { ARG_display, ARG_rotate, ARG_slot, ARG_buffer }; + enum { ARG_display, ARG_rotate, ARG_bus, ARG_buffer }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display, MP_ARG_INT | MP_ARG_REQUIRED }, { MP_QSTR_rotate, MP_ARG_INT, { .u_int = Rotation::ROTATE_0 } }, - { MP_QSTR_slot, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_bus, MP_ARG_OBJ, { .u_obj = mp_const_none } }, { MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, }; @@ -86,141 +87,26 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t self->buffer = m_new(uint8_t, width * height * sizeof(Pen)); } - if (display == DISPLAY_TUFTY_2040) { - self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); - } else { - BG_SPI_SLOT slot = (BG_SPI_SLOT)args[ARG_slot].u_int; - self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, get_spi_pins(slot)); - } - - return MP_OBJ_FROM_PTR(self); -} - -mp_obj_t GenericST7789SPI_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - GenericST7789_obj_t *self = nullptr; - - enum { ARG_width, ARG_height, ARG_rotate, ARG_round, ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_rotate, MP_ARG_INT, {.u_int = Rotation::ROTATE_0} }, - { MP_QSTR_round, MP_ARG_OBJ, {.u_obj = mp_const_false} }, - { MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_spi, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_cs, MP_ARG_INT, {.u_int = pimoroni::SPI_BG_FRONT_CS} }, - { MP_QSTR_dc, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_MISO} }, - { MP_QSTR_sck, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_SCK} }, - { MP_QSTR_mosi, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_MOSI} }, - { MP_QSTR_bl, MP_ARG_INT, {.u_int = pimoroni::SPI_BG_FRONT_PWM} }, - }; - - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - self = m_new_obj(GenericST7789_obj_t); - self->base.type = &GenericST7789_type; - - bool round = args[ARG_round].u_obj == mp_const_true; - Rotation rotate = (Rotation)args[ARG_rotate].u_int; - int width = args[ARG_width].u_int; - int height = args[ARG_height].u_int; - - if (args[ARG_buffer].u_obj != mp_const_none) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - self->buffer = bufinfo.buf; - if(bufinfo.len < (size_t)(width * height * sizeof(Pen))) { - mp_raise_ValueError("Supplied buffer is too small!"); + if (args[ARG_bus].u_obj == mp_const_none) { + self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); + } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) { + _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); + self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins)); + } else { + mp_raise_ValueError("ParallelBus expected!"); } } else { - self->buffer = m_new(uint8_t, width * height * sizeof(Pen)); - } - - int spi_id = args[ARG_spi].u_int; - - // Get SPI bus. - SPIPins bus_pins = { - nullptr, - (uint)args[ARG_cs].u_int, - (uint)args[ARG_sck].u_int, - (uint)args[ARG_mosi].u_int, - (uint)args[ARG_dc].u_int, - args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int - }; - - if(spi_id == -1) { - spi_id = (bus_pins.sck >> 3) & 0b1; // If no spi specified, choose the one for the given SCK pin - } - if(spi_id < 0 || spi_id > 1) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id); - } - - if(!IS_VALID_SCK(spi_id, (int)bus_pins.sck)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin")); - } - - if(!IS_VALID_MOSI(spi_id, (int)bus_pins.mosi)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin")); - } - - bus_pins.spi = (spi_id == 0) ? spi0 : spi1; - - self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, bus_pins); - - return MP_OBJ_FROM_PTR(self); -} - -mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_width, ARG_height, ARG_cs, ARG_dc, ARG_wr_sck, ARG_rd_sck, ARG_d0, ARG_bl, ARG_rotate, ARG_buffer }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_cs, MP_ARG_INT, {.u_int = 10} }, - { MP_QSTR_dc, MP_ARG_INT, {.u_int = 11} }, - { MP_QSTR_wr_sck, MP_ARG_INT, {.u_int = 12} }, - { MP_QSTR_rd_sck, MP_ARG_INT, {.u_int = 13} }, - { MP_QSTR_d0, MP_ARG_INT, {.u_int = 14} }, - - { MP_QSTR_bl, MP_ARG_INT, {.u_int = 2} }, - { MP_QSTR_rotate, MP_ARG_INT, {.u_int = Rotation::ROTATE_0} }, - { MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - }; - - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - GenericST7789_obj_t *self = m_new_obj(GenericST7789_obj_t); - self->base.type = &GenericST7789_type; - - Rotation rotate = (Rotation)args[ARG_rotate].u_int; - int width = args[ARG_width].u_int; - int height = args[ARG_height].u_int; - - if (args[ARG_buffer].u_obj != mp_const_none) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - self->buffer = bufinfo.buf; - if(bufinfo.len < (size_t)(width * height)) { - mp_raise_ValueError("Supplied buffer is too small!"); + if (args[ARG_bus].u_obj == mp_const_none) { + self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT)); + } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) { + _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); + self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins)); + } else { + mp_raise_ValueError("SPIBus expected!"); } - } else { - self->buffer = m_new(uint8_t, width * height); } - ParallelPins bus_pins = { - (uint)args[ARG_cs].u_int, - (uint)args[ARG_dc].u_int, - (uint)args[ARG_wr_sck].u_int, - (uint)args[ARG_rd_sck].u_int, - (uint)args[ARG_d0].u_int, - args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int - }; - - self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, bus_pins); - return MP_OBJ_FROM_PTR(self); } From ae22838151ed5b070b28d5aeabcbce91400ee018 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sun, 29 May 2022 11:35:58 +0100 Subject: [PATCH 20/84] Pimoroni Bus: Tidy up. Print pins. --- .../modules/pimoroni_bus/micropython.cmake | 8 +- .../modules/pimoroni_bus/pimoroni_bus.c | 9 +- .../modules/pimoroni_bus/pimoroni_bus.cpp | 104 ++++++++++-------- .../modules/pimoroni_bus/pimoroni_bus.h | 5 +- 4 files changed, 68 insertions(+), 58 deletions(-) diff --git a/micropython/modules/pimoroni_bus/micropython.cmake b/micropython/modules/pimoroni_bus/micropython.cmake index eec58f1a..c019b8b5 100644 --- a/micropython/modules/pimoroni_bus/micropython.cmake +++ b/micropython/modules/pimoroni_bus/micropython.cmake @@ -17,4 +17,10 @@ target_compile_definitions(usermod_${MOD_NAME} INTERFACE MODULE_${MOD_NAME_UPPER}_ENABLED=1 ) -target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) \ No newline at end of file +target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) + +set_source_files_properties( + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + PROPERTIES COMPILE_FLAGS + "-Wno-discarded-qualifiers" +) \ No newline at end of file diff --git a/micropython/modules/pimoroni_bus/pimoroni_bus.c b/micropython/modules/pimoroni_bus/pimoroni_bus.c index 8a608ba1..aba4341c 100644 --- a/micropython/modules/pimoroni_bus/pimoroni_bus.c +++ b/micropython/modules/pimoroni_bus/pimoroni_bus.c @@ -1,11 +1,6 @@ #include "pimoroni_bus.h" -const mp_obj_type_t SPISlot_type = { - { &mp_type_type }, - .name = MP_QSTR_SPISlot, - .print = PimoroniBus_print, - .make_new = SPISlot_make_new -}; +MP_DEFINE_CONST_FUN_OBJ_1(SPISlot_obj, SPISlot); const mp_obj_type_t SPIPins_type = { { &mp_type_type }, @@ -24,8 +19,8 @@ const mp_obj_type_t ParallelPins_type = { STATIC const mp_map_elem_t pimoroni_bus_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pimoroni_bus) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SPIBus), (mp_obj_t)&SPIPins_type }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SPISlot), (mp_obj_t)&SPISlot_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_ParallelBus), (mp_obj_t)&ParallelPins_type }, + { MP_ROM_QSTR(MP_QSTR_SPISlot), MP_ROM_PTR(&SPISlot_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_pimoroni_bus_globals, pimoroni_bus_globals_table); diff --git a/micropython/modules/pimoroni_bus/pimoroni_bus.cpp b/micropython/modules/pimoroni_bus/pimoroni_bus.cpp index 170fd72e..6a5cf874 100644 --- a/micropython/modules/pimoroni_bus/pimoroni_bus.cpp +++ b/micropython/modules/pimoroni_bus/pimoroni_bus.cpp @@ -11,9 +11,37 @@ extern "C" { void PimoroniBus_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { _PimoroniBus_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PimoroniBus_obj_t); if(self->base.type == &SPIPins_type) { - mp_print_str(print, "SPIBus()"); + SPIPins *pins = (SPIPins *)self->pins; + mp_print_str(print, "SPIBus("); + mp_obj_print_helper(print, mp_obj_new_int((pins->spi == spi0) ? 0 : 1), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->cs), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->sck), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->mosi), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->miso == PIN_UNUSED ? -1 : pins->miso), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->dc == PIN_UNUSED ? -1 : pins->dc), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->bl == PIN_UNUSED ? -1 : pins->bl), PRINT_REPR); + mp_print_str(print, ")"); } else { - mp_print_str(print, "ParallelBus()"); + ParallelPins *pins = (ParallelPins *)self->pins; + mp_print_str(print, "ParallelBus("); + mp_obj_print_helper(print, mp_obj_new_int(pins->cs), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->dc), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->wr_sck), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->rd_sck), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->d0), PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, mp_obj_new_int(pins->bl == PIN_UNUSED ? -1 : pins->bl), PRINT_REPR); + mp_print_str(print, ")"); } (void)kind; } @@ -34,50 +62,32 @@ mp_obj_t SPIPins_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, _PimoroniBus_obj_t *self = m_new_obj(_PimoroniBus_obj_t); self->base.type = &SPIPins_type; - self->pins = m_new(SPIPins, 1); - - SPIPins *pins = (SPIPins *)self->pins; - - pins->spi = ((args[ARG_sck].u_int >> 3) & 0b1) == 0 ? spi0 : spi1; - pins->cs = (uint)args[ARG_cs].u_int; - pins->sck = (uint)args[ARG_sck].u_int; - pins->mosi = (uint)args[ARG_mosi].u_int; - pins->miso = PIN_UNUSED; - pins->dc = (uint)args[ARG_dc].u_int; - pins->bl = args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int; + self->pins = new(m_new(SPIPins, 1)) SPIPins{ + ((args[ARG_sck].u_int >> 3) & 0b1) == 0 ? spi0 : spi1, + (uint)args[ARG_cs].u_int, + (uint)args[ARG_sck].u_int, + (uint)args[ARG_mosi].u_int, + PIN_UNUSED, + (uint)args[ARG_dc].u_int, + args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int + }; return MP_OBJ_FROM_PTR(self); } -mp_obj_t SPISlot_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_slot }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_slot, MP_ARG_INT | MP_ARG_REQUIRED }, - }; +// Factory function. +// Returns an "SPIBus" instance for the given SPI slot. +mp_obj_t SPISlot(mp_obj_t slot_in) { + int slot = mp_obj_get_int(slot_in); - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + _PimoroniBus_obj_t *obj = m_new_obj(_PimoroniBus_obj_t); + obj->base.type = &SPIPins_type; - _PimoroniBus_obj_t *self = m_new_obj(_PimoroniBus_obj_t); - self->base.type = &SPIPins_type; - //self->pins = m_new(SPIPins, 1); - - //SPIPins *pins = (SPIPins *)self->pins; - - SPIPins slot_pins = get_spi_pins((BG_SPI_SLOT)args[ARG_slot].u_int); + SPIPins slot_pins = get_spi_pins((BG_SPI_SLOT)slot); - self->pins = new(m_new(SPIPins, 1)) SPIPins(slot_pins); + obj->pins = new(m_new(SPIPins, 1)) SPIPins(slot_pins); - /* pins->spi = slot_pins.spi; - pins->cs = slot_pins.cs; - pins->sck = slot_pins.sck; - pins->mosi = slot_pins.mosi; - pins->miso = slot_pins.miso; - pins->dc = slot_pins.dc; - pins->bl = slot_pins.bl;*/ - - return MP_OBJ_FROM_PTR(self); + return MP_OBJ_FROM_PTR(obj); } mp_obj_t ParallelPins_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -97,16 +107,14 @@ mp_obj_t ParallelPins_make_new(const mp_obj_type_t *type, size_t n_args, size_t _PimoroniBus_obj_t *self = m_new_obj(_PimoroniBus_obj_t); self->base.type = &ParallelPins_type; - self->pins = m_new(ParallelPins, 1); - - ParallelPins *pins = (ParallelPins *)self->pins; - - pins->cs = (uint)args[ARG_cs].u_int; - pins->dc = (uint)args[ARG_dc].u_int; - pins->wr_sck = (uint)args[ARG_wr_sck].u_int; - pins->rd_sck = (uint)args[ARG_rd_sck].u_int; - pins->d0 = (uint)args[ARG_d0].u_int; - pins->bl = args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int; + self->pins = new(m_new(ParallelPins, 1)) ParallelPins{ + (uint)args[ARG_cs].u_int, + (uint)args[ARG_dc].u_int, + (uint)args[ARG_wr_sck].u_int, + (uint)args[ARG_rd_sck].u_int, + (uint)args[ARG_d0].u_int, + args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int + }; return MP_OBJ_FROM_PTR(self); } diff --git a/micropython/modules/pimoroni_bus/pimoroni_bus.h b/micropython/modules/pimoroni_bus/pimoroni_bus.h index 1ab4413b..3a7e4430 100644 --- a/micropython/modules/pimoroni_bus/pimoroni_bus.h +++ b/micropython/modules/pimoroni_bus/pimoroni_bus.h @@ -11,5 +11,6 @@ typedef struct _PimoroniBus_obj_t { extern void PimoroniBus_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); extern mp_obj_t SPIPins_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 SPISlot_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 ParallelPins_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); \ No newline at end of file +extern mp_obj_t ParallelPins_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 SPISlot(mp_obj_t self_in); \ No newline at end of file From 65788ae6bf48a06ad2e179fd3cdcaa8fd4653e90 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sun, 29 May 2022 13:16:31 +0100 Subject: [PATCH 21/84] ST7789/PicoGraphics: Faster RGB332 mode lookups. Replace palette search in RGB332 mode with a simple return of the RGB565 colour packed to RGB332, since this is identical to its index in the palette. --- libraries/pico_graphics/pico_graphics.cpp | 22 ++++++++++++++++------ libraries/pico_graphics/pico_graphics.hpp | 4 ++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 96f6a0e2..3ff3b84e 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -25,14 +25,18 @@ namespace pimoroni { } int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) { - RGB565 c = palette_mode == PaletteModeRGB332 ? create_pen_rgb332(r, g, b) : create_pen_rgb565(r, g, b); - int result = search_palette(c); + if (palette_mode == PaletteModeRGB332) { + return rgb_to_rgb332_index(r, g, b); // Fast pack RGB into palette index + } else { + RGB565 c = create_pen_rgb565(r, g, b); + int result = search_palette(c); - if (result == -1 && palette_mode == PaletteModeUSER) { - result = put_palette(create_pen_rgb565(r, g, b)); + if (result == -1) { + result = put_palette(create_pen_rgb565(r, g, b)); + } + + return result; } - - return result; } void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) { @@ -48,6 +52,8 @@ namespace pimoroni { } int PicoGraphics::put_palette(RGB565 c) { + if(palette_mode != PaletteModeUSER) return -1; + for(auto i = 0u; i < 256; i++) { if(!(palette_status[i] & (PaletteStatusUsed | PaletteStatusReserved))) { palette[i] = c; @@ -59,11 +65,15 @@ namespace pimoroni { } void PicoGraphics::set_palette(uint8_t i, RGB565 c) { + if(palette_mode != PaletteModeUSER) return; + palette[i] = c; palette_status[i] |= PaletteStatusUsed; } int PicoGraphics::reserve_palette() { + if(palette_mode != PaletteModeUSER) return - 1; + for (auto i = 0u; i < 256; i++) { if (!palette_status[i]) { palette_status[i] = PaletteStatusReserved; diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index f2ee6249..f0258435 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -79,6 +79,10 @@ namespace pimoroni { [[deprecated("Use uint8_t create_pen(uint8_t, uint8_t, uint8_t).")]] void set_pen(uint8_t r, uint8_t g, uint8_t b); + static constexpr Pen rgb_to_rgb332_index(uint8_t r, uint8_t g, uint8_t b) { + return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); + } + static constexpr RGB565 create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) { uint16_t p = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | From b66da12c1b68d545077b43bba55dcd8047271e71 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sun, 29 May 2022 14:42:31 +0100 Subject: [PATCH 22/84] ST7789/PicoDisplay: Update C++ examples. Rename GenericST7789 -> PicoDisplayST7789. --- common/CMakeLists.txt | 1 + common/pimoroni_common.hpp | 4 +- .../breakout_as7262/explorer_bargraph.cmake | 2 +- .../breakout_as7262/explorer_bargraph.cpp | 39 +-- .../breakout_colourlcd240x240/CMakeLists.txt | 2 +- examples/breakout_colourlcd240x240/demo.cpp | 37 ++- examples/breakout_roundlcd/CMakeLists.txt | 4 +- .../{demo.cpp => roundlcd_demo.cpp} | 6 +- examples/pico_display/CMakeLists.txt | 2 +- examples/pico_display/demo.cpp | 4 +- examples/pico_display_2/CMakeLists.txt | 2 +- examples/pico_display_2/demo.cpp | 4 +- examples/pico_enc_explorer/CMakeLists.txt | 4 +- .../{demo.cpp => pico_enc_explorer.cpp} | 43 +-- examples/pico_explorer/CMakeLists.txt | 12 +- examples/pico_explorer/demo.cpp | 227 ---------------- examples/pico_explorer/pico_explorer_demo.cpp | 251 ++++++++++++++++++ examples/pico_explorer_encoder/CMakeLists.txt | 10 +- .../{demo.cpp => pico_explorer_encoder.cpp} | 92 ++++--- examples/pico_pot_explorer/CMakeLists.txt | 4 +- .../{demo.cpp => pico_pot_explorer.cpp} | 43 +-- examples/pico_rtc_display/CMakeLists.txt | 4 +- .../{demo.cpp => pico_rtc_display.cpp} | 104 +++++--- examples/pico_tof_display/CMakeLists.txt | 4 +- .../{demo.cpp => pico_tof_display.cpp} | 118 ++++---- .../pico_trackball_display/CMakeLists.txt | 4 +- .../{demo.cpp => pico_trackball_display.cpp} | 65 ++--- examples/tufty2040/tufty2040_drawing.cmake | 2 +- examples/tufty2040/tufty2040_drawing.cpp | 39 +-- libraries/CMakeLists.txt | 2 +- libraries/generic_st7789/CMakeLists.txt | 1 - libraries/pico_display/pico_display.cmake | 5 +- libraries/pico_display/pico_display.cpp | 86 +----- libraries/pico_display/pico_display.hpp | 24 +- libraries/pico_display_2/pico_display_2.cmake | 14 +- libraries/pico_display_2/pico_display_2.cpp | 86 +----- libraries/pico_display_2/pico_display_2.hpp | 24 +- libraries/pico_explorer/pico_explorer.hpp | 8 + libraries/picographics_st7789/CMakeLists.txt | 1 + .../README.md | 8 +- .../picographics_st7789.cmake} | 2 +- .../picographics_st7789.cpp} | 6 +- .../picographics_st7789.hpp} | 8 +- micropython/modules/st7789/micropython.cmake | 2 +- micropython/modules/st7789/st7789.cpp | 18 +- 45 files changed, 646 insertions(+), 782 deletions(-) rename examples/breakout_roundlcd/{demo.cpp => roundlcd_demo.cpp} (90%) rename examples/pico_enc_explorer/{demo.cpp => pico_enc_explorer.cpp} (73%) delete mode 100644 examples/pico_explorer/demo.cpp create mode 100644 examples/pico_explorer/pico_explorer_demo.cpp rename examples/pico_explorer_encoder/{demo.cpp => pico_explorer_encoder.cpp} (80%) rename examples/pico_pot_explorer/{demo.cpp => pico_pot_explorer.cpp} (71%) rename examples/pico_rtc_display/{demo.cpp => pico_rtc_display.cpp} (75%) rename examples/pico_tof_display/{demo.cpp => pico_tof_display.cpp} (71%) rename examples/pico_trackball_display/{demo.cpp => pico_trackball_display.cpp} (72%) delete mode 100644 libraries/generic_st7789/CMakeLists.txt create mode 100644 libraries/picographics_st7789/CMakeLists.txt rename libraries/{generic_st7789 => picographics_st7789}/README.md (88%) rename libraries/{generic_st7789/generic_st7789.cmake => picographics_st7789/picographics_st7789.cmake} (91%) rename libraries/{generic_st7789/generic_st7789.cpp => picographics_st7789/picographics_st7789.cpp} (50%) rename libraries/{generic_st7789/generic_st7789.hpp => picographics_st7789/picographics_st7789.hpp} (73%) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index fc199f40..3c870348 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -1 +1,2 @@ include(pimoroni_i2c.cmake) +include(pimoroni_bus.cmake) \ No newline at end of file diff --git a/common/pimoroni_common.hpp b/common/pimoroni_common.hpp index 6300a3ac..78481588 100644 --- a/common/pimoroni_common.hpp +++ b/common/pimoroni_common.hpp @@ -108,8 +108,8 @@ namespace pimoroni { uint8_t enable; }; - pin_pair() : first(0), second(0) {} - pin_pair(uint8_t first, uint8_t second) : first(first), second(second) {} + constexpr pin_pair() : first(0), second(0) {} + constexpr pin_pair(uint8_t first, uint8_t second) : first(first), second(second) {} }; struct bool_pair { diff --git a/examples/breakout_as7262/explorer_bargraph.cmake b/examples/breakout_as7262/explorer_bargraph.cmake index 2baa50d4..48b8b989 100644 --- a/examples/breakout_as7262/explorer_bargraph.cmake +++ b/examples/breakout_as7262/explorer_bargraph.cmake @@ -10,7 +10,7 @@ pico_enable_stdio_usb(${OUTPUT_NAME} 1) pico_enable_stdio_uart(${OUTPUT_NAME} 1) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_as7262 pico_explorer) +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_as7262 pico_explorer picographics_st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_as7262/explorer_bargraph.cpp b/examples/breakout_as7262/explorer_bargraph.cpp index 189f624f..130c51a7 100644 --- a/examples/breakout_as7262/explorer_bargraph.cpp +++ b/examples/breakout_as7262/explorer_bargraph.cpp @@ -4,14 +4,16 @@ #include "breakout_as7262.hpp" #include "pico_explorer.hpp" +#include "picographics_st7789.hpp" + using namespace pimoroni; constexpr float INTEGRATION_TIME = 10.0f; I2C i2c(BOARD::PICO_EXPLORER); BreakoutAS7262 as7262(&i2c); -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_explorer(buffer); + +PicoGraphicsST7789 display(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); uint8_t bar_width = PicoExplorer::WIDTH / 6; uint8_t bar_height = PicoExplorer::HEIGHT; @@ -20,13 +22,12 @@ void draw_bar(float scale, uint16_t channel) { int16_t bar_top = bar_height - (bar_height * scale); bar_top = std::max((int16_t)0, bar_top); int16_t current_bar_height = bar_height - bar_top; - pico_explorer.rectangle(Rect(channel * bar_width, bar_top, bar_width, current_bar_height - 1)); + display.rectangle(Rect(channel * bar_width, bar_top, bar_width, current_bar_height - 1)); } int main() { stdio_init_all(); - pico_explorer.init(); as7262.init(); uint8_t dev_type = as7262.device_type(); @@ -43,9 +44,17 @@ int main() { as7262.set_indicator_current(AS7262::indicator_current::ma4); as7262.set_leds(true, true); + Pen BLACK = display.create_pen(0, 0, 0); + Pen RED = display.create_pen(255, 0, 0); + Pen ORANGE = display.create_pen(255, 128, 0); + Pen YELLOW = display.create_pen(255, 255, 0); + Pen GREEN = display.create_pen(0, 255, 0); + Pen BLUE = display.create_pen(0, 0, 255); + Pen VIOLET = display.create_pen(255, 0, 255); + while(true) { - pico_explorer.set_pen(0, 0, 0); - pico_explorer.clear(); + display.set_pen(BLACK); + display.clear(); AS7262::reading reading = as7262.read(); printf("R: %f O: %f Y: %f G: %f B: %f V: %f \n", @@ -64,34 +73,34 @@ int main() { if(reading.blue > m) m = reading.blue; if(reading.violet > m) m = reading.violet; - pico_explorer.set_pen(0, 0, 0); - pico_explorer.clear(); + display.set_pen(BLACK); + display.clear(); // Red - pico_explorer.set_pen(255, 0, 0); + display.set_pen(RED); draw_bar(reading.red / m, 0); // Orange - pico_explorer.set_pen(255, 128, 0); + display.set_pen(ORANGE); draw_bar(reading.orange / m, 1); // Yellow - pico_explorer.set_pen(255, 255, 0); + display.set_pen(YELLOW); draw_bar(reading.yellow / m, 2); // Green - pico_explorer.set_pen(0, 255, 0); + display.set_pen(GREEN); draw_bar(reading.green / m, 3); // Blue - pico_explorer.set_pen(0, 0, 255); + display.set_pen(BLUE); draw_bar(reading.blue / m, 4); // Violet - pico_explorer.set_pen(255, 0, 255); + display.set_pen(VIOLET); draw_bar(reading.violet / m, 5); - pico_explorer.update(); + display.update(); sleep_ms(INTEGRATION_TIME); } diff --git a/examples/breakout_colourlcd240x240/CMakeLists.txt b/examples/breakout_colourlcd240x240/CMakeLists.txt index cc7825d2..26ca71e0 100644 --- a/examples/breakout_colourlcd240x240/CMakeLists.txt +++ b/examples/breakout_colourlcd240x240/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib generic_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib picographics_st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_colourlcd240x240/demo.cpp b/examples/breakout_colourlcd240x240/demo.cpp index 02a0b45c..dce1156d 100644 --- a/examples/breakout_colourlcd240x240/demo.cpp +++ b/examples/breakout_colourlcd240x240/demo.cpp @@ -1,21 +1,20 @@ #include #include -#include "generic_st7789.hpp" +#include "picographics_st7789.hpp" using namespace pimoroni; const int WIDTH = 240; const int HEIGHT = 240; -ST7789Generic display(WIDTH, HEIGHT, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); +PicoGraphicsST7789 display(WIDTH, HEIGHT, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); int main() { - //lcd.configure_display(false); - lcd.set_backlight(255); + display.set_backlight(255); // Delete the default palette and allow us to create up to 256 of our own RGB565 colours - lcd.set_palette_mode(ST7789Generic::PaletteModeUSER); + display.set_palette_mode(PicoGraphicsST7789::PaletteModeUSER); struct pt { float x; @@ -30,40 +29,40 @@ int main() { for(int i = 0; i < 100; i++) { pt shape; shape.r = (rand() % 10) + 3; - shape.x = rand() % (lcd.bounds.w - (shape.r * 2)); - shape.y = rand() % (lcd.bounds.h - (shape.r * 2)); + shape.x = rand() % (display.bounds.w - (shape.r * 2)); + shape.y = rand() % (display.bounds.h - (shape.r * 2)); shape.x += shape.r; shape.y += shape.r; shape.dx = float(rand() % 255) / 64.0f; shape.dy = float(rand() % 255) / 64.0f; - shape.pen = lcd.create_pen(rand() % 255, rand() % 255, rand() % 255); + shape.pen = display.create_pen(rand() % 255, rand() % 255, rand() % 255); shapes.push_back(shape); } - Pen BG = lcd.create_pen(120, 40, 60); - Pen WHITE = lcd.create_pen(255, 255, 255); + Pen BG = display.create_pen(120, 40, 60); + Pen WHITE = display.create_pen(255, 255, 255); while(true) { - lcd.set_pen(BG); - lcd.clear(); + display.set_pen(BG); + display.clear(); for(auto &shape : shapes) { shape.x += shape.dx; shape.y += shape.dy; if(shape.x < shape.r) shape.dx *= -1; - if(shape.x >= lcd.bounds.w - shape.r) shape.dx *= -1; + if(shape.x >= display.bounds.w - shape.r) shape.dx *= -1; if(shape.y < shape.r) shape.dy *= -1; - if(shape.y >= lcd.bounds.h - shape.r) shape.dy *= -1; + if(shape.y >= display.bounds.h - shape.r) shape.dy *= -1; - lcd.set_pen(shape.pen); - lcd.circle(Point(shape.x, shape.y), shape.r); + display.set_pen(shape.pen); + display.circle(Point(shape.x, shape.y), shape.r); } - lcd.set_pen(WHITE); - lcd.text("Hello World", Point(0, 0), 240); + display.set_pen(WHITE); + display.text("Hello World", Point(0, 0), 240); // update screen - lcd.update(); + display.update(); } return 0; diff --git a/examples/breakout_roundlcd/CMakeLists.txt b/examples/breakout_roundlcd/CMakeLists.txt index a671c7bd..daac9779 100644 --- a/examples/breakout_roundlcd/CMakeLists.txt +++ b/examples/breakout_roundlcd/CMakeLists.txt @@ -2,11 +2,11 @@ set(OUTPUT_NAME roundlcd_demo) add_executable( ${OUTPUT_NAME} - demo.cpp + roundlcd_demo.cpp ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib generic_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib picographics_st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) \ No newline at end of file diff --git a/examples/breakout_roundlcd/demo.cpp b/examples/breakout_roundlcd/roundlcd_demo.cpp similarity index 90% rename from examples/breakout_roundlcd/demo.cpp rename to examples/breakout_roundlcd/roundlcd_demo.cpp index b6bb0d0f..aed2862e 100644 --- a/examples/breakout_roundlcd/demo.cpp +++ b/examples/breakout_roundlcd/roundlcd_demo.cpp @@ -3,7 +3,7 @@ #include #include -#include "generic_st7789.hpp" +#include "picographics_st7789.hpp" #include "time.h" // Place a 1.3 Round SPI LCD in the *front* slot of breakout garden. @@ -14,7 +14,7 @@ using namespace pimoroni; const int WIDTH = 240; const int HEIGHT = 240; -ST7789Generic display(WIDTH, HEIGHT, ROTATE_0, true, nullptr, get_spi_pins(BG_SPI_FRONT)); +PicoGraphicsST7789 display(WIDTH, HEIGHT, ROTATE_0, true, nullptr, get_spi_pins(BG_SPI_FRONT)); constexpr float RADIUS = WIDTH / 2; @@ -44,7 +44,7 @@ int main() { display.set_backlight(255); // Delete the default palette and allow us to create up to 256 of our own RGB565 colours - // display.set_palette_mode(ST7789Generic::PaletteModeUSER); + // display.set_palette_mode(PicoGraphicsST7789::PaletteModeUSER); uint32_t steps = 70; float angle_step = 0.5f; diff --git a/examples/pico_display/CMakeLists.txt b/examples/pico_display/CMakeLists.txt index 1e97ebd3..c857d624 100644 --- a/examples/pico_display/CMakeLists.txt +++ b/examples/pico_display/CMakeLists.txt @@ -5,7 +5,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(pico_display_demo pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled pico_display generic_st7789) +target_link_libraries(pico_display_demo pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled pico_display picographics_st7789) # create map/bin/hex file etc. pico_add_extra_outputs(pico_display_demo) \ No newline at end of file diff --git a/examples/pico_display/demo.cpp b/examples/pico_display/demo.cpp index 3c1b2aeb..18508bc9 100644 --- a/examples/pico_display/demo.cpp +++ b/examples/pico_display/demo.cpp @@ -4,12 +4,12 @@ #include #include "pico_display.hpp" -#include "generic_st7789.hpp" +#include "picographics_st7789.hpp" #include "rgbled.hpp" using namespace pimoroni; -ST7789Generic pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0); +PicoGraphicsST7789 pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0); RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); diff --git a/examples/pico_display_2/CMakeLists.txt b/examples/pico_display_2/CMakeLists.txt index 0ceb13d7..51a60e45 100644 --- a/examples/pico_display_2/CMakeLists.txt +++ b/examples/pico_display_2/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled button pico_display_2 generic_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled button pico_display_2 picographics_st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) \ No newline at end of file diff --git a/examples/pico_display_2/demo.cpp b/examples/pico_display_2/demo.cpp index b53f84bc..8f2edd75 100644 --- a/examples/pico_display_2/demo.cpp +++ b/examples/pico_display_2/demo.cpp @@ -4,13 +4,13 @@ #include #include "pico_display_2.hpp" -#include "generic_st7789.hpp" +#include "picographics_st7789.hpp" #include "rgbled.hpp" #include "button.hpp" using namespace pimoroni; -ST7789Generic pico_display(240, 240, ROTATE_0); +PicoGraphicsST7789 pico_display(240, 240, ROTATE_0); RGBLED led(PicoDisplay2::LED_R, PicoDisplay2::LED_G, PicoDisplay2::LED_B); diff --git a/examples/pico_enc_explorer/CMakeLists.txt b/examples/pico_enc_explorer/CMakeLists.txt index a082bef9..5dac8e43 100644 --- a/examples/pico_enc_explorer/CMakeLists.txt +++ b/examples/pico_enc_explorer/CMakeLists.txt @@ -2,11 +2,11 @@ set(OUTPUT_NAME encoder_explorer) add_executable( ${OUTPUT_NAME} - demo.cpp + pico_enc_explorer.cpp ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_encoder pico_explorer) +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_encoder pico_explorer picographics_st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/pico_enc_explorer/demo.cpp b/examples/pico_enc_explorer/pico_enc_explorer.cpp similarity index 73% rename from examples/pico_enc_explorer/demo.cpp rename to examples/pico_enc_explorer/pico_enc_explorer.cpp index 75250a30..4a7b93b9 100644 --- a/examples/pico_enc_explorer/demo.cpp +++ b/examples/pico_enc_explorer/pico_enc_explorer.cpp @@ -6,11 +6,23 @@ #include "pico_explorer.hpp" #include "breakout_encoder.hpp" +#include "picographics_st7789.hpp" using namespace pimoroni; -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_explorer(buffer); +PicoGraphicsST7789 display( + PicoExplorer::WIDTH, + PicoExplorer::HEIGHT, + ROTATE_0, // Rotation + false, // Is it round!? + nullptr, // Buffer + get_spi_pins(BG_SPI_FRONT) +); + +Pen BLACK = display.create_pen(0, 0, 0); +Pen RED = display.create_pen(255, 0, 0); +Pen GREEN = display.create_pen(0, 255, 0); +Pen BLUE = display.create_pen(0, 0, 255); static const uint8_t STEPS_PER_REV = 24; @@ -44,47 +56,49 @@ void count_changed(int16_t count) { from_hsv(h, 1.0f, 1.0f, r, g, b); enc.set_led(r, g, b); - pico_explorer.set_pen(0, 0, 0); - pico_explorer.clear(); + display.set_pen(BLACK); + display.clear(); { - pico_explorer.set_pen(255, 0, 0); + display.set_pen(RED); std::ostringstream ss; ss << "R = "; ss << (int)r; std::string s(ss.str()); - pico_explorer.text(s, Point(10, 10), 220, 6); + display.text(s, Point(10, 10), 220, 6); } { - pico_explorer.set_pen(0, 255, 0); + display.set_pen(GREEN); std::ostringstream ss; ss << "G = "; ss << (int)g; std::string s(ss.str()); - pico_explorer.text(s, Point(10, 70), 220, 6); + display.text(s, Point(10, 70), 220, 6); } { - pico_explorer.set_pen(0, 0, 255); + display.set_pen(BLUE); std::ostringstream ss; ss << "B = "; ss << (int)b; std::string s(ss.str()); - pico_explorer.text(s, Point(10, 130), 220, 6); + display.text(s, Point(10, 130), 220, 6); } { - pico_explorer.set_pen(r, g, b); + // Shouldn't really use create_pen in-line. + // In default (RGB332) palette mode this will lookup the nearest 8-bit colour + display.set_pen(display.create_pen(r, g, b)); std::ostringstream ss; ss << "#"; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)r; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)g; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)b; std::string s(ss.str()); - pico_explorer.text(s, Point(10, 190), 220, 5); + display.text(s, Point(10, 190), 220, 5); } - pico_explorer.update(); + display.update(); } int main() { @@ -93,9 +107,6 @@ int main() { stdio_init_all(); - pico_explorer.init(); - pico_explorer.update(); - int16_t count = 0; if(enc.init()) { printf("Encoder found...\n"); diff --git a/examples/pico_explorer/CMakeLists.txt b/examples/pico_explorer/CMakeLists.txt index 02238a31..669c2b1f 100644 --- a/examples/pico_explorer/CMakeLists.txt +++ b/examples/pico_explorer/CMakeLists.txt @@ -1,21 +1,21 @@ add_executable( - explorer - demo.cpp + pico_explorer_demo + pico_explorer_demo.cpp ) -add_resource(explorer fox.tga) +add_resource(pico_explorer_demo fox.tga) # Pull in pico libraries that we need -target_link_libraries(explorer pico_stdlib pico_explorer msa301) +target_link_libraries(pico_explorer_demo pico_stdlib pico_explorer msa301 picographics_st7789 button motor analog) # create map/bin/hex file etc. -pico_add_extra_outputs(explorer) +pico_add_extra_outputs(pico_explorer_demo) add_executable( text_demo text_demo.cpp ) -target_link_libraries(text_demo pico_stdlib pico_explorer msa301) +target_link_libraries(text_demo pico_stdlib pico_explorer msa301 picographics_st7789) pico_add_extra_outputs(text_demo) \ No newline at end of file diff --git a/examples/pico_explorer/demo.cpp b/examples/pico_explorer/demo.cpp deleted file mode 100644 index f7e72914..00000000 --- a/examples/pico_explorer/demo.cpp +++ /dev/null @@ -1,227 +0,0 @@ -#include -#include -#include -#include - -#include "pico_explorer.hpp" -#include "msa301.hpp" - -using namespace pimoroni; - -extern unsigned char _binary_fox_tga_start[]; - -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_explorer(buffer); -MSA301 msa301; - -uint8_t arrow[] = { - 0b00010000, - 0b00110000, - 0b01110000, - 0b11111111, - 0b11111111, - 0b01110000, - 0b00110000, - 0b00010000 - }; - -uint8_t tick[] = { - 0b00000000, - 0b00000010, - 0b00000111, - 0b01001110, - 0b11111100, - 0b00111000, - 0b00010000, - 0b00000000, - }; - -/* -void sprite(uint8_t *p, int x, int y, bool flip, uint16_t c) { - for(int ay = 0; ay < 8; ay++) { - uint8_t sl = p[ay]; - for(int ax = 0; ax < 8; ax++) { - if(flip) { - if((0b10000000 >> ax) & sl) { - pixel(ax + x, ay + y, c); - } - }else{ - if((0b1 << ax) & sl) { - pixel(ax + x, ay + y, c); - } - } - } - } -}*/ - -int main() { - pico_explorer.init(); - msa301.init(); - - struct pt { - float x; - float y; - uint8_t r; - float dx; - float dy; - uint16_t pen; - }; - - std::vector shapes; - for(int i = 0; i < 100; i++) { - pt shape; - shape.x = rand() % 240; - shape.y = rand() % 135; - shape.r = (rand() % 10) + 3; - shape.dx = float(rand() % 255) / 128.0f; - shape.dy = float(rand() % 255) / 128.0f; - shape.pen = pico_explorer.create_pen(rand() % 255, rand() % 255, rand() % 255); - shapes.push_back(shape); - } - - pico_explorer.set_audio_pin(pico_explorer.GP0); - - Pen BG = pico_explorer.create_pen(120, 40, 60); - Pen WHITE = pico_explorer.create_pen(255, 255, 255); - Pen BOX = pico_explorer.create_pen(55, 65, 75); - Pen PURPLE = pico_explorer.create_pen(255, 0, 255); - - uint32_t i = 0; - while(true) { - pico_explorer.set_pen(BG); - pico_explorer.clear(); - - for(auto &shape : shapes) { - shape.x += shape.dx; - shape.y += shape.dy; - if(shape.x < 0) shape.dx *= -1; - if(shape.x >= pico_explorer.bounds.w) shape.dx *= -1; - if(shape.y < 0) shape.dy *= -1; - if(shape.y >= pico_explorer.bounds.h) shape.dy *= -1; - - pico_explorer.set_pen(shape.pen); - pico_explorer.circle(Point(shape.x, shape.y), shape.r); - } - - float rv = pico_explorer.get_adc(pico_explorer.ADC0); - pico_explorer.set_pen(WHITE); - pico_explorer.circle(Point(rv * 140 + 50, 110), 20); - pico_explorer.set_pen(pico_explorer.create_pen(rv * 255, 0, 0)); - pico_explorer.circle(Point(rv * 140 + 50, 110), 15); - - float gv = pico_explorer.get_adc(pico_explorer.ADC1); - pico_explorer.set_pen(WHITE); - pico_explorer.circle(Point(gv * 140 + 50, 160), 20); - pico_explorer.set_pen(pico_explorer.create_pen(0, gv * 255, 0)); - pico_explorer.circle(Point(gv * 140 + 50, 160), 15); - - float bv = pico_explorer.get_adc(pico_explorer.ADC2); - pico_explorer.set_pen(WHITE); - pico_explorer.circle(Point(bv * 140 + 50, 210), 20); - pico_explorer.set_pen(pico_explorer.create_pen(0, 0, bv * 255)); - pico_explorer.circle(Point(bv * 140 + 50, 210), 15); - - pico_explorer.set_motor(pico_explorer.MOTOR1, pico_explorer.FORWARD, bv); - pico_explorer.set_motor(pico_explorer.MOTOR2, pico_explorer.FORWARD, rv); - - pico_explorer.set_tone(440, 0.5); - - if(pico_explorer.is_pressed(pico_explorer.A)) { - pico_explorer.set_pen(WHITE); - pico_explorer.character('A', Point(120, 180), 5); - } - - if(pico_explorer.is_pressed(pico_explorer.B)) { - pico_explorer.set_pen(WHITE); - pico_explorer.character('B', Point(120, 180), 5); - } - - if(pico_explorer.is_pressed(pico_explorer.X)) { - pico_explorer.set_pen(WHITE); - pico_explorer.character('X', Point(120, 180), 5); - } - - if(pico_explorer.is_pressed(pico_explorer.Y)) { - pico_explorer.set_pen(WHITE); - pico_explorer.character('Y', Point(120, 180), 5); - } - - float tyoff = cos(i / 20.0f) * 50.0f - 50.0f; - Rect text_box(10, 10, 150, 150); - pico_explorer.set_pen(BOX); - pico_explorer.rectangle(text_box); - text_box.deflate(10); - pico_explorer.set_clip(text_box); - pico_explorer.set_pen(WHITE); - pico_explorer.text("This is a test of some text data that should wrap nicely onto multiple lines which is dead useful like.", Point(text_box.x, text_box.y + tyoff), 100); - - float xoff = sin(i / 20.0f) * 50.0f; - xoff += 120 - (81 / 2); - float yoff = cos(i / 20.0f) * 50.0f; - yoff += 120 - (68 / 2); - for(int y = 0; y < 68; y++) { - // uint16_t *dest = pico_explorer.frame_buffer + (y * 240); - uint8_t *src = _binary_fox_tga_start + 18 + (y * 81 * 3); - for(int x = 0; x < 81; x++) { - uint8_t b = *src++; - uint8_t g = *src++; - uint8_t r = *src++; - - pico_explorer.set_pen(r, g, b); - pico_explorer.pixel(Point(x + xoff, 68 - y + yoff)); - } - } - - pico_explorer.remove_clip(); - - pico_explorer.set_pen(WHITE); - pico_explorer.text("x: " + std::to_string(int(msa301.get_axis(msa301.X, 16) * 100)), Point(10, 190), 100); - pico_explorer.text("y: " + std::to_string(int(msa301.get_axis(msa301.Y, 16) * 100)), Point(10, 205), 100); - pico_explorer.text("z: " + std::to_string(int(msa301.get_axis(msa301.Z, 16) * 100)), Point(10, 220), 100); - - uint16_t xpos = (msa301.get_axis(msa301.X, 16) * 120) + 120; - uint16_t ypos = (msa301.get_axis(msa301.Z, 16) * 120) + 120; - pico_explorer.set_pen(WHITE); - pico_explorer.circle(Point(xpos, ypos), 20); - pico_explorer.set_pen(PURPLE); - pico_explorer.circle(Point(xpos, ypos), 15); - - -/* - if(pico_display.is_pressed(pico_display.A)) { - pico_display.rectangle(0, 0, 18, 18); - //sprite(tick, 5, 5, true, green); - }else{ - //sprite(arrow, 10 + bounce, 10, true, white); - } - - if(pico_display.is_pressed(pico_display.B)) { - pico_display.rectangle(0, 49, 18, 18); - //sprite(tick, 5, 54, true, green); - }else{ - //sprite(arrow, 10 - bounce, 50, true, white); - } - - - if(pico_display.is_pressed(pico_display.X)) { - pico_display.rectangle(102, 0, 18, 18); - //sprite(tick, 107, 5, true, green); - }else{ - //sprite(arrow, 102 - bounce, 10, false, white); - } - - if(pico_display.is_pressed(pico_display.Y)) { - pico_display.rectangle(102, 49, 18, 18); - //sprite(tick, 107, 54, true, green); - }else{ - //sprite(arrow, 102 + bounce, 50, false, white); - } -*/ - // update screen - pico_explorer.update(); - - i++; - } - - return 0; -} diff --git a/examples/pico_explorer/pico_explorer_demo.cpp b/examples/pico_explorer/pico_explorer_demo.cpp new file mode 100644 index 00000000..39daaac5 --- /dev/null +++ b/examples/pico_explorer/pico_explorer_demo.cpp @@ -0,0 +1,251 @@ +#include +#include +#include +#include + +#include "pico_explorer.hpp" +#include "picographics_st7789.hpp" +#include "button.hpp" +#include "motor.hpp" +#include "msa301.hpp" +#include "analog.hpp" + +using namespace pimoroni; +using namespace motor; + +extern unsigned char _binary_fox_tga_start[]; + +PicoGraphicsST7789 display( + PicoExplorer::WIDTH, + PicoExplorer::HEIGHT, + ROTATE_0, // Rotation + false, // Is it round!? + nullptr, // Buffer + get_spi_pins(BG_SPI_FRONT) +); + +// Buttons +Button button_a(PicoExplorer::A); +Button button_b(PicoExplorer::B); +Button button_x(PicoExplorer::X); +Button button_y(PicoExplorer::Y); + +Motor motor1(PicoExplorer::MOTOR1_PINS); +Motor motor2(PicoExplorer::MOTOR2_PINS); + +Analog adc0(PicoExplorer::ADC0_PIN); +Analog adc1(PicoExplorer::ADC1_PIN); +Analog adc2(PicoExplorer::ADC2_PIN); + +MSA301 msa301; + +uint8_t arrow[] = { + 0b00010000, + 0b00110000, + 0b01110000, + 0b11111111, + 0b11111111, + 0b01110000, + 0b00110000, + 0b00010000 +}; + +uint8_t tick[] = { + 0b00000000, + 0b00000010, + 0b00000111, + 0b01001110, + 0b11111100, + 0b00111000, + 0b00010000, + 0b00000000, +}; + +/* +void sprite(uint8_t *p, int x, int y, bool flip, uint16_t c) { + for(int ay = 0; ay < 8; ay++) { + uint8_t sl = p[ay]; + for(int ax = 0; ax < 8; ax++) { + if(flip) { + if((0b10000000 >> ax) & sl) { + pixel(ax + x, ay + y, c); + } + }else{ + if((0b1 << ax) & sl) { + pixel(ax + x, ay + y, c); + } + } + } + } +}*/ + +int main() { + msa301.init(); + + struct pt { + float x; + float y; + uint8_t r; + float dx; + float dy; + uint16_t pen; + }; + + std::vector shapes; + for(int i = 0; i < 100; i++) { + pt shape; + shape.x = rand() % 240; + shape.y = rand() % 135; + shape.r = (rand() % 10) + 3; + shape.dx = float(rand() % 255) / 128.0f; + shape.dy = float(rand() % 255) / 128.0f; + shape.pen = display.create_pen(rand() % 255, rand() % 255, rand() % 255); + shapes.push_back(shape); + } + + Pen BG = display.create_pen(120, 40, 60); + Pen WHITE = display.create_pen(255, 255, 255); + Pen BOX = display.create_pen(55, 65, 75); + Pen PURPLE = display.create_pen(255, 0, 255); + + uint32_t i = 0; + while(true) { + display.set_pen(BG); + display.clear(); + + for(auto &shape : shapes) { + shape.x += shape.dx; + shape.y += shape.dy; + if(shape.x < 0) shape.dx *= -1; + if(shape.x >= display.bounds.w) shape.dx *= -1; + if(shape.y < 0) shape.dy *= -1; + if(shape.y >= display.bounds.h) shape.dy *= -1; + + display.set_pen(shape.pen); + display.circle(Point(shape.x, shape.y), shape.r); + } + + float rv = adc0.read_voltage() / 3.3f; + display.set_pen(WHITE); + display.circle(Point(rv * 140 + 50, 110), 20); + display.set_pen(display.create_pen(rv * 255, 0, 0)); + display.circle(Point(rv * 140 + 50, 110), 15); + + float gv = adc1.read_voltage() / 3.3f; + display.set_pen(WHITE); + display.circle(Point(gv * 140 + 50, 160), 20); + display.set_pen(display.create_pen(0, gv * 255, 0)); + display.circle(Point(gv * 140 + 50, 160), 15); + + float bv = adc2.read_voltage() / 3.3f; + display.set_pen(WHITE); + display.circle(Point(bv * 140 + 50, 210), 20); + display.set_pen(display.create_pen(0, 0, bv * 255)); + display.circle(Point(bv * 140 + 50, 210), 15); + + // TODO Find the correct way to translate these in terms of motor + // display.set_motor(display.MOTOR1, display.FORWARD, bv); + // display.set_motor(display.MOTOR2, display.FORWARD, rv); + + // TODO make this work + // display.set_tone(440, 0.5); + + if(button_a.read()) { + display.set_pen(WHITE); + display.character('A', Point(120, 180), 5); + } + + if(button_b.read()) { + display.set_pen(WHITE); + display.character('B', Point(120, 180), 5); + } + + if(button_x.read()) { + display.set_pen(WHITE); + display.character('X', Point(120, 180), 5); + } + + if(button_y.read()) { + display.set_pen(WHITE); + display.character('Y', Point(120, 180), 5); + } + + float tyoff = cos(i / 20.0f) * 50.0f - 50.0f; + Rect text_box(10, 10, 150, 150); + display.set_pen(BOX); + display.rectangle(text_box); + text_box.deflate(10); + display.set_clip(text_box); + display.set_pen(WHITE); + display.text("This is a test of some text data that should wrap nicely onto multiple lines which is dead useful like.", Point(text_box.x, text_box.y + tyoff), 100); + + float xoff = sin(i / 20.0f) * 50.0f; + xoff += 120 - (81 / 2); + float yoff = cos(i / 20.0f) * 50.0f; + yoff += 120 - (68 / 2); + for(int y = 0; y < 68; y++) { + // uint16_t *dest = display.frame_buffer + (y * 240); + uint8_t *src = _binary_fox_tga_start + 18 + (y * 81 * 3); + for(int x = 0; x < 81; x++) { + uint8_t b = *src++; + uint8_t g = *src++; + uint8_t r = *src++; + + display.set_pen(display.create_pen(r, g, b)); + display.pixel(Point(x + xoff, 68 - y + yoff)); + } + } + + display.remove_clip(); + + display.set_pen(WHITE); + display.text("x: " + std::to_string(int(msa301.get_axis(msa301.X, 16) * 100)), Point(10, 190), 100); + display.text("y: " + std::to_string(int(msa301.get_axis(msa301.Y, 16) * 100)), Point(10, 205), 100); + display.text("z: " + std::to_string(int(msa301.get_axis(msa301.Z, 16) * 100)), Point(10, 220), 100); + + uint16_t xpos = (msa301.get_axis(msa301.X, 16) * 120) + 120; + uint16_t ypos = (msa301.get_axis(msa301.Z, 16) * 120) + 120; + display.set_pen(WHITE); + display.circle(Point(xpos, ypos), 20); + display.set_pen(PURPLE); + display.circle(Point(xpos, ypos), 15); + + +/* + if(pico_display.is_pressed(pico_display.A)) { + pico_display.rectangle(0, 0, 18, 18); + //sprite(tick, 5, 5, true, green); + }else{ + //sprite(arrow, 10 + bounce, 10, true, white); + } + + if(pico_display.is_pressed(pico_display.B)) { + pico_display.rectangle(0, 49, 18, 18); + //sprite(tick, 5, 54, true, green); + }else{ + //sprite(arrow, 10 - bounce, 50, true, white); + } + + + if(pico_display.is_pressed(pico_display.X)) { + pico_display.rectangle(102, 0, 18, 18); + //sprite(tick, 107, 5, true, green); + }else{ + //sprite(arrow, 102 - bounce, 10, false, white); + } + + if(pico_display.is_pressed(pico_display.Y)) { + pico_display.rectangle(102, 49, 18, 18); + //sprite(tick, 107, 54, true, green); + }else{ + //sprite(arrow, 102 + bounce, 50, false, white); + } +*/ + // update screen + display.update(); + + i++; + } + + return 0; +} diff --git a/examples/pico_explorer_encoder/CMakeLists.txt b/examples/pico_explorer_encoder/CMakeLists.txt index cab9a39f..bfc53d45 100644 --- a/examples/pico_explorer_encoder/CMakeLists.txt +++ b/examples/pico_explorer_encoder/CMakeLists.txt @@ -1,12 +1,12 @@ add_executable( - explorerencoder - demo.cpp + pico_explorer_encoder + pico_explorer_encoder.cpp ) -pico_generate_pio_header(explorerencoder ${CMAKE_CURRENT_LIST_DIR}/quadrature_out.pio) +pico_generate_pio_header(pico_explorer_encoder ${CMAKE_CURRENT_LIST_DIR}/quadrature_out.pio) # Pull in pico libraries that we need -target_link_libraries(explorerencoder pico_stdlib pico_explorer encoder) +target_link_libraries(pico_explorer_encoder pico_stdlib pico_explorer encoder button motor picographics_st7789) # create map/bin/hex file etc. -pico_add_extra_outputs(explorerencoder) \ No newline at end of file +pico_add_extra_outputs(pico_explorer_encoder) \ No newline at end of file diff --git a/examples/pico_explorer_encoder/demo.cpp b/examples/pico_explorer_encoder/pico_explorer_encoder.cpp similarity index 80% rename from examples/pico_explorer_encoder/demo.cpp rename to examples/pico_explorer_encoder/pico_explorer_encoder.cpp index 98d4a614..b9484730 100644 --- a/examples/pico_explorer_encoder/demo.cpp +++ b/examples/pico_explorer_encoder/pico_explorer_encoder.cpp @@ -4,6 +4,8 @@ #include "pico/stdlib.h" #include "encoder.hpp" #include "quadrature_out.pio.h" +#include "picographics_st7789.hpp" +#include "button.hpp" /* An interactive demo of how rotary encoders work. @@ -31,6 +33,7 @@ be used by jumping GP0 to GP6 and GP1 to GP7. using namespace pimoroni; using namespace encoder; +using namespace motor; //-------------------------------------------------- // Constants @@ -90,8 +93,22 @@ enum DrawState { //-------------------------------------------------- // Variables //-------------------------------------------------- -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_explorer(buffer); +PicoGraphicsST7789 display( + PicoExplorer::WIDTH, + PicoExplorer::HEIGHT, + ROTATE_0, // Rotation + false, // Is it round!? + nullptr, // Buffer + get_spi_pins(BG_SPI_FRONT) +); + +Button button_a(PicoExplorer::A); +Button button_b(PicoExplorer::B); +Button button_x(PicoExplorer::X); +Button button_y(PicoExplorer::Y); + +Motor motor1(PicoExplorer::MOTOR1_PINS); +Motor motor2(PicoExplorer::MOTOR2_PINS); Encoder enc(pio0, 0, ENCODER_PINS, ENCODER_COMMON_PIN, NORMAL_DIR, COUNTS_PER_REV, COUNT_MICROSTEPS, FREQ_DIVIDER); @@ -166,13 +183,13 @@ uint32_t draw_plot(Point p1, Point p2, volatile bool (&readings)[READINGS_SIZE], switch(draw_state) { case DRAW_TRANSITION: for(uint8_t y = p1.y; y < p2.y; y++) - pico_explorer.pixel(Point(x + p1.x, y)); + display.pixel(Point(x + p1.x, y)); break; case DRAW_HIGH: - pico_explorer.pixel(Point(x + p1.x, p1.y)); + display.pixel(Point(x + p1.x, p1.y)); break; case DRAW_LOW: - pico_explorer.pixel(Point(x + p1.x, p2.y - 1)); + display.pixel(Point(x + p1.x, p2.y - 1)); break; } } @@ -215,11 +232,6 @@ void setup() { gpio_pull_down(ENCODER_SWITCH_PIN); } - pico_explorer.init(); - pico_explorer.set_pen(0); - pico_explorer.clear(); - pico_explorer.update(); - enc.init(); bool_pair state = enc.state(); @@ -243,6 +255,7 @@ void setup() { // MAIN //////////////////////////////////////////////////////////////////////////////////////////////////// int main() { + Pen WHITE = display.create_pen(255, 255, 255); // Perform the main setup for the demo setup(); @@ -273,18 +286,21 @@ int main() { Encoder::Capture capture = enc.capture(); // Spin Motor 1 either clockwise or counterclockwise depending on if B or Y are pressed - if(pico_explorer.is_pressed(PicoExplorer::B) && !pico_explorer.is_pressed(PicoExplorer::Y)) { - pico_explorer.set_motor(PicoExplorer::MOTOR1, PicoExplorer::FORWARD, 1.0f); + if(button_b.read() && !button_y.read()) { + // TODO Fix motors + //display.set_motor(PicoExplorer::MOTOR1, PicoExplorer::FORWARD, 1.0f); } - else if(pico_explorer.is_pressed(PicoExplorer::Y) && !pico_explorer.is_pressed(PicoExplorer::B)) { - pico_explorer.set_motor(PicoExplorer::MOTOR1, PicoExplorer::REVERSE, 0.2f); + else if(button_y.read() && !button_b.read()) { + // TODO Fix motors + //display.set_motor(PicoExplorer::MOTOR1, PicoExplorer::REVERSE, 0.2f); } else { - pico_explorer.set_motor(PicoExplorer::MOTOR1, PicoExplorer::STOP); + // TODO Fix motors + //display.set_motor(PicoExplorer::MOTOR1, PicoExplorer::STOP); } // If A has been pressed, zoom the view out to a min of x1 - if(pico_explorer.is_pressed(PicoExplorer::A)) { + if(button_a.read()) { if(!button_latch_a) { button_latch_a = true; current_zoom_level = std::max(current_zoom_level / 2, 1); @@ -295,7 +311,7 @@ int main() { } // If X has been pressed, zoom the view in to the max of x512 - if(pico_explorer.is_pressed(PicoExplorer::X)) { + if(button_x.read()) { if(!button_latch_x) { button_latch_x = true; current_zoom_level = std::min(current_zoom_level * 2, 512); @@ -308,16 +324,16 @@ int main() { //-------------------------------------------------- // Draw the encoder readings to the screen as a signal plot - pico_explorer.set_pen(0, 0, 0); - pico_explorer.clear(); + display.set_pen(display.create_pen(0, 0, 0)); + display.clear(); drawing_to_screen = true; - pico_explorer.set_pen(255, 255, 0); + display.set_pen(display.create_pen(255, 255, 0)); uint32_t local_pos = next_reading_index; uint32_t alignment_offset = draw_plot(Point(0, 10), Point(PicoExplorer::WIDTH, 10 + 50), enc_a_readings, local_pos, current_zoom_level > EDGE_ALIGN_ABOVE_ZOOM); - pico_explorer.set_pen(0, 255, 255); + display.set_pen(display.create_pen(0, 255, 255)); draw_plot(Point(0, 80), Point(PicoExplorer::WIDTH, 80 + 50), enc_b_readings, (local_pos + (READINGS_SIZE - alignment_offset)) % READINGS_SIZE, false); // Copy values that may have been stored in the scratch buffers, back into the main buffers @@ -333,49 +349,49 @@ int main() { drawing_to_screen = false; next_scratch_index = 0; - pico_explorer.set_pen(255, 255, 255); - pico_explorer.character('A', Point(5, 10 + 15), 3); - pico_explorer.character('B', Point(5, 80 + 15), 3); + display.set_pen(WHITE); + display.character('A', Point(5, 10 + 15), 3); + display.character('B', Point(5, 80 + 15), 3); if(current_zoom_level < 10) - pico_explorer.text("x" + std::to_string(current_zoom_level), Point(220, 62), 200, 2); + display.text("x" + std::to_string(current_zoom_level), Point(220, 62), 200, 2); else if(current_zoom_level < 100) - pico_explorer.text("x" + std::to_string(current_zoom_level), Point(210, 62), 200, 2); + display.text("x" + std::to_string(current_zoom_level), Point(210, 62), 200, 2); else - pico_explorer.text("x" + std::to_string(current_zoom_level), Point(200, 62), 200, 2); + display.text("x" + std::to_string(current_zoom_level), Point(200, 62), 200, 2); //-------------------------------------------------- // Write out the count, frequency and rpm of the encoder - pico_explorer.set_pen(8, 8, 8); - pico_explorer.rectangle(Rect(0, 140, PicoExplorer::WIDTH, PicoExplorer::HEIGHT - 140)); + display.set_pen(display.create_pen(8, 8, 8)); + display.rectangle(Rect(0, 140, PicoExplorer::WIDTH, PicoExplorer::HEIGHT - 140)); - pico_explorer.set_pen(64, 64, 64); - pico_explorer.rectangle(Rect(0, 140, PicoExplorer::WIDTH, 2)); + display.set_pen(display.create_pen(64, 64, 64)); + display.rectangle(Rect(0, 140, PicoExplorer::WIDTH, 2)); { std::stringstream sstream; sstream << capture.count(); - pico_explorer.set_pen(255, 255, 255); pico_explorer.text("Count:", Point(10, 150), 200, 3); - pico_explorer.set_pen(255, 128, 255); pico_explorer.text(sstream.str(), Point(110, 150), 200, 3); + display.set_pen(WHITE); display.text("Count:", Point(10, 150), 200, 3); + display.set_pen(display.create_pen(255, 128, 255)); display.text(sstream.str(), Point(110, 150), 200, 3); } { std::stringstream sstream; sstream << std::fixed << std::setprecision(1) << capture.frequency() << "hz"; - pico_explorer.set_pen(255, 255, 255); pico_explorer.text("Freq: ", Point(10, 180), 220, 3); - pico_explorer.set_pen(128, 255, 255); pico_explorer.text(sstream.str(), Point(90, 180), 220, 3); + display.set_pen(WHITE); display.text("Freq: ", Point(10, 180), 220, 3); + display.set_pen(display.create_pen(128, 255, 255)); display.text(sstream.str(), Point(90, 180), 220, 3); } { std::stringstream sstream; sstream << std::fixed << std::setprecision(1) << capture.revolutions_per_minute(); - pico_explorer.set_pen(255, 255, 255); pico_explorer.text("RPM: ", Point(10, 210), 220, 3); - pico_explorer.set_pen(255, 255, 128); pico_explorer.text(sstream.str(), Point(80, 210), 220, 3); + display.set_pen(WHITE); display.text("RPM: ", Point(10, 210), 220, 3); + display.set_pen(display.create_pen(255, 255, 128)); display.text(sstream.str(), Point(80, 210), 220, 3); } - pico_explorer.update(); // Refresh the screen + display.update(); // Refresh the screen gpio_put(PICO_DEFAULT_LED_PIN, false); // Show the screen refresh has ended } } diff --git a/examples/pico_pot_explorer/CMakeLists.txt b/examples/pico_pot_explorer/CMakeLists.txt index dc5649d4..f2b47485 100644 --- a/examples/pico_pot_explorer/CMakeLists.txt +++ b/examples/pico_pot_explorer/CMakeLists.txt @@ -2,11 +2,11 @@ set(OUTPUT_NAME potentiometer_explorer) add_executable( ${OUTPUT_NAME} - demo.cpp + pico_pot_explorer.cpp ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_potentiometer pico_explorer) +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_potentiometer pico_explorer picographics_st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/pico_pot_explorer/demo.cpp b/examples/pico_pot_explorer/pico_pot_explorer.cpp similarity index 71% rename from examples/pico_pot_explorer/demo.cpp rename to examples/pico_pot_explorer/pico_pot_explorer.cpp index 4455c18c..49f4f067 100644 --- a/examples/pico_pot_explorer/demo.cpp +++ b/examples/pico_pot_explorer/pico_pot_explorer.cpp @@ -7,11 +7,23 @@ #include "common/pimoroni_i2c.hpp" #include "pico_explorer.hpp" #include "breakout_potentiometer.hpp" +#include "picographics_st7789.hpp" using namespace pimoroni; -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_explorer(buffer); +PicoGraphicsST7789 display( + PicoExplorer::WIDTH, + PicoExplorer::HEIGHT, + ROTATE_0, // Rotation + false, // Is it round!? + nullptr, // Buffer + get_spi_pins(BG_SPI_FRONT) +); + +Pen BLACK = display.create_pen(0, 0, 0); +Pen RED = display.create_pen(255, 0, 0); +Pen GREEN = display.create_pen(0, 255, 0); +Pen BLUE = display.create_pen(0, 0, 255); I2C i2c(PICO_EXPLORER); BreakoutPotentiometer pot(&i2c); @@ -43,9 +55,6 @@ int main() { stdio_init_all(); - pico_explorer.init(); - pico_explorer.update(); - printf("Starting...\n"); if(pot.init()) { @@ -62,47 +71,49 @@ int main() { from_hsv(percent, 1.0f, 1.0f, r, g, b); pot.set_led(r, g, b); - pico_explorer.set_pen(0, 0, 0); - pico_explorer.clear(); + display.set_pen(BLACK); + display.clear(); { - pico_explorer.set_pen(255, 0, 0); + display.set_pen(RED); std::ostringstream ss; ss << "R = "; ss << (int)r; std::string s(ss.str()); - pico_explorer.text(s, Point(10, 10), 220, 6); + display.text(s, Point(10, 10), 220, 6); } { - pico_explorer.set_pen(0, 255, 0); + display.set_pen(GREEN); std::ostringstream ss; ss << "G = "; ss << (int)g; std::string s(ss.str()); - pico_explorer.text(s, Point(10, 70), 220, 6); + display.text(s, Point(10, 70), 220, 6); } { - pico_explorer.set_pen(0, 0, 255); + display.set_pen(BLUE); std::ostringstream ss; ss << "B = "; ss << (int)b; std::string s(ss.str()); - pico_explorer.text(s, Point(10, 130), 220, 6); + display.text(s, Point(10, 130), 220, 6); } { - pico_explorer.set_pen(r, g, b); + // Shouldn't really use create_pen in-line. + // In default (RGB332) palette mode this will lookup the nearest 8-bit colour + display.set_pen(display.create_pen(r, g, b)); std::ostringstream ss; ss << "#"; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)r; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)g; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)b; std::string s(ss.str()); - pico_explorer.text(s, Point(10, 190), 220, 5); + display.text(s, Point(10, 190), 220, 5); } - pico_explorer.update(); + display.update(); } } else { diff --git a/examples/pico_rtc_display/CMakeLists.txt b/examples/pico_rtc_display/CMakeLists.txt index 8f03ce48..7b2f6207 100644 --- a/examples/pico_rtc_display/CMakeLists.txt +++ b/examples/pico_rtc_display/CMakeLists.txt @@ -2,11 +2,11 @@ set(OUTPUT_NAME rtc_display) add_executable( ${OUTPUT_NAME} - demo.cpp + pico_rtc_display.cpp ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_explorer pico_display breakout_rtc) +target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_explorer pico_display breakout_rtc picographics_st7789 button rgbled) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/pico_rtc_display/demo.cpp b/examples/pico_rtc_display/pico_rtc_display.cpp similarity index 75% rename from examples/pico_rtc_display/demo.cpp rename to examples/pico_rtc_display/pico_rtc_display.cpp index 266d70b8..eee36499 100644 --- a/examples/pico_rtc_display/demo.cpp +++ b/examples/pico_rtc_display/pico_rtc_display.cpp @@ -17,7 +17,7 @@ // To use PicoExplorer rather than PicoDisplay, uncomment the following line // #define USE_PICO_EXPLORER 1 // This: -// - Includes pico_explorer.hpp rather than pico_display.hpp +// - Includes pico_explorer.hpp rather than display.hpp // - Replaces all PicoDisplay references with PicoExplorer // - Leaves out the .set_led() calls in flash_led() #ifdef USE_PICO_EXPLORER @@ -27,6 +27,10 @@ #endif #include "breakout_rtc.hpp" +#include "picographics_st7789.hpp" +#include "drivers/button/button.hpp" +#include "drivers/rgbled/rgbled.hpp" + #define MODE_DISP_CLOCK 0 #define MODE_DISP_TIMER 1 #define MODE_SET_TIMER 2 @@ -36,17 +40,28 @@ using namespace pimoroni; #ifdef USE_PICO_EXPLORER -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_display(buffer); uint16_t screen_width = PicoExplorer::WIDTH; uint16_t screen_height = PicoExplorer::HEIGHT; + +Button button_a(PicoExplorer::A); +Button button_b(PicoExplorer::B); +Button button_x(PicoExplorer::X); +Button button_y(PicoExplorer::Y); + #else -uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT]; -PicoDisplay pico_display(buffer); uint16_t screen_width = PicoDisplay::WIDTH; uint16_t screen_height = PicoDisplay::HEIGHT; + +Button button_a(PicoDisplay::A); +Button button_b(PicoDisplay::B); +Button button_x(PicoDisplay::X); +Button button_y(PicoDisplay::Y); + +RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); #endif +PicoGraphicsST7789 display(screen_width, screen_height, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); + BreakoutRTC rtc; #define LOW_COUNT_MOD 40 @@ -69,17 +84,20 @@ void flash_led(uint32_t curr_count) { #ifndef USE_PICO_EXPLORER if((curr_count % FLASH_MOD) < (FLASH_MOD / 2)) { // value less than half modded number - LED off - pico_display.set_led(0, 0, 0); + led.set_rgb(0, 0, 0); } else { // value more than half modded number - LED on - pico_display.set_led(128, 128, 128); + led.set_rgb(128, 128, 128); } #endif } int main() { - pico_display.init(); + Pen WHITE = display.create_pen(255, 255, 255); + Pen BG = display.create_pen(55, 65, 75); + Pen RED = display.create_pen(255, 0, 0); + Pen GREEN = display.create_pen(0, 255, 0); rtc.init(); // rtc.setup(false); @@ -112,7 +130,7 @@ int main() { while(true) { - if(a_pressed == 0 && pico_display.is_pressed(pico_display.A)) { + if(a_pressed == 0 && button_a.read()) { a_pressed = 1; if(display_mode == MODE_DISP_CLOCK) { // We were displaying clock = set up timer @@ -134,11 +152,11 @@ int main() { display_mode = MODE_SET_TIMER; } } - else if(a_pressed >= 1 && !pico_display.is_pressed(pico_display.A)) { + else if(a_pressed >= 1 && !button_a.read()) { a_pressed = 0; } - if(b_pressed == 0 && pico_display.is_pressed(pico_display.B)) { + if(b_pressed == 0 && button_b.read()) { b_pressed = 1; if((display_mode == MODE_DISP_TIMER) || (display_mode == MODE_SET_TIMER)) { @@ -150,117 +168,117 @@ int main() { timer_count = DEFAULT_TIMER_COUNT; } } - else if(b_pressed >= 1 && !pico_display.is_pressed(pico_display.B)) { + else if(b_pressed >= 1 && !button_b.read()) { b_pressed = 0; } - if(x_pressed == 0 && pico_display.is_pressed(pico_display.X)) { + if(x_pressed == 0 && button_x.read()) { x_pressed = 1; if(display_mode == MODE_SET_TIMER) { // Setting timer - Increment count timer_count++; } } - else if(x_pressed >= 1 && pico_display.is_pressed(pico_display.X)) { + else if(x_pressed >= 1 && button_x.read()) { // Button still pressed - check if has reached repeat count if(repeat_count_reached(x_pressed++)) { timer_count++; } } - else if(x_pressed >= 1 && !pico_display.is_pressed(pico_display.X)) { + else if(x_pressed >= 1 && !button_x.read()) { x_pressed = 0; } - if(y_pressed == 0 && pico_display.is_pressed(pico_display.Y)) { + if(y_pressed == 0 && button_y.read()) { y_pressed = 1; if(display_mode == MODE_SET_TIMER) { // Setting timer - Decrement count if (timer_count >= 1) timer_count--; } } - else if(y_pressed >= 1 && pico_display.is_pressed(pico_display.Y)) { + else if(y_pressed >= 1 && button_y.read()) { // Button still pressed - check if has reached repeat count if(repeat_count_reached(y_pressed++)) { if(timer_count >= 1) timer_count--; } } - else if(y_pressed >= 1 && !pico_display.is_pressed(pico_display.Y)) { + else if(y_pressed >= 1 && !button_y.read()) { y_pressed = 0; } Rect text_box(5, 5, screen_width-10, screen_height-10); - pico_display.set_pen(55, 65, 75); - pico_display.rectangle(text_box); + display.set_pen(BG); + display.rectangle(text_box); // text_box.deflate(10); - pico_display.set_clip(text_box); - pico_display.set_pen(255, 255, 255); + display.set_clip(text_box); + display.set_pen(WHITE); switch(display_mode) { case MODE_DISP_CLOCK: // Show the clock face flash_led(0); if(rtc.update_time()) { - pico_display.text("Set Timer", + display.text("Set Timer", Point(text_box.x, text_box.y+2), 230, 1); - pico_display.set_pen(0, 255, 0); - pico_display.text(rtc.string_date(), + display.set_pen(GREEN); + display.text(rtc.string_date(), Point(text_box.x, text_box.y+20), 230, 4); - pico_display.set_pen(255, 0, 0); - pico_display.text(rtc.string_time(), + display.set_pen(RED); + display.text(rtc.string_time(), Point(text_box.x, text_box.y+60), 230, 6); - pico_display.set_pen(255, 255, 255); - pico_display.text("Clock", + display.set_pen(WHITE); + display.text("Clock", Point(text_box.x, text_box.y+screen_height-20), 230, 1); } else { sprintf(buf, "Time: rtc.updateTime() ret err"); - pico_display.text(buf, + display.text(buf, Point(text_box.x, text_box.y), 30, 2); } break; case MODE_DISP_TIMER: - pico_display.text("Set Timer", + display.text("Set Timer", Point(text_box.x, text_box.y+2), 230, 1); if(rtc.read_timer_interrupt_flag()) { // Go periodic time interupt - say loop ended - pico_display.set_pen(255, 0, 0); + display.set_pen(RED); sprintf(buf, "%s", "Timer complete"); - pico_display.text(buf, + display.text(buf, Point(text_box.x, text_box.y+30), 230, 4); - pico_display.set_pen(255, 255, 255); + display.set_pen(WHITE); flash_led(i); } else { sprintf(buf, "%s %d", "Timer running", rtc.get_timer_count()); - pico_display.text(buf, + display.text(buf, Point(text_box.x, text_box.y+30), 230, 3); } - pico_display.text("Clock", + display.text("Clock", Point(text_box.x, text_box.y+screen_height-20), 230, 1); break; case MODE_SET_TIMER: flash_led(0); - pico_display.text("Run Timer", + display.text("Run Timer", Point(text_box.x, text_box.y+2), 230, 1); - pico_display.text("+ Time", + display.text("+ Time", Point(text_box.x+screen_width-42, text_box.y+2), 230, 1); sprintf(buf, "Time %d secs", timer_count); - pico_display.text(buf, + display.text(buf, Point(text_box.x, text_box.y+30), 230, 3); - pico_display.text("Clock", + display.text("Clock", Point(text_box.x, text_box.y+screen_height-20), 230, 1); - pico_display.text("- Time", + display.text("- Time", Point(text_box.x+screen_width-42, text_box.y+screen_height-20), 230, 1); break; } - pico_display.remove_clip(); + display.remove_clip(); // update screen - pico_display.update(); + display.update(); i++; } diff --git a/examples/pico_tof_display/CMakeLists.txt b/examples/pico_tof_display/CMakeLists.txt index 2b372d56..06a8417a 100644 --- a/examples/pico_tof_display/CMakeLists.txt +++ b/examples/pico_tof_display/CMakeLists.txt @@ -1,10 +1,10 @@ add_executable( tof_display - demo.cpp + pico_tof_display.cpp ) # Pull in pico libraries that we need -target_link_libraries(tof_display pico_stdlib pico_explorer pico_display vl53l1x) +target_link_libraries(tof_display pico_stdlib pico_explorer pico_display vl53l1x picographics_st7789 button) pico_enable_stdio_uart(tof_display 1) diff --git a/examples/pico_tof_display/demo.cpp b/examples/pico_tof_display/pico_tof_display.cpp similarity index 71% rename from examples/pico_tof_display/demo.cpp rename to examples/pico_tof_display/pico_tof_display.cpp index cd750d81..86bacb2f 100644 --- a/examples/pico_tof_display/demo.cpp +++ b/examples/pico_tof_display/pico_tof_display.cpp @@ -24,62 +24,27 @@ #include "pico_display.hpp" #endif #include "vl53l1x.hpp" +#include "drivers/button/button.hpp" + +#include "picographics_st7789.hpp" using namespace pimoroni; -class AutoRepeat { - public: - AutoRepeat(uint32_t repeat_time=200, uint32_t hold_time=1000) { - this->repeat_time = repeat_time; - this->hold_time = hold_time; - } - bool next(uint32_t time, bool state) { - bool changed = state != last_state; - last_state = state; - - if(changed) { - if(state) { - pressed_time = time; - pressed = true; - last_time = time; - return true; - } - else { - pressed_time = 0; - pressed = false; - last_time = 0; - } - } - // Shortcut for no auto-repeat - if(repeat_time == 0) return false; - - if(pressed) { - uint32_t repeat_rate = repeat_time; - if(hold_time > 0 && time - pressed_time > hold_time) { - repeat_rate /= 3; - } - if(time - last_time > repeat_rate) { - last_time = time; - return true; - } - } - - return false; - } - private: - uint32_t repeat_time; - uint32_t hold_time; - bool pressed = false; - bool last_state = false; - uint32_t pressed_time = 0; - uint32_t last_time = 0; -}; - #ifdef USE_PICO_EXPLORER -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_display(buffer); -uint16_t screen_width = PicoExplorer::WIDTH; -uint16_t screen_height = PicoExplorer::HEIGHT; +PicoGraphicsST7789 pico_display( + PicoExplorer::WIDTH, + PicoExplorer::HEIGHT, + ROTATE_0, // Rotation + false, // Is it round!? + nullptr, // Buffer + get_spi_pins(BG_SPI_FRONT) +); + +Button button_a(PicoExplorer::A); +Button button_b(PicoExplorer::B); +Button button_x(PicoExplorer::X); +Button button_y(PicoExplorer::Y); + uint16_t disptext_reminder_size = 2; uint16_t disptext_b_reminder_xoff = 5; uint16_t disptext_b_reminder_yoff = 210; @@ -94,10 +59,20 @@ uint16_t disptext_dist_xoff = 10; uint16_t disptext_dist_yoff = 90; uint16_t disptext_dist_size = 6; #else -uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT]; -PicoDisplay pico_display(buffer); -uint16_t screen_width = PicoDisplay::WIDTH; -uint16_t screen_height = PicoDisplay::HEIGHT; +PicoGraphicsST7789 pico_display( + PicoDisplay::WIDTH, + PicoDisplay::HEIGHT, + ROTATE_0, // Rotation + false, // Is it round!? + nullptr, // Buffer + get_spi_pins(BG_SPI_FRONT) +); + +Button button_a(PicoDisplay::A); +Button button_b(PicoDisplay::B); +Button button_x(PicoDisplay::X); +Button button_y(PicoDisplay::Y); + uint16_t disptext_reminder_size = 2; uint16_t disptext_b_reminder_xoff = 2; uint16_t disptext_b_reminder_yoff = 110; @@ -113,6 +88,10 @@ uint16_t disptext_dist_yoff = 45; uint16_t disptext_dist_size = 4; #endif + +uint16_t screen_width = pico_display.bounds.w; +uint16_t screen_height = pico_display.bounds.h; + #define MM_TO_INCH 25.4 VL53L1X vl53l1x; @@ -124,11 +103,6 @@ const char mode_to_text[4][7] = { "Long" }; -AutoRepeat ar_button_a; -AutoRepeat ar_button_b; -AutoRepeat ar_button_x; -AutoRepeat ar_button_y; - #define FLASH_MOD 20 void flash_led(uint32_t curr_count) { // Flash the LED based on the current loop counter @@ -148,8 +122,6 @@ int main() { bool vl53_present = false; uint16_t vl53_mode = 1; - pico_display.init(); - vl53_present = vl53l1x.init(); uint32_t i = 0; @@ -169,11 +141,15 @@ int main() { // Whether the display is being held bool dist_held = false; + Pen WHITE = pico_display.create_pen(255, 255, 255); + Pen REDDISH = pico_display.create_pen(255, 64, 64); + Pen BG = pico_display.create_pen(55, 65, 75); + while(true) { - // bool a_pressed = ar_button_a.next(i, pico_display.is_pressed(pico_display.A)); - bool b_pressed = ar_button_b.next(i, pico_display.is_pressed(pico_display.B)); - bool x_pressed = ar_button_x.next(i, pico_display.is_pressed(pico_display.X)); - bool y_pressed = ar_button_y.next(i, pico_display.is_pressed(pico_display.Y)); + // bool a_pressed = button_a.read(); + bool b_pressed = button_b.read(); + bool x_pressed = button_x.read(); + bool y_pressed = button_y.read(); if (b_pressed) { dist_held = !dist_held; @@ -192,11 +168,11 @@ int main() { } Rect text_box(5, 5, screen_width-10, screen_height-10); - pico_display.set_pen(55, 65, 75); + pico_display.set_pen(BG); pico_display.rectangle(text_box); // text_box.deflate(10); pico_display.set_clip(text_box); - pico_display.set_pen(255, 255, 255); + pico_display.set_pen(WHITE); // Show the current distance flash_led(0); if (vl53_present) { @@ -207,12 +183,12 @@ int main() { Point(text_box.x+disptext_y_reminder_xoff, text_box.y+disptext_y_reminder_yoff), 230, disptext_reminder_size); if(dist_held) { - pico_display.set_pen(255, 64, 64); + pico_display.set_pen(REDDISH); } pico_display.text("Hold", Point(text_box.x+disptext_b_reminder_xoff, text_box.y+disptext_b_reminder_yoff), 230, disptext_reminder_size); - pico_display.set_pen(255, 255, 255); + pico_display.set_pen(WHITE); sprintf(buf, "Mode: %s", mode_to_text[vl53_mode]); pico_display.text(buf, diff --git a/examples/pico_trackball_display/CMakeLists.txt b/examples/pico_trackball_display/CMakeLists.txt index e860fce5..dc065c5e 100644 --- a/examples/pico_trackball_display/CMakeLists.txt +++ b/examples/pico_trackball_display/CMakeLists.txt @@ -2,11 +2,11 @@ set(OUTPUT_NAME trackball_display) add_executable( ${OUTPUT_NAME} - demo.cpp + pico_trackball_display.cpp ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_explorer pico_display breakout_trackball) +target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_explorer pico_display breakout_trackball picographics_st7789) pico_enable_stdio_uart(${OUTPUT_NAME} 1) diff --git a/examples/pico_trackball_display/demo.cpp b/examples/pico_trackball_display/pico_trackball_display.cpp similarity index 72% rename from examples/pico_trackball_display/demo.cpp rename to examples/pico_trackball_display/pico_trackball_display.cpp index 0250bad5..b045b899 100644 --- a/examples/pico_trackball_display/demo.cpp +++ b/examples/pico_trackball_display/pico_trackball_display.cpp @@ -16,15 +16,17 @@ // To use PicoExplorer rather than PicoDisplay, uncomment the following line #define USE_PICO_EXPLORER 1 // This: -// - Includes pico_explorer.hpp rather than pico_display.hpp +// - Includes pico_explorer.hpp rather than display.hpp // - Replaces all PicoDisplay references with PicoExplorer #ifdef USE_PICO_EXPLORER #include "pico_explorer.hpp" #else -#include "pico_display.hpp" +#include "display.hpp" #endif #include "breakout_trackball.hpp" +#include "picographics_st7789.hpp" + using namespace pimoroni; struct TrackballColour { @@ -35,16 +37,15 @@ struct TrackballColour { }; #ifdef USE_PICO_EXPLORER -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_display(buffer); const uint16_t screen_width = PicoExplorer::WIDTH; const uint16_t screen_height = PicoExplorer::HEIGHT; #else -uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT]; -PicoDisplay pico_display(buffer); const uint16_t screen_width = PicoDisplay::WIDTH; const uint16_t screen_height = PicoDisplay::HEIGHT; #endif + +PicoGraphicsST7789 display(screen_width, screen_height, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); + const Point screen_centre(screen_width / 2, screen_height / 2); const uint16_t circle_radius = std::min(screen_centre.x, screen_centre.y) / 4; const float ring_radius_mult = 0.7f; @@ -71,7 +72,6 @@ bool centre_circle_state = false; int main() { int16_t x = screen_centre.x; int16_t y = screen_centre.y; - pico_display.init(); trackball.init(); @@ -84,52 +84,57 @@ int main() { positions[i] = pos; } + Pen WHITE = display.create_pen(255, 255, 255); + Pen BLACK = display.create_pen(0, 0, 0); + Pen LIGHT_GREY = display.create_pen(212, 212, 212); + Pen MID_GREY = display.create_pen(128, 128, 128); + while(true) { Trackball::State state = trackball.read(); x = std::min(std::max(x - state.left + state.right, 0), (int)screen_width); y = std::min(std::max(y - state.up + state.down, 0), (int)screen_height); Point cursor_pos(x, y); - pico_display.set_pen(0, 0, 0); - pico_display.clear(); + display.set_pen(BLACK); + display.clear(); //Draw a set of circles in a ring around the screen centre for(uint8_t i = 0; i < NUM_CIRCLES; i++) { TrackballColour col = colour_circles[i]; if(circle_states[i]) { - pico_display.set_pen(col.r, col.g, col.b); - pico_display.circle(positions[i], circle_radius + circle_border); - pico_display.set_pen(col.r >> 1, col.g >> 1, col.b >> 1); - pico_display.circle(positions[i], circle_radius); + display.set_pen(display.create_pen(col.r, col.g, col.b)); + display.circle(positions[i], circle_radius + circle_border); + display.set_pen(display.create_pen(col.r >> 1, col.g >> 1, col.b >> 1)); + display.circle(positions[i], circle_radius); } else { - pico_display.set_pen(col.r >> 1, col.g >> 1, col.b >> 1); - pico_display.circle(positions[i], circle_radius + circle_border); - pico_display.set_pen(col.r, col.g, col.b); - pico_display.circle(positions[i], circle_radius); + display.set_pen(display.create_pen(col.r >> 1, col.g >> 1, col.b >> 1)); + display.circle(positions[i], circle_radius + circle_border); + display.set_pen(display.create_pen(col.r, col.g, col.b)); + display.circle(positions[i], circle_radius); } } //Draw a centre circle if(centre_circle_state) { - pico_display.set_pen(255, 255, 255); - pico_display.circle(screen_centre, circle_radius + circle_border); - pico_display.set_pen(128, 128, 128); - pico_display.circle(screen_centre, circle_radius); + display.set_pen(WHITE); + display.circle(screen_centre, circle_radius + circle_border); + display.set_pen(MID_GREY); + display.circle(screen_centre, circle_radius); } else { - pico_display.set_pen(128, 128, 128); - pico_display.circle(screen_centre, circle_radius + circle_border); - pico_display.set_pen(255, 255, 255); - pico_display.circle(screen_centre, circle_radius); + display.set_pen(MID_GREY); + display.circle(screen_centre, circle_radius + circle_border); + display.set_pen(WHITE); + display.circle(screen_centre, circle_radius); } //Draw the cursor - pico_display.set_pen(0, 0, 0); - pico_display.circle(cursor_pos, cursor_radius + cursor_border); - pico_display.set_pen(212, 212, 212); - pico_display.circle(cursor_pos, cursor_radius); + display.set_pen(BLACK); + display.circle(cursor_pos, cursor_radius + cursor_border); + display.set_pen(LIGHT_GREY); + display.circle(cursor_pos, cursor_radius); int16_t x_diff = cursor_pos.x - screen_centre.x; int16_t y_diff = cursor_pos.y - screen_centre.y; @@ -161,7 +166,7 @@ int main() { } // update screen - pico_display.update(); + display.update(); } return 0; diff --git a/examples/tufty2040/tufty2040_drawing.cmake b/examples/tufty2040/tufty2040_drawing.cmake index f918ea3f..ff63d762 100644 --- a/examples/tufty2040/tufty2040_drawing.cmake +++ b/examples/tufty2040/tufty2040_drawing.cmake @@ -4,7 +4,7 @@ add_executable(${OUTPUT_NAME} tufty2040_drawing.cpp) target_link_libraries(${OUTPUT_NAME} tufty2040 hardware_spi - generic_st7789 + picographics_st7789 button ) diff --git a/examples/tufty2040/tufty2040_drawing.cpp b/examples/tufty2040/tufty2040_drawing.cpp index a4bbb99a..63ced2c4 100644 --- a/examples/tufty2040/tufty2040_drawing.cpp +++ b/examples/tufty2040/tufty2040_drawing.cpp @@ -7,7 +7,7 @@ #include "pico/platform.h" #include "common/pimoroni_common.hpp" -#include "generic_st7789.hpp" +#include "picographics_st7789.hpp" #include "tufty2040.hpp" #include "button.hpp" @@ -15,8 +15,7 @@ using namespace pimoroni; Tufty2040 tufty; -// Swap WIDTH and HEIGHT to rotate 90 degrees -ST7789Generic pico_display( +PicoGraphicsST7789 display( Tufty2040::WIDTH, Tufty2040::HEIGHT, ROTATE_0, nullptr, ParallelPins{ Tufty2040::LCD_CS, @@ -60,8 +59,10 @@ void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { } int main() { - pico_display.set_backlight(255); - pico_display.configure_display(true); // Rotate 180 + display.set_backlight(255); + + Pen WHITE = display.create_pen(255, 255, 255); + Pen BG = display.create_pen(120, 40, 60); struct pt { float x; @@ -75,12 +76,12 @@ int main() { std::vector shapes; for(int i = 0; i < 100; i++) { pt shape; - shape.x = rand() % pico_display.bounds.w; - shape.y = rand() % pico_display.bounds.h; + shape.x = rand() % display.bounds.w; + shape.y = rand() % display.bounds.h; shape.r = (rand() % 10) + 3; shape.dx = float(rand() % 255) / 64.0f; shape.dy = float(rand() % 255) / 64.0f; - shape.pen = pico_display.create_pen(rand() % 255, rand() % 255, rand() % 255); + shape.pen = display.create_pen(rand() % 255, rand() % 255, rand() % 255); shapes.push_back(shape); } @@ -89,8 +90,8 @@ int main() { while(true) { - pico_display.set_pen(120, 40, 60); - pico_display.clear(); + display.set_pen(BG); + display.clear(); for(auto &shape : shapes) { shape.x += shape.dx; @@ -99,30 +100,30 @@ int main() { shape.dx *= -1; shape.x = shape.r; } - if((shape.x + shape.r) >= pico_display.bounds.w) { + if((shape.x + shape.r) >= display.bounds.w) { shape.dx *= -1; - shape.x = pico_display.bounds.w - shape.r; + shape.x = display.bounds.w - shape.r; } if((shape.y - shape.r) < 0) { shape.dy *= -1; shape.y = shape.r; } - if((shape.y + shape.r) >= pico_display.bounds.h) { + if((shape.y + shape.r) >= display.bounds.h) { shape.dy *= -1; - shape.y = pico_display.bounds.h - shape.r; + shape.y = display.bounds.h - shape.r; } - pico_display.set_pen(shape.pen); - pico_display.circle(Point(shape.x, shape.y), shape.r); + display.set_pen(shape.pen); + display.circle(Point(shape.x, shape.y), shape.r); } - pico_display.set_pen(255, 255, 255); - pico_display.text("Hello World", text_location, 320); + display.set_pen(WHITE); + display.text("Hello World", text_location, 320); // update screen - pico_display.update(); + display.update(); i+=10; tufty.led(i); diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 47f1031c..4eb2dcd8 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -17,7 +17,7 @@ add_subdirectory(breakout_sgp30) add_subdirectory(breakout_as7262) add_subdirectory(breakout_msa301) add_subdirectory(breakout_bh1745) -add_subdirectory(generic_st7789) +add_subdirectory(picographics_st7789) add_subdirectory(pico_graphics) add_subdirectory(pico_display) add_subdirectory(pico_display_2) diff --git a/libraries/generic_st7789/CMakeLists.txt b/libraries/generic_st7789/CMakeLists.txt deleted file mode 100644 index 6e96f70b..00000000 --- a/libraries/generic_st7789/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -include(generic_st7789.cmake) \ No newline at end of file diff --git a/libraries/pico_display/pico_display.cmake b/libraries/pico_display/pico_display.cmake index 810ddff8..a50b1a4b 100644 --- a/libraries/pico_display/pico_display.cmake +++ b/libraries/pico_display/pico_display.cmake @@ -1,6 +1,3 @@ -include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/st7789/st7789.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/../pico_graphics/pico_graphics.cmake) - add_library(pico_display INTERFACE) target_sources(pico_display INTERFACE @@ -10,4 +7,4 @@ target_sources(pico_display INTERFACE target_include_directories(pico_display INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(pico_display INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma st7789 pico_graphics) \ No newline at end of file +target_link_libraries(pico_display INTERFACE pico_stdlib) \ No newline at end of file diff --git a/libraries/pico_display/pico_display.cpp b/libraries/pico_display/pico_display.cpp index f9f635da..6304d517 100644 --- a/libraries/pico_display/pico_display.cpp +++ b/libraries/pico_display/pico_display.cpp @@ -1,85 +1 @@ -#include -#include - -#include "hardware/gpio.h" // Workaround SDK bug - https://github.com/raspberrypi/pico-sdk/issues/3 -#include "hardware/pwm.h" - -#include "pico_display.hpp" - -namespace pimoroni { - - PicoDisplay::PicoDisplay(void *buf) - : PicoGraphics(WIDTH, HEIGHT, buf), - screen(WIDTH, HEIGHT, ROTATE_0, false, buf, get_spi_pins(BG_SPI_FRONT)) { - __fb = buf; - } - - PicoDisplay::PicoDisplay(void *buf, int width, int height) - : PicoGraphics(width, height, buf), - screen(width, height, ROTATE_0, false, buf, get_spi_pins(BG_SPI_FRONT)) { - __fb = buf; - } - - void PicoDisplay::init() { - // setup the rgb led for pwm control - pwm_config cfg = pwm_get_default_config(); - pwm_config_set_output_polarity(&cfg, true, true); - - // red - pwm_set_wrap(pwm_gpio_to_slice_num(LED_R), 65535); - pwm_init(pwm_gpio_to_slice_num(LED_R), &cfg, true); - gpio_set_function(LED_R, GPIO_FUNC_PWM); - - // green - pwm_set_wrap(pwm_gpio_to_slice_num(LED_G), 65535); - pwm_init(pwm_gpio_to_slice_num(LED_G), &cfg, true); - gpio_set_function(LED_G, GPIO_FUNC_PWM); - - // blue - pwm_set_wrap(pwm_gpio_to_slice_num(LED_B), 65535); - pwm_init(pwm_gpio_to_slice_num(LED_B), &cfg, true); - gpio_set_function(LED_B, GPIO_FUNC_PWM); - - // setup button inputs - gpio_set_function(A, GPIO_FUNC_SIO); gpio_set_dir(A, GPIO_IN); gpio_pull_up(A); - gpio_set_function(B, GPIO_FUNC_SIO); gpio_set_dir(B, GPIO_IN); gpio_pull_up(B); - gpio_set_function(X, GPIO_FUNC_SIO); gpio_set_dir(X, GPIO_IN); gpio_pull_up(X); - gpio_set_function(Y, GPIO_FUNC_SIO); gpio_set_dir(Y, GPIO_IN); gpio_pull_up(Y); - } - - void PicoDisplay::update() { - screen.update(); - } - - void PicoDisplay::set_backlight(uint8_t brightness) { - screen.set_backlight(brightness); - } - - void PicoDisplay::set_led(uint8_t r, uint8_t g, uint8_t b) { - // gamma correct the provided 0-255 brightness value onto a - // 0-65535 range for the pwm counter - static const float gamma = 2.8; - - uint16_t value; - - // red - value = (uint16_t)(pow((float)(r) / 255.0f, gamma) * 65535.0f + 0.5f); - pwm_set_gpio_level(LED_R, value); - - // green - value = (uint16_t)(pow((float)(g) / 255.0f, gamma) * 65535.0f + 0.5f); - pwm_set_gpio_level(LED_G, value); - - // blue - value = (uint16_t)(pow((float)(b) / 255.0f, gamma) * 65535.0f + 0.5f); - pwm_set_gpio_level(LED_B, value); - } - - bool PicoDisplay::is_pressed(uint8_t button) { - return !gpio_get(button); - } - - void PicoDisplay::flip() { - screen.flip(); - } -} +#include "pico_display.hpp" \ No newline at end of file diff --git a/libraries/pico_display/pico_display.hpp b/libraries/pico_display/pico_display.hpp index fea52674..61d3539c 100644 --- a/libraries/pico_display/pico_display.hpp +++ b/libraries/pico_display/pico_display.hpp @@ -1,16 +1,12 @@ #pragma once -#include "drivers/st7789/st7789.hpp" -#include "libraries/pico_graphics/pico_graphics.hpp" +#include "pico/stdlib.h" namespace pimoroni { - - class PicoDisplay : public PicoGraphics { + class PicoDisplay { public: static const int WIDTH = 240; static const int HEIGHT = 135; - static const int PORTRAIT_WIDTH = 135; - static const int PORTRAIT_HEIGHT = 240; static const uint8_t A = 12; static const uint8_t B = 13; static const uint8_t X = 14; @@ -18,21 +14,5 @@ namespace pimoroni { static const uint8_t LED_R = 6; static const uint8_t LED_G = 7; static const uint8_t LED_B = 8; - - void *__fb; - private: - ST7789 screen; - - public: - PicoDisplay(void *buf); - PicoDisplay(void *buf, int width, int height); - - void init(); - void update(); - void set_backlight(uint8_t brightness); - void set_led(uint8_t r, uint8_t g, uint8_t b); - bool is_pressed(uint8_t button); - void flip(); }; - } diff --git a/libraries/pico_display_2/pico_display_2.cmake b/libraries/pico_display_2/pico_display_2.cmake index 1b75294d..b7348688 100644 --- a/libraries/pico_display_2/pico_display_2.cmake +++ b/libraries/pico_display_2/pico_display_2.cmake @@ -1,14 +1,10 @@ -include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/st7789/st7789.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/../pico_graphics/pico_graphics.cmake) +add_library(pico_display_2 INTERFACE) -set(LIB_NAME pico_display_2) -add_library(${LIB_NAME} INTERFACE) - -target_sources(${LIB_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +target_sources(pico_display_2 INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/pico_display_2.cpp ) -target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) +target_include_directories(pico_display_2 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma st7789 pico_graphics) \ No newline at end of file +target_link_libraries(pico_display_2 INTERFACE pico_stdlib) \ No newline at end of file diff --git a/libraries/pico_display_2/pico_display_2.cpp b/libraries/pico_display_2/pico_display_2.cpp index 969df230..abb3e46b 100644 --- a/libraries/pico_display_2/pico_display_2.cpp +++ b/libraries/pico_display_2/pico_display_2.cpp @@ -1,85 +1 @@ -#include -#include - -#include "hardware/gpio.h" // Workaround SDK bug - https://github.com/raspberrypi/pico-sdk/issues/3 -#include "hardware/pwm.h" - -#include "pico_display_2.hpp" - -namespace pimoroni { - - PicoDisplay2::PicoDisplay2(void *buf) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, - PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { - __fb = buf; - } - - PicoDisplay2::PicoDisplay2(void *buf, int width, int height) - : PicoGraphics(width, height, buf), screen(width, height, false, buf, - PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { - __fb = buf; - } - - void PicoDisplay2::init() { - // setup the rgb led for pwm control - pwm_config cfg = pwm_get_default_config(); - pwm_config_set_output_polarity(&cfg, true, true); - - // red - pwm_set_wrap(pwm_gpio_to_slice_num(LED_R), 65535); - pwm_init(pwm_gpio_to_slice_num(LED_R), &cfg, true); - gpio_set_function(LED_R, GPIO_FUNC_PWM); - - // green - pwm_set_wrap(pwm_gpio_to_slice_num(LED_G), 65535); - pwm_init(pwm_gpio_to_slice_num(LED_G), &cfg, true); - gpio_set_function(LED_G, GPIO_FUNC_PWM); - - // blue - pwm_set_wrap(pwm_gpio_to_slice_num(LED_B), 65535); - pwm_init(pwm_gpio_to_slice_num(LED_B), &cfg, true); - gpio_set_function(LED_B, GPIO_FUNC_PWM); - - // setup button inputs - gpio_set_function(A, GPIO_FUNC_SIO); gpio_set_dir(A, GPIO_IN); gpio_pull_up(A); - gpio_set_function(B, GPIO_FUNC_SIO); gpio_set_dir(B, GPIO_IN); gpio_pull_up(B); - gpio_set_function(X, GPIO_FUNC_SIO); gpio_set_dir(X, GPIO_IN); gpio_pull_up(X); - gpio_set_function(Y, GPIO_FUNC_SIO); gpio_set_dir(Y, GPIO_IN); gpio_pull_up(Y); - } - - void PicoDisplay2::update() { - screen.update(); - } - - void PicoDisplay2::set_backlight(uint8_t brightness) { - screen.set_backlight(brightness); - } - - void PicoDisplay2::set_led(uint8_t r, uint8_t g, uint8_t b) { - // gamma correct the provided 0-255 brightness value onto a - // 0-65535 range for the pwm counter - static const float gamma = 2.8; - - uint16_t value; - - // red - value = (uint16_t)(pow((float)(r) / 255.0f, gamma) * 65535.0f + 0.5f); - pwm_set_gpio_level(LED_R, value); - - // green - value = (uint16_t)(pow((float)(g) / 255.0f, gamma) * 65535.0f + 0.5f); - pwm_set_gpio_level(LED_G, value); - - // blue - value = (uint16_t)(pow((float)(b) / 255.0f, gamma) * 65535.0f + 0.5f); - pwm_set_gpio_level(LED_B, value); - } - - bool PicoDisplay2::is_pressed(uint8_t button) { - return !gpio_get(button); - } - - void PicoDisplay2::flip() { - screen.flip(); - } -} +#include "pico_display_2.hpp" \ No newline at end of file diff --git a/libraries/pico_display_2/pico_display_2.hpp b/libraries/pico_display_2/pico_display_2.hpp index 769b983f..bc543f0e 100644 --- a/libraries/pico_display_2/pico_display_2.hpp +++ b/libraries/pico_display_2/pico_display_2.hpp @@ -1,16 +1,12 @@ #pragma once -#include "drivers/st7789/st7789.hpp" -#include "libraries/pico_graphics/pico_graphics.hpp" +#include "pico/stdlib.h" namespace pimoroni { - - class PicoDisplay2 : public PicoGraphics { + class PicoDisplay2 { public: static const int WIDTH = 320; static const int HEIGHT = 240; - static const int PORTRAIT_WIDTH = 240; - static const int PORTRAIT_HEIGHT = 320; static const uint8_t A = 12; static const uint8_t B = 13; static const uint8_t X = 14; @@ -18,21 +14,5 @@ namespace pimoroni { static const uint8_t LED_R = 6; static const uint8_t LED_G = 7; static const uint8_t LED_B = 8; - - void *__fb; - private: - ST7789 screen; - - public: - PicoDisplay2(void *buf); - PicoDisplay2(void *buf, int width, int height); - - void init(); - void update(); - void set_backlight(uint8_t brightness); - void set_led(uint8_t r, uint8_t g, uint8_t b); - bool is_pressed(uint8_t button); - void flip(); }; - } diff --git a/libraries/pico_explorer/pico_explorer.hpp b/libraries/pico_explorer/pico_explorer.hpp index 13933204..b1d0d51b 100644 --- a/libraries/pico_explorer/pico_explorer.hpp +++ b/libraries/pico_explorer/pico_explorer.hpp @@ -2,6 +2,7 @@ #include "drivers/st7789/st7789.hpp" #include "libraries/pico_graphics/pico_graphics.hpp" +#include "drivers/motor/motor.hpp" namespace pimoroni { @@ -18,6 +19,13 @@ namespace pimoroni { static const uint8_t ADC1 = 1; static const uint8_t ADC2 = 2; + static const uint ADC0_PIN = 26; + static const uint ADC1_PIN = 27; + static const uint ADC2_PIN = 28; + + static constexpr pin_pair MOTOR1_PINS{9, 8}; + static constexpr pin_pair MOTOR2_PINS{11, 10}; + static const uint8_t MOTOR1 = 0; static const uint8_t MOTOR2 = 1; diff --git a/libraries/picographics_st7789/CMakeLists.txt b/libraries/picographics_st7789/CMakeLists.txt new file mode 100644 index 00000000..89a60659 --- /dev/null +++ b/libraries/picographics_st7789/CMakeLists.txt @@ -0,0 +1 @@ +include(picographics_st7789.cmake) \ No newline at end of file diff --git a/libraries/generic_st7789/README.md b/libraries/picographics_st7789/README.md similarity index 88% rename from libraries/generic_st7789/README.md rename to libraries/picographics_st7789/README.md index 6a4fe4c6..98d1bb82 100644 --- a/libraries/generic_st7789/README.md +++ b/libraries/picographics_st7789/README.md @@ -1,4 +1,4 @@ -# Genereic ST7789 - Pico Display Pack & Pico Display Pack 2.0" and 240x240 Square & Round LCD Breakouts +# Pico Graphics ST7789 - Pico Display Pack & Pico Display Pack 2.0" and 240x240 Square & Round LCD Breakouts Our Pico Display Packs offers a vibrant 1.14" (240x135) or 2.0" (320x240) IPS LCD screen for your Raspberry Pi Pico it also includes four switches and and an RGB LED! @@ -16,14 +16,14 @@ The following example sets up Pico Display, displays some basic demo text and gr ```c++ #include "pico_display.hpp" -#include "generic_st7789.hpp" +#include "picographics_st7789.hpp" #include "rgbled.hpp" #include "button.hpp" using namespace pimoroni; // Swap WIDTH and HEIGHT to rotate 90 degrees -ST7789Generic pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0); +PicoGraphicsST7789 pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0); // RGB LED controller RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); @@ -83,7 +83,7 @@ int main() { ### PicoGraphics -The generic ST7789 driver uses our Pico Graphics library to draw graphics and text. For more information [read the Pico Graphics function reference.](../pico_graphics/README.md#function-reference). +The Pico Graphics ST7789 driver uses our Pico Graphics library to draw graphics and text. For more information [read the Pico Graphics function reference.](../pico_graphics/README.md#function-reference). You will also need to use the RGBLED library to drive the RGB LED, and the Button library for the four buttons. diff --git a/libraries/generic_st7789/generic_st7789.cmake b/libraries/picographics_st7789/picographics_st7789.cmake similarity index 91% rename from libraries/generic_st7789/generic_st7789.cmake rename to libraries/picographics_st7789/picographics_st7789.cmake index 25a98272..1196c95c 100644 --- a/libraries/generic_st7789/generic_st7789.cmake +++ b/libraries/picographics_st7789/picographics_st7789.cmake @@ -1,4 +1,4 @@ -set(LIB_NAME generic_st7789) +set(LIB_NAME picographics_st7789) add_library(${LIB_NAME} INTERFACE) target_sources(${LIB_NAME} INTERFACE diff --git a/libraries/generic_st7789/generic_st7789.cpp b/libraries/picographics_st7789/picographics_st7789.cpp similarity index 50% rename from libraries/generic_st7789/generic_st7789.cpp rename to libraries/picographics_st7789/picographics_st7789.cpp index 7bb09a4b..328755f8 100644 --- a/libraries/generic_st7789/generic_st7789.cpp +++ b/libraries/picographics_st7789/picographics_st7789.cpp @@ -1,15 +1,15 @@ #include #include -#include "generic_st7789.hpp" +#include "picographics_st7789.hpp" namespace pimoroni { - void ST7789Generic::update() { + void PicoGraphicsST7789::update() { st7789.update(palette); } - void ST7789Generic::set_backlight(uint8_t brightness) { + void PicoGraphicsST7789::set_backlight(uint8_t brightness) { st7789.set_backlight(brightness); } } diff --git a/libraries/generic_st7789/generic_st7789.hpp b/libraries/picographics_st7789/picographics_st7789.hpp similarity index 73% rename from libraries/generic_st7789/generic_st7789.hpp rename to libraries/picographics_st7789/picographics_st7789.hpp index 857027bb..b0e87307 100644 --- a/libraries/generic_st7789/generic_st7789.hpp +++ b/libraries/picographics_st7789/picographics_st7789.hpp @@ -6,24 +6,24 @@ namespace pimoroni { - class ST7789Generic : public PicoGraphics { + class PicoGraphicsST7789 : public PicoGraphics { private: ST7789 st7789; public: - ST7789Generic(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) : + PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) : PicoGraphics(width, height, frame_buffer), st7789(width, height, rotation, round, frame_buffer, get_spi_pins(BG_SPI_FRONT)) { common_init(); }; - ST7789Generic(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) : + PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) : PicoGraphics(width, height, frame_buffer), st7789(width, height, rotation, round, frame_buffer, bus_pins) { common_init(); }; - ST7789Generic(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) : + PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) : PicoGraphics(width, height, frame_buffer), st7789(width, height, rotation, frame_buffer, bus_pins) { common_init(); diff --git a/micropython/modules/st7789/micropython.cmake b/micropython/modules/st7789/micropython.cmake index 4d7714b3..5af5eec9 100644 --- a/micropython/modules/st7789/micropython.cmake +++ b/micropython/modules/st7789/micropython.cmake @@ -5,7 +5,7 @@ add_library(usermod_${MOD_NAME} INTERFACE) target_sources(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/generic_st7789/generic_st7789.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/picographics_st7789/picographics_st7789.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 0e7efb34..7e9d827b 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -1,4 +1,4 @@ -#include "libraries/generic_st7789/generic_st7789.hpp" +#include "libraries/picographics_st7789/picographics_st7789.hpp" #include "common/pimoroni_common.hpp" #include "common/pimoroni_bus.hpp" @@ -24,7 +24,7 @@ enum ST7789Display { typedef struct _GenericST7789_obj_t { mp_obj_base_t base; - ST7789Generic *st7789; + PicoGraphicsST7789 *st7789; void *buffer; } GenericST7789_obj_t; @@ -89,19 +89,19 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t if (display == DISPLAY_TUFTY_2040) { if (args[ARG_bus].u_obj == mp_const_none) { - self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); + self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) { _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); - self->st7789 = m_new_class(ST7789Generic, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins)); + self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins)); } else { mp_raise_ValueError("ParallelBus expected!"); } } else { if (args[ARG_bus].u_obj == mp_const_none) { - self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT)); + self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT)); } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) { _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); - self->st7789 = m_new_class(ST7789Generic, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins)); + self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins)); } else { mp_raise_ValueError("SPIBus expected!"); } @@ -157,7 +157,7 @@ mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { } mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(ST7789Generic::create_pen_rgb332( + return mp_obj_new_int(PicoGraphicsST7789::create_pen_rgb332( mp_obj_get_int(r), mp_obj_get_int(g), mp_obj_get_int(b) @@ -165,7 +165,7 @@ mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { } mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(ST7789Generic::create_pen_rgb565( + return mp_obj_new_int(PicoGraphicsST7789::create_pen_rgb565( mp_obj_get_int(r), mp_obj_get_int(g), mp_obj_get_int(b) @@ -183,7 +183,7 @@ mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen) { mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - self->st7789->set_palette_mode((ST7789Generic::PaletteMode)mp_obj_get_int(mode)); + self->st7789->set_palette_mode((PicoGraphicsST7789::PaletteMode)mp_obj_get_int(mode)); return mp_const_none; } From 7068217ccb1ad45345d8a76eee31e750f95d6a1f Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Sun, 29 May 2022 14:44:50 +0100 Subject: [PATCH 23/84] Fix linting error. --- micropython/modules_py/pimoroni.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/modules_py/pimoroni.py b/micropython/modules_py/pimoroni.py index 0e513e51..8c8504f8 100644 --- a/micropython/modules_py/pimoroni.py +++ b/micropython/modules_py/pimoroni.py @@ -187,7 +187,7 @@ class PID: class Buzzer: def __init__(self, pin): self.pwm = PWM(Pin(pin)) - + def set_tone(self, freq, duty=0.5): if freq < 50.0: # uh... https://github.com/micropython/micropython/blob/af64c2ddbd758ab6bac0fcca94c66d89046663be/ports/rp2/machine_pwm.c#L105-L119 self.pwm.duty_u16(0) From 751916e7b9c59b5d3c386a0ad5a36ea019cab64e Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 30 May 2022 11:51:38 +0100 Subject: [PATCH 24/84] Pico Explorer: Use Motor. --- examples/pico_explorer/pico_explorer_demo.cpp | 7 ++++--- .../pico_explorer_encoder/pico_explorer_encoder.cpp | 11 ++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/examples/pico_explorer/pico_explorer_demo.cpp b/examples/pico_explorer/pico_explorer_demo.cpp index 39daaac5..ea88ae2a 100644 --- a/examples/pico_explorer/pico_explorer_demo.cpp +++ b/examples/pico_explorer/pico_explorer_demo.cpp @@ -81,6 +81,8 @@ void sprite(uint8_t *p, int x, int y, bool flip, uint16_t c) { int main() { msa301.init(); + motor1.init(); + motor2.init(); struct pt { float x; @@ -143,9 +145,8 @@ int main() { display.set_pen(display.create_pen(0, 0, bv * 255)); display.circle(Point(bv * 140 + 50, 210), 15); - // TODO Find the correct way to translate these in terms of motor - // display.set_motor(display.MOTOR1, display.FORWARD, bv); - // display.set_motor(display.MOTOR2, display.FORWARD, rv); + motor1.speed(bv); + motor2.speed(rv); // TODO make this work // display.set_tone(440, 0.5); diff --git a/examples/pico_explorer_encoder/pico_explorer_encoder.cpp b/examples/pico_explorer_encoder/pico_explorer_encoder.cpp index b9484730..d95afb68 100644 --- a/examples/pico_explorer_encoder/pico_explorer_encoder.cpp +++ b/examples/pico_explorer_encoder/pico_explorer_encoder.cpp @@ -108,7 +108,6 @@ Button button_x(PicoExplorer::X); Button button_y(PicoExplorer::Y); Motor motor1(PicoExplorer::MOTOR1_PINS); -Motor motor2(PicoExplorer::MOTOR2_PINS); Encoder enc(pio0, 0, ENCODER_PINS, ENCODER_COMMON_PIN, NORMAL_DIR, COUNTS_PER_REV, COUNT_MICROSTEPS, FREQ_DIVIDER); @@ -232,6 +231,7 @@ void setup() { gpio_pull_down(ENCODER_SWITCH_PIN); } + motor1.init(); enc.init(); bool_pair state = enc.state(); @@ -287,16 +287,13 @@ int main() { // Spin Motor 1 either clockwise or counterclockwise depending on if B or Y are pressed if(button_b.read() && !button_y.read()) { - // TODO Fix motors - //display.set_motor(PicoExplorer::MOTOR1, PicoExplorer::FORWARD, 1.0f); + motor1.speed(1.0f); // Full forward } else if(button_y.read() && !button_b.read()) { - // TODO Fix motors - //display.set_motor(PicoExplorer::MOTOR1, PicoExplorer::REVERSE, 0.2f); + motor1.speed(-0.2f); // Reverse } else { - // TODO Fix motors - //display.set_motor(PicoExplorer::MOTOR1, PicoExplorer::STOP); + motor1.speed(0.0f); // Stop } // If A has been pressed, zoom the view out to a min of x1 From dbed4a463f0f2a28f51aa419bfb148b4dcea72bf Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 6 Jun 2022 12:05:44 +0100 Subject: [PATCH 25/84] ST7789: Minor code tidyup. --- micropython/modules/st7789/st7789.c | 14 ++-- micropython/modules/st7789/st7789.cpp | 95 +++++++++------------------ micropython/modules/st7789/st7789.h | 10 +++ 3 files changed, 49 insertions(+), 70 deletions(-) diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index 243cf10b..f79e3fc4 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -84,13 +84,13 @@ STATIC const mp_map_elem_t st7789_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PALETTE_RGB332), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_PALETTE_USER), MP_ROM_INT(1) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_240X240), MP_ROM_INT(0) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_ROUND_LCD_240X240), MP_ROM_INT(1) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY), MP_ROM_INT(2) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY_2), MP_ROM_INT(3) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_EXPLORER), MP_ROM_INT(4) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_TUFTY_2040), MP_ROM_INT(5) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_ENVIRO_PLUS), MP_ROM_INT(6) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_240X240), MP_ROM_INT(DISPLAY_LCD_240X240) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_ROUND_LCD_240X240), MP_ROM_INT(DISPLAY_ROUND_LCD_240X240) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY), MP_ROM_INT(DISPLAY_PICO_DISPLAY) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY_2), MP_ROM_INT(DISPLAY_PICO_DISPLAY_2) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_EXPLORER), MP_ROM_INT(DISPLAY_PICO_EXPLORER) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_TUFTY_2040), MP_ROM_INT(DISPLAY_TUFTY_2040) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_ENVIRO_PLUS), MP_ROM_INT(DISPLAY_ENVIRO_PLUS) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_st7789_globals, st7789_globals_table); diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 7e9d827b..03cff7f0 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -12,16 +12,6 @@ extern "C" { #include "st7789.h" #include "micropython/modules/pimoroni_bus/pimoroni_bus.h" -enum ST7789Display { - DISPLAY_LCD_240X240=0, - DISPLAY_ROUND_LCD_240X240, - DISPLAY_PICO_DISPLAY, - DISPLAY_PICO_DISPLAY_2, - DISPLAY_PICO_EXPLORER, - DISPLAY_TUFTY_2040, - DISPLAY_ENVIRO_PLUS -}; - typedef struct _GenericST7789_obj_t { mp_obj_base_t base; PicoGraphicsST7789 *st7789; @@ -110,7 +100,6 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t return MP_OBJ_FROM_PTR(self); } -/***** Methods *****/ mp_obj_t GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); @@ -130,9 +119,10 @@ mp_obj_t GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) { mp_obj_t GenericST7789_get_bounds(mp_obj_t self_in) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - mp_obj_t tuple[2]; - tuple[0] = mp_obj_new_int(self->st7789->bounds.w); - tuple[1] = mp_obj_new_int(self->st7789->bounds.h); + mp_obj_t tuple[2] = { + mp_obj_new_int(self->st7789->bounds.w), + mp_obj_new_int(self->st7789->bounds.h) + }; return mp_obj_new_tuple(2, tuple); } @@ -148,10 +138,9 @@ mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { float b = mp_obj_get_float(brightness); - if(b < 0 || b > 1.0f) - mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); - else - self->st7789->set_backlight((uint8_t)(b * 255.0f)); + if(b < 0 || b > 1.0f) mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); + + self->st7789->set_backlight((uint8_t)(b * 255.0f)); return mp_const_none; } @@ -204,9 +193,7 @@ mp_obj_t GenericST7789_reserve_palette(mp_obj_t self_in) { int result = self->st7789->reserve_palette(); - if (result == -1) { - mp_raise_ValueError("reserve_palette failed. No space in palette!"); - } + if (result == -1) mp_raise_ValueError("reserve_palette failed. No space in palette!"); return mp_obj_new_int(result); } @@ -231,9 +218,7 @@ mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_ma args[ARG_b].u_int & 0xff ); - if (result == -1) { - mp_raise_ValueError("create_pen failed. No matching colour or space in palette!"); - } + if (result == -1) mp_raise_ValueError("create_pen failed. No matching colour or space in palette!"); return mp_obj_new_int(result); } @@ -258,8 +243,7 @@ mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_ int w = args[ARG_w].u_int; int h = args[ARG_h].u_int; - Rect r(x, y, w, h); - self->st7789->set_clip(r); + self->st7789->set_clip({x, y, w, h}); return mp_const_none; } @@ -281,10 +265,10 @@ mp_obj_t GenericST7789_clear(mp_obj_t self_in) { mp_obj_t GenericST7789_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - self->st7789->pixel(Point( + self->st7789->pixel({ mp_obj_get_int(x), mp_obj_get_int(y) - )); + }); return mp_const_none; } @@ -307,8 +291,7 @@ mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_ma int y = args[ARG_y].u_int; int l = args[ARG_l].u_int; - Point p(x, y); - self->st7789->pixel_span(p, l); + self->st7789->pixel_span({x, y}, l); return mp_const_none; } @@ -333,8 +316,7 @@ mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map int w = args[ARG_w].u_int; int h = args[ARG_h].u_int; - Rect r(x, y, w, h); - self->st7789->rectangle(r); + self->st7789->rectangle({x, y, w, h}); return mp_const_none; } @@ -357,8 +339,7 @@ mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t int y = args[ARG_y].u_int; int r = args[ARG_r].u_int; - Point p(x, y); - self->st7789->circle(p, r); + self->st7789->circle({x, y}, r); return mp_const_none; } @@ -448,8 +429,6 @@ mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_ int width = self->st7789->measure_text(t, scale); return mp_obj_new_int(width); - - return mp_const_none; } mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -462,13 +441,11 @@ mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t if(n_args == 2) { if(mp_obj_is_type(pos_args[1], &mp_type_list)) { mp_obj_list_t *points = MP_OBJ_TO_PTR2(pos_args[1], mp_obj_list_t); - if(points->len > 0) { - num_tuples = points->len; - tuples = points->items; - } - else { - mp_raise_ValueError("poly(): cannot provide an empty list"); - } + + if(points->len <= 0) mp_raise_ValueError("poly(): cannot provide an empty list"); + + num_tuples = points->len; + tuples = points->items; } else { mp_raise_TypeError("poly(): can't convert object to list"); @@ -479,19 +456,16 @@ mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t std::vector points; for(size_t i = 0; i < num_tuples; i++) { mp_obj_t obj = tuples[i]; - if(!mp_obj_is_type(obj, &mp_type_tuple)) { - mp_raise_ValueError("poly(): can't convert object to tuple"); - } - else { - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(obj, mp_obj_tuple_t); - if(tuple->len != 2) { - mp_raise_ValueError("poly(): tuple must only contain two numbers"); - } - points.push_back(Point( - mp_obj_get_int(tuple->items[0]), - mp_obj_get_int(tuple->items[1])) - ); - } + if(!mp_obj_is_type(obj, &mp_type_tuple)) mp_raise_ValueError("poly(): can't convert object to tuple"); + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(obj, mp_obj_tuple_t); + + if(tuple->len != 2) mp_raise_ValueError("poly(): tuple must only contain two numbers"); + + points.push_back({ + mp_obj_get_int(tuple->items[0]), + mp_obj_get_int(tuple->items[1]) + }); } self->st7789->polygon(points); } @@ -523,10 +497,7 @@ mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_ int x3 = args[ARG_x3].u_int; int y3 = args[ARG_y3].u_int; - Point p1(x1, y1); - Point p2(x2, y2); - Point p3(x3, y3); - self->st7789->triangle(p1, p2, p3); + self->st7789->triangle({x1, y1}, {x2, y2}, {x3, y3}); return mp_const_none; } @@ -551,9 +522,7 @@ mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k int x2 = args[ARG_x2].u_int; int y2 = args[ARG_y2].u_int; - Point p1(x1, y1); - Point p2(x2, y2); - self->st7789->line(p1, p2); + self->st7789->line({x1, y1}, {x2, y2}); return mp_const_none; } diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h index af025054..a9eb4b62 100644 --- a/micropython/modules/st7789/st7789.h +++ b/micropython/modules/st7789/st7789.h @@ -1,6 +1,16 @@ #include "py/runtime.h" #include "py/objstr.h" +enum ST7789Display { + DISPLAY_LCD_240X240=0, + DISPLAY_ROUND_LCD_240X240, + DISPLAY_PICO_DISPLAY, + DISPLAY_PICO_DISPLAY_2, + DISPLAY_PICO_EXPLORER, + DISPLAY_TUFTY_2040, + DISPLAY_ENVIRO_PLUS +}; + // Type extern const mp_obj_type_t GenericST7789_type; From 7e4725d1cdc77e8f9ce72a2dea20a0c8a591cc59 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 6 Jun 2022 17:54:15 +0100 Subject: [PATCH 26/84] ST7789/PicoGraphics: Templated framebuffer formats. --- drivers/st7789/st7789.cmake | 2 +- drivers/st7789/st7789.cpp | 96 ++++++ drivers/st7789/st7789.hpp | 19 +- libraries/pico_graphics/pico_graphics.cpp | 184 +++-------- libraries/pico_graphics/pico_graphics.hpp | 300 ++++++++++++++---- .../picographics_st7789.cpp | 6 - .../picographics_st7789.hpp | 30 +- micropython/modules/st7789/st7789.c | 10 +- micropython/modules/st7789/st7789.cpp | 64 ++-- micropython/modules/st7789/st7789.h | 5 +- 10 files changed, 460 insertions(+), 256 deletions(-) diff --git a/drivers/st7789/st7789.cmake b/drivers/st7789/st7789.cmake index 80420fef..a08f111c 100644 --- a/drivers/st7789/st7789.cmake +++ b/drivers/st7789/st7789.cmake @@ -9,4 +9,4 @@ target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) target_include_directories(st7789 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma) +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma pico_graphics) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 32068544..251d98d4 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -200,7 +200,102 @@ namespace pimoroni { gpio_put(cs, 1); } + + void ST7789::update(PicoGraphics *graphics) { + command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); + } + void ST7789::update(PicoGraphics *graphics) { + uint8_t command = reg::RAMWR; + + gpio_put(dc, 0); // command mode + + gpio_put(cs, 0); + + if(spi) { + spi_write_blocking(spi, &command, 1); + } else { + write_blocking_parallel(&command, 1); + } + + gpio_put(dc, 1); // data mode + + uint16_t row_buf[width]; + + for(auto y = 0u; y < height; y++) { + graphics->get_data(y, &row_buf); + // TODO: Add DMA->SPI / PIO while we prep the next row + if(spi) { + spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); + } else { + write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); + } + } + + gpio_put(cs, 1); + } + + void ST7789::update(PicoGraphics *graphics) { + uint8_t command = reg::RAMWR; + + gpio_put(dc, 0); // command mode + + gpio_put(cs, 0); + + if(spi) { + spi_write_blocking(spi, &command, 1); + } else { + write_blocking_parallel(&command, 1); + } + + gpio_put(dc, 1); // data mode + + uint16_t row_buf[width]; + + for(auto y = 0u; y < height; y++) { + graphics->get_data(y, &row_buf); + // TODO: Add DMA->SPI / PIO while we prep the next row + if(spi) { + spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); + } else { + write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); + } + } + + gpio_put(cs, 1); + } + + void ST7789::update(PicoGraphics *graphics) { + uint8_t command = reg::RAMWR; + + gpio_put(dc, 0); // command mode + + gpio_put(cs, 0); + + if(spi) { + spi_write_blocking(spi, &command, 1); + } else { + write_blocking_parallel(&command, 1); + } + + gpio_put(dc, 1); // data mode + + uint16_t row_buf[width]; + + for(auto y = 0u; y < height; y++) { + graphics->get_data(y, &row_buf); + // TODO: Add DMA->SPI / PIO while we prep the next row + if(spi) { + spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); + } else { + write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); + } + } + + gpio_put(cs, 1); + } + +/* // Native 16-bit framebuffer update void ST7789::update() { command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); @@ -238,6 +333,7 @@ namespace pimoroni { gpio_put(cs, 1); } + */ void ST7789::set_backlight(uint8_t brightness) { // gamma correct the provided 0-255 brightness value onto a diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index 228dc1f1..48f7ef61 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -5,6 +5,7 @@ #include "hardware/pwm.h" #include "common/pimoroni_common.hpp" #include "common/pimoroni_bus.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include @@ -41,15 +42,11 @@ namespace pimoroni { public: - - // frame buffer where pixel data is stored - void *frame_buffer; - // Parallel init ST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins pins) : spi(nullptr), width(width), height(height), rotation(rotation), round(false), - cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl), frame_buffer(frame_buffer) { + cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl) { gpio_set_function(wr_sck, GPIO_FUNC_SIO); gpio_set_dir(wr_sck, GPIO_OUT); @@ -71,7 +68,7 @@ namespace pimoroni { ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins pins) : spi(pins.spi), width(width), height(height), rotation(rotation), round(round), - cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl), frame_buffer(frame_buffer) { + cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl) { // configure spi interface and pins spi_init(spi, SPI_BAUD); @@ -86,17 +83,15 @@ namespace pimoroni { void command(uint8_t command, size_t len = 0, const char *data = NULL); void set_backlight(uint8_t brightness); - void update(); - void update(uint16_t *palette); + void update(PicoGraphics *graphics); + void update(PicoGraphics *graphics); + void update(PicoGraphics *graphics); + void update(PicoGraphics *graphics); private: void configure_display(Rotation rotate); void write_blocking_parallel(const uint8_t *src, size_t len); void common_init() { - if(!this->frame_buffer) { - this->frame_buffer = new uint8_t[width * height]; - } - gpio_set_function(dc, GPIO_FUNC_SIO); gpio_set_dir(dc, GPIO_OUT); diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 3ff3b84e..098a16aa 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -1,135 +1,40 @@ #include "pico_graphics.hpp" namespace pimoroni { - PicoGraphics::PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) - : frame_buffer((Pen *)frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { - set_font(&font6); - set_palette_mode(PaletteModeRGB332); - }; - void PicoGraphics::set_font(const bitmap::font_t *font){ + template + void PicoGraphics::set_font(const bitmap::font_t *font){ this->font = font; } - void PicoGraphics::set_pen(Pen p) { - pen = p; + template + void PicoGraphics::set_pen(uint16_t p) { + pen.set_color(p); } - void PicoGraphics::set_palette_mode(PaletteMode mode) { - palette_mode = mode; - if(mode == PaletteModeRGB332) { - rgb332_palette(); - } else { - empty_palette(); - } - } - - int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) { - if (palette_mode == PaletteModeRGB332) { - return rgb_to_rgb332_index(r, g, b); // Fast pack RGB into palette index - } else { - RGB565 c = create_pen_rgb565(r, g, b); - int result = search_palette(c); - - if (result == -1) { - result = put_palette(create_pen_rgb565(r, g, b)); - } - - return result; - } - } - - void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) { - int result = create_pen(r, g, b); - (void)result; - } - - int PicoGraphics::search_palette(RGB565 c) { - for(auto i = 0u; i < 256; i++) { - if((palette_status[i] & PaletteStatusUsed) && palette[i] == c) return i; - } - return -1; - } - - int PicoGraphics::put_palette(RGB565 c) { - if(palette_mode != PaletteModeUSER) return -1; - - for(auto i = 0u; i < 256; i++) { - if(!(palette_status[i] & (PaletteStatusUsed | PaletteStatusReserved))) { - palette[i] = c; - palette_status[i] = PaletteStatusUsed; - return i; - } - } - return -1; - } - - void PicoGraphics::set_palette(uint8_t i, RGB565 c) { - if(palette_mode != PaletteModeUSER) return; - - palette[i] = c; - palette_status[i] |= PaletteStatusUsed; - } - - int PicoGraphics::reserve_palette() { - if(palette_mode != PaletteModeUSER) return - 1; - - for (auto i = 0u; i < 256; i++) { - if (!palette_status[i]) { - palette_status[i] = PaletteStatusReserved; - return i; - } - } - return -1; - } - - void PicoGraphics::empty_palette() { - for (auto i = 0u; i < 256; i++) { - palette[i] = 0; - palette_status[i] = 0; - } - } - - void PicoGraphics::rgb332_palette() { - for (auto i = 0u; i < 256; i++) { - // Convert the implicit RGB332 (i) into RGB565 - // 0b11100 000 0b00011100 0b00000011 - palette[i] = ((i & 0b11100000) << 8) | ((i & 0b00011100) << 6) | ((i & 0b00000011) << 3); - palette[i] = __builtin_bswap16(palette[i]); - palette_status[i] = PaletteStatusUsed; - } - } - - void PicoGraphics::set_clip(const Rect &r) { + template + void PicoGraphics::set_clip(const Rect &r) { clip = bounds.intersection(r); } - void PicoGraphics::remove_clip() { + template + void PicoGraphics::remove_clip() { clip = bounds; } - Pen* PicoGraphics::ptr(const Rect &r) { - return frame_buffer + r.x + r.y * bounds.w; - } - - Pen* PicoGraphics::ptr(const Point &p) { - return frame_buffer + p.x + p.y * bounds.w; - } - - Pen* PicoGraphics::ptr(int32_t x, int32_t y) { - return frame_buffer + x + y * bounds.w; - } - - void PicoGraphics::clear() { + template + void PicoGraphics::clear() { rectangle(clip); } - void PicoGraphics::pixel(const Point &p) { + template + void PicoGraphics::pixel(const Point &p) { if(!clip.contains(p)) return; - *ptr(p) = pen; + pen.set_pixel(frame_buffer, p.x, p.y, bounds.w); } - void PicoGraphics::pixel_span(const Point &p, int32_t l) { + template + void PicoGraphics::pixel_span(const Point &p, int32_t l) { // check if span in bounds if( p.x + l < clip.x || p.x >= clip.x + clip.w || p.y < clip.y || p.y >= clip.y + clip.h) return; @@ -139,31 +44,36 @@ namespace pimoroni { if(clipped.x < clip.x) {l += clipped.x - clip.x; clipped.x = clip.x;} if(clipped.x + l >= clip.x + clip.w) {l = clip.x + clip.w - clipped.x;} - Pen *dest = ptr(clipped); + Point dest(clipped.x, clipped.y); while(l--) { - *dest++ = pen; + pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); + dest.x++; } } - void PicoGraphics::rectangle(const Rect &r) { + template + void PicoGraphics::rectangle(const Rect &r) { // clip and/or discard depending on rectangle visibility Rect clipped = r.intersection(clip); if(clipped.empty()) return; - Pen *dest = ptr(clipped); + Point dest(clipped.x, clipped.y); while(clipped.h--) { // draw span of pixels for this row - for(int32_t i = 0; i < clipped.w; i++) { - *dest++ = pen; - } + pixel_span(dest, clipped.w); + /*for(int32_t i = 0; i < clipped.w; i++) { + pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); + dest.x++; + }*/ // move to next scanline - dest += bounds.w - clipped.w; + dest.y++; } } - void PicoGraphics::circle(const Point &p, int32_t radius) { + template + void PicoGraphics::circle(const Point &p, int32_t radius) { // circle in screen bounds? Rect bounds = Rect(p.x - radius, p.y - radius, radius * 2, radius * 2); if(!bounds.intersects(clip)) return; @@ -191,19 +101,22 @@ namespace pimoroni { } } - void PicoGraphics::character(const char c, const Point &p, uint8_t scale) { + template + void PicoGraphics::character(const char c, const Point &p, uint8_t scale) { bitmap::character(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){ rectangle(Rect(x, y, w, h)); }, c, p.x, p.y, scale); } - void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) { + template + void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) { bitmap::text(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){ rectangle(Rect(x, y, w, h)); }, t, p.x, p.y, wrap, scale); } - int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) { + template + int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) { return bitmap::measure_text(font, t, scale); } @@ -215,7 +128,8 @@ namespace pimoroni { return (p1.y == p2.y && p1.x > p2.x) || (p1.y < p2.y); } - void PicoGraphics::triangle(Point p1, Point p2, Point p3) { + template + void PicoGraphics::triangle(Point p1, Point p2, Point p3) { Rect triangle_bounds( Point(std::min(p1.x, std::min(p2.x, p3.x)), std::min(p1.y, std::min(p2.y, p3.y))), Point(std::max(p1.x, std::max(p2.x, p3.x)), std::max(p1.y, std::max(p2.y, p3.y)))); @@ -257,13 +171,13 @@ namespace pimoroni { int32_t w1 = w1row; int32_t w2 = w2row; - Pen *dest = ptr(triangle_bounds.x, triangle_bounds.y + y); + Point dest = Point(triangle_bounds.x, triangle_bounds.y + y); for (int32_t x = 0; x < triangle_bounds.w; x++) { if ((w0 | w1 | w2) >= 0) { - *dest = pen; + pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); } - dest++; + dest.x++; w0 += a12; w1 += a20; @@ -276,7 +190,8 @@ namespace pimoroni { } } - void PicoGraphics::polygon(const std::vector &points) { + template + void PicoGraphics::polygon(const std::vector &points) { static int32_t nodes[64]; // maximum allowed number of nodes per scanline for polygon rendering int32_t miny = points[0].y, maxy = points[0].y; @@ -322,7 +237,8 @@ namespace pimoroni { } } - void PicoGraphics::line(Point p1, Point p2) { + template + void PicoGraphics::line(Point p1, Point p2) { // fast horizontal line if(p1.y == p2.y) { int32_t start = std::max(clip.x, std::min(p1.x, p2.x)); @@ -335,10 +251,10 @@ namespace pimoroni { if(p1.x == p2.x) { int32_t start = std::max(clip.y, std::min(p1.y, p2.y)); int32_t length = std::min(clip.y + clip.h, std::max(p1.y, p2.y)) - start; - Pen *dest = ptr(p1.x, start); + Point dest(p1.x, start); while(length--) { - *dest = pen; - dest += bounds.w; + pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); + dest.y++; } return; } @@ -357,7 +273,7 @@ namespace pimoroni { int32_t x = p1.x; int32_t y = p1.y << 16; while(s--) { - pixel(Point(x, y >> 16)); + pen.set_pixel(frame_buffer, x, y >> 16, bounds.w); y += sy; x += sx; } @@ -369,7 +285,7 @@ namespace pimoroni { int32_t y = p1.y; int32_t x = p1.x << 16; while(s--) { - pixel(Point(x >> 16, y)); + pen.set_pixel(frame_buffer, x >> 16, y, bounds.w); y += sy; x += sx; } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index f0258435..d8b4d8d4 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -9,9 +9,9 @@ // a tiny little graphics library for our Pico products // supports only 16-bit (565) RGB framebuffers namespace pimoroni { - - typedef uint8_t Pen; + typedef uint8_t RGB332; typedef uint16_t RGB565; + typedef int Pen; struct Rect; @@ -44,59 +44,255 @@ namespace pimoroni { void deflate(int32_t v); }; + class PicoGraphicsPenType { + public: + + struct PaletteEntry { + RGB565 color; + bool used; + }; + + static constexpr RGB332 rgb_to_rgb332(uint8_t r, uint8_t g, uint8_t b) { + return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); + } + + static constexpr RGB565 rgb332_to_rgb565(RGB332 c) { + uint16_t p = ((c & 0b11100000) << 8) | + ((c & 0b00011100) << 6) | + ((c & 0b00000011) << 3); + return __builtin_bswap16(p); + } + + static constexpr RGB565 rgb_to_rgb565(uint8_t r, uint8_t g, uint8_t b) { + uint16_t p = ((r & 0b11111000) << 8) | + ((g & 0b11111100) << 3) | + ((b & 0b11111000) >> 3); + + return __builtin_bswap16(p); + } + + virtual void set_pixel(void *frame_buffer, uint x, uint y, uint stride); + virtual int create(uint8_t r, uint8_t g, uint8_t b); + virtual void set_color(uint c); + virtual void set_color(uint8_t r, uint8_t g, uint8_t b); + virtual void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b); + + virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length); + static size_t buffer_size(uint w, uint h); // Must be static, since user must know required size to alloc framebuffer + }; + + class PenP4 : public PicoGraphicsPenType { + public: + uint8_t color; + PaletteEntry palette[8]; + PenP4() { + palette[0].color = rgb_to_rgb565(57, 48, 57); // Black + palette[1].color = rgb_to_rgb565(255, 255, 255); // White + palette[2].color = rgb_to_rgb565(58, 91, 70); // Green + palette[3].color = rgb_to_rgb565(61, 59, 94); // Blue + palette[4].color = rgb_to_rgb565(156, 72, 75); // Red + palette[5].color = rgb_to_rgb565(208, 190, 71); // Yellow + palette[6].color = rgb_to_rgb565(177, 106, 73); // Orange + palette[7].color = rgb_to_rgb565(255, 255, 255); // Clear + } + void set_color(uint c) { + color = c & 0xf; + } + void set_color(uint8_t r, uint8_t g, uint8_t b) override { + // TODO look up closest palette colour, or just NOOP? + } + void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {} + void reset_color(uint8_t i) {} + int create(uint8_t r, uint8_t g, uint8_t b) override { + return -1; // Can never create new colours, fixed palette! + } + void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + uint8_t *p = &buf[(x / 2) + (y * stride / 2)]; + + uint8_t o = (~x & 0b1) * 4; // bit offset within byte + uint8_t m = ~(0b1111 << o); // bit mask for byte + uint8_t b = color << o; // bit value shifted to position + + *p &= m; // clear bits + *p |= b; // set value + } + void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { + uint8_t *src = (uint8_t *)frame_buffer; + uint16_t *dst = (uint16_t *)result; + for(auto x = 0u; x < length; x++) { + uint8_t c = src[(offset / 2) + (x / 2)]; + uint8_t o = (~x & 0b1) * 4; // bit offset within byte + uint8_t b = (c >> o) & 0xf; // bit value shifted to position + dst[x] = palette[b].color; + } + } + static size_t buffer_size(uint w, uint h) { + return w * h / 2; + } + }; + + class PenP8 : public PicoGraphicsPenType { + public: + uint8_t color; + PaletteEntry palette[256]; + PenP8() { + for(auto i = 0u; i < 256; i++) { + reset_color(i); + } + } + void set_color(uint c) override { + color = c; + } + void set_color(uint8_t r, uint8_t g, uint8_t b) override { + // TODO look up closest palette colour, or just NOOP? + } + void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { + palette[i].color = rgb_to_rgb565(r, g, b); + palette[i].used = true; + } + void reset_color(uint8_t i) { + palette[i].color = 0; + palette[i].used = false; + } + int create(uint8_t r, uint8_t g, uint8_t b) override { + // Create a colour and place it in the palette if there's space + RGB565 c = rgb_to_rgb565(r, g, b); + for(auto i = 0u; i < 256u; i++) { + if(!palette[i].used) { + palette[i].color = c; + palette[i].used = true; + return i; + } + } + return -1; + } + void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { + uint8_t *buf = (uint8_t *)frame_buffer; + buf[y * stride + x] = color; + } + void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { + uint8_t *src = (uint8_t *)frame_buffer; + uint16_t *dst = (uint16_t *)result; + for(auto x = 0u; x < length; x++) { + dst[x] = palette[src[offset + x]].color; + } + } + static size_t buffer_size(uint w, uint h) { + return w * h; + } + }; + + class PenRGB332 : public PicoGraphicsPenType { + public: + RGB332 color; + PaletteEntry palette[256]; + PenRGB332() { + for(auto i = 0u; i < 256; i++) { + reset_color(i); + } + } + void set_color(uint c) { + color = c; + } + void set_color(uint8_t r, uint8_t g, uint8_t b) override { + color = rgb_to_rgb332(r, g, b); + } + void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { + palette[i].color = rgb_to_rgb565(r, g, b); + palette[i].used = true; + } + void reset_color(uint8_t i) { + palette[i].color = rgb332_to_rgb565(i); + palette[i].used = true; + } + int create(uint8_t r, uint8_t g, uint8_t b) override { + return rgb_to_rgb332(r, g, b); + } + void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { + uint8_t *buf = (uint8_t *)frame_buffer; + buf[y * stride + x] = color; + } + void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { + uint8_t *src = (uint8_t *)frame_buffer; + uint16_t *dst = (uint16_t *)result; + for(auto x = 0u; x < length; x++) { + dst[x] = palette[src[offset + x]].color; + } + } + static size_t buffer_size(uint w, uint h) { + return w * h; + } + }; + + class PenRGB565 : public PicoGraphicsPenType { + public: + uint16_t color; + void set_color(uint c) override { + color = c; + } + void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { + // Palette only. Does nothing. + } + void reset_color(uint8_t i) { + // Palette only. Does nothing. + } + void set_color(uint8_t r, uint8_t g, uint8_t b) override { + color = rgb_to_rgb565(r, g, b); + } + int create(uint8_t r, uint8_t g, uint8_t b) override { + return rgb_to_rgb565(r, g, b); + } + void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { + uint16_t *buf = (uint16_t *)frame_buffer; + buf[y * stride + x] = color; + } + void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { + } + static size_t buffer_size(uint w, uint h) { + return w * h * sizeof(RGB565); + } + }; + + template class PicoGraphics { public: - Pen *frame_buffer; + void *frame_buffer; Rect bounds; Rect clip; - Pen pen; - const bitmap::font_t *font; - RGB565 palette[256]; - uint8_t palette_status[256]; - - enum PaletteMode { - PaletteModeRGB332 = 0, - PaletteModeUSER = 1 - }; - - enum PaletteStatus : uint8_t { - PaletteStatusReserved = 1, - PaletteStatusUsed = 2 - }; - - PaletteMode palette_mode = PaletteModeRGB332; + T pen; public: - PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer); + PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) + : frame_buffer(frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { + set_font(&font6); + if(frame_buffer == nullptr) { + frame_buffer = (void *)(new uint8_t[pen.buffer_size(width, height)]); + } + }; + void set_font(const bitmap::font_t *font); - void set_pen(Pen p); - void set_palette_mode(PaletteMode mode); + void set_pen(uint16_t p); - [[deprecated("Use uint8_t create_pen(uint8_t, uint8_t, uint8_t).")]] - void set_pen(uint8_t r, uint8_t g, uint8_t b); - - static constexpr Pen rgb_to_rgb332_index(uint8_t r, uint8_t g, uint8_t b) { - return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); + int create_pen(uint8_t r, uint8_t g, uint8_t b) { + return pen.create(r, g, b); } - static constexpr RGB565 create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) { - uint16_t p = ((r & 0b11111000) << 8) | - ((g & 0b11111100) << 3) | - ((b & 0b11111000) >> 3); - - return __builtin_bswap16(p); + void set_pen(uint8_t r, uint8_t g, uint8_t b) { + pen.set_color(r, g, b); } - - static constexpr RGB565 create_pen_rgb332(uint8_t r, uint8_t g, uint8_t b) { - uint16_t p = ((r & 0b11100000) << 8) | - ((g & 0b11100000) << 3) | - ((b & 0b11000000) >> 3); - return __builtin_bswap16(p); + void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { + pen.update_color(i, r, g, b); + } + + void reset_pen(uint8_t i) { + pen.reset_color(i); } void set_dimensions(int width, int height) { @@ -106,23 +302,16 @@ namespace pimoroni { clip.h = height; } - int create_pen(uint8_t r, uint8_t g, uint8_t b); - - int reserve_palette(); - void empty_palette(); - void rgb332_palette(); - - int search_palette(RGB565 c); - int get_palette(uint8_t i); - void set_palette(uint8_t i, RGB565 c); - int put_palette(RGB565 c); - void set_clip(const Rect &r); void remove_clip(); - Pen* ptr(const Point &p); - Pen* ptr(const Rect &r); - Pen* ptr(int32_t x, int32_t y); + void* get_data() { + return frame_buffer; + } + + void get_data(uint y, void *row_buf) { + pen.palette_lookup(frame_buffer, row_buf, y * bounds.w, bounds.w); + } void clear(); void pixel(const Point &p); @@ -137,4 +326,9 @@ namespace pimoroni { void line(Point p1, Point p2); }; + template class PicoGraphics; + template class PicoGraphics; + template class PicoGraphics; + template class PicoGraphics; + } diff --git a/libraries/picographics_st7789/picographics_st7789.cpp b/libraries/picographics_st7789/picographics_st7789.cpp index 328755f8..5bd9bd69 100644 --- a/libraries/picographics_st7789/picographics_st7789.cpp +++ b/libraries/picographics_st7789/picographics_st7789.cpp @@ -5,11 +5,5 @@ namespace pimoroni { - void PicoGraphicsST7789::update() { - st7789.update(palette); - } - void PicoGraphicsST7789::set_backlight(uint8_t brightness) { - st7789.set_backlight(brightness); - } } diff --git a/libraries/picographics_st7789/picographics_st7789.hpp b/libraries/picographics_st7789/picographics_st7789.hpp index b0e87307..a4428d2c 100644 --- a/libraries/picographics_st7789/picographics_st7789.hpp +++ b/libraries/picographics_st7789/picographics_st7789.hpp @@ -6,42 +6,46 @@ namespace pimoroni { - class PicoGraphicsST7789 : public PicoGraphics { + template + class PicoGraphicsST7789 : public PicoGraphics { private: ST7789 st7789; public: PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) : - PicoGraphics(width, height, frame_buffer), + PicoGraphics(width, height, frame_buffer), st7789(width, height, rotation, round, frame_buffer, get_spi_pins(BG_SPI_FRONT)) { common_init(); }; PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) : - PicoGraphics(width, height, frame_buffer), + PicoGraphics(width, height, frame_buffer), st7789(width, height, rotation, round, frame_buffer, bus_pins) { common_init(); }; PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) : - PicoGraphics(width, height, frame_buffer), + PicoGraphics(width, height, frame_buffer), st7789(width, height, rotation, frame_buffer, bus_pins) { common_init(); }; void common_init() { - this->frame_buffer = (Pen *)st7789.frame_buffer; - this->st7789.init(); - this->set_dimensions(this->st7789.width, this->st7789.height); - this->st7789.update(palette); + st7789.init(); + this->set_dimensions(st7789.width, st7789.height); + st7789.update(this); + } + + void update() { + st7789.update(this); + } + + void set_backlight(uint8_t brightness) { + st7789.set_backlight(brightness); } - void update(); - void set_backlight(uint8_t brightness); - void configure_display(bool rotate180); void set_framebuffer(void* frame_buffer) { - this->frame_buffer = (Pen *)frame_buffer; - st7789.frame_buffer = frame_buffer; + this->frame_buffer = frame_buffer; } }; diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index f79e3fc4..af4e1eb5 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -10,9 +10,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_backlight_obj, GenericST7789_set_bac MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_framebuffer_obj, GenericST7789_set_framebuffer); // Palette management -MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_palette_mode_obj, GenericST7789_set_palette_mode); -MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_set_palette_obj, GenericST7789_set_palette); -MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_reserve_palette_obj, GenericST7789_reserve_palette); +MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_update_pen_obj, 4, GenericST7789_update_pen); +MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_reset_pen_obj, GenericST7789_reset_pen); // Pen MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_pen_obj, GenericST7789_set_pen); @@ -41,9 +40,8 @@ STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) }, { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_palette_mode), MP_ROM_PTR(&GenericST7789_set_palette_mode_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_palette), MP_ROM_PTR(&GenericST7789_set_palette_obj) }, - { MP_ROM_QSTR(MP_QSTR_reserve_palette), MP_ROM_PTR(&GenericST7789_reserve_palette_obj) }, + { MP_ROM_QSTR(MP_QSTR_update_pen), MP_ROM_PTR(&GenericST7789_update_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_pen), MP_ROM_PTR(&GenericST7789_reset_pen_obj) }, { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) }, diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 03cff7f0..8099f1e3 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -4,7 +4,9 @@ #include "micropython/modules/util.hpp" - +#ifndef PICO_GRAPHICS_PEN_TYPE +#define PICO_GRAPHICS_PEN_TYPE PenP4 +#endif using namespace pimoroni; @@ -14,7 +16,7 @@ extern "C" { typedef struct _GenericST7789_obj_t { mp_obj_base_t base; - PicoGraphicsST7789 *st7789; + PicoGraphicsST7789 *st7789; void *buffer; } GenericST7789_obj_t; @@ -66,32 +68,34 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t break; } + size_t required_size = PICO_GRAPHICS_PEN_TYPE::buffer_size(width, height); + if (args[ARG_buffer].u_obj != mp_const_none) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); self->buffer = bufinfo.buf; - if(bufinfo.len < (size_t)(width * height * sizeof(Pen))) { + if(bufinfo.len < (size_t)(required_size)) { mp_raise_ValueError("Supplied buffer is too small!"); } } else { - self->buffer = m_new(uint8_t, width * height * sizeof(Pen)); + self->buffer = m_new(uint8_t, required_size); } if (display == DISPLAY_TUFTY_2040) { if (args[ARG_bus].u_obj == mp_const_none) { - self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); + self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) { _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); - self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins)); + self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins)); } else { mp_raise_ValueError("ParallelBus expected!"); } } else { if (args[ARG_bus].u_obj == mp_const_none) { - self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT)); + self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT)); } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) { _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); - self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins)); + self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins)); } else { mp_raise_ValueError("SPIBus expected!"); } @@ -146,7 +150,7 @@ mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { } mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(PicoGraphicsST7789::create_pen_rgb332( + return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb332( mp_obj_get_int(r), mp_obj_get_int(g), mp_obj_get_int(b) @@ -154,7 +158,7 @@ mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { } mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(PicoGraphicsST7789::create_pen_rgb565( + return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb565( mp_obj_get_int(r), mp_obj_get_int(g), mp_obj_get_int(b) @@ -164,40 +168,44 @@ mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - self->st7789->set_pen(mp_obj_get_int(pen) & 0xff); + self->st7789->set_pen(mp_obj_get_int(pen)); return mp_const_none; } -mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode) { +mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - self->st7789->set_palette_mode((PicoGraphicsST7789::PaletteMode)mp_obj_get_int(mode)); + self->st7789->reset_pen(mp_obj_get_int(pen)); return mp_const_none; } -mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t colour) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); +mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_i, ARG_r, ARG_g, ARG_b }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_i, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT } + }; - self->st7789->set_palette( - mp_obj_get_int(index) & 0xff, - mp_obj_get_int(colour) & 0xffff + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); + + self->st7789->update_pen( + args[ARG_i].u_int & 0xff, + args[ARG_r].u_int & 0xff, + args[ARG_g].u_int & 0xff, + args[ARG_b].u_int & 0xff ); return mp_const_none; } -mp_obj_t GenericST7789_reserve_palette(mp_obj_t self_in) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - - int result = self->st7789->reserve_palette(); - - if (result == -1) mp_raise_ValueError("reserve_palette failed. No space in palette!"); - - return mp_obj_new_int(result); -} - mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_self, ARG_r, ARG_g, ARG_b }; static const mp_arg_t allowed_args[] = { diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h index a9eb4b62..b65b6fd1 100644 --- a/micropython/modules/st7789/st7789.h +++ b/micropython/modules/st7789/st7789.h @@ -27,9 +27,8 @@ extern mp_obj_t GenericST7789_update(mp_obj_t self_in); extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness); // Palette management -extern mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode); -extern mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t colour); -extern mp_obj_t GenericST7789_reserve_palette(mp_obj_t self_in); +extern mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen); // Pen extern mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen); From cf6b6e04f4263b99b6e36daa1c21dccce2c4611b Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Jun 2022 11:03:38 +0100 Subject: [PATCH 27/84] ST7789: Simplify MicroPython bindings. Kwargs should not be used unless there are non-required arguments with default values. Save ~290 bytes and a bunch of noisy lines of code. --- micropython/modules/st7789/st7789.c | 16 +-- micropython/modules/st7789/st7789.cpp | 199 ++++++++------------------ micropython/modules/st7789/st7789.h | 18 ++- 3 files changed, 76 insertions(+), 157 deletions(-) diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index af4e1eb5..500cd9af 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -10,27 +10,27 @@ MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_backlight_obj, GenericST7789_set_bac MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_framebuffer_obj, GenericST7789_set_framebuffer); // Palette management -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_update_pen_obj, 4, GenericST7789_update_pen); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_update_pen_obj, 5, 5, GenericST7789_update_pen); MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_reset_pen_obj, GenericST7789_reset_pen); // Pen MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_pen_obj, GenericST7789_set_pen); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_create_pen_obj, 3, GenericST7789_create_pen); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_create_pen_obj, 4, 4, GenericST7789_create_pen); // Primitives -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_clip_obj, 1, GenericST7789_set_clip); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_set_clip_obj, 5, 5, GenericST7789_set_clip); MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_remove_clip_obj, GenericST7789_remove_clip); MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_clear_obj, GenericST7789_clear); MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_pixel_obj, GenericST7789_pixel); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_pixel_span_obj, 1, GenericST7789_pixel_span); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_rectangle_obj, 1, GenericST7789_rectangle); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_circle_obj, 1, GenericST7789_circle); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_pixel_span_obj, 4, 4, GenericST7789_pixel_span); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_rectangle_obj, 5, 5, GenericST7789_rectangle); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_circle_obj, 4, 4, GenericST7789_circle); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_character_obj, 1, GenericST7789_character); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_text_obj, 1, GenericST7789_text); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_measure_text_obj, 1, GenericST7789_measure_text); MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_polygon_obj, 2, GenericST7789_polygon); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_triangle_obj, 1, GenericST7789_triangle); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_line_obj, 1, GenericST7789_line); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_triangle_obj, 7, 7, GenericST7789_triangle); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_line_obj, 5, 5, GenericST7789_line); // Utility MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_get_bounds_obj, GenericST7789_get_bounds); diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 8099f1e3..d53dd10f 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -5,7 +5,7 @@ #include "micropython/modules/util.hpp" #ifndef PICO_GRAPHICS_PEN_TYPE -#define PICO_GRAPHICS_PEN_TYPE PenP4 +#define PICO_GRAPHICS_PEN_TYPE PenRGB332 #endif using namespace pimoroni; @@ -181,49 +181,30 @@ mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen) { return mp_const_none; } -mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_i, ARG_r, ARG_g, ARG_b }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_i, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT } - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); self->st7789->update_pen( - args[ARG_i].u_int & 0xff, - args[ARG_r].u_int & 0xff, - args[ARG_g].u_int & 0xff, - args[ARG_b].u_int & 0xff + mp_obj_get_int(args[ARG_i]) & 0xff, + mp_obj_get_int(args[ARG_r]) & 0xff, + mp_obj_get_int(args[ARG_g]) & 0xff, + mp_obj_get_int(args[ARG_b]) & 0xff ); return mp_const_none; } -mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_r, ARG_g, ARG_b }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT } - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); int result = self->st7789->create_pen( - args[ARG_r].u_int & 0xff, - args[ARG_g].u_int & 0xff, - args[ARG_b].u_int & 0xff + mp_obj_get_int(args[ARG_r]) & 0xff, + mp_obj_get_int(args[ARG_g]) & 0xff, + mp_obj_get_int(args[ARG_b]) & 0xff ); if (result == -1) mp_raise_ValueError("create_pen failed. No matching colour or space in palette!"); @@ -231,33 +212,24 @@ mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_ma return mp_obj_new_int(result); } -mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int w = args[ARG_w].u_int; - int h = args[ARG_h].u_int; - - self->st7789->set_clip({x, y, w, h}); + self->st7789->set_clip({ + mp_obj_get_int(args[ARG_x]), + mp_obj_get_int(args[ARG_y]), + mp_obj_get_int(args[ARG_w]), + mp_obj_get_int(args[ARG_h]) + }); return mp_const_none; } mp_obj_t GenericST7789_remove_clip(mp_obj_t self_in) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); + self->st7789->remove_clip(); return mp_const_none; @@ -265,6 +237,7 @@ mp_obj_t GenericST7789_remove_clip(mp_obj_t self_in) { mp_obj_t GenericST7789_clear(mp_obj_t self_in) { GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); + self->st7789->clear(); return mp_const_none; @@ -281,73 +254,43 @@ mp_obj_t GenericST7789_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y) { return mp_const_none; } -mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_l }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_l, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int l = args[ARG_l].u_int; - - self->st7789->pixel_span({x, y}, l); + self->st7789->pixel_span({ + mp_obj_get_int(args[ARG_x]), + mp_obj_get_int(args[ARG_y]) + }, mp_obj_get_int(args[ARG_l])); return mp_const_none; } -mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int w = args[ARG_w].u_int; - int h = args[ARG_h].u_int; - - self->st7789->rectangle({x, y, w, h}); + self->st7789->rectangle({ + mp_obj_get_int(args[ARG_x]), + mp_obj_get_int(args[ARG_y]), + mp_obj_get_int(args[ARG_w]), + mp_obj_get_int(args[ARG_h]) + }); return mp_const_none; } -mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_r }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int r = args[ARG_r].u_int; - - self->st7789->circle({x, y}, r); + self->st7789->circle({ + mp_obj_get_int(args[ARG_x]), + mp_obj_get_int(args[ARG_y]) + }, mp_obj_get_int(args[ARG_r])); return mp_const_none; } @@ -481,56 +424,34 @@ mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t return mp_const_none; } -mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_x3, ARG_y3 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x3, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y3, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); - - int x1 = args[ARG_x1].u_int; - int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x2].u_int; - int y2 = args[ARG_y2].u_int; - int x3 = args[ARG_x3].u_int; - int y3 = args[ARG_y3].u_int; - - self->st7789->triangle({x1, y1}, {x2, y2}, {x3, y3}); + self->st7789->triangle( + {mp_obj_get_int(args[ARG_x1]), + mp_obj_get_int(args[ARG_y1])}, + {mp_obj_get_int(args[ARG_x2]), + mp_obj_get_int(args[ARG_y2])}, + {mp_obj_get_int(args[ARG_x3]), + mp_obj_get_int(args[ARG_y3])} + ); return mp_const_none; } -mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); - - int x1 = args[ARG_x1].u_int; - int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x2].u_int; - int y2 = args[ARG_y2].u_int; - - self->st7789->line({x1, y1}, {x2, y2}); + self->st7789->line( + {mp_obj_get_int(args[ARG_x1]), + mp_obj_get_int(args[ARG_y1])}, + {mp_obj_get_int(args[ARG_x2]), + mp_obj_get_int(args[ARG_y2])} + ); return mp_const_none; } diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h index b65b6fd1..fee2259a 100644 --- a/micropython/modules/st7789/st7789.h +++ b/micropython/modules/st7789/st7789.h @@ -20,34 +20,32 @@ extern mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); // Class methods extern mp_obj_t GenericST7789_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 GenericST7789SPI_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 GenericST7789Parallel_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 GenericST7789_update(mp_obj_t self_in); extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness); // Palette management -extern mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *args); extern mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen); // Pen extern mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen); -extern mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *args); // Primitives -extern mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *args); extern mp_obj_t GenericST7789_remove_clip(mp_obj_t self_in); extern mp_obj_t GenericST7789_clear(mp_obj_t self_in); extern mp_obj_t GenericST7789_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y); -extern mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *args); +extern mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *args); +extern mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *args); extern mp_obj_t GenericST7789_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *args); +extern mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *args); // Utility extern mp_obj_t GenericST7789_get_bounds(mp_obj_t self_in); From 1a251822f540891f6db81ed375c673528d351682 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Jun 2022 12:55:02 +0100 Subject: [PATCH 28/84] ST7735: Update 160x80 LCD to new PicoGraphics --- drivers/st7735/st7735.cpp | 58 +- drivers/st7735/st7735.hpp | 78 +-- drivers/st7789/st7789.hpp | 4 +- .../breakout_colourlcd160x80.cpp | 52 -- .../breakout_colourlcd160x80.hpp | 34 +- libraries/pico_graphics/pico_graphics.hpp | 10 +- .../picographics_st7789.hpp | 6 +- .../breakout_colourlcd160x80.c | 57 +- .../breakout_colourlcd160x80.cpp | 557 ++++++++---------- .../breakout_colourlcd160x80.h | 50 +- .../micropython.cmake | 8 +- micropython/modules/st7789/st7789.c | 3 - 12 files changed, 358 insertions(+), 559 deletions(-) diff --git a/drivers/st7735/st7735.cpp b/drivers/st7735/st7735.cpp index c3ed0aa6..41f30f00 100644 --- a/drivers/st7735/st7735.cpp +++ b/drivers/st7735/st7735.cpp @@ -67,7 +67,6 @@ namespace pimoroni { }; void ST7735::init(bool auto_init_sequence) { - // configure spi interface and pins spi_init(spi, spi_baud); gpio_set_function(dc, GPIO_FUNC_SIO); @@ -76,21 +75,9 @@ namespace pimoroni { gpio_set_function(cs, GPIO_FUNC_SIO); gpio_set_dir(cs, GPIO_OUT); - gpio_set_function(sck, GPIO_FUNC_SPI); + gpio_set_function(sck, GPIO_FUNC_SPI); gpio_set_function(mosi, GPIO_FUNC_SPI); - if(miso != PIN_UNUSED) { - gpio_set_function(miso, GPIO_FUNC_SPI); - } - - // if supported by the display then the vsync pin is - // toggled high during vertical blanking period - if(vsync != PIN_UNUSED) { - gpio_set_function(vsync, GPIO_FUNC_SIO); - gpio_set_dir(vsync, GPIO_IN); - gpio_set_pulls(vsync, false, true); - } - // if a backlight pin is provided then set it up for // pwm control if(bl != PIN_UNUSED) { @@ -98,6 +85,7 @@ namespace pimoroni { pwm_set_wrap(pwm_gpio_to_slice_num(bl), 65535); pwm_init(pwm_gpio_to_slice_num(bl), &cfg, true); gpio_set_function(bl, GPIO_FUNC_PWM); + set_backlight(0); // Turn backlight off initially to avoid nasty surprises } // if auto_init_sequence then send initialisation sequence @@ -155,30 +143,10 @@ namespace pimoroni { command(reg::DISPON); sleep_ms(100); } - } - spi_inst_t* ST7735::get_spi() const { - return spi; - } - - int ST7735::get_cs() const { - return cs; - } - - int ST7735::get_dc() const { - return dc; - } - - int ST7735::get_sck() const { - return sck; - } - - int ST7735::get_mosi() const { - return mosi; - } - - int ST7735::get_bl() const { - return bl; + if(bl != PIN_UNUSED) { + set_backlight(255); // Turn backlight on now surprises have passed + } } void ST7735::command(uint8_t command, size_t len, const char *data) { @@ -196,23 +164,21 @@ namespace pimoroni { } // Native 16-bit framebuffer update - void ST7735::update() { - command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); + void ST7735::update(PicoGraphics *graphics) { + command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); } // 8-bit framebuffer with palette conversion update - void ST7735::update(uint16_t *palette) { + void ST7735::update(PicoGraphics *graphics) { command(reg::RAMWR); - uint16_t row[width]; gpio_put(dc, 1); // data mode gpio_put(cs, 0); + + uint16_t row_buf[width]; for(auto y = 0u; y < height; y++) { - for(auto x = 0u; x < width; x++) { - auto i = y * width + x; - row[x] = palette[((uint8_t *)frame_buffer)[i]]; - } + graphics->get_data(y, &row_buf); // TODO: Add DMA->SPI / PIO while we prep the next row - spi_write_blocking(spi, (const uint8_t*)row, width * sizeof(uint16_t)); + spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); } gpio_put(cs, 1); } diff --git a/drivers/st7735/st7735.hpp b/drivers/st7735/st7735.hpp index 75c739c3..f794f665 100644 --- a/drivers/st7735/st7735.hpp +++ b/drivers/st7735/st7735.hpp @@ -2,7 +2,9 @@ #include "hardware/spi.h" #include "hardware/gpio.h" -#include "../../common/pimoroni_common.hpp" +#include "common/pimoroni_common.hpp" +#include "common/pimoroni_bus.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" namespace pimoroni { @@ -10,13 +12,6 @@ namespace pimoroni { //-------------------------------------------------- // Constants //-------------------------------------------------- - public: - static const uint8_t DEFAULT_CS_PIN = 17; - static const uint8_t DEFAULT_DC_PIN = 16; - static const uint8_t DEFAULT_SCK_PIN = 18; - static const uint8_t DEFAULT_MOSI_PIN = 19; - static const uint8_t DEFAULT_BL_PIN = 20; - private: static const uint8_t ROWS = 162; static const uint8_t COLS = 132; @@ -28,81 +23,46 @@ namespace pimoroni { // screen properties uint16_t width; uint16_t height; - uint16_t row_stride; - public: - // frame buffer where pixel data is stored - void *frame_buffer; - - private: spi_inst_t *spi = spi0; uint32_t dma_channel; // interface pins with our standard defaults where appropriate - uint cs = DEFAULT_CS_PIN; - uint dc = DEFAULT_DC_PIN; - uint sck = DEFAULT_SCK_PIN; - uint mosi = DEFAULT_MOSI_PIN; - uint miso = PIN_UNUSED; // we generally don't use this pin - uint bl = DEFAULT_BL_PIN; - uint vsync = PIN_UNUSED; // only available on some products + uint cs; + uint dc; + uint sck; + uint mosi; + uint bl; uint32_t spi_baud = 30 * 1024 * 1024; uint8_t offset_cols = 0; uint8_t offset_rows = 0; - //-------------------------------------------------- // Constructors/Destructor //-------------------------------------------------- public: - ST7735(uint16_t width, uint16_t height, void *frame_buffer, BG_SPI_SLOT slot) : - width(width), height(height), frame_buffer(frame_buffer) { - switch(slot) { - case PICO_EXPLORER_ONBOARD: // Don't read too much into this, the case is just here to avoid a compile error - cs = SPI_BG_FRONT_CS; - bl = PIN_UNUSED; - break; - case BG_SPI_FRONT: - cs = SPI_BG_FRONT_CS; - bl = SPI_BG_FRONT_PWM; - break; - case BG_SPI_BACK: - cs = SPI_BG_BACK_CS; - bl = SPI_BG_BACK_PWM; - break; + ST7735(uint16_t width, uint16_t height, SPIPins pins) : + width(width), height(height), + spi(pins.spi), cs(pins.cs), dc(pins.dc), sck(pins.sck), mosi(pins.mosi), bl(pins.bl) { + init(); } - } - - ST7735(uint16_t width, uint16_t height, void *frame_buffer) : - width(width), height(height), frame_buffer(frame_buffer) {} - - ST7735(uint16_t width, uint16_t height, void *frame_buffer, - spi_inst_t *spi, - uint8_t cs, uint8_t dc, uint8_t sck, uint8_t mosi, uint8_t miso = -1, uint8_t bl = -1) : - width(width), height(height), frame_buffer(frame_buffer), - spi(spi), cs(cs), dc(dc), sck(sck), mosi(mosi), miso(miso), bl(bl) {} //-------------------------------------------------- // Methods //-------------------------------------------------- public: - void init(bool auto_init_sequence = true); - - spi_inst_t* get_spi() const; - int get_cs() const; - int get_dc() const; - int get_sck() const; - int get_mosi() const; - int get_bl() const; - - void command(uint8_t command, size_t len = 0, const char *data = NULL); - void update(); - void update(uint16_t *palette); + // Update functions for supported Pen types + void update(PicoGraphics *graphics); + void update(PicoGraphics *graphics); void set_backlight(uint8_t brightness); + + private: + void init(bool auto_init_sequence = true); + void command(uint8_t command, size_t len = 0, const char *data = NULL); }; } diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index 48f7ef61..d1b1dd4b 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -43,7 +43,7 @@ namespace pimoroni { public: // Parallel init - ST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins pins) : + ST7789(uint16_t width, uint16_t height, Rotation rotation, ParallelPins pins) : spi(nullptr), width(width), height(height), rotation(rotation), round(false), cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl) { @@ -65,7 +65,7 @@ namespace pimoroni { } // Serial init - ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins pins) : + ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, SPIPins pins) : spi(pins.spi), width(width), height(height), rotation(rotation), round(round), cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl) { diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp index 393e04e2..d35e831e 100644 --- a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp +++ b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp @@ -2,57 +2,5 @@ namespace pimoroni { - BreakoutColourLCD160x80::BreakoutColourLCD160x80(void *buf) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf) { - __fb = buf; - } - - BreakoutColourLCD160x80::BreakoutColourLCD160x80(void *buf, spi_inst_t *spi, - uint cs, uint dc, uint sck, uint mosi, uint miso, uint bl) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, spi, cs, dc, sck, mosi, miso, bl) { - __fb = buf; - } - - BreakoutColourLCD160x80::BreakoutColourLCD160x80(void *buf, BG_SPI_SLOT slot) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, slot) { - __fb = buf; - } - - void BreakoutColourLCD160x80::init() { - // initialise the screen - screen.init(); - } - - spi_inst_t* BreakoutColourLCD160x80::get_spi() const { - return screen.get_spi(); - } - - int BreakoutColourLCD160x80::get_cs() const { - return screen.get_cs(); - } - - int BreakoutColourLCD160x80::get_dc() const { - return screen.get_dc(); - } - - int BreakoutColourLCD160x80::get_sck() const { - return screen.get_sck(); - } - - int BreakoutColourLCD160x80::get_mosi() const { - return screen.get_mosi(); - } - - int BreakoutColourLCD160x80::get_bl() const { - return screen.get_bl(); - } - - void BreakoutColourLCD160x80::update() { - screen.update(palette); - } - - void BreakoutColourLCD160x80::set_backlight(uint8_t brightness) { - screen.set_backlight(brightness); - } } \ No newline at end of file diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp index 13582bf1..b814daab 100644 --- a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp +++ b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp @@ -3,10 +3,11 @@ #include "drivers/st7735/st7735.hpp" #include "libraries/pico_graphics/pico_graphics.hpp" #include "common/pimoroni_common.hpp" +#include "common/pimoroni_bus.hpp" namespace pimoroni { - class BreakoutColourLCD160x80 : public PicoGraphics { + class BreakoutColourLCD160x80 : public PicoGraphics { //-------------------------------------------------- // Constants //-------------------------------------------------- @@ -17,8 +18,6 @@ namespace pimoroni { //-------------------------------------------------- // Variables //-------------------------------------------------- - public: - void *__fb; private: ST7735 screen; @@ -27,27 +26,22 @@ namespace pimoroni { // Constructors/Destructor //-------------------------------------------------- public: - BreakoutColourLCD160x80(void *buf); - BreakoutColourLCD160x80(void *buf, spi_inst_t *spi, - uint cs, uint dc, uint sck, uint mosi, uint miso = PIN_UNUSED, uint bl = PIN_UNUSED); - BreakoutColourLCD160x80(void *buf, BG_SPI_SLOT slot); + BreakoutColourLCD160x80(void *frame_buffer) + : BreakoutColourLCD160x80(frame_buffer, get_spi_pins(BG_SPI_FRONT)) { + } - //-------------------------------------------------- - // Methods - //-------------------------------------------------- - public: - void init(); + BreakoutColourLCD160x80(void *frame_buffer, SPIPins bus_pins) + : PicoGraphics(WIDTH, HEIGHT, frame_buffer), screen(WIDTH, HEIGHT, bus_pins){ + } - spi_inst_t* get_spi() const; - int get_cs() const; - int get_dc() const; - int get_sck() const; - int get_mosi() const; - int get_bl() const; + void update() { + screen.update(this); + } - void update(); - void set_backlight(uint8_t brightness); + void set_backlight(uint8_t brightness) { + screen.set_backlight(brightness); + } }; } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index d8b4d8d4..1700cca4 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -260,8 +260,8 @@ namespace pimoroni { public: void *frame_buffer; - Rect bounds; - Rect clip; + Rect bounds; + Rect clip; const bitmap::font_t *font; @@ -271,8 +271,8 @@ namespace pimoroni { PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) : frame_buffer(frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { set_font(&font6); - if(frame_buffer == nullptr) { - frame_buffer = (void *)(new uint8_t[pen.buffer_size(width, height)]); + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[pen.buffer_size(width, height)]); } }; @@ -305,7 +305,7 @@ namespace pimoroni { void set_clip(const Rect &r); void remove_clip(); - void* get_data() { + void *get_data() { return frame_buffer; } diff --git a/libraries/picographics_st7789/picographics_st7789.hpp b/libraries/picographics_st7789/picographics_st7789.hpp index a4428d2c..157391be 100644 --- a/libraries/picographics_st7789/picographics_st7789.hpp +++ b/libraries/picographics_st7789/picographics_st7789.hpp @@ -14,19 +14,19 @@ namespace pimoroni { public: PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) : PicoGraphics(width, height, frame_buffer), - st7789(width, height, rotation, round, frame_buffer, get_spi_pins(BG_SPI_FRONT)) { + st7789(width, height, rotation, round, get_spi_pins(BG_SPI_FRONT)) { common_init(); }; PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) : PicoGraphics(width, height, frame_buffer), - st7789(width, height, rotation, round, frame_buffer, bus_pins) { + st7789(width, height, rotation, round, bus_pins) { common_init(); }; PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) : PicoGraphics(width, height, frame_buffer), - st7789(width, height, rotation, frame_buffer, bus_pins) { + st7789(width, height, rotation, bus_pins) { common_init(); }; diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c index aab86b02..7fff1281 100644 --- a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c +++ b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c @@ -4,52 +4,64 @@ // BreakoutColourLCD160x80 Class //////////////////////////////////////////////////////////////////////////////////////////////////// -/***** Methods *****/ +// Module functions +STATIC MP_DEFINE_CONST_FUN_OBJ_3(BreakoutColourLCD160x80_module_RGB565_obj, BreakoutColourLCD160x80_module_RGB565); + +// Class Methods MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_update_obj, BreakoutColourLCD160x80_update); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_set_backlight_obj, 1, BreakoutColourLCD160x80_set_backlight); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_set_pen_obj, 1, BreakoutColourLCD160x80_set_pen); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_create_pen_obj, 1, BreakoutColourLCD160x80_create_pen); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_set_clip_obj, 1, BreakoutColourLCD160x80_set_clip); +MP_DEFINE_CONST_FUN_OBJ_2(BreakoutColourLCD160x80_set_backlight_obj, BreakoutColourLCD160x80_set_backlight); + +// Pen +MP_DEFINE_CONST_FUN_OBJ_2(BreakoutColourLCD160x80_set_pen_obj, BreakoutColourLCD160x80_set_pen); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_create_pen_obj, 4, 4, BreakoutColourLCD160x80_create_pen); + +// Primitives +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_set_clip_obj, 5, 5, BreakoutColourLCD160x80_set_clip); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_remove_clip_obj, BreakoutColourLCD160x80_remove_clip); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_clear_obj, BreakoutColourLCD160x80_clear); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_pixel_obj, 1, BreakoutColourLCD160x80_pixel); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_pixel_span_obj, 1, BreakoutColourLCD160x80_pixel_span); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_rectangle_obj, 1, BreakoutColourLCD160x80_rectangle); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_circle_obj, 1, BreakoutColourLCD160x80_circle); +MP_DEFINE_CONST_FUN_OBJ_3(BreakoutColourLCD160x80_pixel_obj, BreakoutColourLCD160x80_pixel); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_pixel_span_obj, 4, 4, BreakoutColourLCD160x80_pixel_span); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_rectangle_obj, 5, 5, BreakoutColourLCD160x80_rectangle); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_circle_obj, 4, 4, BreakoutColourLCD160x80_circle); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_character_obj, 1, BreakoutColourLCD160x80_character); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_text_obj, 1, BreakoutColourLCD160x80_text); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_polygon_obj, 1, BreakoutColourLCD160x80_polygon); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_triangle_obj, 1, BreakoutColourLCD160x80_triangle); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_line_obj, 1, BreakoutColourLCD160x80_line); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_measure_text_obj, 1, BreakoutColourLCD160x80_measure_text); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_polygon_obj, 2, BreakoutColourLCD160x80_polygon); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_triangle_obj, 7, 7, BreakoutColourLCD160x80_triangle); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_line_obj, 5, 5, BreakoutColourLCD160x80_line); + +// Utility +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_get_bounds_obj, BreakoutColourLCD160x80_get_bounds); /***** Binding of Methods *****/ STATIC const mp_rom_map_elem_t BreakoutColourLCD160x80_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&BreakoutColourLCD160x80_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&BreakoutColourLCD160x80_set_backlight_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&BreakoutColourLCD160x80_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&BreakoutColourLCD160x80_set_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&BreakoutColourLCD160x80_update_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&BreakoutColourLCD160x80_set_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&BreakoutColourLCD160x80_create_pen_obj) }, { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&BreakoutColourLCD160x80_set_clip_obj) }, { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&BreakoutColourLCD160x80_remove_clip_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&BreakoutColourLCD160x80_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&BreakoutColourLCD160x80_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&BreakoutColourLCD160x80_pixel_span_obj) }, { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&BreakoutColourLCD160x80_rectangle_obj) }, { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&BreakoutColourLCD160x80_circle_obj) }, { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&BreakoutColourLCD160x80_character_obj) }, { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&BreakoutColourLCD160x80_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_measure_text), MP_ROM_PTR(&BreakoutColourLCD160x80_measure_text_obj) }, { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&BreakoutColourLCD160x80_polygon_obj) }, { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&BreakoutColourLCD160x80_triangle_obj) }, { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&BreakoutColourLCD160x80_line_obj) }, - { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(WIDTH) }, - { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(HEIGHT) }, + + { MP_ROM_QSTR(MP_QSTR_get_bounds), MP_ROM_PTR(&BreakoutColourLCD160x80_get_bounds_obj) } }; STATIC MP_DEFINE_CONST_DICT(BreakoutColourLCD160x80_locals_dict, BreakoutColourLCD160x80_locals_dict_table); /***** Class Definition *****/ -const mp_obj_type_t breakout_colourlcd160x80_BreakoutColourLCD160x80_type = { +const mp_obj_type_t BreakoutColourLCD160x80_type = { { &mp_type_type }, .name = MP_QSTR_breakout_colourlcd160x80, - .print = BreakoutColourLCD160x80_print, .make_new = BreakoutColourLCD160x80_make_new, .locals_dict = (mp_obj_dict_t*)&BreakoutColourLCD160x80_locals_dict, }; @@ -62,7 +74,12 @@ const mp_obj_type_t breakout_colourlcd160x80_BreakoutColourLCD160x80_type = { /***** Globals Table *****/ STATIC const mp_map_elem_t breakout_colourlcd160x80_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_colourlcd160x80) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutColourLCD160x80), (mp_obj_t)&breakout_colourlcd160x80_BreakoutColourLCD160x80_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutColourLCD160x80), (mp_obj_t)&BreakoutColourLCD160x80_type }, + + { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&BreakoutColourLCD160x80_module_RGB565_obj) }, + + { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(WIDTH) }, + { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(HEIGHT) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_colourlcd160x80_globals, breakout_colourlcd160x80_globals_table); diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp index f51f5f50..785b8e31 100644 --- a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp +++ b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp @@ -1,4 +1,7 @@ #include "libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp" +#include "common/pimoroni_common.hpp" +#include "common/pimoroni_bus.hpp" + #include "micropython/modules/util.hpp" @@ -6,339 +9,233 @@ using namespace pimoroni; extern "C" { #include "breakout_colourlcd160x80.h" +#include "micropython/modules/pimoroni_bus/pimoroni_bus.h" /***** Variables Struct *****/ -typedef struct _breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t { +typedef struct _BreakoutColourLCD160x80_obj_t { mp_obj_base_t base; BreakoutColourLCD160x80 *breakout; -} breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t; + void *buffer; +} BreakoutColourLCD160x80_obj_t; -/***** Print *****/ -void BreakoutColourLCD160x80_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - (void)kind; //Unused input parameter - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - BreakoutColourLCD160x80* breakout = self->breakout; - mp_print_str(print, "BreakoutColourLCD160x80("); - - mp_print_str(print, "spi = "); - mp_obj_print_helper(print, mp_obj_new_int((breakout->get_spi() == spi0) ? 0 : 1), PRINT_REPR); - - mp_print_str(print, ", cs = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_cs()), PRINT_REPR); - - mp_print_str(print, ", dc = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_dc()), PRINT_REPR); - - mp_print_str(print, ", sck = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_sck()), PRINT_REPR); - - mp_print_str(print, ", mosi = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_mosi()), PRINT_REPR); - - mp_print_str(print, ", bl = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_bl()), PRINT_REPR); - - mp_print_str(print, ")"); -} /***** Constructor *****/ mp_obj_t BreakoutColourLCD160x80_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = nullptr; + BreakoutColourLCD160x80_obj_t *self = nullptr; - if(n_args + n_kw == 2) { - enum { ARG_buffer, ARG_slot }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_slot, MP_ARG_REQUIRED | MP_ARG_INT }, - }; + enum { ARG_bus, ARG_buffer }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bus, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - int slot = args[ARG_slot].u_int; - if(slot == BG_SPI_FRONT || slot == BG_SPI_BACK) { - self = m_new_obj(breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - self->base.type = &breakout_colourlcd160x80_BreakoutColourLCD160x80_type; + self = m_new_obj(BreakoutColourLCD160x80_obj_t); + self->base.type = &BreakoutColourLCD160x80_type; - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - - self->breakout = m_new_class(BreakoutColourLCD160x80, bufinfo.buf, (BG_SPI_SLOT)slot); - } - else { - mp_raise_ValueError("slot not a valid value. Expected 0 to 1"); - } - } - else { - enum { ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_spi, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_cs, MP_ARG_INT, {.u_int = ST7735::DEFAULT_CS_PIN} }, - { MP_QSTR_dc, MP_ARG_INT, {.u_int = ST7735::DEFAULT_DC_PIN} }, - { MP_QSTR_sck, MP_ARG_INT, {.u_int = ST7735::DEFAULT_SCK_PIN} }, - { MP_QSTR_mosi, MP_ARG_INT, {.u_int = ST7735::DEFAULT_MOSI_PIN} }, - { MP_QSTR_bl, MP_ARG_INT, {.u_int = ST7735::DEFAULT_BL_PIN} }, - }; - - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + // Get or create a suitable framebuffer + // save a pointer onto the object so that GC can find it + size_t required_size = PenRGB565::buffer_size(WIDTH, HEIGHT); + if (args[ARG_buffer].u_obj != mp_const_none) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - - // Get SPI bus. - int spi_id = args[ARG_spi].u_int; - int sck = args[ARG_sck].u_int; - int mosi = args[ARG_mosi].u_int; - - if(spi_id == -1) { - spi_id = (sck >> 3) & 0b1; // If no spi specified, choose the one for the given SCK pin + self->buffer = bufinfo.buf; + if(bufinfo.len < (size_t)(required_size)) { + mp_raise_ValueError("Supplied buffer is too small!"); } - if(spi_id < 0 || spi_id > 1) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id); - } - - if(!IS_VALID_SCK(spi_id, sck)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin")); - } - - if(!IS_VALID_MOSI(spi_id, mosi)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin")); - } - - self = m_new_obj(breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - self->base.type = &breakout_colourlcd160x80_BreakoutColourLCD160x80_type; - - spi_inst_t *spi = (spi_id == 0) ? spi0 : spi1; - self->breakout = m_new_class(BreakoutColourLCD160x80, bufinfo.buf, spi, - args[ARG_cs].u_int, args[ARG_dc].u_int, sck, mosi, PIN_UNUSED, args[ARG_bl].u_int); + } else { + self->buffer = m_new(uint8_t, required_size); } - self->breakout->init(); + // Check the bus argument for a valid SPIBus + // or just build the class and accept the defaults. + if (args[ARG_bus].u_obj == mp_const_none) { + self->breakout = m_new_class(BreakoutColourLCD160x80, self->buffer); + } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) { + _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); + self->breakout = m_new_class(BreakoutColourLCD160x80, self->buffer, *(SPIPins *)(bus->pins)); + } else { + mp_raise_ValueError("SPIBus expected!"); + } return MP_OBJ_FROM_PTR(self); } /***** Methods *****/ +mp_obj_t BreakoutColourLCD160x80_get_bounds(mp_obj_t self_in) { + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); + mp_obj_t tuple[2] = { + mp_obj_new_int(self->breakout->bounds.w), + mp_obj_new_int(self->breakout->bounds.h) + }; + return mp_obj_new_tuple(2, tuple); +} + mp_obj_t BreakoutColourLCD160x80_update(mp_obj_t self_in) { - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); self->breakout->update(); return mp_const_none; } -mp_obj_t BreakoutColourLCD160x80_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_brightness }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_brightness, MP_ARG_REQUIRED | MP_ARG_OBJ }, - }; +mp_obj_t BreakoutColourLCD160x80_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + float b = mp_obj_get_float(brightness); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + if(b < 0 || b > 1.0f) mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); - float brightness = mp_obj_get_float(args[ARG_brightness].u_obj); - - if(brightness < 0 || brightness > 1.0f) - mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); - else - self->breakout->set_backlight((uint8_t)(brightness * 255.0f)); + self->breakout->set_backlight((uint8_t)(b * 255.0f)); return mp_const_none; } -mp_obj_t BreakoutColourLCD160x80_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutColourLCD160x80_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { + return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb332( + mp_obj_get_int(r), + mp_obj_get_int(g), + mp_obj_get_int(b) + )); +} - enum { ARG_self, ARG_pen }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT }, - }; +mp_obj_t BreakoutColourLCD160x80_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { + return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb565( + mp_obj_get_int(r), + mp_obj_get_int(g), + mp_obj_get_int(b) + )); +} - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); +mp_obj_t BreakoutColourLCD160x80_set_pen(mp_obj_t self_in, mp_obj_t pen) { + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - - int pen = args[ARG_pen].u_int; - - if(pen < 0 || pen > 0xffff) - mp_raise_ValueError("p is not a valid pen."); - else - self->breakout->set_pen(pen); + self->breakout->set_pen(mp_obj_get_int(pen)); return mp_const_none; } -mp_obj_t BreakoutColourLCD160x80_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - int pen = 0; +mp_obj_t BreakoutColourLCD160x80_reset_pen(mp_obj_t self_in, mp_obj_t pen) { + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); + self->breakout->reset_pen(mp_obj_get_int(pen)); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_update_pen(size_t n_args, const mp_obj_t *args) { + enum { ARG_self, ARG_i, ARG_r, ARG_g, ARG_b }; + + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); + + self->breakout->update_pen( + mp_obj_get_int(args[ARG_i]) & 0xff, + mp_obj_get_int(args[ARG_r]) & 0xff, + mp_obj_get_int(args[ARG_g]) & 0xff, + mp_obj_get_int(args[ARG_b]) & 0xff + ); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_create_pen(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_r, ARG_g, ARG_b }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + int result = self->breakout->create_pen( + mp_obj_get_int(args[ARG_r]) & 0xff, + mp_obj_get_int(args[ARG_g]) & 0xff, + mp_obj_get_int(args[ARG_b]) & 0xff + ); - int r = args[ARG_r].u_int; - int g = args[ARG_g].u_int; - int b = args[ARG_b].u_int; + if (result == -1) mp_raise_ValueError("create_pen failed. No matching colour or space in palette!"); - 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 - pen = self->breakout->create_pen(r, g, b); - - return mp_obj_new_int(pen); + return mp_obj_new_int(result); } -mp_obj_t BreakoutColourLCD160x80_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutColourLCD160x80_set_clip(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int w = args[ARG_w].u_int; - int h = args[ARG_h].u_int; - - Rect r(x, y, w, h); - self->breakout->set_clip(r); + self->breakout->set_clip({ + mp_obj_get_int(args[ARG_x]), + mp_obj_get_int(args[ARG_y]), + mp_obj_get_int(args[ARG_w]), + mp_obj_get_int(args[ARG_h]) + }); return mp_const_none; } mp_obj_t BreakoutColourLCD160x80_remove_clip(mp_obj_t self_in) { - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); + self->breakout->remove_clip(); return mp_const_none; } mp_obj_t BreakoutColourLCD160x80_clear(mp_obj_t self_in) { - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); + self->breakout->clear(); return mp_const_none; } -mp_obj_t BreakoutColourLCD160x80_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - }; +mp_obj_t BreakoutColourLCD160x80_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y) { + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - - Point p(x, y); - self->breakout->pixel(p); + self->breakout->pixel({ + mp_obj_get_int(x), + mp_obj_get_int(y) + }); return mp_const_none; } -mp_obj_t BreakoutColourLCD160x80_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutColourLCD160x80_pixel_span(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_l }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_l, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int l = args[ARG_l].u_int; - - Point p(x, y); - self->breakout->pixel_span(p, l); + self->breakout->pixel_span({ + mp_obj_get_int(args[ARG_x]), + mp_obj_get_int(args[ARG_y]) + }, mp_obj_get_int(args[ARG_l])); return mp_const_none; } -mp_obj_t BreakoutColourLCD160x80_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutColourLCD160x80_rectangle(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int w = args[ARG_w].u_int; - int h = args[ARG_h].u_int; - - Rect r(x, y, w, h); - self->breakout->rectangle(r); + self->breakout->rectangle({ + mp_obj_get_int(args[ARG_x]), + mp_obj_get_int(args[ARG_y]), + mp_obj_get_int(args[ARG_w]), + mp_obj_get_int(args[ARG_h]) + }); return mp_const_none; } -mp_obj_t BreakoutColourLCD160x80_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutColourLCD160x80_circle(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_r }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int r = args[ARG_r].u_int; - - Point p(x, y); - self->breakout->circle(p, r); + self->breakout->circle({ + mp_obj_get_int(args[ARG_x]), + mp_obj_get_int(args[ARG_y]) + }, mp_obj_get_int(args[ARG_r])); return mp_const_none; } @@ -348,15 +245,15 @@ mp_obj_t BreakoutColourLCD160x80_character(size_t n_args, const mp_obj_t *pos_ar static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_char, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, BreakoutColourLCD160x80_obj_t); int c = mp_obj_get_int(args[ARG_char].u_obj); int x = args[ARG_x].u_int; @@ -382,118 +279,124 @@ mp_obj_t BreakoutColourLCD160x80_text(size_t n_args, const mp_obj_t *pos_args, m mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, BreakoutColourLCD160x80_obj_t); mp_obj_t text_obj = args[ARG_text].u_obj; - if(mp_obj_is_str_or_bytes(text_obj)) { - GET_STR_DATA_LEN(text_obj, str, str_len); - std::string t((const char*)str); + if(!mp_obj_is_str_or_bytes(text_obj)) mp_raise_TypeError("text: string required"); - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int wrap = args[ARG_wrap].u_int; - int scale = args[ARG_scale].u_int; + GET_STR_DATA_LEN(text_obj, str, str_len); - self->breakout->text(t, Point(x, y), wrap, scale); - } - else if(mp_obj_is_float(text_obj)) { - mp_raise_TypeError("can't convert 'float' object to str implicitly"); - } - else if(mp_obj_is_int(text_obj)) { - mp_raise_TypeError("can't convert 'int' object to str implicitly"); - } - else if(mp_obj_is_bool(text_obj)) { - mp_raise_TypeError("can't convert 'bool' object to str implicitly"); - } - else { - mp_raise_TypeError("can't convert object to str implicitly"); - } + std::string t((const char*)str); + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + int wrap = args[ARG_wrap].u_int; + int scale = args[ARG_scale].u_int; + + self->breakout->text(t, Point(x, y), wrap, scale); return mp_const_none; } +mp_obj_t BreakoutColourLCD160x80_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_text, ARG_scale }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, BreakoutColourLCD160x80_obj_t); + + mp_obj_t text_obj = args[ARG_text].u_obj; + + if(!mp_obj_is_str_or_bytes(text_obj)) mp_raise_TypeError("text: string required"); + + GET_STR_DATA_LEN(text_obj, str, str_len); + + std::string t((const char*)str); + + int scale = args[ARG_scale].u_int; + + int width = self->breakout->measure_text(t, scale); + + return mp_obj_new_int(width); +} + mp_obj_t BreakoutColourLCD160x80_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // enum { ARG_self, ARG_x, ARG_y, ARG_r }; - // static const mp_arg_t allowed_args[] = { - // { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - // { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, - // { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, - // { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - // }; + size_t num_tuples = n_args - 1; + const mp_obj_t *tuples = pos_args + 1; - // mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - // mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], BreakoutColourLCD160x80_obj_t); - // breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + // Check if there is only one argument, which might be a list + if(n_args == 2) { + if(mp_obj_is_type(pos_args[1], &mp_type_list)) { + mp_obj_list_t *points = MP_OBJ_TO_PTR2(pos_args[1], mp_obj_list_t); - // int x = args[ARG_x].u_int; - // int y = args[ARG_y].u_int; - // int r = args[ARG_r].u_int; + if(points->len <= 0) mp_raise_ValueError("poly(): cannot provide an empty list"); - // Point p(x, y); - // self->breakout->circle(p, r); + num_tuples = points->len; + tuples = points->items; + } + else { + mp_raise_TypeError("poly(): can't convert object to list"); + } + } - mp_raise_NotImplementedError("polygon is not implemented. Please avoid using this function for now"); + if(num_tuples > 0) { + std::vector points; + for(size_t i = 0; i < num_tuples; i++) { + mp_obj_t obj = tuples[i]; + if(!mp_obj_is_type(obj, &mp_type_tuple)) mp_raise_ValueError("poly(): can't convert object to tuple"); + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(obj, mp_obj_tuple_t); + + if(tuple->len != 2) mp_raise_ValueError("poly(): tuple must only contain two numbers"); + + points.push_back({ + mp_obj_get_int(tuple->items[0]), + mp_obj_get_int(tuple->items[1]) + }); + } + self->breakout->polygon(points); + } return mp_const_none; } -mp_obj_t BreakoutColourLCD160x80_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutColourLCD160x80_triangle(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_x3, ARG_y3 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x3, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y3, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - - int x1 = args[ARG_x1].u_int; - int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x2].u_int; - int y2 = args[ARG_y2].u_int; - int x3 = args[ARG_x3].u_int; - int y3 = args[ARG_y3].u_int; - - Point p1(x1, y1); - Point p2(x2, y2); - Point p3(x3, y3); - self->breakout->triangle(p1, p2, p3); + self->breakout->triangle( + {mp_obj_get_int(args[ARG_x1]), + mp_obj_get_int(args[ARG_y1])}, + {mp_obj_get_int(args[ARG_x2]), + mp_obj_get_int(args[ARG_y2])}, + {mp_obj_get_int(args[ARG_x3]), + mp_obj_get_int(args[ARG_y3])} + ); return mp_const_none; } -mp_obj_t BreakoutColourLCD160x80_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutColourLCD160x80_line(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); - - int x1 = args[ARG_x1].u_int; - int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x2].u_int; - int y2 = args[ARG_y2].u_int; - - Point p1(x1, y1); - Point p2(x2, y2); - self->breakout->line(p1, p2); + self->breakout->line( + {mp_obj_get_int(args[ARG_x1]), + mp_obj_get_int(args[ARG_y1])}, + {mp_obj_get_int(args[ARG_x2]), + mp_obj_get_int(args[ARG_y2])} + ); return mp_const_none; } diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h index 166c06a4..ca5386d3 100644 --- a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h +++ b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h @@ -2,31 +2,39 @@ #include "py/runtime.h" #include "py/objstr.h" -/***** Constants *****/ static const int WIDTH = 160; static const int HEIGHT = 80; +// Type +extern const mp_obj_type_t BreakoutColourLCD160x80_type; -/***** Extern of Class Definition *****/ -extern const mp_obj_type_t breakout_colourlcd160x80_BreakoutColourLCD160x80_type; +// Module functions +extern mp_obj_t BreakoutColourLCD160x80_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); -/***** Extern of Class Methods *****/ -extern void BreakoutColourLCD160x80_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +// Class methods extern mp_obj_t BreakoutColourLCD160x80_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 BreakoutColourLCD160x80_update(mp_obj_t self_in); -extern mp_obj_t BreakoutColourLCD160x80_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_remove_clip(mp_obj_t self_in); -extern mp_obj_t BreakoutColourLCD160x80_clear(mp_obj_t self_in); -extern mp_obj_t BreakoutColourLCD160x80_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); \ No newline at end of file +extern mp_obj_t BreakoutColourLCD160x80_update(mp_obj_t self_in); +extern mp_obj_t BreakoutColourLCD160x80_set_backlight(mp_obj_t self_in, mp_obj_t brightness); + +// Pen +extern mp_obj_t BreakoutColourLCD160x80_set_pen(mp_obj_t self_in, mp_obj_t pen); +extern mp_obj_t BreakoutColourLCD160x80_create_pen(size_t n_args, const mp_obj_t *args); + +// Primitives +extern mp_obj_t BreakoutColourLCD160x80_set_clip(size_t n_args, const mp_obj_t *args); +extern mp_obj_t BreakoutColourLCD160x80_remove_clip(mp_obj_t self_in); +extern mp_obj_t BreakoutColourLCD160x80_clear(mp_obj_t self_in); +extern mp_obj_t BreakoutColourLCD160x80_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y); +extern mp_obj_t BreakoutColourLCD160x80_pixel_span(size_t n_args, const mp_obj_t *args); +extern mp_obj_t BreakoutColourLCD160x80_rectangle(size_t n_args, const mp_obj_t *args); +extern mp_obj_t BreakoutColourLCD160x80_circle(size_t n_args, const mp_obj_t *args); +extern mp_obj_t BreakoutColourLCD160x80_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_triangle(size_t n_args, const mp_obj_t *args); +extern mp_obj_t BreakoutColourLCD160x80_line(size_t n_args, const mp_obj_t *args); + +// Utility +extern mp_obj_t BreakoutColourLCD160x80_get_bounds(mp_obj_t self_in); \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd160x80/micropython.cmake b/micropython/modules/breakout_colourlcd160x80/micropython.cmake index f2dde212..7146a5ff 100644 --- a/micropython/modules/breakout_colourlcd160x80/micropython.cmake +++ b/micropython/modules/breakout_colourlcd160x80/micropython.cmake @@ -19,4 +19,10 @@ target_compile_definitions(usermod_${MOD_NAME} INTERFACE -DMODULE_${MOD_NAME_UPPER}_ENABLED=1 ) -target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) \ No newline at end of file +target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) + +set_source_files_properties( + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + PROPERTIES COMPILE_FLAGS + "-Wno-discarded-qualifiers" +) \ No newline at end of file diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c index 500cd9af..02c477a8 100644 --- a/micropython/modules/st7789/st7789.c +++ b/micropython/modules/st7789/st7789.c @@ -79,9 +79,6 @@ STATIC const mp_map_elem_t st7789_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_RGB332), MP_ROM_PTR(&GenericST7789_module_RGB332_obj) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&GenericST7789_module_RGB565_obj) }, - { MP_ROM_QSTR(MP_QSTR_PALETTE_RGB332), MP_ROM_INT(0) }, - { MP_ROM_QSTR(MP_QSTR_PALETTE_USER), MP_ROM_INT(1) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_240X240), MP_ROM_INT(DISPLAY_LCD_240X240) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_ROUND_LCD_240X240), MP_ROM_INT(DISPLAY_ROUND_LCD_240X240) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY), MP_ROM_INT(DISPLAY_PICO_DISPLAY) }, From 67f1331b23e7d71e2f1c02606e3ce26122c71584 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Jun 2022 16:37:06 +0100 Subject: [PATCH 29/84] ST7789 -> PicoGraphics * Absorb ST7735 support into the generic ST7789 driver and rename to PicoGraphics * Delete obsolete MicroPython modules * Refactor PicoGraphics to inherited class for each pen type * Refactor ST7789 and ST7735 to derive from DisplayDriver * Allow user to set pen_type in MicroPython constructor for RGB565, RGB332, P8 and P4 modes --- drivers/st7735/st7735.cpp | 29 +- drivers/st7735/st7735.hpp | 13 +- drivers/st7789/st7789.cpp | 158 ++---- drivers/st7789/st7789.hpp | 42 +- examples/pico_display_2/demo.cpp | 48 +- .../breakout_colourlcd160x80.hpp | 4 +- libraries/pico_graphics/pico_graphics.cpp | 87 ++- libraries/pico_graphics/pico_graphics.hpp | 273 +++++---- .../picographics_st7789.hpp | 10 +- .../modules/badger2040-micropython.cmake | 3 - .../breakout_colourlcd160x80.c | 95 ---- .../breakout_colourlcd160x80.cpp | 403 ------------- .../breakout_colourlcd160x80.h | 40 -- .../micropython.cmake | 28 - .../breakout_colourlcd240x240.c | 78 --- .../breakout_colourlcd240x240.cpp | 531 ------------------ .../breakout_colourlcd240x240.h | 32 -- .../micropython.cmake | 22 - .../breakout_roundlcd/breakout_roundlcd.c | 78 --- .../breakout_roundlcd/breakout_roundlcd.cpp | 512 ----------------- .../breakout_roundlcd/breakout_roundlcd.h | 32 -- .../breakout_roundlcd/micropython.cmake | 20 - micropython/modules/micropython-common.cmake | 3 +- micropython/modules/pico_display/README.md | 211 ------- .../modules/pico_display/images/circle.png | Bin 5200 -> 0 bytes .../modules/pico_display/images/clip.png | Bin 6696 -> 0 bytes .../modules/pico_display/images/rectangle.png | Bin 4814 -> 0 bytes .../pico_display/images/text_scale.png | Bin 6698 -> 0 bytes .../modules/pico_display/micropython.cmake | 26 - .../modules/pico_display/pico_display.c | 74 --- .../modules/pico_display/pico_display.cpp | 323 ----------- .../modules/pico_display/pico_display.h | 26 - micropython/modules/pico_display_2/README.md | 206 ------- .../modules/pico_display_2/images/circle.png | Bin 5200 -> 0 bytes .../modules/pico_display_2/images/clip.png | Bin 6696 -> 0 bytes .../pico_display_2/images/rectangle.png | Bin 4814 -> 0 bytes .../pico_display_2/images/text_scale.png | Bin 6698 -> 0 bytes .../modules/pico_display_2/micropython.cmake | 28 - .../modules/pico_display_2/pico_display_2.c | 74 --- .../modules/pico_display_2/pico_display_2.cpp | 323 ----------- .../modules/pico_display_2/pico_display_2.h | 26 - .../micropython.cmake | 4 +- .../modules/picographics/picographics.c | 104 ++++ .../picographics.cpp} | 275 +++++---- .../modules/picographics/picographics.h | 61 ++ micropython/modules/st7789/st7789.c | 98 ---- micropython/modules/st7789/st7789.h | 52 -- micropython/modules/ulab | 2 +- 48 files changed, 613 insertions(+), 3841 deletions(-) delete mode 100644 micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c delete mode 100644 micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp delete mode 100644 micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h delete mode 100644 micropython/modules/breakout_colourlcd160x80/micropython.cmake delete mode 100644 micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.c delete mode 100644 micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp delete mode 100644 micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.h delete mode 100644 micropython/modules/breakout_colourlcd240x240/micropython.cmake delete mode 100644 micropython/modules/breakout_roundlcd/breakout_roundlcd.c delete mode 100644 micropython/modules/breakout_roundlcd/breakout_roundlcd.cpp delete mode 100644 micropython/modules/breakout_roundlcd/breakout_roundlcd.h delete mode 100644 micropython/modules/breakout_roundlcd/micropython.cmake delete mode 100644 micropython/modules/pico_display/README.md delete mode 100644 micropython/modules/pico_display/images/circle.png delete mode 100644 micropython/modules/pico_display/images/clip.png delete mode 100644 micropython/modules/pico_display/images/rectangle.png delete mode 100644 micropython/modules/pico_display/images/text_scale.png delete mode 100644 micropython/modules/pico_display/micropython.cmake delete mode 100755 micropython/modules/pico_display/pico_display.c delete mode 100644 micropython/modules/pico_display/pico_display.cpp delete mode 100644 micropython/modules/pico_display/pico_display.h delete mode 100644 micropython/modules/pico_display_2/README.md delete mode 100644 micropython/modules/pico_display_2/images/circle.png delete mode 100644 micropython/modules/pico_display_2/images/clip.png delete mode 100644 micropython/modules/pico_display_2/images/rectangle.png delete mode 100644 micropython/modules/pico_display_2/images/text_scale.png delete mode 100644 micropython/modules/pico_display_2/micropython.cmake delete mode 100755 micropython/modules/pico_display_2/pico_display_2.c delete mode 100644 micropython/modules/pico_display_2/pico_display_2.cpp delete mode 100644 micropython/modules/pico_display_2/pico_display_2.h rename micropython/modules/{st7789 => picographics}/micropython.cmake (87%) create mode 100644 micropython/modules/picographics/picographics.c rename micropython/modules/{st7789/st7789.cpp => picographics/picographics.cpp} (52%) create mode 100644 micropython/modules/picographics/picographics.h delete mode 100644 micropython/modules/st7789/st7789.c delete mode 100644 micropython/modules/st7789/st7789.h diff --git a/drivers/st7735/st7735.cpp b/drivers/st7735/st7735.cpp index 41f30f00..ee306bb9 100644 --- a/drivers/st7735/st7735.cpp +++ b/drivers/st7735/st7735.cpp @@ -164,23 +164,22 @@ namespace pimoroni { } // Native 16-bit framebuffer update - void ST7735::update(PicoGraphics *graphics) { - command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); - } + void ST7735::update(PicoGraphics *graphics) { + if(graphics->pen_type == PicoGraphics::PEN_RGB565) { + command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); + } else { + command(reg::RAMWR); + gpio_put(dc, 1); // data mode + gpio_put(cs, 0); - // 8-bit framebuffer with palette conversion update - void ST7735::update(PicoGraphics *graphics) { - command(reg::RAMWR); - gpio_put(dc, 1); // data mode - gpio_put(cs, 0); - - uint16_t row_buf[width]; - for(auto y = 0u; y < height; y++) { - graphics->get_data(y, &row_buf); - // TODO: Add DMA->SPI / PIO while we prep the next row - spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); + uint16_t row_buf[width]; + for(auto y = 0u; y < height; y++) { + graphics->get_data(y, &row_buf); + // TODO: Add DMA->SPI / PIO while we prep the next row + spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); + } + gpio_put(cs, 1); } - gpio_put(cs, 1); } void ST7735::set_backlight(uint8_t brightness) { diff --git a/drivers/st7735/st7735.hpp b/drivers/st7735/st7735.hpp index f794f665..66edf56e 100644 --- a/drivers/st7735/st7735.hpp +++ b/drivers/st7735/st7735.hpp @@ -8,7 +8,7 @@ namespace pimoroni { - class ST7735 { + class ST7735 : public DisplayDriver { //-------------------------------------------------- // Constants //-------------------------------------------------- @@ -20,9 +20,6 @@ namespace pimoroni { // Variables //-------------------------------------------------- private: - // screen properties - uint16_t width; - uint16_t height; spi_inst_t *spi = spi0; @@ -45,7 +42,7 @@ namespace pimoroni { //-------------------------------------------------- public: ST7735(uint16_t width, uint16_t height, SPIPins pins) : - width(width), height(height), + DisplayDriver(width, height, ROTATE_0), spi(pins.spi), cs(pins.cs), dc(pins.dc), sck(pins.sck), mosi(pins.mosi), bl(pins.bl) { init(); } @@ -55,10 +52,8 @@ namespace pimoroni { // Methods //-------------------------------------------------- public: - // Update functions for supported Pen types - void update(PicoGraphics *graphics); - void update(PicoGraphics *graphics); - void set_backlight(uint8_t brightness); + void update(PicoGraphics *graphics) override; + void set_backlight(uint8_t brightness) override; private: void init(bool auto_init_sequence = true); diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 251d98d4..f432e793 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -46,7 +46,23 @@ namespace pimoroni { PWMFRSEL = 0xCC }; - void ST7789::init() { + void ST7789::common_init() { + gpio_set_function(dc, GPIO_FUNC_SIO); + gpio_set_dir(dc, GPIO_OUT); + + gpio_set_function(cs, GPIO_FUNC_SIO); + gpio_set_dir(cs, GPIO_OUT); + + // if a backlight pin is provided then set it up for + // pwm control + if(bl != PIN_UNUSED) { + pwm_config cfg = pwm_get_default_config(); + pwm_set_wrap(pwm_gpio_to_slice_num(bl), 65535); + pwm_init(pwm_gpio_to_slice_num(bl), &cfg, true); + gpio_set_function(bl, GPIO_FUNC_PWM); + set_backlight(0); // Turn backlight off initially to avoid nasty surprises + } + command(reg::SWRESET); sleep_ms(150); @@ -201,140 +217,40 @@ namespace pimoroni { gpio_put(cs, 1); } - void ST7789::update(PicoGraphics *graphics) { - command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); - } - - void ST7789::update(PicoGraphics *graphics) { - uint8_t command = reg::RAMWR; - - gpio_put(dc, 0); // command mode - - gpio_put(cs, 0); - - if(spi) { - spi_write_blocking(spi, &command, 1); + void ST7789::update(PicoGraphics *graphics) { + if(graphics->pen_type == PicoGraphics::PEN_RGB565) { + command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); } else { - write_blocking_parallel(&command, 1); - } + uint8_t command = reg::RAMWR; - gpio_put(dc, 1); // data mode + gpio_put(dc, 0); // command mode - uint16_t row_buf[width]; + gpio_put(cs, 0); - for(auto y = 0u; y < height; y++) { - graphics->get_data(y, &row_buf); - // TODO: Add DMA->SPI / PIO while we prep the next row if(spi) { - spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); + spi_write_blocking(spi, &command, 1); } else { - write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); + write_blocking_parallel(&command, 1); } - } - gpio_put(cs, 1); - } + gpio_put(dc, 1); // data mode - void ST7789::update(PicoGraphics *graphics) { - uint8_t command = reg::RAMWR; + uint16_t row_buf[width]; - gpio_put(dc, 0); // command mode - - gpio_put(cs, 0); - - if(spi) { - spi_write_blocking(spi, &command, 1); - } else { - write_blocking_parallel(&command, 1); - } - - gpio_put(dc, 1); // data mode - - uint16_t row_buf[width]; - - for(auto y = 0u; y < height; y++) { - graphics->get_data(y, &row_buf); - // TODO: Add DMA->SPI / PIO while we prep the next row - if(spi) { - spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); - } else { - write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); + for(auto y = 0u; y < height; y++) { + graphics->get_data(y, &row_buf); + // TODO: Add DMA->SPI / PIO while we prep the next row + if(spi) { + spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); + } else { + write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); + } } - } - gpio_put(cs, 1); + gpio_put(cs, 1); + } } - void ST7789::update(PicoGraphics *graphics) { - uint8_t command = reg::RAMWR; - - gpio_put(dc, 0); // command mode - - gpio_put(cs, 0); - - if(spi) { - spi_write_blocking(spi, &command, 1); - } else { - write_blocking_parallel(&command, 1); - } - - gpio_put(dc, 1); // data mode - - uint16_t row_buf[width]; - - for(auto y = 0u; y < height; y++) { - graphics->get_data(y, &row_buf); - // TODO: Add DMA->SPI / PIO while we prep the next row - if(spi) { - spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); - } else { - write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); - } - } - - gpio_put(cs, 1); - } - -/* - // Native 16-bit framebuffer update - void ST7789::update() { - command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); - } - - // 8-bit framebuffer with palette conversion update - void ST7789::update(uint16_t *palette) { - uint8_t command = reg::RAMWR; - uint16_t row[width]; - - gpio_put(dc, 0); // command mode - - gpio_put(cs, 0); - - if(spi) { - spi_write_blocking(spi, &command, 1); - } else { - write_blocking_parallel(&command, 1); - } - - gpio_put(dc, 1); // data mode - - for(auto y = 0u; y < height; y++) { - for(auto x = 0u; x < width; x++) { - auto i = y * width + x; - row[x] = palette[((uint8_t *)frame_buffer)[i]]; - } - // TODO: Add DMA->SPI / PIO while we prep the next row - if(spi) { - spi_write_blocking(spi, (const uint8_t*)row, width * sizeof(uint16_t)); - } else { - write_blocking_parallel((const uint8_t*)row, width * sizeof(uint16_t)); - } - } - - gpio_put(cs, 1); - } - */ - void ST7789::set_backlight(uint8_t brightness) { // gamma correct the provided 0-255 brightness value onto a // 0-65535 range for the pwm counter diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index d1b1dd4b..5be438c3 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -12,14 +12,10 @@ namespace pimoroni { - class ST7789 { + class ST7789 : public DisplayDriver { spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE; public: - // screen properties - uint16_t width; - uint16_t height; - Rotation rotation; bool round; //-------------------------------------------------- @@ -44,8 +40,8 @@ namespace pimoroni { public: // Parallel init ST7789(uint16_t width, uint16_t height, Rotation rotation, ParallelPins pins) : - spi(nullptr), - width(width), height(height), rotation(rotation), round(false), + DisplayDriver(width, height, rotation), + spi(nullptr), round(false), cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl) { gpio_set_function(wr_sck, GPIO_FUNC_SIO); @@ -66,8 +62,8 @@ namespace pimoroni { // Serial init ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, SPIPins pins) : - spi(pins.spi), - width(width), height(height), rotation(rotation), round(round), + DisplayDriver(width, height, rotation), + spi(pins.spi), round(round), cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl) { // configure spi interface and pins @@ -79,35 +75,15 @@ namespace pimoroni { common_init(); } - void init(); - void command(uint8_t command, size_t len = 0, const char *data = NULL); - void set_backlight(uint8_t brightness); - void update(PicoGraphics *graphics); - void update(PicoGraphics *graphics); - void update(PicoGraphics *graphics); - void update(PicoGraphics *graphics); + void update(PicoGraphics *graphics) override; + void set_backlight(uint8_t brightness) override; private: + void common_init(); void configure_display(Rotation rotate); void write_blocking_parallel(const uint8_t *src, size_t len); - void common_init() { - gpio_set_function(dc, GPIO_FUNC_SIO); - gpio_set_dir(dc, GPIO_OUT); - - gpio_set_function(cs, GPIO_FUNC_SIO); - gpio_set_dir(cs, GPIO_OUT); - - // if a backlight pin is provided then set it up for - // pwm control - if(bl != PIN_UNUSED) { - pwm_config cfg = pwm_get_default_config(); - pwm_set_wrap(pwm_gpio_to_slice_num(bl), 65535); - pwm_init(pwm_gpio_to_slice_num(bl), &cfg, true); - gpio_set_function(bl, GPIO_FUNC_PWM); - set_backlight(0); // Turn backlight off initially to avoid nasty surprises - } - } + void command(uint8_t command, size_t len = 0, const char *data = NULL); }; } diff --git a/examples/pico_display_2/demo.cpp b/examples/pico_display_2/demo.cpp index 8f2edd75..65968e78 100644 --- a/examples/pico_display_2/demo.cpp +++ b/examples/pico_display_2/demo.cpp @@ -3,14 +3,16 @@ #include #include -#include "pico_display_2.hpp" -#include "picographics_st7789.hpp" +#include "graphics_2.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics->hpp" #include "rgbled.hpp" #include "button.hpp" using namespace pimoroni; -PicoGraphicsST7789 pico_display(240, 240, ROTATE_0); +ST7789 st7789(320, 240, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics graphics; RGBLED led(PicoDisplay2::LED_R, PicoDisplay2::LED_G, PicoDisplay2::LED_B); @@ -40,7 +42,13 @@ void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { } int main() { - pico_display.set_backlight(255); + st7789.set_backlight(255); + + // 150k RAM, 65K colours + // graphics = new PicoGraphics_PenRGB565(st7789.width, st7789.height, nullptr); + + // 75k RAM, 256 colours + graphics = new PicoGraphics_PenRGB332(st7789.width, st7789.height, nullptr); struct pt { float x; @@ -54,19 +62,19 @@ int main() { std::vector shapes; for(int i = 0; i < 100; i++) { pt shape; - shape.x = rand() % pico_display.bounds.w; - shape.y = rand() % pico_display.bounds.h; + shape.x = rand() % graphics->bounds.w; + shape.y = rand() % graphics->bounds.h; shape.r = (rand() % 10) + 3; shape.dx = float(rand() % 255) / 64.0f; shape.dy = float(rand() % 255) / 64.0f; - shape.pen = pico_display.create_pen(rand() % 255, rand() % 255, rand() % 255); + shape.pen = graphics->create_pen(rand() % 255, rand() % 255, rand() % 255); shapes.push_back(shape); } Point text_location(0, 0); - Pen BG = pico_display.create_pen(120, 40, 60); - Pen WHITE = pico_display.create_pen(255, 255, 255); + Pen BG = graphics->create_pen(120, 40, 60); + Pen WHITE = graphics->create_pen(255, 255, 255); while(true) { if(button_a.raw()) text_location.x -= 1; @@ -75,8 +83,8 @@ int main() { if(button_x.raw()) text_location.y -= 1; if(button_y.raw()) text_location.y += 1; - pico_display.set_pen(BG); - pico_display.clear(); + graphics->set_pen(BG); + graphics->clear(); for(auto &shape : shapes) { shape.x += shape.dx; @@ -85,21 +93,21 @@ int main() { shape.dx *= -1; shape.x = shape.r; } - if((shape.x + shape.r) >= pico_display.bounds.w) { + if((shape.x + shape.r) >= graphics->bounds.w) { shape.dx *= -1; - shape.x = pico_display.bounds.w - shape.r; + shape.x = graphics->bounds.w - shape.r; } if((shape.y - shape.r) < 0) { shape.dy *= -1; shape.y = shape.r; } - if((shape.y + shape.r) >= pico_display.bounds.h) { + if((shape.y + shape.r) >= graphics->bounds.h) { shape.dy *= -1; - shape.y = pico_display.bounds.h - shape.r; + shape.y = graphics->bounds.h - shape.r; } - pico_display.set_pen(shape.pen); - pico_display.circle(Point(shape.x, shape.y), shape.r); + graphics->set_pen(shape.pen); + graphics->circle(Point(shape.x, shape.y), shape.r); } @@ -111,11 +119,11 @@ int main() { led.set_rgb(r, g, b); - pico_display.set_pen(WHITE); - pico_display.text("Hello World", text_location, 320); + graphics->set_pen(WHITE); + graphics->text("Hello World", text_location, 320); // update screen - pico_display.update(); + st7789.update(graphics); } return 0; diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp index b814daab..b2eadd27 100644 --- a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp +++ b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp @@ -7,7 +7,7 @@ namespace pimoroni { - class BreakoutColourLCD160x80 : public PicoGraphics { + class BreakoutColourLCD160x80 : public PicoGraphics_PenRGB565 { //-------------------------------------------------- // Constants //-------------------------------------------------- @@ -32,7 +32,7 @@ namespace pimoroni { } BreakoutColourLCD160x80(void *frame_buffer, SPIPins bus_pins) - : PicoGraphics(WIDTH, HEIGHT, frame_buffer), screen(WIDTH, HEIGHT, bus_pins){ + : PicoGraphics_PenRGB565(WIDTH, HEIGHT, frame_buffer), screen(WIDTH, HEIGHT, bus_pins){ } void update() { diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 098a16aa..6b38fe08 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -2,39 +2,51 @@ namespace pimoroni { - template - void PicoGraphics::set_font(const bitmap::font_t *font){ + void PicoGraphics::set_pen(uint c) {}; + void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) {}; + void PicoGraphics::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {}; + void PicoGraphics::reset_pen(uint8_t i) {}; + int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;}; + void PicoGraphics::set_pixel(void *frame_buffer, uint x, uint y, uint stride) {}; + void PicoGraphics::palette_lookup(void *frame_buffer, void *result, uint offset, uint length) {}; + + void PicoGraphics::set_dimensions(int width, int height) { + bounds.w = width; + bounds.h = height; + clip.w = width; + clip.h = height; + } + + void *PicoGraphics::get_data() { + return frame_buffer; + } + + void PicoGraphics::get_data(uint y, void *row_buf) { + palette_lookup(frame_buffer, row_buf, y * bounds.w, bounds.w); + } + + void PicoGraphics::set_font(const bitmap::font_t *font){ this->font = font; } - template - void PicoGraphics::set_pen(uint16_t p) { - pen.set_color(p); - } - - template - void PicoGraphics::set_clip(const Rect &r) { + void PicoGraphics::set_clip(const Rect &r) { clip = bounds.intersection(r); } - template - void PicoGraphics::remove_clip() { + void PicoGraphics::remove_clip() { clip = bounds; } - template - void PicoGraphics::clear() { + void PicoGraphics::clear() { rectangle(clip); } - template - void PicoGraphics::pixel(const Point &p) { + void PicoGraphics::pixel(const Point &p) { if(!clip.contains(p)) return; - pen.set_pixel(frame_buffer, p.x, p.y, bounds.w); + set_pixel(frame_buffer, p.x, p.y, bounds.w); } - template - void PicoGraphics::pixel_span(const Point &p, int32_t l) { + void PicoGraphics::pixel_span(const Point &p, int32_t l) { // check if span in bounds if( p.x + l < clip.x || p.x >= clip.x + clip.w || p.y < clip.y || p.y >= clip.y + clip.h) return; @@ -46,13 +58,12 @@ namespace pimoroni { Point dest(clipped.x, clipped.y); while(l--) { - pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); + set_pixel(frame_buffer, dest.x, dest.y, bounds.w); dest.x++; } } - template - void PicoGraphics::rectangle(const Rect &r) { + void PicoGraphics::rectangle(const Rect &r) { // clip and/or discard depending on rectangle visibility Rect clipped = r.intersection(clip); @@ -62,18 +73,12 @@ namespace pimoroni { while(clipped.h--) { // draw span of pixels for this row pixel_span(dest, clipped.w); - /*for(int32_t i = 0; i < clipped.w; i++) { - pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); - dest.x++; - }*/ - // move to next scanline dest.y++; } } - template - void PicoGraphics::circle(const Point &p, int32_t radius) { + void PicoGraphics::circle(const Point &p, int32_t radius) { // circle in screen bounds? Rect bounds = Rect(p.x - radius, p.y - radius, radius * 2, radius * 2); if(!bounds.intersects(clip)) return; @@ -101,22 +106,19 @@ namespace pimoroni { } } - template - void PicoGraphics::character(const char c, const Point &p, uint8_t scale) { + void PicoGraphics::character(const char c, const Point &p, uint8_t scale) { bitmap::character(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){ rectangle(Rect(x, y, w, h)); }, c, p.x, p.y, scale); } - template - void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) { + void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) { bitmap::text(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){ rectangle(Rect(x, y, w, h)); }, t, p.x, p.y, wrap, scale); } - template - int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) { + int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) { return bitmap::measure_text(font, t, scale); } @@ -128,8 +130,7 @@ namespace pimoroni { return (p1.y == p2.y && p1.x > p2.x) || (p1.y < p2.y); } - template - void PicoGraphics::triangle(Point p1, Point p2, Point p3) { + void PicoGraphics::triangle(Point p1, Point p2, Point p3) { Rect triangle_bounds( Point(std::min(p1.x, std::min(p2.x, p3.x)), std::min(p1.y, std::min(p2.y, p3.y))), Point(std::max(p1.x, std::max(p2.x, p3.x)), std::max(p1.y, std::max(p2.y, p3.y)))); @@ -174,7 +175,7 @@ namespace pimoroni { Point dest = Point(triangle_bounds.x, triangle_bounds.y + y); for (int32_t x = 0; x < triangle_bounds.w; x++) { if ((w0 | w1 | w2) >= 0) { - pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); + set_pixel(frame_buffer, dest.x, dest.y, bounds.w); } dest.x++; @@ -190,8 +191,7 @@ namespace pimoroni { } } - template - void PicoGraphics::polygon(const std::vector &points) { + void PicoGraphics::polygon(const std::vector &points) { static int32_t nodes[64]; // maximum allowed number of nodes per scanline for polygon rendering int32_t miny = points[0].y, maxy = points[0].y; @@ -237,8 +237,7 @@ namespace pimoroni { } } - template - void PicoGraphics::line(Point p1, Point p2) { + void PicoGraphics::line(Point p1, Point p2) { // fast horizontal line if(p1.y == p2.y) { int32_t start = std::max(clip.x, std::min(p1.x, p2.x)); @@ -253,7 +252,7 @@ namespace pimoroni { int32_t length = std::min(clip.y + clip.h, std::max(p1.y, p2.y)) - start; Point dest(p1.x, start); while(length--) { - pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w); + set_pixel(frame_buffer, dest.x, dest.y, bounds.w); dest.y++; } return; @@ -273,7 +272,7 @@ namespace pimoroni { int32_t x = p1.x; int32_t y = p1.y << 16; while(s--) { - pen.set_pixel(frame_buffer, x, y >> 16, bounds.w); + set_pixel(frame_buffer, x, y >> 16, bounds.w); y += sy; x += sx; } @@ -285,7 +284,7 @@ namespace pimoroni { int32_t y = p1.y; int32_t x = p1.x << 16; while(s--) { - pen.set_pixel(frame_buffer, x >> 16, y, bounds.w); + set_pixel(frame_buffer, x >> 16, y, bounds.w); y += sy; x += sx; } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 1700cca4..b4462748 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -5,9 +5,14 @@ #include #include #include "libraries/bitmap_fonts/font6_data.hpp" +#include "common/pimoroni_common.hpp" -// a tiny little graphics library for our Pico products -// supports only 16-bit (565) RGB framebuffers +// A tiny graphics library for our Pico products +// supports: +// - 16-bit (565) RGB +// - 8-bit (332) RGB +// - 8-bit with 16-bit 256 entry palette +// - 4-bit with 16-bit 8 entry palette namespace pimoroni { typedef uint8_t RGB332; typedef uint16_t RGB565; @@ -44,48 +49,95 @@ namespace pimoroni { void deflate(int32_t v); }; - class PicoGraphicsPenType { - public: + class PicoGraphics { + public: + struct PaletteEntry { + RGB565 color; + bool used; + }; - struct PaletteEntry { - RGB565 color; - bool used; - }; + enum PenType { + PEN_P2 = 0, + PEN_P4, + PEN_P8, + PEN_RGB332, + PEN_RGB565 + }; - static constexpr RGB332 rgb_to_rgb332(uint8_t r, uint8_t g, uint8_t b) { - return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); - } + void *frame_buffer; - static constexpr RGB565 rgb332_to_rgb565(RGB332 c) { - uint16_t p = ((c & 0b11100000) << 8) | - ((c & 0b00011100) << 6) | - ((c & 0b00000011) << 3); - return __builtin_bswap16(p); - } + PenType pen_type; + Rect bounds; + Rect clip; - static constexpr RGB565 rgb_to_rgb565(uint8_t r, uint8_t g, uint8_t b) { - uint16_t p = ((r & 0b11111000) << 8) | - ((g & 0b11111100) << 3) | - ((b & 0b11111000) >> 3); + const bitmap::font_t *font; - return __builtin_bswap16(p); - } + static constexpr RGB332 rgb_to_rgb332(uint8_t r, uint8_t g, uint8_t b) { + return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); + } - virtual void set_pixel(void *frame_buffer, uint x, uint y, uint stride); - virtual int create(uint8_t r, uint8_t g, uint8_t b); - virtual void set_color(uint c); - virtual void set_color(uint8_t r, uint8_t g, uint8_t b); - virtual void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b); + static constexpr RGB565 rgb332_to_rgb565(RGB332 c) { + uint16_t p = ((c & 0b11100000) << 8) | + ((c & 0b00011100) << 6) | + ((c & 0b00000011) << 3); + return __builtin_bswap16(p); + } - virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length); - static size_t buffer_size(uint w, uint h); // Must be static, since user must know required size to alloc framebuffer + static constexpr RGB565 rgb_to_rgb565(uint8_t r, uint8_t g, uint8_t b) { + uint16_t p = ((r & 0b11111000) << 8) | + ((g & 0b11111100) << 3) | + ((b & 0b11111000) >> 3); + + return __builtin_bswap16(p); + } + + PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) + : frame_buffer(frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { + set_font(&font6); + }; + + virtual void set_pen(uint c); + virtual void set_pen(uint8_t r, uint8_t g, uint8_t b); + virtual void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b); + virtual void reset_pen(uint8_t i); + virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); + virtual void set_pixel(void *frame_buffer, uint x, uint y, uint stride); + virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length); + + void set_font(const bitmap::font_t *font); + + void set_dimensions(int width, int height); + + void *get_data(); + void get_data(uint y, void *row_buf); + + void set_clip(const Rect &r); + void remove_clip(); + + void clear(); + void pixel(const Point &p); + void pixel_span(const Point &p, int32_t l); + void rectangle(const Rect &r); + void circle(const Point &p, int32_t r); + void character(const char c, const Point &p, uint8_t scale = 2); + void text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale = 2); + int32_t measure_text(const std::string &t, uint8_t scale = 2); + void polygon(const std::vector &points); + void triangle(Point p1, Point p2, Point p3); + void line(Point p1, Point p2); }; - class PenP4 : public PicoGraphicsPenType { + + class PicoGraphics_PenP4 : public PicoGraphics { public: uint8_t color; PaletteEntry palette[8]; - PenP4() { + PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer) + : PicoGraphics(width, height, frame_buffer) { + this->pen_type = PEN_P4; + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); + } palette[0].color = rgb_to_rgb565(57, 48, 57); // Black palette[1].color = rgb_to_rgb565(255, 255, 255); // White palette[2].color = rgb_to_rgb565(58, 91, 70); // Green @@ -95,17 +147,12 @@ namespace pimoroni { palette[6].color = rgb_to_rgb565(177, 106, 73); // Orange palette[7].color = rgb_to_rgb565(255, 255, 255); // Clear } - void set_color(uint c) { + void set_pen(uint c) { color = c & 0xf; } - void set_color(uint8_t r, uint8_t g, uint8_t b) override { + void set_pen(uint8_t r, uint8_t g, uint8_t b) override { // TODO look up closest palette colour, or just NOOP? } - void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {} - void reset_color(uint8_t i) {} - int create(uint8_t r, uint8_t g, uint8_t b) override { - return -1; // Can never create new colours, fixed palette! - } void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { // pointer to byte in framebuffer that contains this pixel uint8_t *buf = (uint8_t *)frame_buffer; @@ -133,30 +180,35 @@ namespace pimoroni { } }; - class PenP8 : public PicoGraphicsPenType { + class PicoGraphics_PenP8 : public PicoGraphics { public: uint8_t color; PaletteEntry palette[256]; - PenP8() { + PicoGraphics_PenP8(uint16_t width, uint16_t height, void *frame_buffer) + : PicoGraphics(width, height, frame_buffer) { + this->pen_type = PEN_P8; + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); + } for(auto i = 0u; i < 256; i++) { - reset_color(i); + reset_pen(i); } } - void set_color(uint c) override { + void set_pen(uint c) override { color = c; } - void set_color(uint8_t r, uint8_t g, uint8_t b) override { + void set_pen(uint8_t r, uint8_t g, uint8_t b) override { // TODO look up closest palette colour, or just NOOP? } - void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { + void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { palette[i].color = rgb_to_rgb565(r, g, b); palette[i].used = true; } - void reset_color(uint8_t i) { + void reset_pen(uint8_t i) override { palette[i].color = 0; palette[i].used = false; } - int create(uint8_t r, uint8_t g, uint8_t b) override { + int create_pen(uint8_t r, uint8_t g, uint8_t b) override { // Create a colour and place it in the palette if there's space RGB565 c = rgb_to_rgb565(r, g, b); for(auto i = 0u; i < 256u; i++) { @@ -184,30 +236,35 @@ namespace pimoroni { } }; - class PenRGB332 : public PicoGraphicsPenType { + class PicoGraphics_PenRGB332 : public PicoGraphics { public: RGB332 color; PaletteEntry palette[256]; - PenRGB332() { + PicoGraphics_PenRGB332(uint16_t width, uint16_t height, void *frame_buffer) + : PicoGraphics(width, height, frame_buffer) { + this->pen_type = PEN_RGB332; + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); + } for(auto i = 0u; i < 256; i++) { - reset_color(i); + reset_pen(i); } } - void set_color(uint c) { + void set_pen(uint c) override { color = c; } - void set_color(uint8_t r, uint8_t g, uint8_t b) override { + void set_pen(uint8_t r, uint8_t g, uint8_t b) override { color = rgb_to_rgb332(r, g, b); } - void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { + void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { palette[i].color = rgb_to_rgb565(r, g, b); palette[i].used = true; } - void reset_color(uint8_t i) { + void reset_pen(uint8_t i) override { palette[i].color = rgb332_to_rgb565(i); palette[i].used = true; } - int create(uint8_t r, uint8_t g, uint8_t b) override { + int create_pen(uint8_t r, uint8_t g, uint8_t b) override { return rgb_to_rgb332(r, g, b); } void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { @@ -226,109 +283,45 @@ namespace pimoroni { } }; - class PenRGB565 : public PicoGraphicsPenType { + class PicoGraphics_PenRGB565 : public PicoGraphics { public: - uint16_t color; - void set_color(uint c) override { + RGB565 color; + PicoGraphics_PenRGB565(uint16_t width, uint16_t height, void *frame_buffer) + : PicoGraphics(width, height, frame_buffer) { + this->pen_type = PEN_RGB565; + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); + } + } + void set_pen(uint c) override { color = c; } - void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { - // Palette only. Does nothing. - } - void reset_color(uint8_t i) { - // Palette only. Does nothing. - } - void set_color(uint8_t r, uint8_t g, uint8_t b) override { + void set_pen(uint8_t r, uint8_t g, uint8_t b) override { color = rgb_to_rgb565(r, g, b); } - int create(uint8_t r, uint8_t g, uint8_t b) override { + int create_pen(uint8_t r, uint8_t g, uint8_t b) override { return rgb_to_rgb565(r, g, b); } void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { uint16_t *buf = (uint16_t *)frame_buffer; buf[y * stride + x] = color; } - void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { - } static size_t buffer_size(uint w, uint h) { return w * h * sizeof(RGB565); } }; - template - class PicoGraphics { - public: - void *frame_buffer; + class DisplayDriver { + public: + uint16_t width; + uint16_t height; + Rotation rotation; - Rect bounds; - Rect clip; + DisplayDriver(uint16_t width, uint16_t height, Rotation rotation) + : width(width), height(height), rotation(rotation) {}; - const bitmap::font_t *font; - - T pen; - - public: - PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) - : frame_buffer(frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { - set_font(&font6); - if(this->frame_buffer == nullptr) { - this->frame_buffer = (void *)(new uint8_t[pen.buffer_size(width, height)]); - } - }; - - void set_font(const bitmap::font_t *font); - void set_pen(uint16_t p); - - int create_pen(uint8_t r, uint8_t g, uint8_t b) { - return pen.create(r, g, b); - } - - void set_pen(uint8_t r, uint8_t g, uint8_t b) { - pen.set_color(r, g, b); - } - - void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { - pen.update_color(i, r, g, b); - } - - void reset_pen(uint8_t i) { - pen.reset_color(i); - } - - void set_dimensions(int width, int height) { - bounds.w = width; - bounds.h = height; - clip.w = width; - clip.h = height; - } - - void set_clip(const Rect &r); - void remove_clip(); - - void *get_data() { - return frame_buffer; - } - - void get_data(uint y, void *row_buf) { - pen.palette_lookup(frame_buffer, row_buf, y * bounds.w, bounds.w); - } - - void clear(); - void pixel(const Point &p); - void pixel_span(const Point &p, int32_t l); - void rectangle(const Rect &r); - void circle(const Point &p, int32_t r); - void character(const char c, const Point &p, uint8_t scale = 2); - void text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale = 2); - int32_t measure_text(const std::string &t, uint8_t scale = 2); - void polygon(const std::vector &points); - void triangle(Point p1, Point p2, Point p3); - void line(Point p1, Point p2); + virtual void update(PicoGraphics *display); + virtual void set_backlight(uint8_t brightness); }; - template class PicoGraphics; - template class PicoGraphics; - template class PicoGraphics; - template class PicoGraphics; - } diff --git a/libraries/picographics_st7789/picographics_st7789.hpp b/libraries/picographics_st7789/picographics_st7789.hpp index 157391be..96ec537f 100644 --- a/libraries/picographics_st7789/picographics_st7789.hpp +++ b/libraries/picographics_st7789/picographics_st7789.hpp @@ -6,32 +6,30 @@ namespace pimoroni { - template - class PicoGraphicsST7789 : public PicoGraphics { + class PicoGraphicsST7789 : public PicoGraphics_PenRGB565 { private: ST7789 st7789; public: PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) : - PicoGraphics(width, height, frame_buffer), + PicoGraphics_PenRGB565(width, height, frame_buffer), st7789(width, height, rotation, round, get_spi_pins(BG_SPI_FRONT)) { common_init(); }; PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) : - PicoGraphics(width, height, frame_buffer), + PicoGraphics_PenRGB565(width, height, frame_buffer), st7789(width, height, rotation, round, bus_pins) { common_init(); }; PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) : - PicoGraphics(width, height, frame_buffer), + PicoGraphics_PenRGB565(width, height, frame_buffer), st7789(width, height, rotation, bus_pins) { common_init(); }; void common_init() { - st7789.init(); this->set_dimensions(st7789.width, st7789.height); st7789.update(this); } diff --git a/micropython/modules/badger2040-micropython.cmake b/micropython/modules/badger2040-micropython.cmake index 5b3aae32..0bb41c5c 100644 --- a/micropython/modules/badger2040-micropython.cmake +++ b/micropython/modules/badger2040-micropython.cmake @@ -10,9 +10,7 @@ include(breakout_dotmatrix/micropython) include(breakout_encoder/micropython) include(breakout_ioexpander/micropython) include(breakout_ltr559/micropython) -include(breakout_colourlcd160x80/micropython) include(breakout_as7262/micropython) -#include(breakout_roundlcd/micropython) # replaced with Generic ST7789 include(breakout_rgbmatrix5x5/micropython) include(breakout_matrix11x7/micropython) include(breakout_msa301/micropython) @@ -22,7 +20,6 @@ include(breakout_potentiometer/micropython) include(breakout_rtc/micropython) include(breakout_trackball/micropython) include(breakout_sgp30/micropython) -# include(breakout_colourlcd240x240/micropython) # replaced with Generic ST7789 include(breakout_bh1745/micropython) include(breakout_bme68x/micropython) include(breakout_bme280/micropython) diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c deleted file mode 100644 index 7fff1281..00000000 --- a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c +++ /dev/null @@ -1,95 +0,0 @@ -#include "breakout_colourlcd160x80.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// BreakoutColourLCD160x80 Class -//////////////////////////////////////////////////////////////////////////////////////////////////// - -// Module functions -STATIC MP_DEFINE_CONST_FUN_OBJ_3(BreakoutColourLCD160x80_module_RGB565_obj, BreakoutColourLCD160x80_module_RGB565); - -// Class Methods -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_update_obj, BreakoutColourLCD160x80_update); -MP_DEFINE_CONST_FUN_OBJ_2(BreakoutColourLCD160x80_set_backlight_obj, BreakoutColourLCD160x80_set_backlight); - -// Pen -MP_DEFINE_CONST_FUN_OBJ_2(BreakoutColourLCD160x80_set_pen_obj, BreakoutColourLCD160x80_set_pen); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_create_pen_obj, 4, 4, BreakoutColourLCD160x80_create_pen); - -// Primitives -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_set_clip_obj, 5, 5, BreakoutColourLCD160x80_set_clip); -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_remove_clip_obj, BreakoutColourLCD160x80_remove_clip); -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_clear_obj, BreakoutColourLCD160x80_clear); -MP_DEFINE_CONST_FUN_OBJ_3(BreakoutColourLCD160x80_pixel_obj, BreakoutColourLCD160x80_pixel); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_pixel_span_obj, 4, 4, BreakoutColourLCD160x80_pixel_span); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_rectangle_obj, 5, 5, BreakoutColourLCD160x80_rectangle); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_circle_obj, 4, 4, BreakoutColourLCD160x80_circle); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_character_obj, 1, BreakoutColourLCD160x80_character); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_text_obj, 1, BreakoutColourLCD160x80_text); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_measure_text_obj, 1, BreakoutColourLCD160x80_measure_text); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_polygon_obj, 2, BreakoutColourLCD160x80_polygon); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_triangle_obj, 7, 7, BreakoutColourLCD160x80_triangle); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(BreakoutColourLCD160x80_line_obj, 5, 5, BreakoutColourLCD160x80_line); - -// Utility -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_get_bounds_obj, BreakoutColourLCD160x80_get_bounds); - -/***** Binding of Methods *****/ -STATIC const mp_rom_map_elem_t BreakoutColourLCD160x80_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&BreakoutColourLCD160x80_pixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&BreakoutColourLCD160x80_set_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&BreakoutColourLCD160x80_update_obj) }, - - { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&BreakoutColourLCD160x80_set_backlight_obj) }, - { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&BreakoutColourLCD160x80_create_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&BreakoutColourLCD160x80_set_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&BreakoutColourLCD160x80_remove_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&BreakoutColourLCD160x80_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&BreakoutColourLCD160x80_pixel_span_obj) }, - { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&BreakoutColourLCD160x80_rectangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&BreakoutColourLCD160x80_circle_obj) }, - { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&BreakoutColourLCD160x80_character_obj) }, - { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&BreakoutColourLCD160x80_text_obj) }, - { MP_ROM_QSTR(MP_QSTR_measure_text), MP_ROM_PTR(&BreakoutColourLCD160x80_measure_text_obj) }, - { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&BreakoutColourLCD160x80_polygon_obj) }, - { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&BreakoutColourLCD160x80_triangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&BreakoutColourLCD160x80_line_obj) }, - - { MP_ROM_QSTR(MP_QSTR_get_bounds), MP_ROM_PTR(&BreakoutColourLCD160x80_get_bounds_obj) } -}; -STATIC MP_DEFINE_CONST_DICT(BreakoutColourLCD160x80_locals_dict, BreakoutColourLCD160x80_locals_dict_table); - -/***** Class Definition *****/ -const mp_obj_type_t BreakoutColourLCD160x80_type = { - { &mp_type_type }, - .name = MP_QSTR_breakout_colourlcd160x80, - .make_new = BreakoutColourLCD160x80_make_new, - .locals_dict = (mp_obj_dict_t*)&BreakoutColourLCD160x80_locals_dict, -}; - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// breakout_colourlcd160x80 Module -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Globals Table *****/ -STATIC const mp_map_elem_t breakout_colourlcd160x80_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_colourlcd160x80) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutColourLCD160x80), (mp_obj_t)&BreakoutColourLCD160x80_type }, - - { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&BreakoutColourLCD160x80_module_RGB565_obj) }, - - { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(WIDTH) }, - { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(HEIGHT) }, -}; -STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_colourlcd160x80_globals, breakout_colourlcd160x80_globals_table); - -/***** Module Definition *****/ -const mp_obj_module_t breakout_colourlcd160x80_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_breakout_colourlcd160x80_globals, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -MP_REGISTER_MODULE(MP_QSTR_breakout_colourlcd160x80, breakout_colourlcd160x80_user_cmodule, MODULE_BREAKOUT_COLOURLCD160X80_ENABLED); -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp deleted file mode 100644 index 785b8e31..00000000 --- a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp +++ /dev/null @@ -1,403 +0,0 @@ -#include "libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp" -#include "common/pimoroni_common.hpp" -#include "common/pimoroni_bus.hpp" - -#include "micropython/modules/util.hpp" - - -using namespace pimoroni; - -extern "C" { -#include "breakout_colourlcd160x80.h" -#include "micropython/modules/pimoroni_bus/pimoroni_bus.h" - -/***** Variables Struct *****/ -typedef struct _BreakoutColourLCD160x80_obj_t { - mp_obj_base_t base; - BreakoutColourLCD160x80 *breakout; - void *buffer; -} BreakoutColourLCD160x80_obj_t; - - -/***** Constructor *****/ -mp_obj_t BreakoutColourLCD160x80_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - BreakoutColourLCD160x80_obj_t *self = nullptr; - - enum { ARG_bus, ARG_buffer }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_bus, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - }; - - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - self = m_new_obj(BreakoutColourLCD160x80_obj_t); - self->base.type = &BreakoutColourLCD160x80_type; - - // Get or create a suitable framebuffer - // save a pointer onto the object so that GC can find it - size_t required_size = PenRGB565::buffer_size(WIDTH, HEIGHT); - - if (args[ARG_buffer].u_obj != mp_const_none) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - self->buffer = bufinfo.buf; - if(bufinfo.len < (size_t)(required_size)) { - mp_raise_ValueError("Supplied buffer is too small!"); - } - } else { - self->buffer = m_new(uint8_t, required_size); - } - - // Check the bus argument for a valid SPIBus - // or just build the class and accept the defaults. - if (args[ARG_bus].u_obj == mp_const_none) { - self->breakout = m_new_class(BreakoutColourLCD160x80, self->buffer); - } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) { - _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); - self->breakout = m_new_class(BreakoutColourLCD160x80, self->buffer, *(SPIPins *)(bus->pins)); - } else { - mp_raise_ValueError("SPIBus expected!"); - } - - return MP_OBJ_FROM_PTR(self); -} - -/***** Methods *****/ -mp_obj_t BreakoutColourLCD160x80_get_bounds(mp_obj_t self_in) { - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - mp_obj_t tuple[2] = { - mp_obj_new_int(self->breakout->bounds.w), - mp_obj_new_int(self->breakout->bounds.h) - }; - return mp_obj_new_tuple(2, tuple); -} - -mp_obj_t BreakoutColourLCD160x80_update(mp_obj_t self_in) { - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - self->breakout->update(); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - - float b = mp_obj_get_float(brightness); - - if(b < 0 || b > 1.0f) mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); - - self->breakout->set_backlight((uint8_t)(b * 255.0f)); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb332( - mp_obj_get_int(r), - mp_obj_get_int(g), - mp_obj_get_int(b) - )); -} - -mp_obj_t BreakoutColourLCD160x80_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb565( - mp_obj_get_int(r), - mp_obj_get_int(g), - mp_obj_get_int(b) - )); -} - -mp_obj_t BreakoutColourLCD160x80_set_pen(mp_obj_t self_in, mp_obj_t pen) { - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - - self->breakout->set_pen(mp_obj_get_int(pen)); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_reset_pen(mp_obj_t self_in, mp_obj_t pen) { - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - - self->breakout->reset_pen(mp_obj_get_int(pen)); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_update_pen(size_t n_args, const mp_obj_t *args) { - enum { ARG_self, ARG_i, ARG_r, ARG_g, ARG_b }; - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - - self->breakout->update_pen( - mp_obj_get_int(args[ARG_i]) & 0xff, - mp_obj_get_int(args[ARG_r]) & 0xff, - mp_obj_get_int(args[ARG_g]) & 0xff, - mp_obj_get_int(args[ARG_b]) & 0xff - ); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_create_pen(size_t n_args, const mp_obj_t *args) { - enum { ARG_self, ARG_r, ARG_g, ARG_b }; - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - - int result = self->breakout->create_pen( - mp_obj_get_int(args[ARG_r]) & 0xff, - mp_obj_get_int(args[ARG_g]) & 0xff, - mp_obj_get_int(args[ARG_b]) & 0xff - ); - - if (result == -1) mp_raise_ValueError("create_pen failed. No matching colour or space in palette!"); - - return mp_obj_new_int(result); -} - -mp_obj_t BreakoutColourLCD160x80_set_clip(size_t n_args, const mp_obj_t *args) { - enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - - self->breakout->set_clip({ - mp_obj_get_int(args[ARG_x]), - mp_obj_get_int(args[ARG_y]), - mp_obj_get_int(args[ARG_w]), - mp_obj_get_int(args[ARG_h]) - }); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_remove_clip(mp_obj_t self_in) { - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - - self->breakout->remove_clip(); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_clear(mp_obj_t self_in) { - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - - self->breakout->clear(); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y) { - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, BreakoutColourLCD160x80_obj_t); - - self->breakout->pixel({ - mp_obj_get_int(x), - mp_obj_get_int(y) - }); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_pixel_span(size_t n_args, const mp_obj_t *args) { - enum { ARG_self, ARG_x, ARG_y, ARG_l }; - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - - self->breakout->pixel_span({ - mp_obj_get_int(args[ARG_x]), - mp_obj_get_int(args[ARG_y]) - }, mp_obj_get_int(args[ARG_l])); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_rectangle(size_t n_args, const mp_obj_t *args) { - enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - - self->breakout->rectangle({ - mp_obj_get_int(args[ARG_x]), - mp_obj_get_int(args[ARG_y]), - mp_obj_get_int(args[ARG_w]), - mp_obj_get_int(args[ARG_h]) - }); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_circle(size_t n_args, const mp_obj_t *args) { - enum { ARG_self, ARG_x, ARG_y, ARG_r }; - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - - self->breakout->circle({ - mp_obj_get_int(args[ARG_x]), - mp_obj_get_int(args[ARG_y]) - }, mp_obj_get_int(args[ARG_r])); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_char, ARG_x, ARG_y, ARG_scale }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_char, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, BreakoutColourLCD160x80_obj_t); - - int c = mp_obj_get_int(args[ARG_char].u_obj); - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int scale = args[ARG_scale].u_int; - - self->breakout->character((char)c, Point(x, y), scale); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_wordwrap, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, BreakoutColourLCD160x80_obj_t); - - mp_obj_t text_obj = args[ARG_text].u_obj; - - if(!mp_obj_is_str_or_bytes(text_obj)) mp_raise_TypeError("text: string required"); - - GET_STR_DATA_LEN(text_obj, str, str_len); - - std::string t((const char*)str); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int wrap = args[ARG_wrap].u_int; - int scale = args[ARG_scale].u_int; - - self->breakout->text(t, Point(x, y), wrap, scale); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_text, ARG_scale }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, BreakoutColourLCD160x80_obj_t); - - mp_obj_t text_obj = args[ARG_text].u_obj; - - if(!mp_obj_is_str_or_bytes(text_obj)) mp_raise_TypeError("text: string required"); - - GET_STR_DATA_LEN(text_obj, str, str_len); - - std::string t((const char*)str); - - int scale = args[ARG_scale].u_int; - - int width = self->breakout->measure_text(t, scale); - - return mp_obj_new_int(width); -} - -mp_obj_t BreakoutColourLCD160x80_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - size_t num_tuples = n_args - 1; - const mp_obj_t *tuples = pos_args + 1; - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], BreakoutColourLCD160x80_obj_t); - - // Check if there is only one argument, which might be a list - if(n_args == 2) { - if(mp_obj_is_type(pos_args[1], &mp_type_list)) { - mp_obj_list_t *points = MP_OBJ_TO_PTR2(pos_args[1], mp_obj_list_t); - - if(points->len <= 0) mp_raise_ValueError("poly(): cannot provide an empty list"); - - num_tuples = points->len; - tuples = points->items; - } - else { - mp_raise_TypeError("poly(): can't convert object to list"); - } - } - - if(num_tuples > 0) { - std::vector points; - for(size_t i = 0; i < num_tuples; i++) { - mp_obj_t obj = tuples[i]; - if(!mp_obj_is_type(obj, &mp_type_tuple)) mp_raise_ValueError("poly(): can't convert object to tuple"); - - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(obj, mp_obj_tuple_t); - - if(tuple->len != 2) mp_raise_ValueError("poly(): tuple must only contain two numbers"); - - points.push_back({ - mp_obj_get_int(tuple->items[0]), - mp_obj_get_int(tuple->items[1]) - }); - } - self->breakout->polygon(points); - } - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_triangle(size_t n_args, const mp_obj_t *args) { - enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_x3, ARG_y3 }; - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - - self->breakout->triangle( - {mp_obj_get_int(args[ARG_x1]), - mp_obj_get_int(args[ARG_y1])}, - {mp_obj_get_int(args[ARG_x2]), - mp_obj_get_int(args[ARG_y2])}, - {mp_obj_get_int(args[ARG_x3]), - mp_obj_get_int(args[ARG_y3])} - ); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD160x80_line(size_t n_args, const mp_obj_t *args) { - enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2 }; - - BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], BreakoutColourLCD160x80_obj_t); - - self->breakout->line( - {mp_obj_get_int(args[ARG_x1]), - mp_obj_get_int(args[ARG_y1])}, - {mp_obj_get_int(args[ARG_x2]), - mp_obj_get_int(args[ARG_y2])} - ); - - return mp_const_none; -} -} diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h deleted file mode 100644 index ca5386d3..00000000 --- a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h +++ /dev/null @@ -1,40 +0,0 @@ -// Include MicroPython API. -#include "py/runtime.h" -#include "py/objstr.h" - -static const int WIDTH = 160; -static const int HEIGHT = 80; - -// Type -extern const mp_obj_type_t BreakoutColourLCD160x80_type; - -// Module functions -extern mp_obj_t BreakoutColourLCD160x80_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); - -// Class methods -extern mp_obj_t BreakoutColourLCD160x80_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 BreakoutColourLCD160x80_update(mp_obj_t self_in); -extern mp_obj_t BreakoutColourLCD160x80_set_backlight(mp_obj_t self_in, mp_obj_t brightness); - -// Pen -extern mp_obj_t BreakoutColourLCD160x80_set_pen(mp_obj_t self_in, mp_obj_t pen); -extern mp_obj_t BreakoutColourLCD160x80_create_pen(size_t n_args, const mp_obj_t *args); - -// Primitives -extern mp_obj_t BreakoutColourLCD160x80_set_clip(size_t n_args, const mp_obj_t *args); -extern mp_obj_t BreakoutColourLCD160x80_remove_clip(mp_obj_t self_in); -extern mp_obj_t BreakoutColourLCD160x80_clear(mp_obj_t self_in); -extern mp_obj_t BreakoutColourLCD160x80_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y); -extern mp_obj_t BreakoutColourLCD160x80_pixel_span(size_t n_args, const mp_obj_t *args); -extern mp_obj_t BreakoutColourLCD160x80_rectangle(size_t n_args, const mp_obj_t *args); -extern mp_obj_t BreakoutColourLCD160x80_circle(size_t n_args, const mp_obj_t *args); -extern mp_obj_t BreakoutColourLCD160x80_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD160x80_triangle(size_t n_args, const mp_obj_t *args); -extern mp_obj_t BreakoutColourLCD160x80_line(size_t n_args, const mp_obj_t *args); - -// Utility -extern mp_obj_t BreakoutColourLCD160x80_get_bounds(mp_obj_t self_in); \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd160x80/micropython.cmake b/micropython/modules/breakout_colourlcd160x80/micropython.cmake deleted file mode 100644 index 7146a5ff..00000000 --- a/micropython/modules/breakout_colourlcd160x80/micropython.cmake +++ /dev/null @@ -1,28 +0,0 @@ -set(MOD_NAME breakout_colourlcd160x80) -string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) -add_library(usermod_${MOD_NAME} INTERFACE) - -target_sources(usermod_${MOD_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7735/st7735.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp -) - -target_include_directories(usermod_${MOD_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR} -) - -target_compile_definitions(usermod_${MOD_NAME} INTERFACE - -DMODULE_${MOD_NAME_UPPER}_ENABLED=1 -) - -target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) - -set_source_files_properties( - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c - PROPERTIES COMPILE_FLAGS - "-Wno-discarded-qualifiers" -) \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.c b/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.c deleted file mode 100644 index 885df270..00000000 --- a/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "breakout_colourlcd240x240.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// BreakoutColourLCD240x240 Class -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Methods *****/ -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD240x240_update_obj, BreakoutColourLCD240x240_update); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_set_backlight_obj, 1, BreakoutColourLCD240x240_set_backlight); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_set_pen_obj, 1, BreakoutColourLCD240x240_set_pen); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_create_pen_obj, 1, BreakoutColourLCD240x240_create_pen); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_set_clip_obj, 1, BreakoutColourLCD240x240_set_clip); -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD240x240_remove_clip_obj, BreakoutColourLCD240x240_remove_clip); -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD240x240_clear_obj, BreakoutColourLCD240x240_clear); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_pixel_obj, 1, BreakoutColourLCD240x240_pixel); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_pixel_span_obj, 1, BreakoutColourLCD240x240_pixel_span); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_rectangle_obj, 1, BreakoutColourLCD240x240_rectangle); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_circle_obj, 1, BreakoutColourLCD240x240_circle); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_character_obj, 1, BreakoutColourLCD240x240_character); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_text_obj, 1, BreakoutColourLCD240x240_text); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_polygon_obj, 1, BreakoutColourLCD240x240_polygon); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_triangle_obj, 1, BreakoutColourLCD240x240_triangle); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD240x240_line_obj, 1, BreakoutColourLCD240x240_line); - -/***** Binding of Methods *****/ -STATIC const mp_rom_map_elem_t BreakoutColourLCD240x240_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&BreakoutColourLCD240x240_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&BreakoutColourLCD240x240_set_backlight_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&BreakoutColourLCD240x240_set_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&BreakoutColourLCD240x240_create_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&BreakoutColourLCD240x240_set_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&BreakoutColourLCD240x240_remove_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&BreakoutColourLCD240x240_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&BreakoutColourLCD240x240_pixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&BreakoutColourLCD240x240_pixel_span_obj) }, - { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&BreakoutColourLCD240x240_rectangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&BreakoutColourLCD240x240_circle_obj) }, - { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&BreakoutColourLCD240x240_character_obj) }, - { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&BreakoutColourLCD240x240_text_obj) }, - { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&BreakoutColourLCD240x240_polygon_obj) }, - { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&BreakoutColourLCD240x240_triangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&BreakoutColourLCD240x240_line_obj) }, - { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(WIDTH) }, - { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(HEIGHT) }, -}; -STATIC MP_DEFINE_CONST_DICT(BreakoutColourLCD240x240_locals_dict, BreakoutColourLCD240x240_locals_dict_table); - -/***** Class Definition *****/ -const mp_obj_type_t breakout_colourlcd240x240_BreakoutColourLCD240x240_type = { - { &mp_type_type }, - .name = MP_QSTR_breakout_colourlcd240x240, - .print = BreakoutColourLCD240x240_print, - .make_new = BreakoutColourLCD240x240_make_new, - .locals_dict = (mp_obj_dict_t*)&BreakoutColourLCD240x240_locals_dict, -}; - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// breakout_colourlcd240x240 Module -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Globals Table *****/ -STATIC const mp_map_elem_t breakout_colourlcd240x240_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_colourlcd240x240) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutColourLCD240x240), (mp_obj_t)&breakout_colourlcd240x240_BreakoutColourLCD240x240_type }, -}; -STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_colourlcd240x240_globals, breakout_colourlcd240x240_globals_table); - -/***** Module Definition *****/ -const mp_obj_module_t breakout_colourlcd240x240_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_breakout_colourlcd240x240_globals, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -MP_REGISTER_MODULE(MP_QSTR_breakout_colourlcd240x240, breakout_colourlcd240x240_user_cmodule, MODULE_BREAKOUT_COLOURLCD240X240_ENABLED); -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp b/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp deleted file mode 100644 index f08e3723..00000000 --- a/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp +++ /dev/null @@ -1,531 +0,0 @@ -#include "libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.hpp" - -#include "micropython/modules/util.hpp" - - - -using namespace pimoroni; - -extern "C" { -#include "breakout_colourlcd240x240.h" - -/***** Variables Struct *****/ -typedef struct _breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t { - mp_obj_base_t base; - BreakoutColourLCD240x240 *breakout; -} breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t; - -/***** Print *****/ -void BreakoutColourLCD240x240_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - (void)kind; //Unused input parameter - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - BreakoutColourLCD240x240* breakout = self->breakout; - mp_print_str(print, "BreakoutColourLCD240x240("); - - mp_print_str(print, "spi = "); - mp_obj_print_helper(print, mp_obj_new_int((breakout->get_spi() == spi0) ? 0 : 1), PRINT_REPR); - - mp_print_str(print, ", cs = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_cs()), PRINT_REPR); - - mp_print_str(print, ", dc = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_dc()), PRINT_REPR); - - mp_print_str(print, ", sck = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_sck()), PRINT_REPR); - - mp_print_str(print, ", mosi = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_mosi()), PRINT_REPR); - - mp_print_str(print, ", bl = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_bl()), PRINT_REPR); - - mp_print_str(print, ")"); -} - -/***** Constructor *****/ -mp_obj_t BreakoutColourLCD240x240_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = nullptr; - - if(n_args + n_kw == 2) { - enum { ARG_buffer, ARG_slot }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_slot, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - int slot = args[ARG_slot].u_int; - if(slot == BG_SPI_FRONT || slot == BG_SPI_BACK) { - self = m_new_obj(breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - self->base.type = &breakout_colourlcd240x240_BreakoutColourLCD240x240_type; - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - - self->breakout = new BreakoutColourLCD240x240((uint16_t *)bufinfo.buf, (BG_SPI_SLOT)slot); - } - else { - mp_raise_ValueError("slot not a valid value. Expected 0 to 1"); - } - } - else { - enum { ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_spi, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_cs, MP_ARG_INT, {.u_int = pimoroni::SPI_BG_FRONT_CS} }, - { MP_QSTR_dc, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_MISO} }, - { MP_QSTR_sck, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_SCK} }, - { MP_QSTR_mosi, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_MOSI} }, - { MP_QSTR_bl, MP_ARG_INT, {.u_int = pimoroni::SPI_BG_FRONT_PWM} }, - }; - - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - - // Get SPI bus. - int spi_id = args[ARG_spi].u_int; - int sck = args[ARG_sck].u_int; - int mosi = args[ARG_mosi].u_int; - - if(spi_id == -1) { - spi_id = (sck >> 3) & 0b1; // If no spi specified, choose the one for the given SCK pin - } - if(spi_id < 0 || spi_id > 1) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id); - } - - if(!IS_VALID_SCK(spi_id, sck)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin")); - } - - if(!IS_VALID_MOSI(spi_id, mosi)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin")); - } - - self = m_new_obj(breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - self->base.type = &breakout_colourlcd240x240_BreakoutColourLCD240x240_type; - - spi_inst_t *spi = (spi_id == 0) ? spi0 : spi1; - self->breakout = new BreakoutColourLCD240x240((uint16_t *)bufinfo.buf, spi, - args[ARG_cs].u_int, args[ARG_dc].u_int, sck, mosi, args[ARG_bl].u_int); - } - - self->breakout->init(); - - return MP_OBJ_FROM_PTR(self); -} - -/***** Methods *****/ -mp_obj_t BreakoutColourLCD240x240_update(mp_obj_t self_in) { - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - self->breakout->update(); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_brightness }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_brightness, MP_ARG_REQUIRED | MP_ARG_OBJ }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - float brightness = mp_obj_get_float(args[ARG_brightness].u_obj); - - if(brightness < 0 || brightness > 1.0f) - mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); - else - self->breakout->set_backlight((uint8_t)(brightness * 255.0f)); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - if(n_args <= 2) { - enum { ARG_self, ARG_pen }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int pen = args[ARG_pen].u_int; - - if(pen < 0 || pen > 0xffff) - mp_raise_ValueError("p is not a valid pen."); - else - self->breakout->set_pen(pen); - } - else { - enum { ARG_self, ARG_r, ARG_g, ARG_b }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int r = args[ARG_r].u_int; - int g = args[ARG_g].u_int; - int b = args[ARG_b].u_int; - - 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 - self->breakout->set_pen(r, g, b); - } - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - int pen = 0; - - enum { ARG_self, ARG_r, ARG_g, ARG_b }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int r = args[ARG_r].u_int; - int g = args[ARG_g].u_int; - int b = args[ARG_b].u_int; - - 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 - pen = self->breakout->create_pen(r, g, b); - - return mp_obj_new_int(pen); -} - -mp_obj_t BreakoutColourLCD240x240_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int w = args[ARG_w].u_int; - int h = args[ARG_h].u_int; - - Rect r(x, y, w, h); - self->breakout->set_clip(r); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_remove_clip(mp_obj_t self_in) { - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - self->breakout->remove_clip(); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_clear(mp_obj_t self_in) { - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - self->breakout->clear(); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - - Point p(x, y); - self->breakout->pixel(p); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y, ARG_l }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_l, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int l = args[ARG_l].u_int; - - Point p(x, y); - self->breakout->pixel_span(p, l); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int w = args[ARG_w].u_int; - int h = args[ARG_h].u_int; - - Rect r(x, y, w, h); - self->breakout->rectangle(r); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y, ARG_r }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int r = args[ARG_r].u_int; - - Point p(x, y); - self->breakout->circle(p, r); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_char, ARG_x, ARG_y, ARG_scale }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_char, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int c = mp_obj_get_int(args[ARG_char].u_obj); - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int scale = args[ARG_scale].u_int; - - self->breakout->character((char)c, Point(x, y), scale); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_wordwrap, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - mp_obj_t text_obj = args[ARG_text].u_obj; - if(mp_obj_is_str_or_bytes(text_obj)) { - GET_STR_DATA_LEN(text_obj, str, str_len); - - std::string t((const char*)str); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int wrap = args[ARG_wrap].u_int; - int scale = args[ARG_scale].u_int; - - self->breakout->text(t, Point(x, y), wrap, scale); - } - else if(mp_obj_is_float(text_obj)) { - mp_raise_TypeError("can't convert 'float' object to str implicitly"); - } - else if(mp_obj_is_int(text_obj)) { - mp_raise_TypeError("can't convert 'int' object to str implicitly"); - } - else if(mp_obj_is_bool(text_obj)) { - mp_raise_TypeError("can't convert 'bool' object to str implicitly"); - } - else { - mp_raise_TypeError("can't convert object to str implicitly"); - } - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // enum { ARG_self, ARG_x, ARG_y, ARG_r }; - // static const mp_arg_t allowed_args[] = { - // { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - // { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, - // { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, - // { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - // }; - - // mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - // mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - // breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - // int x = args[ARG_x].u_int; - // int y = args[ARG_y].u_int; - // int r = args[ARG_r].u_int; - - // Point p(x, y); - // self->breakout->circle(p, r); - - mp_raise_NotImplementedError("polygon is not implemented. Please avoid using this function for now"); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_x3, ARG_y3 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x3, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y3, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int x1 = args[ARG_x1].u_int; - int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x2].u_int; - int y2 = args[ARG_y2].u_int; - int x3 = args[ARG_x3].u_int; - int y3 = args[ARG_y3].u_int; - - Point p1(x1, y1); - Point p2(x2, y2); - Point p3(x3, y3); - self->breakout->triangle(p1, p2, p3); - - return mp_const_none; -} - -mp_obj_t BreakoutColourLCD240x240_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd240x240_BreakoutColourLCD240x240_obj_t); - - int x1 = args[ARG_x1].u_int; - int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x2].u_int; - int y2 = args[ARG_y2].u_int; - - Point p1(x1, y1); - Point p2(x2, y2); - self->breakout->line(p1, p2); - - return mp_const_none; -} -} diff --git a/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.h b/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.h deleted file mode 100644 index 80f0bb47..00000000 --- a/micropython/modules/breakout_colourlcd240x240/breakout_colourlcd240x240.h +++ /dev/null @@ -1,32 +0,0 @@ -// Include MicroPython API. -#include "py/runtime.h" -#include "py/objstr.h" - -/***** Constants *****/ -static const int WIDTH = 240; -static const int HEIGHT = 240; - - -/***** Extern of Class Definition *****/ -extern const mp_obj_type_t breakout_colourlcd240x240_BreakoutColourLCD240x240_type; - -/***** Extern of Class Methods *****/ -extern void BreakoutColourLCD240x240_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); -extern mp_obj_t BreakoutColourLCD240x240_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 BreakoutColourLCD240x240_update(mp_obj_t self_in); -extern mp_obj_t BreakoutColourLCD240x240_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); - -extern mp_obj_t BreakoutColourLCD240x240_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_remove_clip(mp_obj_t self_in); -extern mp_obj_t BreakoutColourLCD240x240_clear(mp_obj_t self_in); -extern mp_obj_t BreakoutColourLCD240x240_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutColourLCD240x240_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd240x240/micropython.cmake b/micropython/modules/breakout_colourlcd240x240/micropython.cmake deleted file mode 100644 index 04d91d80..00000000 --- a/micropython/modules/breakout_colourlcd240x240/micropython.cmake +++ /dev/null @@ -1,22 +0,0 @@ -set(MOD_NAME breakout_colourlcd240x240) -string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) -add_library(usermod_${MOD_NAME} INTERFACE) - -target_sources(usermod_${MOD_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp -) - -target_include_directories(usermod_${MOD_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR} -) - -target_compile_definitions(usermod_${MOD_NAME} INTERFACE - -DMODULE_${MOD_NAME_UPPER}_ENABLED=1 -) - -target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) \ No newline at end of file diff --git a/micropython/modules/breakout_roundlcd/breakout_roundlcd.c b/micropython/modules/breakout_roundlcd/breakout_roundlcd.c deleted file mode 100644 index 3f597f67..00000000 --- a/micropython/modules/breakout_roundlcd/breakout_roundlcd.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "breakout_roundlcd.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// BreakoutRoundLCD Class -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Methods *****/ -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRoundLCD_update_obj, BreakoutRoundLCD_update); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_set_backlight_obj, 1, BreakoutRoundLCD_set_backlight); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_set_pen_obj, 1, BreakoutRoundLCD_set_pen); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_create_pen_obj, 1, BreakoutRoundLCD_create_pen); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_set_clip_obj, 1, BreakoutRoundLCD_set_clip); -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRoundLCD_remove_clip_obj, BreakoutRoundLCD_remove_clip); -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRoundLCD_clear_obj, BreakoutRoundLCD_clear); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_pixel_obj, 1, BreakoutRoundLCD_pixel); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_pixel_span_obj, 1, BreakoutRoundLCD_pixel_span); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_rectangle_obj, 1, BreakoutRoundLCD_rectangle); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_circle_obj, 1, BreakoutRoundLCD_circle); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_character_obj, 1, BreakoutRoundLCD_character); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_text_obj, 1, BreakoutRoundLCD_text); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_polygon_obj, 1, BreakoutRoundLCD_polygon); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_triangle_obj, 1, BreakoutRoundLCD_triangle); -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRoundLCD_line_obj, 1, BreakoutRoundLCD_line); - -/***** Binding of Methods *****/ -STATIC const mp_rom_map_elem_t BreakoutRoundLCD_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&BreakoutRoundLCD_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&BreakoutRoundLCD_set_backlight_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&BreakoutRoundLCD_set_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&BreakoutRoundLCD_create_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&BreakoutRoundLCD_set_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&BreakoutRoundLCD_remove_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&BreakoutRoundLCD_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&BreakoutRoundLCD_pixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&BreakoutRoundLCD_pixel_span_obj) }, - { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&BreakoutRoundLCD_rectangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&BreakoutRoundLCD_circle_obj) }, - { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&BreakoutRoundLCD_character_obj) }, - { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&BreakoutRoundLCD_text_obj) }, - { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&BreakoutRoundLCD_polygon_obj) }, - { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&BreakoutRoundLCD_triangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&BreakoutRoundLCD_line_obj) }, - { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(WIDTH) }, - { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(HEIGHT) }, -}; -STATIC MP_DEFINE_CONST_DICT(BreakoutRoundLCD_locals_dict, BreakoutRoundLCD_locals_dict_table); - -/***** Class Definition *****/ -const mp_obj_type_t breakout_roundlcd_BreakoutRoundLCD_type = { - { &mp_type_type }, - .name = MP_QSTR_BreakoutRoundLCD, - .print = BreakoutRoundLCD_print, - .make_new = BreakoutRoundLCD_make_new, - .locals_dict = (mp_obj_dict_t*)&BreakoutRoundLCD_locals_dict, -}; - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// breakout_roundlcd Module -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Globals Table *****/ -STATIC const mp_map_elem_t breakout_roundlcd_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_roundlcd) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutRoundLCD), (mp_obj_t)&breakout_roundlcd_BreakoutRoundLCD_type }, -}; -STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_roundlcd_globals, breakout_roundlcd_globals_table); - -/***** Module Definition *****/ -const mp_obj_module_t breakout_roundlcd_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_breakout_roundlcd_globals, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -MP_REGISTER_MODULE(MP_QSTR_breakout_roundlcd, breakout_roundlcd_user_cmodule, MODULE_BREAKOUT_ROUNDLCD_ENABLED); -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/micropython/modules/breakout_roundlcd/breakout_roundlcd.cpp b/micropython/modules/breakout_roundlcd/breakout_roundlcd.cpp deleted file mode 100644 index 282c68f5..00000000 --- a/micropython/modules/breakout_roundlcd/breakout_roundlcd.cpp +++ /dev/null @@ -1,512 +0,0 @@ -#include "libraries/breakout_roundlcd/breakout_roundlcd.hpp" - -#include "micropython/modules/util.hpp" - - - -using namespace pimoroni; - -extern "C" { -#include "breakout_roundlcd.h" - -/***** Variables Struct *****/ -typedef struct _breakout_roundlcd_BreakoutRoundLCD_obj_t { - mp_obj_base_t base; - BreakoutRoundLCD *breakout; -} breakout_roundlcd_BreakoutRoundLCD_obj_t; - -/***** Print *****/ -void BreakoutRoundLCD_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - (void)kind; //Unused input parameter - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_roundlcd_BreakoutRoundLCD_obj_t); - BreakoutRoundLCD* breakout = self->breakout; - mp_print_str(print, "BreakoutRoundLCD("); - - mp_print_str(print, "spi = "); - mp_obj_print_helper(print, mp_obj_new_int((breakout->get_spi() == spi0) ? 0 : 1), PRINT_REPR); - - mp_print_str(print, ", cs = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_cs()), PRINT_REPR); - - mp_print_str(print, ", dc = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_dc()), PRINT_REPR); - - mp_print_str(print, ", sck = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_sck()), PRINT_REPR); - - mp_print_str(print, ", mosi = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_mosi()), PRINT_REPR); - - mp_print_str(print, ", bl = "); - mp_obj_print_helper(print, mp_obj_new_int(breakout->get_bl()), PRINT_REPR); - - mp_print_str(print, ")"); -} - -/***** Constructor *****/ -mp_obj_t BreakoutRoundLCD_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = nullptr; - - if(n_args + n_kw == 2) { - enum { ARG_buffer, ARG_slot }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_slot, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - int slot = args[ARG_slot].u_int; - if(slot == BG_SPI_FRONT || slot == BG_SPI_BACK) { - self = m_new_obj(breakout_roundlcd_BreakoutRoundLCD_obj_t); - self->base.type = &breakout_roundlcd_BreakoutRoundLCD_type; - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - - self->breakout = new BreakoutRoundLCD((uint16_t *)bufinfo.buf, (BG_SPI_SLOT)slot); - } - else { - mp_raise_ValueError("slot not a valid value. Expected 0 to 1"); - } - } - else { - enum { ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_spi, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_cs, MP_ARG_INT, {.u_int = pimoroni::SPI_BG_FRONT_CS} }, - { MP_QSTR_dc, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_MISO} }, - { MP_QSTR_sck, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_SCK} }, - { MP_QSTR_mosi, MP_ARG_INT, {.u_int = pimoroni::SPI_DEFAULT_MOSI} }, - { MP_QSTR_bl, MP_ARG_INT, {.u_int = pimoroni::SPI_BG_FRONT_PWM} }, - }; - - // Parse args. - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - - // Get SPI bus. - int spi_id = args[ARG_spi].u_int; - int sck = args[ARG_sck].u_int; - int mosi = args[ARG_mosi].u_int; - - if(spi_id == -1) { - spi_id = (sck >> 3) & 0b1; // If no spi specified, choose the one for the given SCK pin - } - if(spi_id < 0 || spi_id > 1) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id); - } - - if(!IS_VALID_SCK(spi_id, sck)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin")); - } - - if(!IS_VALID_MOSI(spi_id, mosi)) { - mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin")); - } - - self = m_new_obj(breakout_roundlcd_BreakoutRoundLCD_obj_t); - self->base.type = &breakout_roundlcd_BreakoutRoundLCD_type; - - spi_inst_t *spi = (spi_id == 0) ? spi0 : spi1; - self->breakout = new BreakoutRoundLCD((uint16_t *)bufinfo.buf, spi, - args[ARG_cs].u_int, args[ARG_dc].u_int, sck, mosi, args[ARG_bl].u_int); - } - - self->breakout->init(); - - return MP_OBJ_FROM_PTR(self); -} - -/***** Methods *****/ -mp_obj_t BreakoutRoundLCD_update(mp_obj_t self_in) { - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_roundlcd_BreakoutRoundLCD_obj_t); - self->breakout->update(); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_brightness }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_brightness, MP_ARG_REQUIRED | MP_ARG_OBJ }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - float brightness = mp_obj_get_float(args[ARG_brightness].u_obj); - - if(brightness < 0 || brightness > 1.0f) - mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); - else - self->breakout->set_backlight((uint8_t)(brightness * 255.0f)); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - if(n_args <= 2) { - enum { ARG_self, ARG_pen }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int pen = args[ARG_pen].u_int; - - if(pen < 0 || pen > 0xffff) - mp_raise_ValueError("p is not a valid pen."); - else - self->breakout->set_pen(pen); - } - else { - enum { ARG_self, ARG_r, ARG_g, ARG_b }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int r = args[ARG_r].u_int; - int g = args[ARG_g].u_int; - int b = args[ARG_b].u_int; - - 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 - self->breakout->set_pen(r, g, b); - } - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - int pen = 0; - - enum { ARG_self, ARG_r, ARG_g, ARG_b }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int r = args[ARG_r].u_int; - int g = args[ARG_g].u_int; - int b = args[ARG_b].u_int; - - 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 - pen = self->breakout->create_pen(r, g, b); - - return mp_obj_new_int(pen); -} - -mp_obj_t BreakoutRoundLCD_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int w = args[ARG_w].u_int; - int h = args[ARG_h].u_int; - - Rect r(x, y, w, h); - self->breakout->set_clip(r); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_remove_clip(mp_obj_t self_in) { - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_roundlcd_BreakoutRoundLCD_obj_t); - self->breakout->remove_clip(); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_clear(mp_obj_t self_in) { - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_roundlcd_BreakoutRoundLCD_obj_t); - self->breakout->clear(); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - - Point p(x, y); - self->breakout->pixel(p); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y, ARG_l }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_l, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int l = args[ARG_l].u_int; - - Point p(x, y); - self->breakout->pixel_span(p, l); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int w = args[ARG_w].u_int; - int h = args[ARG_h].u_int; - - Rect r(x, y, w, h); - self->breakout->rectangle(r); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x, ARG_y, ARG_r }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int r = args[ARG_r].u_int; - - Point p(x, y); - self->breakout->circle(p, r); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_char, ARG_x, ARG_y, ARG_scale }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_char, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int c = mp_obj_get_int(args[ARG_char].u_obj); - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int scale = args[ARG_scale].u_int; - - self->breakout->character((char)c, Point(x, y), scale); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_wordwrap, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - mp_obj_t text_obj = args[ARG_text].u_obj; - if(mp_obj_is_str_or_bytes(text_obj)) { - GET_STR_DATA_LEN(text_obj, str, str_len); - - std::string t((const char*)str); - - int x = args[ARG_x].u_int; - int y = args[ARG_y].u_int; - int wrap = args[ARG_wrap].u_int; - int scale = args[ARG_scale].u_int; - - self->breakout->text(t, Point(x, y), wrap, scale); - } - else if(mp_obj_is_float(text_obj)) { - mp_raise_TypeError("can't convert 'float' object to str implicitly"); - } - else if(mp_obj_is_int(text_obj)) { - mp_raise_TypeError("can't convert 'int' object to str implicitly"); - } - else if(mp_obj_is_bool(text_obj)) { - mp_raise_TypeError("can't convert 'bool' object to str implicitly"); - } - else { - mp_raise_TypeError("can't convert object to str implicitly"); - } - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - mp_raise_NotImplementedError("polygon is not implemented. Please avoid using this function for now"); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_x3, ARG_y3 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x3, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y3, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int x1 = args[ARG_x1].u_int; - int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x2].u_int; - int y2 = args[ARG_y2].u_int; - int x3 = args[ARG_x3].u_int; - int y3 = args[ARG_y3].u_int; - - Point p1(x1, y1); - Point p2(x2, y2); - Point p3(x3, y3); - self->breakout->triangle(p1, p2, p3); - - return mp_const_none; -} - -mp_obj_t BreakoutRoundLCD_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - breakout_roundlcd_BreakoutRoundLCD_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_roundlcd_BreakoutRoundLCD_obj_t); - - int x1 = args[ARG_x1].u_int; - int y1 = args[ARG_y1].u_int; - int x2 = args[ARG_x2].u_int; - int y2 = args[ARG_y2].u_int; - - Point p1(x1, y1); - Point p2(x2, y2); - self->breakout->line(p1, p2); - - return mp_const_none; -} -} diff --git a/micropython/modules/breakout_roundlcd/breakout_roundlcd.h b/micropython/modules/breakout_roundlcd/breakout_roundlcd.h deleted file mode 100644 index 8a390d09..00000000 --- a/micropython/modules/breakout_roundlcd/breakout_roundlcd.h +++ /dev/null @@ -1,32 +0,0 @@ -// Include MicroPython API. -#include "py/runtime.h" -#include "py/objstr.h" - -/***** Constants *****/ -static const int WIDTH = 240; -static const int HEIGHT = 240; - - -/***** Extern of Class Definition *****/ -extern const mp_obj_type_t breakout_roundlcd_BreakoutRoundLCD_type; - -/***** Extern of Class Methods *****/ -extern void BreakoutRoundLCD_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); -extern mp_obj_t BreakoutRoundLCD_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 BreakoutRoundLCD_update(mp_obj_t self_in); -extern mp_obj_t BreakoutRoundLCD_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); - -extern mp_obj_t BreakoutRoundLCD_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_remove_clip(mp_obj_t self_in); -extern mp_obj_t BreakoutRoundLCD_clear(mp_obj_t self_in); -extern mp_obj_t BreakoutRoundLCD_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t BreakoutRoundLCD_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); \ No newline at end of file diff --git a/micropython/modules/breakout_roundlcd/micropython.cmake b/micropython/modules/breakout_roundlcd/micropython.cmake deleted file mode 100644 index aeb65d94..00000000 --- a/micropython/modules/breakout_roundlcd/micropython.cmake +++ /dev/null @@ -1,20 +0,0 @@ -set(MOD_NAME breakout_roundlcd) -string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) -add_library(usermod_${MOD_NAME} INTERFACE) - -target_sources(usermod_${MOD_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp -) - -target_include_directories(usermod_${MOD_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR} -) - -target_compile_definitions(usermod_${MOD_NAME} INTERFACE - -DMODULE_${MOD_NAME_UPPER}_ENABLED=1 -) - -target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) \ No newline at end of file diff --git a/micropython/modules/micropython-common.cmake b/micropython/modules/micropython-common.cmake index fe32f7d8..949a3133 100644 --- a/micropython/modules/micropython-common.cmake +++ b/micropython/modules/micropython-common.cmake @@ -5,7 +5,6 @@ include(breakout_dotmatrix/micropython) include(breakout_encoder/micropython) include(breakout_ioexpander/micropython) include(breakout_ltr559/micropython) -include(breakout_colourlcd160x80/micropython) include(breakout_as7262/micropython) include(breakout_rgbmatrix5x5/micropython) include(breakout_matrix11x7/micropython) @@ -42,7 +41,7 @@ include(qrcode/micropython/micropython) include(adcfft/micropython) include(pcf85063a/micropython) -include(st7789/micropython) +include(picographics/micropython) include(jpegdec/micropython) include(modules_py/modules_py) diff --git a/micropython/modules/pico_display/README.md b/micropython/modules/pico_display/README.md deleted file mode 100644 index ba25cc6f..00000000 --- a/micropython/modules/pico_display/README.md +++ /dev/null @@ -1,211 +0,0 @@ -# Pico Display Pack - MicroPython - -Pico Display Pack is a vibrant 1.14", 240 x 135 pixel IPS LCD screen for your Raspberry Pi Pico, with four useful buttons and a RGB LED. [Buy one here!](https://shop.pimoroni.com/products/pico-display-pack) - -We've included helper functions to handle every aspect of drawing to the screen and interfacing with the buttons and LED. See the [function reference](#function-reference) for details. Scroll down to the bottom for links to more resources! - -- [Example Program](#example-program) -- [Function Reference](#function-reference) - - [init](#init) - - [set_backlight](#set_backlight) - - [set_led](#set_led) - - [is_pressed](#is_pressed) - - [update](#update) - - [set_pen](#set_pen) - - [create_pen](#create_pen) - - [clear](#clear) - - [pixel](#pixel) - - [pixel_span](#pixel_span) - - [rectangle](#rectangle) - - [circle](#circle) - - [character](#character) - - [text](#text) - - [set_clip](#set_clip) - - [remove_clip](#remove_clip) - - [More Resources](#more-resources) - -## Example Program - -The following example sets up Pico Display, displays some basic demo text and illuminates the RGB LED green when the A button is pressed. - -```python -import utime -import picodisplay - -# Initialise Picodisplay with a bytearray display buffer -buf = bytearray(picodisplay.get_width() * picodisplay.get_height() * 2) -picodisplay.init(buf) -picodisplay.set_backlight(1.0) - -picodisplay.set_pen(255, 0, 0) # Set a red pen -picodisplay.clear() # Clear the display buffer -picodisplay.set_pen(255, 255, 255) # Set a white pen -picodisplay.text("pico display", 10, 10, 240, 6) # Add some text -picodisplay.update() # Update the display with our changes - -picodisplay.set_led(255, 0, 0) # Set the RGB LED to red -utime.sleep(1) # Wait for a second -picodisplay.set_led(0, 255, 0) # Set the RGB LED to green -utime.sleep(1) # Wait for a second -picodisplay.set_led(0, 0, 255) # Set the RGB LED to blue - -while picodisplay.is_pressed(picodisplay.BUTTON_A) == False: - pass - -picodisplay.set_led(0, 255, 0) # Set the RGB LED to green -``` - -## Function Reference - -### init - -Sets up Pico Display. `init` must be called before any other functions since it configures the required PWM and GPIO. `init()` needs a bytearray type display buffer that MicroPython's garbage collection isn't going to eat, make sure you create one and pass it in like so: - -```python -buf = bytearray(picodisplay.get_width() * picodisplay.get_height() * 2) -picodisplay.init(buf) -``` - -### set_backlight - -Sets the display backlight from 0.0 to 1.0. - -```python -picodisplay.set_backlight(brightness) -``` - -Uses hardware PWM to dim the display backlight, dimming values are gamma-corrected to provide smooth brightness transitions across the full range of intensity. This may result in some low values mapping as "off." - -### set_led - -Sets the RGB LED on Pico Display with an RGB triplet. - -```python -picodisplay.set_led(r, g, b) -``` - -Uses hardware PWM to drive the LED. Values are automatically gamma-corrected to provide smooth brightness transitions and low values may map as "off." - -### is_pressed - -Reads the GPIO pin connected to one of Pico Display's buttons, returning `True` if it's pressed and `False` if it is released. - -```python -picodisplay.is_pressed(button) -``` - -The button value should be a number denoting a pin, and constants `picodisplay.BUTTON_A`, `picodisplay.BUTTON_B`, `picodisplay.BUTTON_X` and `picodisplay.BUTTON_Y` are supplied to make it easier. e: - -```python -is_a_button_pressed = picodisplay.is_pressed(picodisplay.BUTTON_A) -``` - -### update - -To display your changes on Pico Display's screen you need to call `update`. - -```python -picodisplay.update() -``` - -### set_pen - -Sets the colour to be used by subsequent calls to drawing functions. The values for `r`, `g` and `b` should be from 0-255 inclusive. - -```python -picodisplay.set_pen(r, g, b) -``` - -### create_pen - -Creates a pen which can be stored as a variable for faster re-use of the same colour through calls to `set_pen`. The values for `r`, `g` and `b` should be from 0-255 inclusive. - -```python -pen_colour = picodisplay.create_pen(r, g, b) -picodisplay.set_pen(penColour) -``` - -### clear - -Fills the display buffer with the currently set pen colour. - -```python -picodisplay.clear() -``` - -### pixel - -Sets a single pixel in the display buffer to the current pen colour. The `x` and `y` parameters determine the X and Y coordinates of the drawn pixel in the buffer. - -```python -picodisplay.pixel(x, y) -``` - -### pixel_span - -Draws a horizontal line of pixels to the buffer. The `x` and `y` parameters specify the coordinates of the first pixel of the line. The `l` parameter describes the length of the line in pixels. This function will only extend the line towards the end of the screen, i.e. the `x` coordinate should specify the left hand extreme of the line. - -```python -picodisplay.pixel_span(x, y, l) -``` - -### rectangle - -Draws a rectangle filled with the current pen colour to the buffer. The `x` and `y` parameters specify the upper left corner of the rectangle, `w` specifies the width in pixels, and `h` the height. - -```python -picodisplay.rectangle(x, y, w, h) -``` - -![Rectangle function explanation image](/micropython/modules/pico_display/images/rectangle.png) - -### circle - -Draws a circle filled with the current pen colour to the buffer. The `x` and `y` parameters specify the centre of the circle, `r` specifies the radius in pixels. - -```python -picodisplay.circle(x, y, r) -``` - -![Circle function explanation image](/micropython/modules/pico_display/images/circle.png) - -### character - -Draws a single character to the display buffer in the current pen colour. The `c` parameter should be the ASCII numerical representation of the character to be printed, `x` and `y` describe the top-left corner of the character's drawing field. The `character` function can also be given an optional 4th parameter, `scale`, describing the scale of the character to be drawn. Default value is 2. - -```python -char_a = ord('a') -picodisplay.character(char_a, x, y) -picodisplay.character(char_a, x, y, scale) -``` - -### text - -Draws a string of text to the display buffer in the current pen colour. The `string` parameter is the string of text to be drawn, and `x` and `y` specify the upper left corner of the drawing field. The `wrap` parameter describes the width, in pixels, after which the next word in the string will be drawn on a new line underneath the current text. This will wrap the string over multiple lines if required. This function also has an optional parameter, `scale`, which describes the size of the characters to be drawn. The default `scale` is 2. - -```python -picodisplay.text(string, x, y, wrap) -picodisplay.text(string, x, y, wrap, scale) -``` - -![Text scale explanation image](/micropython/modules/pico_display/images/text_scale.png) - -### set_clip - -This function defines a rectangular area outside which no drawing actions will take effect. If a drawing action crosses the boundary of the clip then only the pixels inside the clip will be drawn. Note that `clip` does not remove pixels which have already been drawn, it only prevents new pixels being drawn outside the described area. A more visual description of the function of clips can be found below. Only one clip can be active at a time, and defining a new clip replaces any previous clips. The `x` and `y` parameters describe the upper-left corner of the clip area, `w` and `h` describe the width and height in pixels. - -```python -picodisplay.set_clip(x, y, w, h) -``` - -![Clip function explanation image](/micropython/modules/pico_display/images/clip.png) - -### remove_clip - -This function removes any currently implemented clip. - -## More Resources - -- [Display Pack Guide by UnfinishedStuff](https://github.com/UnfinishedStuff/Pimoroni_Pico_Display_Pack_documentation) - more detail on functions and code examples -- [Display Pack Workout by tonygo2](https://www.instructables.com/Pimoroni-Pico-Display-Workout/) - a comprehensive demo -- [picofont by Les Wright](https://github.com/leswright1977/picofont) - implementing custom fonts using pure MicroPython diff --git a/micropython/modules/pico_display/images/circle.png b/micropython/modules/pico_display/images/circle.png deleted file mode 100644 index 4efadd9cd87a6b82c01fdbc653e95e405bce6974..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5200 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 diff --git a/micropython/modules/pico_display/images/rectangle.png b/micropython/modules/pico_display/images/rectangle.png deleted file mode 100644 index 4e0c3467565964aa03a06bc76cc7eea23fa43ff5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4814 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 DFnxLN diff --git a/micropython/modules/pico_display/images/text_scale.png b/micropython/modules/pico_display/images/text_scale.png deleted file mode 100644 index 1f029ed2c0258c7d36abc78a28b670ac92b2c4b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6698 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 diff --git a/micropython/modules/pico_display/micropython.cmake b/micropython/modules/pico_display/micropython.cmake deleted file mode 100644 index 5735edeb..00000000 --- a/micropython/modules/pico_display/micropython.cmake +++ /dev/null @@ -1,26 +0,0 @@ -add_library(usermod_pico_display INTERFACE) - -target_sources(usermod_pico_display INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/pico_display.c - ${CMAKE_CURRENT_LIST_DIR}/pico_display.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_display/pico_display.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp -) - -target_include_directories(usermod_pico_display INTERFACE - ${CMAKE_CURRENT_LIST_DIR} -) - -target_compile_definitions(usermod_pico_display INTERFACE - MODULE_PICODISPLAY_ENABLED=1 -) - -target_link_libraries(usermod INTERFACE usermod_pico_display) - -set_source_files_properties( - ${CMAKE_CURRENT_LIST_DIR}/pico_display.c - PROPERTIES COMPILE_FLAGS - "-Wno-discarded-qualifiers -Wno-implicit-int" -) diff --git a/micropython/modules/pico_display/pico_display.c b/micropython/modules/pico_display/pico_display.c deleted file mode 100755 index ee0f70c6..00000000 --- a/micropython/modules/pico_display/pico_display.c +++ /dev/null @@ -1,74 +0,0 @@ -#include "pico_display.h" - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// picodisplay Module -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Module Functions *****/ -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay_init_obj, picodisplay_init); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_get_width_obj, picodisplay_get_width); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_get_height_obj, picodisplay_get_height); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_update_obj, picodisplay_update); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay_set_backlight_obj, picodisplay_set_backlight); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay_set_led_obj, picodisplay_set_led); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay_is_pressed_obj, picodisplay_is_pressed); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_flip_obj, picodisplay_flip); - -//From PicoGraphics parent class -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_set_pen_obj, 1, 3, picodisplay_set_pen); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay_create_pen_obj, picodisplay_create_pen); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_set_clip_obj, 4, 4, picodisplay_set_clip); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_remove_clip_obj, picodisplay_remove_clip); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_clear_obj, picodisplay_clear); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(picodisplay_pixel_obj, picodisplay_pixel); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay_pixel_span_obj, picodisplay_pixel_span); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_rectangle_obj, 4, 4, picodisplay_rectangle); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay_circle_obj, picodisplay_circle); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_character_obj, 3, 4, picodisplay_character); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_text_obj, 4, 5, picodisplay_text); - - -/***** Globals Table *****/ -STATIC const mp_map_elem_t picodisplay_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picodisplay) }, - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picodisplay_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picodisplay_get_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picodisplay_get_height_obj) }, - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picodisplay_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&picodisplay_set_backlight_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&picodisplay_set_led_obj) }, - { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picodisplay_is_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_flip), MP_ROM_PTR(&picodisplay_flip_obj) }, - - { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&picodisplay_set_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&picodisplay_create_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&picodisplay_set_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&picodisplay_remove_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picodisplay_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&picodisplay_pixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&picodisplay_pixel_span_obj) }, - { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&picodisplay_rectangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&picodisplay_circle_obj) }, - { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&picodisplay_character_obj) }, - { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&picodisplay_text_obj) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(12) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(13) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(14) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(15) }, - { MP_ROM_QSTR(MP_QSTR_LED_R), MP_ROM_INT(6) }, - { MP_ROM_QSTR(MP_QSTR_LED_G), MP_ROM_INT(7) }, - { MP_ROM_QSTR(MP_QSTR_LED_B), MP_ROM_INT(8) }, -}; -STATIC MP_DEFINE_CONST_DICT(mp_module_picodisplay_globals, picodisplay_globals_table); - -/***** Module Definition *****/ -const mp_obj_module_t picodisplay_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_picodisplay_globals, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -MP_REGISTER_MODULE(MP_QSTR_picodisplay, picodisplay_user_cmodule, MODULE_PICODISPLAY_ENABLED); -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/micropython/modules/pico_display/pico_display.cpp b/micropython/modules/pico_display/pico_display.cpp deleted file mode 100644 index 985ba4a4..00000000 --- a/micropython/modules/pico_display/pico_display.cpp +++ /dev/null @@ -1,323 +0,0 @@ -#include "hardware/spi.h" -#include "hardware/sync.h" -#include "pico/binary_info.h" - -#include "libraries/pico_display/pico_display.hpp"zzz - -using namespace pimoroni; - -PicoDisplay *display = nullptr; - - -extern "C" { -#include "pico_display.h" - -#define NOT_INITIALISED_MSG "Cannot call this function, as picodisplay is not initialised. Call picodisplay.init() first." - -mp_obj_t picodisplay_buf_obj; - -mp_obj_t picodisplay_init(mp_obj_t buf_obj) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_obj, &bufinfo, MP_BUFFER_RW); - picodisplay_buf_obj = buf_obj; - - // If a display already exists, delete it - if(display != nullptr) { - delete display; - } - - // Create a new display pointing to the newly provided buffer - display = new PicoDisplay(bufinfo.buf); - display->init(); - - return mp_const_none; -} - -mp_obj_t picodisplay_get_width() { - return mp_obj_new_int(PicoDisplay::WIDTH); -} - -mp_obj_t picodisplay_get_height() { - return mp_obj_new_int(PicoDisplay::HEIGHT); -} - -mp_obj_t picodisplay_update() { - if(display != nullptr) - display->update(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_flip() { - if(display != nullptr) - display->flip(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_set_backlight(mp_obj_t brightness_obj) { - if(display != nullptr) { - 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"); - else - display->set_backlight((uint8_t)(brightness * 255.0f)); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) { - if(display != nullptr) { - int r = mp_obj_get_int(r_obj); - int g = mp_obj_get_int(g_obj); - int b = mp_obj_get_int(b_obj); - - 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 - display->set_led(r, g, b); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_is_pressed(mp_obj_t button_obj) { - if(display != nullptr) { - return display->is_pressed(mp_obj_get_int(button_obj)) ? mp_const_true : mp_const_false; - } - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - return mp_const_none; -} - -mp_obj_t picodisplay_set_pen(mp_uint_t n_args, const mp_obj_t *args) { - if(display != nullptr) { - switch(n_args) { - case 1: { - int p = mp_obj_get_int(args[0]); - - if(p < 0 || p > 0xffff) - mp_raise_ValueError("p is not a valid pen."); - else - display->set_pen(p); - } break; - - case 3: { - int r = mp_obj_get_int(args[0]); - int g = mp_obj_get_int(args[1]); - int b = mp_obj_get_int(args[2]); - - 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 - display->set_pen(r, g, b); - } break; - - default: { - char *buffer; - buffer = (char*)malloc(100); - sprintf(buffer, "function takes 1 or 3 (r,g,b) positional arguments but %d were given", n_args); - mp_raise_TypeError(buffer); - } break; - } - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) { - int pen = 0; - - if(display != nullptr) { - int r = mp_obj_get_int(r_obj); - int g = mp_obj_get_int(g_obj); - int b = mp_obj_get_int(b_obj); - - 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 - pen = display->create_pen(r, g, b); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_obj_new_int(pen); -} - -mp_obj_t picodisplay_set_clip(mp_uint_t n_args, const mp_obj_t *args) { - (void)n_args; //Unused input parameter, we know it's 4 - - if(display != nullptr) { - int x = mp_obj_get_int(args[0]); - int y = mp_obj_get_int(args[1]); - int w = mp_obj_get_int(args[2]); - int h = mp_obj_get_int(args[3]); - - Rect r(x, y, w, h); - display->set_clip(r); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_remove_clip() { - if(display != nullptr) - display->remove_clip(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_clear() { - if(display != nullptr) - display->clear(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_pixel(mp_obj_t x_obj, mp_obj_t y_obj) { - if(display != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - - Point p(x, y); - display->pixel(p); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj) { - if(display != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - int l = mp_obj_get_int(l_obj); - - Point p(x, y); - display->pixel_span(p, l); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_rectangle(mp_uint_t n_args, const mp_obj_t *args) { - (void)n_args; //Unused input parameter, we know it's 4 - - if(display != nullptr) { - int x = mp_obj_get_int(args[0]); - int y = mp_obj_get_int(args[1]); - int w = mp_obj_get_int(args[2]); - int h = mp_obj_get_int(args[3]); - - Rect r(x, y, w, h); - display->rectangle(r); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj) { - if(display != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - int r = mp_obj_get_int(r_obj); - - Point p(x, y); - display->circle(p, r); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay_character(mp_uint_t n_args, const mp_obj_t *args) { - if(display != nullptr) { - int c = mp_obj_get_int(args[0]); - int x = mp_obj_get_int(args[1]); - int y = mp_obj_get_int(args[2]); - - Point p(x, y); - if(n_args == 4) { - int scale = mp_obj_get_int(args[3]); - display->character((char)c, p, scale); - } - else - display->character((char)c, p); - } - - return mp_const_none; -} - -mp_obj_t picodisplay_text(mp_uint_t n_args, const mp_obj_t *args) { - if(display != nullptr) { - if(mp_obj_is_str_or_bytes(args[0])) { - GET_STR_DATA_LEN(args[0], str, str_len); - - std::string t((const char*)str); - - int x = mp_obj_get_int(args[1]); - int y = mp_obj_get_int(args[2]); - int wrap = mp_obj_get_int(args[3]); - - Point p(x, y); - if(n_args == 5) { - int scale = mp_obj_get_int(args[4]); - display->text(t, p, wrap, scale); - } - else - display->text(t, p, wrap); - } - else if(mp_obj_is_float(args[0])) { - mp_raise_TypeError("can't convert 'float' object to str implicitly"); - } - else if(mp_obj_is_int(args[0])) { - mp_raise_TypeError("can't convert 'int' object to str implicitly"); - } - else if(mp_obj_is_bool(args[0])) { - mp_raise_TypeError("can't convert 'bool' object to str implicitly"); - } - else { - mp_raise_TypeError("can't convert object to str implicitly"); - } - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} -} diff --git a/micropython/modules/pico_display/pico_display.h b/micropython/modules/pico_display/pico_display.h deleted file mode 100644 index 1234e434..00000000 --- a/micropython/modules/pico_display/pico_display.h +++ /dev/null @@ -1,26 +0,0 @@ -// Include MicroPython API. -#include "py/runtime.h" -#include "py/objstr.h" - -// Declare the functions we'll make available in Python -extern mp_obj_t picodisplay_init(mp_obj_t buf_obj); -extern mp_obj_t picodisplay_get_width(); -extern mp_obj_t picodisplay_get_height(); -extern mp_obj_t picodisplay_set_backlight(mp_obj_t brightness_obj); -extern mp_obj_t picodisplay_update(); -extern mp_obj_t picodisplay_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj); -extern mp_obj_t picodisplay_is_pressed(mp_obj_t button_obj); -extern mp_obj_t picodisplay_flip(); - -// From PicoGraphics parent class -extern mp_obj_t picodisplay_set_pen(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picodisplay_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj); -extern mp_obj_t picodisplay_set_clip(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picodisplay_remove_clip(); -extern mp_obj_t picodisplay_clear(); -extern mp_obj_t picodisplay_pixel(mp_obj_t x_obj, mp_obj_t y_obj); -extern mp_obj_t picodisplay_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj); -extern mp_obj_t picodisplay_rectangle(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picodisplay_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj); -extern mp_obj_t picodisplay_character(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picodisplay_text(mp_uint_t n_args, const mp_obj_t *args); diff --git a/micropython/modules/pico_display_2/README.md b/micropython/modules/pico_display_2/README.md deleted file mode 100644 index ccf580c4..00000000 --- a/micropython/modules/pico_display_2/README.md +++ /dev/null @@ -1,206 +0,0 @@ -# Pico Display Pack - MicroPython - -Pico Display 2.0" Pack is a vibrant 2.0", 320 x 240 pixel IPS LCD screen for your Raspberry Pi Pico, with four useful buttons and a RGB LED. [Click here](https://shop.pimoroni.com/products/pico-display-pack) to find out more! - -We've included helper functions to handle every aspect of drawing to the screen and interfacing with the buttons and LED. See the [function reference](#function-reference) for details. - -Check out [UnfinishedStuff's excellent Display Pack guide](https://github.com/UnfinishedStuff/Pimoroni_Pico_Display_Pack_documentation) for more detail on the functions and code examples, and [tonygo2's Display Pack Workout](https://www.instructables.com/Pimoroni-Pico-Display-Workout/) for a comprehensive demo! - -- [Example Program](#example-program) -- [Function Reference](#function-reference) - - [init](#init) - - [set_backlight](#set_backlight) - - [set_led](#set_led) - - [is_pressed](#is_pressed) - - [update](#update) - - [set_pen](#set_pen) - - [create_pen](#create_pen) - - [clear](#clear) - - [pixel](#pixel) - - [pixel_span](#pixel_span) - - [rectangle](#rectangle) - - [circle](#circle) - - [character](#character) - - [text](#text) - - [set_clip](#set_clip) - - [remove_clip](#remove_clip) - -## Example Program - -The following example sets up Pico Display, displays some basic demo text and illuminates the RGB LED green when the A button is pressed. - -```python -import utime -import picodisplay2 as picodisplay - -# Initialise Picodisplay with a bytearray display buffer -buf = bytearray(picodisplay.get_width() * picodisplay.get_height() * 2) -picodisplay.init(buf) -picodisplay.set_backlight(1.0) - -picodisplay.set_pen(255, 0, 0) # Set a red pen -picodisplay.clear() # Clear the display buffer -picodisplay.set_pen(255, 255, 255) # Set a white pen -picodisplay.text("pico display", 10, 10, 240, 6) # Add some text -picodisplay.update() # Update the display with our changes - -picodisplay.set_led(255, 0, 0) # Set the RGB LED to red -utime.sleep(1) # Wait for a second -picodisplay.set_led(0, 255, 0) # Set the RGB LED to green -utime.sleep(1) # Wait for a second -picodisplay.set_led(0, 0, 255) # Set the RGB LED to blue - -while picodisplay.is_pressed(picodisplay.BUTTON_A) == False: - pass - -picodisplay.set_led(0, 255, 0) # Set the RGB LED to green -``` - -## Function Reference - -### init - -Sets up Pico Display. `init` must be called before any other functions since it configures the required PWM and GPIO. `init()` needs a bytearray type display buffer that MicroPython's garbage collection isn't going to eat, make sure you create one and pass it in like so: - -```python -buf = bytearray(picodisplay.get_width() * picodisplay.get_height() * 2) -picodisplay.init(buf) -``` - -### set_backlight - -Sets the display backlight from 0.0 to 1.0. - -```python -picodisplay.set_backlight(brightness) -``` - -Uses hardware PWM to dim the display backlight, dimming values are gamma-corrected to provide smooth brightness transitions across the full range of intensity. This may result in some low values mapping as "off." - -### set_led - -Sets the RGB LED on Pico Display with an RGB triplet. - -```python -picodisplay.set_led(r, g, b) -``` - -Uses hardware PWM to drive the LED. Values are automatically gamma-corrected to provide smooth brightness transitions and low values may map as "off." - -### is_pressed - -Reads the GPIO pin connected to one of Pico Display's buttons, returning `True` if it's pressed and `False` if it is released. - -```python -picodisplay.is_pressed(button) -``` - -The button value should be a number denoting a pin, and constants `picodisplay.BUTTON_A`, `picodisplay.BUTTON_B`, `picodisplay.BUTTON_X` and `picodisplay.BUTTON_Y` are supplied to make it easier. e: - -```python -is_a_button_pressed = picodisplay.is_pressed(picodisplay.BUTTON_A) -``` - -### update - -To display your changes on Pico Display's screen you need to call `update`. - -```python -picodisplay.update() -``` - -### set_pen - -Sets the colour to be used by subsequent calls to drawing functions. The values for `r`, `g` and `b` should be from 0-255 inclusive. - -```python -picodisplay.set_pen(r, g, b) -``` - -### create_pen - -Creates a pen which can be stored as a variable for faster re-use of the same colour through calls to `set_pen`. The values for `r`, `g` and `b` should be from 0-255 inclusive. - -```python -pen_colour = picodisplay.create_pen(r, g, b) -picodisplay.set_pen(penColour) -``` - -### clear - -Fills the display buffer with the currently set pen colour. - -```python -picodisplay.clear() -``` - -### pixel - -Sets a single pixel in the display buffer to the current pen colour. The `x` and `y` parameters determine the X and Y coordinates of the drawn pixel in the buffer. - -```python -picodisplay.pixel(x, y) -``` - -### pixel_span - -Draws a horizontal line of pixels to the buffer. The `x` and `y` parameters specify the coordinates of the first pixel of the line. The `l` parameter describes the length of the line in pixels. This function will only extend the line towards the end of the screen, i.e. the `x` coordinate should specify the left hand extreme of the line. - -```python -picodisplay.pixel_span(x, y, l) -``` - -### rectangle - -Draws a rectangle filled with the current pen colour to the buffer. The `x` and `y` parameters specify the upper left corner of the rectangle, `w` specifies the width in pixels, and `h` the height. - -```python -picodisplay.rectangle(x, y, w, h) -``` - -![Rectangle function explanation image](/micropython/modules/pico_display/images/rectangle.png) - -### circle - -Draws a circle filled with the current pen colour to the buffer. The `x` and `y` parameters specify the centre of the circle, `r` specifies the radius in pixels. - -```python -picodisplay.circle(x, y, r) -``` - -![Circle function explanation image](/micropython/modules/pico_display/images/circle.png) - -### character - -Draws a single character to the display buffer in the current pen colour. The `c` parameter should be the ASCII numerical representation of the character to be printed, `x` and `y` describe the top-left corner of the character's drawing field. The `character` function can also be given an optional 4th parameter, `scale`, describing the scale of the character to be drawn. Default value is 2. - -```python -char_a = ord('a') -picodisplay.character(char_a, x, y) -picodisplay.character(char_a, x, y, scale) -``` - -### text - -Draws a string of text to the display buffer in the current pen colour. The `string` parameter is the string of text to be drawn, and `x` and `y` specify the upper left corner of the drawing field. The `wrap` parameter describes the width, in pixels, after which the next word in the string will be drawn on a new line underneath the current text. This will wrap the string over multiple lines if required. This function also has an optional parameter, `scale`, which describes the size of the characters to be drawn. The default `scale` is 2. - -```python -picodisplay.text(string, x, y, wrap) -picodisplay.text(string, x, y, wrap, scale) -``` - -![Text scale explanation image](/micropython/modules/pico_display/images/text_scale.png) - -### set_clip - -This function defines a rectangular area outside which no drawing actions will take effect. If a drawing action crosses the boundary of the clip then only the pixels inside the clip will be drawn. Note that `clip` does not remove pixels which have already been drawn, it only prevents new pixels being drawn outside the described area. A more visual description of the function of clips can be found below. Only one clip can be active at a time, and defining a new clip replaces any previous clips. The `x` and `y` parameters describe the upper-left corner of the clip area, `w` and `h` describe the width and height in pixels. - -```python -picodisplay.set_clip(x, y, w, h) -``` - -![Clip function explanation image](/micropython/modules/pico_display/images/clip.png) - -### remove_clip - -This function removes any currently implemented clip. diff --git a/micropython/modules/pico_display_2/images/circle.png b/micropython/modules/pico_display_2/images/circle.png deleted file mode 100644 index 4efadd9cd87a6b82c01fdbc653e95e405bce6974..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5200 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 diff --git a/micropython/modules/pico_display_2/images/rectangle.png b/micropython/modules/pico_display_2/images/rectangle.png deleted file mode 100644 index 4e0c3467565964aa03a06bc76cc7eea23fa43ff5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4814 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 DFnxLN diff --git a/micropython/modules/pico_display_2/images/text_scale.png b/micropython/modules/pico_display_2/images/text_scale.png deleted file mode 100644 index 1f029ed2c0258c7d36abc78a28b670ac92b2c4b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6698 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 diff --git a/micropython/modules/pico_display_2/micropython.cmake b/micropython/modules/pico_display_2/micropython.cmake deleted file mode 100644 index bb710909..00000000 --- a/micropython/modules/pico_display_2/micropython.cmake +++ /dev/null @@ -1,28 +0,0 @@ -set(MOD_NAME pico_display_2) -string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) -add_library(usermod_${MOD_NAME} INTERFACE) - -target_sources(usermod_${MOD_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp -) - -target_include_directories(usermod_${MOD_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR} -) - -target_compile_definitions(usermod_${MOD_NAME} INTERFACE - MODULE_${MOD_NAME_UPPER}_ENABLED=1 -) - -target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) - -set_source_files_properties( - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c - PROPERTIES COMPILE_FLAGS - "-Wno-discarded-qualifiers -Wno-implicit-int" -) diff --git a/micropython/modules/pico_display_2/pico_display_2.c b/micropython/modules/pico_display_2/pico_display_2.c deleted file mode 100755 index f0ca3fe7..00000000 --- a/micropython/modules/pico_display_2/pico_display_2.c +++ /dev/null @@ -1,74 +0,0 @@ -#include "pico_display_2.h" - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// picodisplay2 Module -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Module Functions *****/ -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay2_init_obj, picodisplay2_init); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_get_width_obj, picodisplay2_get_width); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_get_height_obj, picodisplay2_get_height); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_update_obj, picodisplay2_update); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay2_set_backlight_obj, picodisplay2_set_backlight); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay2_set_led_obj, picodisplay2_set_led); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay2_is_pressed_obj, picodisplay2_is_pressed); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_flip_obj, picodisplay2_flip); - -//From PicoGraphics parent class -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_set_pen_obj, 1, 3, picodisplay2_set_pen); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay2_create_pen_obj, picodisplay2_create_pen); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_set_clip_obj, 4, 4, picodisplay2_set_clip); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_remove_clip_obj, picodisplay2_remove_clip); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_clear_obj, picodisplay2_clear); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(picodisplay2_pixel_obj, picodisplay2_pixel); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay2_pixel_span_obj, picodisplay2_pixel_span); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_rectangle_obj, 4, 4, picodisplay2_rectangle); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay2_circle_obj, picodisplay2_circle); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_character_obj, 3, 4, picodisplay2_character); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_text_obj, 4, 5, picodisplay2_text); - - -/***** Globals Table *****/ -STATIC const mp_map_elem_t picodisplay2_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picodisplay2) }, - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picodisplay2_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picodisplay2_get_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picodisplay2_get_height_obj) }, - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picodisplay2_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&picodisplay2_set_backlight_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&picodisplay2_set_led_obj) }, - { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picodisplay2_is_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_flip), MP_ROM_PTR(&picodisplay2_flip_obj) }, - - { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&picodisplay2_set_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&picodisplay2_create_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&picodisplay2_set_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&picodisplay2_remove_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picodisplay2_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&picodisplay2_pixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&picodisplay2_pixel_span_obj) }, - { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&picodisplay2_rectangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&picodisplay2_circle_obj) }, - { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&picodisplay2_character_obj) }, - { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&picodisplay2_text_obj) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(12) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(13) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(14) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(15) }, - { MP_ROM_QSTR(MP_QSTR_LED_R), MP_ROM_INT(6) }, - { MP_ROM_QSTR(MP_QSTR_LED_G), MP_ROM_INT(7) }, - { MP_ROM_QSTR(MP_QSTR_LED_B), MP_ROM_INT(8) }, -}; -STATIC MP_DEFINE_CONST_DICT(mp_module_picodisplay2_globals, picodisplay2_globals_table); - -/***** Module Definition *****/ -const mp_obj_module_t picodisplay2_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_picodisplay2_globals, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -MP_REGISTER_MODULE(MP_QSTR_picodisplay2, picodisplay2_user_cmodule, MODULE_PICO_DISPLAY_2_ENABLED); -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/micropython/modules/pico_display_2/pico_display_2.cpp b/micropython/modules/pico_display_2/pico_display_2.cpp deleted file mode 100644 index 831407f4..00000000 --- a/micropython/modules/pico_display_2/pico_display_2.cpp +++ /dev/null @@ -1,323 +0,0 @@ -#include "hardware/spi.h" -#include "hardware/sync.h" -#include "pico/binary_info.h" - -#include "libraries/pico_display_2/pico_display_2.hpp" - -using namespace pimoroni; - -PicoDisplay2 *display2 = nullptr; - - -extern "C" { -#include "pico_display_2.h" - -#define NOT_INITIALISED_MSG "Cannot call this function, as picodisplay2 is not initialised. Call picodisplay2.init() first." - -mp_obj_t picodisplay2_buf_obj; - -mp_obj_t picodisplay2_init(mp_obj_t buf_obj) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_obj, &bufinfo, MP_BUFFER_RW); - picodisplay2_buf_obj = buf_obj; - - // If a display already exists, delete it - if(display2 != nullptr) { - delete display2; - } - - // Create a new display pointing to the newly provided buffer - display2 = new PicoDisplay2(bufinfo.buf); - display2->init(); - - return mp_const_none; -} - -mp_obj_t picodisplay2_get_width() { - return mp_obj_new_int(PicoDisplay2::WIDTH); -} - -mp_obj_t picodisplay2_get_height() { - return mp_obj_new_int(PicoDisplay2::HEIGHT); -} - -mp_obj_t picodisplay2_update() { - if(display2 != nullptr) - display2->update(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_flip() { - if(display2 != nullptr) - display2->flip(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_set_backlight(mp_obj_t brightness_obj) { - if(display2 != nullptr) { - 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"); - else - display2->set_backlight((uint8_t)(brightness * 255.0f)); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) { - if(display2 != nullptr) { - int r = mp_obj_get_int(r_obj); - int g = mp_obj_get_int(g_obj); - int b = mp_obj_get_int(b_obj); - - 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 - display2->set_led(r, g, b); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_is_pressed(mp_obj_t button_obj) { - if(display2 != nullptr) { - return display2->is_pressed(mp_obj_get_int(button_obj)) ? mp_const_true : mp_const_false; - } - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - return mp_const_none; -} - -mp_obj_t picodisplay2_set_pen(mp_uint_t n_args, const mp_obj_t *args) { - if(display2 != nullptr) { - switch(n_args) { - case 1: { - int p = mp_obj_get_int(args[0]); - - if(p < 0 || p > 0xffff) - mp_raise_ValueError("p is not a valid pen."); - else - display2->set_pen(p); - } break; - - case 3: { - int r = mp_obj_get_int(args[0]); - int g = mp_obj_get_int(args[1]); - int b = mp_obj_get_int(args[2]); - - 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 - display2->set_pen(r, g, b); - } break; - - default: { - char *buffer; - buffer = (char*)malloc(100); - sprintf(buffer, "function takes 1 or 3 (r,g,b) positional arguments but %d were given", n_args); - mp_raise_TypeError(buffer); - } break; - } - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) { - int pen = 0; - - if(display2 != nullptr) { - int r = mp_obj_get_int(r_obj); - int g = mp_obj_get_int(g_obj); - int b = mp_obj_get_int(b_obj); - - 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 - pen = display2->create_pen(r, g, b); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_obj_new_int(pen); -} - -mp_obj_t picodisplay2_set_clip(mp_uint_t n_args, const mp_obj_t *args) { - (void)n_args; //Unused input parameter, we know it's 4 - - if(display2 != nullptr) { - int x = mp_obj_get_int(args[0]); - int y = mp_obj_get_int(args[1]); - int w = mp_obj_get_int(args[2]); - int h = mp_obj_get_int(args[3]); - - Rect r(x, y, w, h); - display2->set_clip(r); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_remove_clip() { - if(display2 != nullptr) - display2->remove_clip(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_clear() { - if(display2 != nullptr) - display2->clear(); - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_pixel(mp_obj_t x_obj, mp_obj_t y_obj) { - if(display2 != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - - Point p(x, y); - display2->pixel(p); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj) { - if(display2 != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - int l = mp_obj_get_int(l_obj); - - Point p(x, y); - display2->pixel_span(p, l); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_rectangle(mp_uint_t n_args, const mp_obj_t *args) { - (void)n_args; //Unused input parameter, we know it's 4 - - if(display2 != nullptr) { - int x = mp_obj_get_int(args[0]); - int y = mp_obj_get_int(args[1]); - int w = mp_obj_get_int(args[2]); - int h = mp_obj_get_int(args[3]); - - Rect r(x, y, w, h); - display2->rectangle(r); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj) { - if(display2 != nullptr) { - int x = mp_obj_get_int(x_obj); - int y = mp_obj_get_int(y_obj); - int r = mp_obj_get_int(r_obj); - - Point p(x, y); - display2->circle(p, r); - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} - -mp_obj_t picodisplay2_character(mp_uint_t n_args, const mp_obj_t *args) { - if(display2 != nullptr) { - int c = mp_obj_get_int(args[0]); - int x = mp_obj_get_int(args[1]); - int y = mp_obj_get_int(args[2]); - - Point p(x, y); - if(n_args == 4) { - int scale = mp_obj_get_int(args[3]); - display2->character((char)c, p, scale); - } - else - display2->character((char)c, p); - } - - return mp_const_none; -} - -mp_obj_t picodisplay2_text(mp_uint_t n_args, const mp_obj_t *args) { - if(display2 != nullptr) { - if(mp_obj_is_str_or_bytes(args[0])) { - GET_STR_DATA_LEN(args[0], str, str_len); - - std::string t((const char*)str); - - int x = mp_obj_get_int(args[1]); - int y = mp_obj_get_int(args[2]); - int wrap = mp_obj_get_int(args[3]); - - Point p(x, y); - if(n_args == 5) { - int scale = mp_obj_get_int(args[4]); - display2->text(t, p, wrap, scale); - } - else - display2->text(t, p, wrap); - } - else if(mp_obj_is_float(args[0])) { - mp_raise_TypeError("can't convert 'float' object to str implicitly"); - } - else if(mp_obj_is_int(args[0])) { - mp_raise_TypeError("can't convert 'int' object to str implicitly"); - } - else if(mp_obj_is_bool(args[0])) { - mp_raise_TypeError("can't convert 'bool' object to str implicitly"); - } - else { - mp_raise_TypeError("can't convert object to str implicitly"); - } - } - else - mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); - - return mp_const_none; -} -} diff --git a/micropython/modules/pico_display_2/pico_display_2.h b/micropython/modules/pico_display_2/pico_display_2.h deleted file mode 100644 index bccd69dd..00000000 --- a/micropython/modules/pico_display_2/pico_display_2.h +++ /dev/null @@ -1,26 +0,0 @@ -// Include MicroPython API. -#include "py/runtime.h" -#include "py/objstr.h" - -// Declare the functions we'll make available in Python -extern mp_obj_t picodisplay2_init(mp_obj_t buf_obj); -extern mp_obj_t picodisplay2_get_width(); -extern mp_obj_t picodisplay2_get_height(); -extern mp_obj_t picodisplay2_set_backlight(mp_obj_t brightness_obj); -extern mp_obj_t picodisplay2_update(); -extern mp_obj_t picodisplay2_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj); -extern mp_obj_t picodisplay2_is_pressed(mp_obj_t button_obj); -extern mp_obj_t picodisplay2_flip(); - -// From PicoGraphics parent class -extern mp_obj_t picodisplay2_set_pen(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picodisplay2_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj); -extern mp_obj_t picodisplay2_set_clip(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picodisplay2_remove_clip(); -extern mp_obj_t picodisplay2_clear(); -extern mp_obj_t picodisplay2_pixel(mp_obj_t x_obj, mp_obj_t y_obj); -extern mp_obj_t picodisplay2_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj); -extern mp_obj_t picodisplay2_rectangle(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picodisplay2_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj); -extern mp_obj_t picodisplay2_character(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picodisplay2_text(mp_uint_t n_args, const mp_obj_t *args); diff --git a/micropython/modules/st7789/micropython.cmake b/micropython/modules/picographics/micropython.cmake similarity index 87% rename from micropython/modules/st7789/micropython.cmake rename to micropython/modules/picographics/micropython.cmake index 5af5eec9..d1f6dc11 100644 --- a/micropython/modules/st7789/micropython.cmake +++ b/micropython/modules/picographics/micropython.cmake @@ -1,12 +1,12 @@ -set(MOD_NAME st7789) +set(MOD_NAME picographics) string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) add_library(usermod_${MOD_NAME} INTERFACE) target_sources(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/picographics_st7789/picographics_st7789.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7735/st7735.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp ) diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c new file mode 100644 index 00000000..11b6a31d --- /dev/null +++ b/micropython/modules/picographics/picographics.c @@ -0,0 +1,104 @@ +#include "picographics.h" + +// Module functions +STATIC MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_module_RGB332_obj, ModPicoGraphics_module_RGB332); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_module_RGB565_obj, ModPicoGraphics_module_RGB565); + +// Class Methods +MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_update_obj, ModPicoGraphics_update); +MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_backlight_obj, ModPicoGraphics_set_backlight); +MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_framebuffer_obj, ModPicoGraphics_set_framebuffer); + +// Palette management +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_update_pen_obj, 5, 5, ModPicoGraphics_update_pen); +MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_reset_pen_obj, ModPicoGraphics_reset_pen); + +// Pen +MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_pen_obj, ModPicoGraphics_set_pen); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_create_pen_obj, 4, 4, ModPicoGraphics_create_pen); + +// Primitives +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_set_clip_obj, 5, 5, ModPicoGraphics_set_clip); +MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_remove_clip_obj, ModPicoGraphics_remove_clip); +MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_clear_obj, ModPicoGraphics_clear); +MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_pixel_obj, ModPicoGraphics_pixel); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_pixel_span_obj, 4, 4, ModPicoGraphics_pixel_span); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_rectangle_obj, 5, 5, ModPicoGraphics_rectangle); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_circle_obj, 4, 4, ModPicoGraphics_circle); +MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_character_obj, 1, ModPicoGraphics_character); +MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_text_obj, 1, ModPicoGraphics_text); +MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_measure_text_obj, 1, ModPicoGraphics_measure_text); +MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_polygon_obj, 2, ModPicoGraphics_polygon); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_triangle_obj, 7, 7, ModPicoGraphics_triangle); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_line_obj, 5, 5, ModPicoGraphics_line); + +// Utility +MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_get_bounds_obj, ModPicoGraphics_get_bounds); + +STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&ModPicoGraphics_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&ModPicoGraphics_set_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&ModPicoGraphics_update_obj) }, + + { MP_ROM_QSTR(MP_QSTR_update_pen), MP_ROM_PTR(&ModPicoGraphics_update_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_pen), MP_ROM_PTR(&ModPicoGraphics_reset_pen_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&ModPicoGraphics_set_backlight_obj) }, + { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&ModPicoGraphics_create_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&ModPicoGraphics_set_clip_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&ModPicoGraphics_remove_clip_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&ModPicoGraphics_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&ModPicoGraphics_pixel_span_obj) }, + { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&ModPicoGraphics_rectangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&ModPicoGraphics_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&ModPicoGraphics_character_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&ModPicoGraphics_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_measure_text), MP_ROM_PTR(&ModPicoGraphics_measure_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&ModPicoGraphics_polygon_obj) }, + { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&ModPicoGraphics_triangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&ModPicoGraphics_line_obj) }, + + { MP_ROM_QSTR(MP_QSTR_get_bounds), MP_ROM_PTR(&ModPicoGraphics_get_bounds_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_framebuffer), MP_ROM_PTR(&ModPicoGraphics_set_framebuffer_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(ModPicoGraphics_locals_dict, ModPicoGraphics_locals_dict_table); + +/***** Class Definition *****/ +const mp_obj_type_t ModPicoGraphics_type = { + { &mp_type_type }, + .name = MP_QSTR_picographics, + .make_new = ModPicoGraphics_make_new, + .locals_dict = (mp_obj_dict_t*)&ModPicoGraphics_locals_dict, +}; + +/***** Module Globals *****/ +STATIC const mp_map_elem_t picographics_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_picographics) }, + { MP_ROM_QSTR(MP_QSTR_PicoGraphics), (mp_obj_t)&ModPicoGraphics_type }, + + { MP_ROM_QSTR(MP_QSTR_RGB332), MP_ROM_PTR(&ModPicoGraphics_module_RGB332_obj) }, + { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&ModPicoGraphics_module_RGB565_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_240X240), MP_ROM_INT(DISPLAY_LCD_240X240) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_ROUND_LCD_240X240), MP_ROM_INT(DISPLAY_ROUND_LCD_240X240) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY), MP_ROM_INT(DISPLAY_PICO_DISPLAY) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY_2), MP_ROM_INT(DISPLAY_PICO_DISPLAY_2) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_EXPLORER), MP_ROM_INT(DISPLAY_PICO_EXPLORER) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_TUFTY_2040), MP_ROM_INT(DISPLAY_TUFTY_2040) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_ENVIRO_PLUS), MP_ROM_INT(DISPLAY_ENVIRO_PLUS) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_160X80), MP_ROM_INT(DISPLAY_LCD_160X80) }, + + { MP_ROM_QSTR(MP_QSTR_PEN_P4), MP_ROM_INT(PEN_P4) }, + { MP_ROM_QSTR(MP_QSTR_PEN_P8), MP_ROM_INT(PEN_P8) }, + { MP_ROM_QSTR(MP_QSTR_PEN_RGB332), MP_ROM_INT(PEN_RGB332) }, + { MP_ROM_QSTR(MP_QSTR_PEN_RGB565), MP_ROM_INT(PEN_RGB565) }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_picographics_globals, picographics_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t picographics_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_picographics_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_picographics, picographics_user_cmodule, MODULE_PICOGRAPHICS_ENABLED); \ No newline at end of file diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/picographics/picographics.cpp similarity index 52% rename from micropython/modules/st7789/st7789.cpp rename to micropython/modules/picographics/picographics.cpp index d53dd10f..329f2977 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -1,49 +1,50 @@ -#include "libraries/picographics_st7789/picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "drivers/st7735/st7735.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include "common/pimoroni_common.hpp" #include "common/pimoroni_bus.hpp" #include "micropython/modules/util.hpp" -#ifndef PICO_GRAPHICS_PEN_TYPE -#define PICO_GRAPHICS_PEN_TYPE PenRGB332 -#endif - using namespace pimoroni; extern "C" { -#include "st7789.h" +#include "picographics.h" #include "micropython/modules/pimoroni_bus/pimoroni_bus.h" -typedef struct _GenericST7789_obj_t { +typedef struct _ModPicoGraphics_obj_t { mp_obj_base_t base; - PicoGraphicsST7789 *st7789; + PicoGraphics *graphics; + DisplayDriver *display; void *buffer; -} GenericST7789_obj_t; +} ModPicoGraphics_obj_t; -mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - GenericST7789_obj_t *self = nullptr; +mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + ModPicoGraphics_obj_t *self = nullptr; - enum { ARG_display, ARG_rotate, ARG_bus, ARG_buffer }; + enum { ARG_display, ARG_rotate, ARG_bus, ARG_buffer, ARG_pen_type }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display, MP_ARG_INT | MP_ARG_REQUIRED }, { MP_QSTR_rotate, MP_ARG_INT, { .u_int = Rotation::ROTATE_0 } }, { MP_QSTR_bus, MP_ARG_OBJ, { .u_obj = mp_const_none } }, { MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_pen_type, MP_ARG_INT, { .u_int = PEN_RGB332 } }, }; // Parse args. mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - self = m_new_obj(GenericST7789_obj_t); - self->base.type = &GenericST7789_type; + self = m_new_obj(ModPicoGraphics_obj_t); + self->base.type = &ModPicoGraphics_type; Rotation rotate = (Rotation)args[ARG_rotate].u_int; bool round = false; int width = 0; int height = 0; - ST7789Display display = (ST7789Display)args[ARG_display].u_int; + PicoGraphicsPenType pen_type = (PicoGraphicsPenType)args[ARG_pen_type].u_int; + PicoGraphicsDisplay display = (PicoGraphicsDisplay)args[ARG_display].u_int; switch(display) { case DISPLAY_PICO_DISPLAY: @@ -66,9 +67,64 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t height = 240; round = true; break; + case DISPLAY_LCD_160X80: + width = 160; + height = 80; + break; + default: + mp_raise_ValueError("Unsupported display!"); + break; // unreachable } - size_t required_size = PICO_GRAPHICS_PEN_TYPE::buffer_size(width, height); + // Try to create an appropriate display driver + if (display == DISPLAY_TUFTY_2040) { + if (args[ARG_bus].u_obj == mp_const_none) { + self->display = m_new_class(ST7789, width, height, rotate, {10, 11, 12, 13, 14, 2}); + } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) { + _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); + self->display = m_new_class(ST7789, width, height, rotate, *(ParallelPins *)(bus->pins)); + } else { + mp_raise_ValueError("ParallelBus expected!"); + } + } else if (display == DISPLAY_LCD_160X80) { + if (args[ARG_bus].u_obj == mp_const_none) { + self->display = m_new_class(ST7735, width, height, get_spi_pins(BG_SPI_FRONT)); + } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) { + _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); + self->display = m_new_class(ST7735, width, height, *(SPIPins *)(bus->pins)); + } else { + mp_raise_ValueError("SPIBus expected!"); + } + } else { + if (args[ARG_bus].u_obj == mp_const_none) { + self->display = m_new_class(ST7789, width, height, rotate, round, get_spi_pins(BG_SPI_FRONT)); + } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) { + _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); + self->display = m_new_class(ST7789, width, height, rotate, round, *(SPIPins *)(bus->pins)); + } else { + mp_raise_ValueError("SPIBus expected!"); + } + } + + // Create or fetch buffer + size_t required_size = 0; + switch(pen_type) { + case PEN_P4: + required_size = PicoGraphics_PenP4::buffer_size(width, height); + break; + case PEN_P8: + required_size = PicoGraphics_PenP8::buffer_size(width, height); + break; + case PEN_RGB332: + required_size = PicoGraphics_PenRGB332::buffer_size(width, height); + break; + case PEN_RGB565: + required_size = PicoGraphics_PenRGB565::buffer_size(width, height); + break; + default: + mp_raise_ValueError("Unsupported display!"); + break; // unreachable + } if (args[ARG_buffer].u_obj != mp_const_none) { mp_buffer_info_t bufinfo; @@ -81,112 +137,121 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t self->buffer = m_new(uint8_t, required_size); } - if (display == DISPLAY_TUFTY_2040) { - if (args[ARG_bus].u_obj == mp_const_none) { - self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2}); - } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) { - _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); - self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins)); - } else { - mp_raise_ValueError("ParallelBus expected!"); - } - } else { - if (args[ARG_bus].u_obj == mp_const_none) { - self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT)); - } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) { - _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); - self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins)); - } else { - mp_raise_ValueError("SPIBus expected!"); - } + // Create an instance of the graphics library + // use the *driver* width/height because they may have been swapped due to rotation + switch(pen_type) { + case PEN_P4: + self->graphics = m_new_class(PicoGraphics_PenP4, self->display->width, self->display->height, self->buffer); + break; + case PEN_P8: + self->graphics = m_new_class(PicoGraphics_PenP8, self->display->width, self->display->height, self->buffer); + break; + case PEN_RGB332: + self->graphics = m_new_class(PicoGraphics_PenRGB332, self->display->width, self->display->height, self->buffer); + break; + case PEN_RGB565: + self->graphics = m_new_class(PicoGraphics_PenRGB565, self->display->width, self->display->height, self->buffer); + break; + default: + break; } + // Clear the buffer + self->graphics->set_pen(0); + self->graphics->clear(); + + // Update the LCD from the graphics library + self->display->update(self->graphics); + return MP_OBJ_FROM_PTR(self); } -mp_obj_t GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); +mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) { + (void)self_in; + (void)framebuffer; + /* + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); if (framebuffer == mp_const_none) { - m_del(uint8_t, self->buffer, self->st7789->bounds.w * self->st7789->bounds.h); + m_del(uint8_t, self->buffer, self->graphics->bounds.w * self->graphics->bounds.h); self->buffer = nullptr; - self->st7789->set_framebuffer(nullptr); + self->graphics->set_framebuffer(nullptr); } else { mp_buffer_info_t bufinfo; mp_get_buffer_raise(framebuffer, &bufinfo, MP_BUFFER_RW); self->buffer = bufinfo.buf; - self->st7789->set_framebuffer(self->buffer); + self->graphics->set_framebuffer(self->buffer); } - + */ return mp_const_none; } -mp_obj_t GenericST7789_get_bounds(mp_obj_t self_in) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); +mp_obj_t ModPicoGraphics_get_bounds(mp_obj_t self_in) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); mp_obj_t tuple[2] = { - mp_obj_new_int(self->st7789->bounds.w), - mp_obj_new_int(self->st7789->bounds.h) + mp_obj_new_int(self->graphics->bounds.w), + mp_obj_new_int(self->graphics->bounds.h) }; return mp_obj_new_tuple(2, tuple); } -mp_obj_t GenericST7789_update(mp_obj_t self_in) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); - self->st7789->update(); +mp_obj_t ModPicoGraphics_update(mp_obj_t self_in) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); + self->display->update(self->graphics); return mp_const_none; } -mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); +mp_obj_t ModPicoGraphics_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); float b = mp_obj_get_float(brightness); if(b < 0 || b > 1.0f) mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); - self->st7789->set_backlight((uint8_t)(b * 255.0f)); + self->display->set_backlight((uint8_t)(b * 255.0f)); return mp_const_none; } -mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb332( +mp_obj_t ModPicoGraphics_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { + return mp_obj_new_int(PicoGraphics::rgb_to_rgb332( mp_obj_get_int(r), mp_obj_get_int(g), mp_obj_get_int(b) )); } -mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb565( +mp_obj_t ModPicoGraphics_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { + return mp_obj_new_int(PicoGraphics::rgb_to_rgb565( mp_obj_get_int(r), mp_obj_get_int(g), mp_obj_get_int(b) )); } -mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); +mp_obj_t ModPicoGraphics_set_pen(mp_obj_t self_in, mp_obj_t pen) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); - self->st7789->set_pen(mp_obj_get_int(pen)); + self->graphics->set_pen(mp_obj_get_int(pen)); return mp_const_none; } -mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); +mp_obj_t ModPicoGraphics_reset_pen(mp_obj_t self_in, mp_obj_t pen) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); - self->st7789->reset_pen(mp_obj_get_int(pen)); + self->graphics->reset_pen(mp_obj_get_int(pen)); return mp_const_none; } -mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *args) { +mp_obj_t ModPicoGraphics_update_pen(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_i, ARG_r, ARG_g, ARG_b }; - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); - self->st7789->update_pen( + self->graphics->update_pen( mp_obj_get_int(args[ARG_i]) & 0xff, mp_obj_get_int(args[ARG_r]) & 0xff, mp_obj_get_int(args[ARG_g]) & 0xff, @@ -196,12 +261,12 @@ mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *args) { +mp_obj_t ModPicoGraphics_create_pen(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_r, ARG_g, ARG_b }; - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); - int result = self->st7789->create_pen( + int result = self->graphics->create_pen( mp_obj_get_int(args[ARG_r]) & 0xff, mp_obj_get_int(args[ARG_g]) & 0xff, mp_obj_get_int(args[ARG_b]) & 0xff @@ -212,12 +277,12 @@ mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *args) { return mp_obj_new_int(result); } -mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *args) { +mp_obj_t ModPicoGraphics_set_clip(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); - self->st7789->set_clip({ + self->graphics->set_clip({ mp_obj_get_int(args[ARG_x]), mp_obj_get_int(args[ARG_y]), mp_obj_get_int(args[ARG_w]), @@ -227,26 +292,26 @@ mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -mp_obj_t GenericST7789_remove_clip(mp_obj_t self_in) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); +mp_obj_t ModPicoGraphics_remove_clip(mp_obj_t self_in) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); - self->st7789->remove_clip(); + self->graphics->remove_clip(); return mp_const_none; } -mp_obj_t GenericST7789_clear(mp_obj_t self_in) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); +mp_obj_t ModPicoGraphics_clear(mp_obj_t self_in) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); - self->st7789->clear(); + self->graphics->clear(); return mp_const_none; } -mp_obj_t GenericST7789_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y) { - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t); +mp_obj_t ModPicoGraphics_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); - self->st7789->pixel({ + self->graphics->pixel({ mp_obj_get_int(x), mp_obj_get_int(y) }); @@ -254,12 +319,12 @@ mp_obj_t GenericST7789_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y) { return mp_const_none; } -mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *args) { +mp_obj_t ModPicoGraphics_pixel_span(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_l }; - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); - self->st7789->pixel_span({ + self->graphics->pixel_span({ mp_obj_get_int(args[ARG_x]), mp_obj_get_int(args[ARG_y]) }, mp_obj_get_int(args[ARG_l])); @@ -267,12 +332,12 @@ mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *args) { +mp_obj_t ModPicoGraphics_rectangle(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); - self->st7789->rectangle({ + self->graphics->rectangle({ mp_obj_get_int(args[ARG_x]), mp_obj_get_int(args[ARG_y]), mp_obj_get_int(args[ARG_w]), @@ -282,12 +347,12 @@ mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *args) { +mp_obj_t ModPicoGraphics_circle(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_r }; - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); - self->st7789->circle({ + self->graphics->circle({ mp_obj_get_int(args[ARG_x]), mp_obj_get_int(args[ARG_y]) }, mp_obj_get_int(args[ARG_r])); @@ -295,7 +360,7 @@ mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -mp_obj_t GenericST7789_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t ModPicoGraphics_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_self, ARG_char, ARG_x, ARG_y, ARG_scale }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -308,19 +373,19 @@ mp_obj_t GenericST7789_character(size_t n_args, const mp_obj_t *pos_args, mp_map mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, ModPicoGraphics_obj_t); int c = mp_obj_get_int(args[ARG_char].u_obj); int x = args[ARG_x].u_int; int y = args[ARG_y].u_int; int scale = args[ARG_scale].u_int; - self->st7789->character((char)c, Point(x, y), scale); + self->graphics->character((char)c, Point(x, y), scale); return mp_const_none; } -mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -334,7 +399,7 @@ mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, ModPicoGraphics_obj_t); mp_obj_t text_obj = args[ARG_text].u_obj; @@ -349,12 +414,12 @@ mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k int wrap = args[ARG_wrap].u_int; int scale = args[ARG_scale].u_int; - self->st7789->text(t, Point(x, y), wrap, scale); + self->graphics->text(t, Point(x, y), wrap, scale); return mp_const_none; } -mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_self, ARG_text, ARG_scale }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -365,7 +430,7 @@ mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, ModPicoGraphics_obj_t); mp_obj_t text_obj = args[ARG_text].u_obj; @@ -377,16 +442,16 @@ mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_ int scale = args[ARG_scale].u_int; - int width = self->st7789->measure_text(t, scale); + int width = self->graphics->measure_text(t, scale); return mp_obj_new_int(width); } -mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t ModPicoGraphics_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { size_t num_tuples = n_args - 1; const mp_obj_t *tuples = pos_args + 1; - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], ModPicoGraphics_obj_t); // Check if there is only one argument, which might be a list if(n_args == 2) { @@ -418,18 +483,18 @@ mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t mp_obj_get_int(tuple->items[1]) }); } - self->st7789->polygon(points); + self->graphics->polygon(points); } return mp_const_none; } -mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *args) { +mp_obj_t ModPicoGraphics_triangle(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_x3, ARG_y3 }; - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); - self->st7789->triangle( + self->graphics->triangle( {mp_obj_get_int(args[ARG_x1]), mp_obj_get_int(args[ARG_y1])}, {mp_obj_get_int(args[ARG_x2]), @@ -441,12 +506,12 @@ mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *args) { +mp_obj_t ModPicoGraphics_line(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2 }; - GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], GenericST7789_obj_t); + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); - self->st7789->line( + self->graphics->line( {mp_obj_get_int(args[ARG_x1]), mp_obj_get_int(args[ARG_y1])}, {mp_obj_get_int(args[ARG_x2]), diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h new file mode 100644 index 00000000..c6e55ee0 --- /dev/null +++ b/micropython/modules/picographics/picographics.h @@ -0,0 +1,61 @@ +#include "py/runtime.h" +#include "py/objstr.h" + +enum PicoGraphicsDisplay { + DISPLAY_LCD_240X240=0, + DISPLAY_ROUND_LCD_240X240, + DISPLAY_PICO_DISPLAY, + DISPLAY_PICO_DISPLAY_2, + DISPLAY_PICO_EXPLORER, + DISPLAY_TUFTY_2040, + DISPLAY_ENVIRO_PLUS, + DISPLAY_LCD_160X80 +}; + +enum PicoGraphicsPenType { + PEN_P2 = 0, + PEN_P4, + PEN_P8, + PEN_RGB332, + PEN_RGB565 +}; + +// Type +extern const mp_obj_type_t ModPicoGraphics_type; + +// Module functions +extern mp_obj_t ModPicoGraphics_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b); +extern mp_obj_t ModPicoGraphics_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); + +// Class methods +extern mp_obj_t ModPicoGraphics_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 ModPicoGraphics_update(mp_obj_t self_in); +extern mp_obj_t ModPicoGraphics_set_backlight(mp_obj_t self_in, mp_obj_t brightness); + +// Palette management +extern mp_obj_t ModPicoGraphics_update_pen(size_t n_args, const mp_obj_t *args); +extern mp_obj_t ModPicoGraphics_reset_pen(mp_obj_t self_in, mp_obj_t pen); + +// Pen +extern mp_obj_t ModPicoGraphics_set_pen(mp_obj_t self_in, mp_obj_t pen); +extern mp_obj_t ModPicoGraphics_create_pen(size_t n_args, const mp_obj_t *args); + +// Primitives +extern mp_obj_t ModPicoGraphics_set_clip(size_t n_args, const mp_obj_t *args); +extern mp_obj_t ModPicoGraphics_remove_clip(mp_obj_t self_in); +extern mp_obj_t ModPicoGraphics_clear(mp_obj_t self_in); +extern mp_obj_t ModPicoGraphics_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y); +extern mp_obj_t ModPicoGraphics_pixel_span(size_t n_args, const mp_obj_t *args); +extern mp_obj_t ModPicoGraphics_rectangle(size_t n_args, const mp_obj_t *args); +extern mp_obj_t ModPicoGraphics_circle(size_t n_args, const mp_obj_t *args); +extern mp_obj_t ModPicoGraphics_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t ModPicoGraphics_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t ModPicoGraphics_triangle(size_t n_args, const mp_obj_t *args); +extern mp_obj_t ModPicoGraphics_line(size_t n_args, const mp_obj_t *args); + +// Utility +extern mp_obj_t ModPicoGraphics_get_bounds(mp_obj_t self_in); +extern mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); \ No newline at end of file diff --git a/micropython/modules/st7789/st7789.c b/micropython/modules/st7789/st7789.c deleted file mode 100644 index 02c477a8..00000000 --- a/micropython/modules/st7789/st7789.c +++ /dev/null @@ -1,98 +0,0 @@ -#include "st7789.h" - -// Module functions -STATIC MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_module_RGB332_obj, GenericST7789_module_RGB332); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_module_RGB565_obj, GenericST7789_module_RGB565); - -// Class Methods -MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_update_obj, GenericST7789_update); -MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_backlight_obj, GenericST7789_set_backlight); -MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_framebuffer_obj, GenericST7789_set_framebuffer); - -// Palette management -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_update_pen_obj, 5, 5, GenericST7789_update_pen); -MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_reset_pen_obj, GenericST7789_reset_pen); - -// Pen -MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_pen_obj, GenericST7789_set_pen); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_create_pen_obj, 4, 4, GenericST7789_create_pen); - -// Primitives -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_set_clip_obj, 5, 5, GenericST7789_set_clip); -MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_remove_clip_obj, GenericST7789_remove_clip); -MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_clear_obj, GenericST7789_clear); -MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_pixel_obj, GenericST7789_pixel); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_pixel_span_obj, 4, 4, GenericST7789_pixel_span); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_rectangle_obj, 5, 5, GenericST7789_rectangle); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_circle_obj, 4, 4, GenericST7789_circle); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_character_obj, 1, GenericST7789_character); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_text_obj, 1, GenericST7789_text); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_measure_text_obj, 1, GenericST7789_measure_text); -MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_polygon_obj, 2, GenericST7789_polygon); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_triangle_obj, 7, 7, GenericST7789_triangle); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(GenericST7789_line_obj, 5, 5, GenericST7789_line); - -// Utility -MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_get_bounds_obj, GenericST7789_get_bounds); - -STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&GenericST7789_pixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) }, - - { MP_ROM_QSTR(MP_QSTR_update_pen), MP_ROM_PTR(&GenericST7789_update_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_reset_pen), MP_ROM_PTR(&GenericST7789_reset_pen_obj) }, - - { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) }, - { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&GenericST7789_set_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&GenericST7789_remove_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&GenericST7789_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&GenericST7789_pixel_span_obj) }, - { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&GenericST7789_rectangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&GenericST7789_circle_obj) }, - { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&GenericST7789_character_obj) }, - { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&GenericST7789_text_obj) }, - { MP_ROM_QSTR(MP_QSTR_measure_text), MP_ROM_PTR(&GenericST7789_measure_text_obj) }, - { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&GenericST7789_polygon_obj) }, - { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&GenericST7789_triangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&GenericST7789_line_obj) }, - - { MP_ROM_QSTR(MP_QSTR_get_bounds), MP_ROM_PTR(&GenericST7789_get_bounds_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_framebuffer), MP_ROM_PTR(&GenericST7789_set_framebuffer_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(GenericST7789_locals_dict, GenericST7789_locals_dict_table); - -/***** Class Definition *****/ -const mp_obj_type_t GenericST7789_type = { - { &mp_type_type }, - .name = MP_QSTR_st7789, - .make_new = GenericST7789_make_new, - .locals_dict = (mp_obj_dict_t*)&GenericST7789_locals_dict, -}; - -/***** Module Globals *****/ -STATIC const mp_map_elem_t st7789_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) }, - { MP_ROM_QSTR(MP_QSTR_ST7789), (mp_obj_t)&GenericST7789_type }, - - { MP_ROM_QSTR(MP_QSTR_RGB332), MP_ROM_PTR(&GenericST7789_module_RGB332_obj) }, - { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&GenericST7789_module_RGB565_obj) }, - - { MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_240X240), MP_ROM_INT(DISPLAY_LCD_240X240) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_ROUND_LCD_240X240), MP_ROM_INT(DISPLAY_ROUND_LCD_240X240) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY), MP_ROM_INT(DISPLAY_PICO_DISPLAY) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_DISPLAY_2), MP_ROM_INT(DISPLAY_PICO_DISPLAY_2) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_EXPLORER), MP_ROM_INT(DISPLAY_PICO_EXPLORER) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_TUFTY_2040), MP_ROM_INT(DISPLAY_TUFTY_2040) }, - { MP_ROM_QSTR(MP_QSTR_DISPLAY_ENVIRO_PLUS), MP_ROM_INT(DISPLAY_ENVIRO_PLUS) }, -}; -STATIC MP_DEFINE_CONST_DICT(mp_module_st7789_globals, st7789_globals_table); - -/***** Module Definition *****/ -const mp_obj_module_t st7789_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_st7789_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_st7789, st7789_user_cmodule, MODULE_ST7789_ENABLED); \ No newline at end of file diff --git a/micropython/modules/st7789/st7789.h b/micropython/modules/st7789/st7789.h deleted file mode 100644 index fee2259a..00000000 --- a/micropython/modules/st7789/st7789.h +++ /dev/null @@ -1,52 +0,0 @@ -#include "py/runtime.h" -#include "py/objstr.h" - -enum ST7789Display { - DISPLAY_LCD_240X240=0, - DISPLAY_ROUND_LCD_240X240, - DISPLAY_PICO_DISPLAY, - DISPLAY_PICO_DISPLAY_2, - DISPLAY_PICO_EXPLORER, - DISPLAY_TUFTY_2040, - DISPLAY_ENVIRO_PLUS -}; - -// Type -extern const mp_obj_type_t GenericST7789_type; - -// Module functions -extern mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b); -extern mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); - -// Class methods -extern mp_obj_t GenericST7789_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 GenericST7789_update(mp_obj_t self_in); -extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness); - -// Palette management -extern mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *args); -extern mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen); - -// Pen -extern mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen); -extern mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *args); - -// Primitives -extern mp_obj_t GenericST7789_set_clip(size_t n_args, const mp_obj_t *args); -extern mp_obj_t GenericST7789_remove_clip(mp_obj_t self_in); -extern mp_obj_t GenericST7789_clear(mp_obj_t self_in); -extern mp_obj_t GenericST7789_pixel(mp_obj_t self_in, mp_obj_t x, mp_obj_t y); -extern mp_obj_t GenericST7789_pixel_span(size_t n_args, const mp_obj_t *args); -extern mp_obj_t GenericST7789_rectangle(size_t n_args, const mp_obj_t *args); -extern mp_obj_t GenericST7789_circle(size_t n_args, const mp_obj_t *args); -extern mp_obj_t GenericST7789_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t GenericST7789_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t GenericST7789_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t GenericST7789_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t GenericST7789_triangle(size_t n_args, const mp_obj_t *args); -extern mp_obj_t GenericST7789_line(size_t n_args, const mp_obj_t *args); - -// Utility -extern mp_obj_t GenericST7789_get_bounds(mp_obj_t self_in); -extern mp_obj_t GenericST7789_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); \ No newline at end of file diff --git a/micropython/modules/ulab b/micropython/modules/ulab index d4383449..24caf74d 160000 --- a/micropython/modules/ulab +++ b/micropython/modules/ulab @@ -1 +1 @@ -Subproject commit d438344943ab4383dae86b4620075ea877dec535 +Subproject commit 24caf74d90e88a62a030309d229155e210d897ac From f5d7f341455cf6fd8564bfec62fb8948f7b724a4 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Jun 2022 17:08:01 +0100 Subject: [PATCH 30/84] ulab: Fix broken submodule. --- micropython/modules/micropython-tiny2040.cmake | 2 -- micropython/modules/ulab | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/micropython/modules/micropython-tiny2040.cmake b/micropython/modules/micropython-tiny2040.cmake index f4e90728..d7f7a2ca 100644 --- a/micropython/modules/micropython-tiny2040.cmake +++ b/micropython/modules/micropython-tiny2040.cmake @@ -5,5 +5,3 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") include(micropython-common) - -enable_ulab() diff --git a/micropython/modules/ulab b/micropython/modules/ulab index 24caf74d..0c7c6b88 160000 --- a/micropython/modules/ulab +++ b/micropython/modules/ulab @@ -1 +1 @@ -Subproject commit 24caf74d90e88a62a030309d229155e210d897ac +Subproject commit 0c7c6b88f3ec1b1d11d2f7d8b185e28ac657c06d From 4848e7ba596f94d1b2a129657bbac5bb9656568c Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Jun 2022 19:02:30 +0100 Subject: [PATCH 31/84] PicoGraphics/ST7789/ST3375: Fixup C++ examples and libraries. --- drivers/st7735/st7735.cmake | 2 +- .../breakout_as7262/explorer_bargraph.cmake | 2 +- .../breakout_as7262/explorer_bargraph.cpp | 49 +++--- .../breakout_colourlcd160x80/CMakeLists.txt | 4 +- .../colorlcd_160x80_demo.cpp | 59 ++++++++ examples/breakout_colourlcd160x80/demo.cpp | 62 -------- .../breakout_colourlcd240x240/CMakeLists.txt | 4 +- .../colorlcd_240x240_demo.cpp | 68 +++++++++ examples/breakout_colourlcd240x240/demo.cpp | 69 --------- examples/breakout_roundlcd/CMakeLists.txt | 2 +- examples/breakout_roundlcd/roundlcd_demo.cpp | 29 ++-- examples/pico_display/CMakeLists.txt | 4 +- .../{demo.cpp => pico_display_demo.cpp} | 50 ++++--- examples/pico_display_2/CMakeLists.txt | 4 +- .../{demo.cpp => pico_display_2_demo.cpp} | 44 +++--- examples/pico_enc_explorer/CMakeLists.txt | 2 +- .../pico_enc_explorer/pico_enc_explorer.cpp | 43 +++--- examples/pico_explorer/CMakeLists.txt | 4 +- examples/pico_explorer/pico_explorer_demo.cpp | 141 +++++++----------- examples/pico_explorer/text_demo.cpp | 35 +++-- examples/pico_explorer_encoder/CMakeLists.txt | 2 +- .../pico_explorer_encoder.cpp | 63 ++++---- examples/pico_pot_explorer/CMakeLists.txt | 2 +- .../pico_pot_explorer/pico_pot_explorer.cpp | 43 +++--- examples/pico_rtc_display/CMakeLists.txt | 2 +- .../pico_rtc_display/pico_rtc_display.cpp | 64 ++++---- examples/pico_tof_display/CMakeLists.txt | 2 +- .../pico_tof_display/pico_tof_display.cpp | 64 ++++---- .../pico_trackball_display/CMakeLists.txt | 2 +- .../pico_trackball_display.cpp | 62 ++++---- examples/tufty2040/tufty2040_drawing.cmake | 3 +- examples/tufty2040/tufty2040_drawing.cpp | 45 +++--- libraries/CMakeLists.txt | 2 - .../breakout_colourlcd160x80/CMakeLists.txt | 1 - .../breakout_colourlcd160x80.cmake | 11 -- .../breakout_colourlcd160x80.cpp | 6 - .../breakout_colourlcd160x80.hpp | 47 ------ .../breakout_colourlcd240x240/CMakeLists.txt | 11 -- .../breakout_colourlcd240x240.cmake | 14 -- .../breakout_colourlcd240x240.cpp | 58 ------- .../breakout_colourlcd240x240.hpp | 53 ------- libraries/breakout_roundlcd/CMakeLists.txt | 11 -- .../breakout_roundlcd/breakout_roundlcd.cmake | 14 -- .../breakout_roundlcd/breakout_roundlcd.cpp | 59 -------- .../breakout_roundlcd/breakout_roundlcd.hpp | 55 ------- libraries/pico_explorer/pico_explorer.cpp | 123 +-------------- libraries/pico_explorer/pico_explorer.hpp | 23 +-- libraries/pico_graphics/pico_graphics.cmake | 2 +- libraries/pico_graphics/pico_graphics.hpp | 4 +- libraries/picographics_st7789/CMakeLists.txt | 1 - libraries/picographics_st7789/README.md | 106 ------------- .../picographics_st7789.cmake | 11 -- .../picographics_st7789.cpp | 9 -- .../picographics_st7789.hpp | 50 ------- 54 files changed, 492 insertions(+), 1210 deletions(-) create mode 100644 examples/breakout_colourlcd160x80/colorlcd_160x80_demo.cpp delete mode 100644 examples/breakout_colourlcd160x80/demo.cpp create mode 100644 examples/breakout_colourlcd240x240/colorlcd_240x240_demo.cpp delete mode 100644 examples/breakout_colourlcd240x240/demo.cpp rename examples/pico_display/{demo.cpp => pico_display_demo.cpp} (56%) rename examples/pico_display_2/{demo.cpp => pico_display_2_demo.cpp} (70%) delete mode 100644 libraries/breakout_colourlcd160x80/CMakeLists.txt delete mode 100644 libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cmake delete mode 100644 libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp delete mode 100644 libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp delete mode 100644 libraries/breakout_colourlcd240x240/CMakeLists.txt delete mode 100644 libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.cmake delete mode 100644 libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp delete mode 100644 libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.hpp delete mode 100644 libraries/breakout_roundlcd/CMakeLists.txt delete mode 100644 libraries/breakout_roundlcd/breakout_roundlcd.cmake delete mode 100644 libraries/breakout_roundlcd/breakout_roundlcd.cpp delete mode 100644 libraries/breakout_roundlcd/breakout_roundlcd.hpp delete mode 100644 libraries/picographics_st7789/CMakeLists.txt delete mode 100644 libraries/picographics_st7789/README.md delete mode 100644 libraries/picographics_st7789/picographics_st7789.cmake delete mode 100644 libraries/picographics_st7789/picographics_st7789.cpp delete mode 100644 libraries/picographics_st7789/picographics_st7789.hpp diff --git a/drivers/st7735/st7735.cmake b/drivers/st7735/st7735.cmake index 3a44ee58..85c8ae60 100644 --- a/drivers/st7735/st7735.cmake +++ b/drivers/st7735/st7735.cmake @@ -7,4 +7,4 @@ target_sources(${DRIVER_NAME} INTERFACE target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma) +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma) diff --git a/examples/breakout_as7262/explorer_bargraph.cmake b/examples/breakout_as7262/explorer_bargraph.cmake index 48b8b989..2972e1a0 100644 --- a/examples/breakout_as7262/explorer_bargraph.cmake +++ b/examples/breakout_as7262/explorer_bargraph.cmake @@ -10,7 +10,7 @@ pico_enable_stdio_usb(${OUTPUT_NAME} 1) pico_enable_stdio_uart(${OUTPUT_NAME} 1) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_as7262 pico_explorer picographics_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_as7262 pico_explorer pico_graphics st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_as7262/explorer_bargraph.cpp b/examples/breakout_as7262/explorer_bargraph.cpp index 130c51a7..35ba9c6f 100644 --- a/examples/breakout_as7262/explorer_bargraph.cpp +++ b/examples/breakout_as7262/explorer_bargraph.cpp @@ -4,7 +4,8 @@ #include "breakout_as7262.hpp" #include "pico_explorer.hpp" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" using namespace pimoroni; @@ -13,16 +14,18 @@ constexpr float INTEGRATION_TIME = 10.0f; I2C i2c(BOARD::PICO_EXPLORER); BreakoutAS7262 as7262(&i2c); -PicoGraphicsST7789 display(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); +ST7789 st7789(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); -uint8_t bar_width = PicoExplorer::WIDTH / 6; -uint8_t bar_height = PicoExplorer::HEIGHT; void draw_bar(float scale, uint16_t channel) { + static uint8_t bar_width = st7789.width / 6; + static uint8_t bar_height = st7789.height; + int16_t bar_top = bar_height - (bar_height * scale); bar_top = std::max((int16_t)0, bar_top); int16_t current_bar_height = bar_height - bar_top; - display.rectangle(Rect(channel * bar_width, bar_top, bar_width, current_bar_height - 1)); + graphics.rectangle(Rect(channel * bar_width, bar_top, bar_width, current_bar_height - 1)); } int main() { @@ -44,17 +47,17 @@ int main() { as7262.set_indicator_current(AS7262::indicator_current::ma4); as7262.set_leds(true, true); - Pen BLACK = display.create_pen(0, 0, 0); - Pen RED = display.create_pen(255, 0, 0); - Pen ORANGE = display.create_pen(255, 128, 0); - Pen YELLOW = display.create_pen(255, 255, 0); - Pen GREEN = display.create_pen(0, 255, 0); - Pen BLUE = display.create_pen(0, 0, 255); - Pen VIOLET = display.create_pen(255, 0, 255); + Pen BLACK = graphics.create_pen(0, 0, 0); + Pen RED = graphics.create_pen(255, 0, 0); + Pen ORANGE = graphics.create_pen(255, 128, 0); + Pen YELLOW = graphics.create_pen(255, 255, 0); + Pen GREEN = graphics.create_pen(0, 255, 0); + Pen BLUE = graphics.create_pen(0, 0, 255); + Pen VIOLET = graphics.create_pen(255, 0, 255); while(true) { - display.set_pen(BLACK); - display.clear(); + graphics.set_pen(BLACK); + graphics.clear(); AS7262::reading reading = as7262.read(); printf("R: %f O: %f Y: %f G: %f B: %f V: %f \n", @@ -73,34 +76,34 @@ int main() { if(reading.blue > m) m = reading.blue; if(reading.violet > m) m = reading.violet; - display.set_pen(BLACK); - display.clear(); + graphics.set_pen(BLACK); + graphics.clear(); // Red - display.set_pen(RED); + graphics.set_pen(RED); draw_bar(reading.red / m, 0); // Orange - display.set_pen(ORANGE); + graphics.set_pen(ORANGE); draw_bar(reading.orange / m, 1); // Yellow - display.set_pen(YELLOW); + graphics.set_pen(YELLOW); draw_bar(reading.yellow / m, 2); // Green - display.set_pen(GREEN); + graphics.set_pen(GREEN); draw_bar(reading.green / m, 3); // Blue - display.set_pen(BLUE); + graphics.set_pen(BLUE); draw_bar(reading.blue / m, 4); // Violet - display.set_pen(VIOLET); + graphics.set_pen(VIOLET); draw_bar(reading.violet / m, 5); - display.update(); + st7789.update(&graphics); sleep_ms(INTEGRATION_TIME); } diff --git a/examples/breakout_colourlcd160x80/CMakeLists.txt b/examples/breakout_colourlcd160x80/CMakeLists.txt index c54ee549..93f98791 100644 --- a/examples/breakout_colourlcd160x80/CMakeLists.txt +++ b/examples/breakout_colourlcd160x80/CMakeLists.txt @@ -2,11 +2,11 @@ set(OUTPUT_NAME colourlcd160x80_demo) add_executable( ${OUTPUT_NAME} - demo.cpp + colorlcd_160x80_demo.cpp ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_colourlcd160x80) +target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_graphics st7735 hardware_spi) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_colourlcd160x80/colorlcd_160x80_demo.cpp b/examples/breakout_colourlcd160x80/colorlcd_160x80_demo.cpp new file mode 100644 index 00000000..e94c985c --- /dev/null +++ b/examples/breakout_colourlcd160x80/colorlcd_160x80_demo.cpp @@ -0,0 +1,59 @@ +#include +#include + +#include "drivers/st7735/st7735.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" + +using namespace pimoroni; + +ST7735 st7735(160, 80, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenP8 graphics(st7735.width, st7735.height, nullptr); + +int main() { + st7735.set_backlight(255); + + struct pt { + float x; + float y; + uint8_t r; + float dx; + float dy; + Pen pen; + }; + + std::vector shapes; + for(int i = 0; i < 1000; i++) { + pt shape; + shape.x = rand() % graphics.bounds.w; + shape.y = rand() % graphics.bounds.h; + shape.r = (rand() % 10) + 3; + shape.dx = float(rand() % 255) / 128.0f; + shape.dy = float(rand() % 255) / 128.0f; + shape.pen = graphics.create_pen(rand() % 255, rand() % 255, rand() % 255); + shapes.push_back(shape); + } + + uint8_t bg = graphics.create_pen(120, 40, 60); + + while(true) { + graphics.set_pen(bg); + graphics.clear(); + + for(auto &shape : shapes) { + shape.x += shape.dx; + shape.y += shape.dy; + if(shape.x < 0) shape.dx *= -1; + if(shape.x >= graphics.bounds.w) shape.dx *= -1; + if(shape.y < 0) shape.dy *= -1; + if(shape.y >= graphics.bounds.h) shape.dy *= -1; + + graphics.set_pen(shape.pen); + graphics.circle(Point(shape.x, shape.y), shape.r); + } + + // update screen + st7735.update(&graphics); + } + + return 0; +} diff --git a/examples/breakout_colourlcd160x80/demo.cpp b/examples/breakout_colourlcd160x80/demo.cpp deleted file mode 100644 index f2757536..00000000 --- a/examples/breakout_colourlcd160x80/demo.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -#include "breakout_colourlcd160x80.hpp" - -using namespace pimoroni; - -uint8_t buffer[BreakoutColourLCD160x80::WIDTH * BreakoutColourLCD160x80::HEIGHT]; -BreakoutColourLCD160x80 lcd((void *)buffer); - -int main() { - lcd.init(); - lcd.set_backlight(255); - - // Delete the default palette and allow us to create up to 256 of our own RGB565 colours - lcd.set_palette_mode(BreakoutColourLCD160x80::PaletteModeUSER); - - struct pt { - float x; - float y; - uint8_t r; - float dx; - float dy; - Pen pen; - }; - - std::vector shapes; - for(int i = 0; i < 1000; i++) { - pt shape; - shape.x = rand() % lcd.bounds.w; - shape.y = rand() % lcd.bounds.h; - shape.r = (rand() % 10) + 3; - shape.dx = float(rand() % 255) / 128.0f; - shape.dy = float(rand() % 255) / 128.0f; - shape.pen = lcd.create_pen(rand() % 255, rand() % 255, rand() % 255); - shapes.push_back(shape); - } - - uint8_t bg = lcd.create_pen(120, 40, 60); - - while(true) { - lcd.set_pen(bg); - lcd.clear(); - - for(auto &shape : shapes) { - shape.x += shape.dx; - shape.y += shape.dy; - if(shape.x < 0) shape.dx *= -1; - if(shape.x >= lcd.bounds.w) shape.dx *= -1; - if(shape.y < 0) shape.dy *= -1; - if(shape.y >= lcd.bounds.h) shape.dy *= -1; - - lcd.set_pen(shape.pen); - lcd.circle(Point(shape.x, shape.y), shape.r); - } - - // update screen - lcd.update(); - } - - return 0; -} diff --git a/examples/breakout_colourlcd240x240/CMakeLists.txt b/examples/breakout_colourlcd240x240/CMakeLists.txt index 26ca71e0..bcb4b533 100644 --- a/examples/breakout_colourlcd240x240/CMakeLists.txt +++ b/examples/breakout_colourlcd240x240/CMakeLists.txt @@ -2,11 +2,11 @@ set(OUTPUT_NAME colourlcd240x240_demo) add_executable( ${OUTPUT_NAME} - demo.cpp + colorlcd_240x240_demo.cpp ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib picographics_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_graphics st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_colourlcd240x240/colorlcd_240x240_demo.cpp b/examples/breakout_colourlcd240x240/colorlcd_240x240_demo.cpp new file mode 100644 index 00000000..e4fb9f4b --- /dev/null +++ b/examples/breakout_colourlcd240x240/colorlcd_240x240_demo.cpp @@ -0,0 +1,68 @@ +#include +#include + +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" + +using namespace pimoroni; + +const int WIDTH = 240; +const int HEIGHT = 240; + +ST7789 st7789(WIDTH, HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); + +int main() { + st7789.set_backlight(255); + + struct pt { + float x; + float y; + uint8_t r; + float dx; + float dy; + Pen pen; + }; + + std::vector shapes; + for(int i = 0; i < 100; i++) { + pt shape; + shape.r = (rand() % 10) + 3; + shape.x = rand() % (graphics.bounds.w - (shape.r * 2)); + shape.y = rand() % (graphics.bounds.h - (shape.r * 2)); + shape.x += shape.r; + shape.y += shape.r; + shape.dx = float(rand() % 255) / 64.0f; + shape.dy = float(rand() % 255) / 64.0f; + shape.pen = graphics.create_pen(rand() % 255, rand() % 255, rand() % 255); + shapes.push_back(shape); + } + + Pen BG = graphics.create_pen(120, 40, 60); + Pen WHITE = graphics.create_pen(255, 255, 255); + + while(true) { + graphics.set_pen(BG); + graphics.clear(); + + for(auto &shape : shapes) { + shape.x += shape.dx; + shape.y += shape.dy; + if(shape.x < shape.r) shape.dx *= -1; + if(shape.x >= graphics.bounds.w - shape.r) shape.dx *= -1; + if(shape.y < shape.r) shape.dy *= -1; + if(shape.y >= graphics.bounds.h - shape.r) shape.dy *= -1; + + graphics.set_pen(shape.pen); + graphics.circle(Point(shape.x, shape.y), shape.r); + } + + graphics.set_pen(WHITE); + graphics.text("Hello World", Point(0, 0), 240); + + // update screen + st7789.update(&graphics); + } + + return 0; +} diff --git a/examples/breakout_colourlcd240x240/demo.cpp b/examples/breakout_colourlcd240x240/demo.cpp deleted file mode 100644 index dce1156d..00000000 --- a/examples/breakout_colourlcd240x240/demo.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include - -#include "picographics_st7789.hpp" - -using namespace pimoroni; - -const int WIDTH = 240; -const int HEIGHT = 240; - -PicoGraphicsST7789 display(WIDTH, HEIGHT, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); - -int main() { - display.set_backlight(255); - - // Delete the default palette and allow us to create up to 256 of our own RGB565 colours - display.set_palette_mode(PicoGraphicsST7789::PaletteModeUSER); - - struct pt { - float x; - float y; - uint8_t r; - float dx; - float dy; - Pen pen; - }; - - std::vector shapes; - for(int i = 0; i < 100; i++) { - pt shape; - shape.r = (rand() % 10) + 3; - shape.x = rand() % (display.bounds.w - (shape.r * 2)); - shape.y = rand() % (display.bounds.h - (shape.r * 2)); - shape.x += shape.r; - shape.y += shape.r; - shape.dx = float(rand() % 255) / 64.0f; - shape.dy = float(rand() % 255) / 64.0f; - shape.pen = display.create_pen(rand() % 255, rand() % 255, rand() % 255); - shapes.push_back(shape); - } - - Pen BG = display.create_pen(120, 40, 60); - Pen WHITE = display.create_pen(255, 255, 255); - - while(true) { - display.set_pen(BG); - display.clear(); - - for(auto &shape : shapes) { - shape.x += shape.dx; - shape.y += shape.dy; - if(shape.x < shape.r) shape.dx *= -1; - if(shape.x >= display.bounds.w - shape.r) shape.dx *= -1; - if(shape.y < shape.r) shape.dy *= -1; - if(shape.y >= display.bounds.h - shape.r) shape.dy *= -1; - - display.set_pen(shape.pen); - display.circle(Point(shape.x, shape.y), shape.r); - } - - display.set_pen(WHITE); - display.text("Hello World", Point(0, 0), 240); - - // update screen - display.update(); - } - - return 0; -} diff --git a/examples/breakout_roundlcd/CMakeLists.txt b/examples/breakout_roundlcd/CMakeLists.txt index daac9779..abf05124 100644 --- a/examples/breakout_roundlcd/CMakeLists.txt +++ b/examples/breakout_roundlcd/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib picographics_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_graphics st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) \ No newline at end of file diff --git a/examples/breakout_roundlcd/roundlcd_demo.cpp b/examples/breakout_roundlcd/roundlcd_demo.cpp index aed2862e..54b7fcc8 100644 --- a/examples/breakout_roundlcd/roundlcd_demo.cpp +++ b/examples/breakout_roundlcd/roundlcd_demo.cpp @@ -3,7 +3,8 @@ #include #include -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include "time.h" // Place a 1.3 Round SPI LCD in the *front* slot of breakout garden. @@ -14,7 +15,8 @@ using namespace pimoroni; const int WIDTH = 240; const int HEIGHT = 240; -PicoGraphicsST7789 display(WIDTH, HEIGHT, ROTATE_0, true, nullptr, get_spi_pins(BG_SPI_FRONT)); +ST7789 st7789(WIDTH, HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); constexpr float RADIUS = WIDTH / 2; @@ -37,29 +39,26 @@ Pen from_hsv(float h, float s, float v) { case 5: r = v; g = p; b = q; break; } - return display.create_pen(r, g, b); + return graphics.create_pen(r, g, b); } int main() { - display.set_backlight(255); - - // Delete the default palette and allow us to create up to 256 of our own RGB565 colours - // display.set_palette_mode(PicoGraphicsST7789::PaletteModeUSER); + st7789.set_backlight(255); uint32_t steps = 70; float angle_step = 0.5f; - Pen BLACK = display.create_pen(0, 0, 0); - Pen WHITE = display.create_pen(255, 255, 255); + Pen BLACK = graphics.create_pen(0, 0, 0); + Pen WHITE = graphics.create_pen(255, 255, 255); while(1) { absolute_time_t at = get_absolute_time(); uint64_t t = to_us_since_boot(at) / 100000; float angle = (t % 360) * M_PI / 180.0f; - display.set_pen(BLACK); - display.clear(); - display.set_pen(WHITE); + graphics.set_pen(BLACK); + graphics.clear(); + graphics.set_pen(WHITE); for(auto step = 0u; step < steps; step++) { auto distance = RADIUS / steps * step; @@ -74,11 +73,11 @@ int main() { auto p = from_hsv((t / 10.0f) + distance / 120.0f, 1.0, 1.0); - display.set_pen(p); - display.circle(Point(x, y), l); + graphics.set_pen(p); + graphics.circle(Point(x, y), l); } - display.update(); + st7789.update(&graphics); sleep_ms(10); } } \ No newline at end of file diff --git a/examples/pico_display/CMakeLists.txt b/examples/pico_display/CMakeLists.txt index c857d624..d6f1847a 100644 --- a/examples/pico_display/CMakeLists.txt +++ b/examples/pico_display/CMakeLists.txt @@ -1,11 +1,11 @@ add_executable( pico_display_demo - demo.cpp + pico_display_demo.cpp image_data.cpp ) # Pull in pico libraries that we need -target_link_libraries(pico_display_demo pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled pico_display picographics_st7789) +target_link_libraries(pico_display_demo pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled pico_display pico_graphics st7789) # create map/bin/hex file etc. pico_add_extra_outputs(pico_display_demo) \ No newline at end of file diff --git a/examples/pico_display/demo.cpp b/examples/pico_display/pico_display_demo.cpp similarity index 56% rename from examples/pico_display/demo.cpp rename to examples/pico_display/pico_display_demo.cpp index 18508bc9..6cc55122 100644 --- a/examples/pico_display/demo.cpp +++ b/examples/pico_display/pico_display_demo.cpp @@ -4,18 +4,20 @@ #include #include "pico_display.hpp" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include "rgbled.hpp" using namespace pimoroni; -PicoGraphicsST7789 pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0); +ST7789 st7789(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); int main() { - pico_display.set_backlight(100); + st7789.set_backlight(100); struct pt { float x; @@ -34,30 +36,30 @@ int main() { shape.r = (rand() % 10) + 3; shape.dx = float(rand() % 255) / 128.0f; shape.dy = float(rand() % 255) / 128.0f; - shape.pen = pico_display.create_pen(rand() % 255, rand() % 255, rand() % 255); + shape.pen = graphics.create_pen(rand() % 255, rand() % 255, rand() % 255); shapes.push_back(shape); } uint32_t i = 0; - Pen BG = pico_display.create_pen(120, 40, 60); - Pen YELLOW = pico_display.create_pen(255, 255, 0); - Pen TEAL = pico_display.create_pen(0, 255, 255); - Pen WHITE = pico_display.create_pen(255, 255, 255); + Pen BG = graphics.create_pen(120, 40, 60); + Pen YELLOW = graphics.create_pen(255, 255, 0); + Pen TEAL = graphics.create_pen(0, 255, 255); + Pen WHITE = graphics.create_pen(255, 255, 255); while(true) { - pico_display.set_pen(BG); - pico_display.clear(); + graphics.set_pen(BG); + graphics.clear(); for(auto &shape : shapes) { shape.x += shape.dx; shape.y += shape.dy; if(shape.x < 0) shape.dx *= -1; - if(shape.x >= pico_display.bounds.w) shape.dx *= -1; + if(shape.x >= graphics.bounds.w) shape.dx *= -1; if(shape.y < 0) shape.dy *= -1; - if(shape.y >= pico_display.bounds.h) shape.dy *= -1; + if(shape.y >= graphics.bounds.h) shape.dy *= -1; - pico_display.set_pen(shape.pen); - pico_display.circle(Point(shape.x, shape.y), shape.r); + graphics.set_pen(shape.pen); + graphics.circle(Point(shape.x, shape.y), shape.r); } float led_step = fmod(i / 20.0f, M_PI * 2.0f); @@ -73,17 +75,17 @@ int main() { poly.push_back(Point(50, 85)); poly.push_back(Point(30, 45)); - pico_display.set_pen(YELLOW); + graphics.set_pen(YELLOW); //pico_display.pixel(Point(0, 0)); - pico_display.polygon(poly); + graphics.polygon(poly); - pico_display.set_pen(TEAL); - pico_display.triangle(Point(50, 50), Point(130, 80), Point(80, 110)); + graphics.set_pen(TEAL); + graphics.triangle(Point(50, 50), Point(130, 80), Point(80, 110)); - pico_display.set_pen(WHITE); - pico_display.line(Point(50, 50), Point(120, 80)); - pico_display.line(Point(20, 20), Point(120, 20)); - pico_display.line(Point(20, 20), Point(20, 120)); + graphics.set_pen(WHITE); + graphics.line(Point(50, 50), Point(120, 80)); + graphics.line(Point(20, 20), Point(120, 20)); + graphics.line(Point(20, 20), Point(20, 120)); for(int r = 0; r < 30; r++) { for(int j = 0; j < 10; j++) { @@ -92,12 +94,12 @@ int main() { rads += (float(j) / 100.0f); float cx = sin(rads) * 300.0f; float cy = cos(rads) * 300.0f; - pico_display.line(Point(120, 67), Point(cx + 120, cy + 67)); + graphics.line(Point(120, 67), Point(cx + 120, cy + 67)); } } // update screen - pico_display.update(); + st7789.update(&graphics); sleep_ms(1000 / 60); i++; } diff --git a/examples/pico_display_2/CMakeLists.txt b/examples/pico_display_2/CMakeLists.txt index 51a60e45..0dfd3438 100644 --- a/examples/pico_display_2/CMakeLists.txt +++ b/examples/pico_display_2/CMakeLists.txt @@ -2,11 +2,11 @@ set(OUTPUT_NAME pico_display2_demo) add_executable( ${OUTPUT_NAME} - demo.cpp + pico_display_2_demo.cpp ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled button pico_display_2 picographics_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib hardware_spi hardware_pwm hardware_dma rgbled button pico_display_2 st7789 pico_graphics) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) \ No newline at end of file diff --git a/examples/pico_display_2/demo.cpp b/examples/pico_display_2/pico_display_2_demo.cpp similarity index 70% rename from examples/pico_display_2/demo.cpp rename to examples/pico_display_2/pico_display_2_demo.cpp index 65968e78..ad9d9bdf 100644 --- a/examples/pico_display_2/demo.cpp +++ b/examples/pico_display_2/pico_display_2_demo.cpp @@ -3,16 +3,16 @@ #include #include -#include "graphics_2.hpp" +#include "libraries/pico_display_2/pico_display_2.hpp" #include "drivers/st7789/st7789.hpp" -#include "libraries/pico_graphics/pico_graphics->hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include "rgbled.hpp" #include "button.hpp" using namespace pimoroni; ST7789 st7789(320, 240, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); -PicoGraphics graphics; +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); RGBLED led(PicoDisplay2::LED_R, PicoDisplay2::LED_G, PicoDisplay2::LED_B); @@ -44,12 +44,6 @@ void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { int main() { st7789.set_backlight(255); - // 150k RAM, 65K colours - // graphics = new PicoGraphics_PenRGB565(st7789.width, st7789.height, nullptr); - - // 75k RAM, 256 colours - graphics = new PicoGraphics_PenRGB332(st7789.width, st7789.height, nullptr); - struct pt { float x; float y; @@ -62,19 +56,19 @@ int main() { std::vector shapes; for(int i = 0; i < 100; i++) { pt shape; - shape.x = rand() % graphics->bounds.w; - shape.y = rand() % graphics->bounds.h; + shape.x = rand() % graphics.bounds.w; + shape.y = rand() % graphics.bounds.h; shape.r = (rand() % 10) + 3; shape.dx = float(rand() % 255) / 64.0f; shape.dy = float(rand() % 255) / 64.0f; - shape.pen = graphics->create_pen(rand() % 255, rand() % 255, rand() % 255); + shape.pen = graphics.create_pen(rand() % 255, rand() % 255, rand() % 255); shapes.push_back(shape); } Point text_location(0, 0); - Pen BG = graphics->create_pen(120, 40, 60); - Pen WHITE = graphics->create_pen(255, 255, 255); + Pen BG = graphics.create_pen(120, 40, 60); + Pen WHITE = graphics.create_pen(255, 255, 255); while(true) { if(button_a.raw()) text_location.x -= 1; @@ -83,8 +77,8 @@ int main() { if(button_x.raw()) text_location.y -= 1; if(button_y.raw()) text_location.y += 1; - graphics->set_pen(BG); - graphics->clear(); + graphics.set_pen(BG); + graphics.clear(); for(auto &shape : shapes) { shape.x += shape.dx; @@ -93,21 +87,21 @@ int main() { shape.dx *= -1; shape.x = shape.r; } - if((shape.x + shape.r) >= graphics->bounds.w) { + if((shape.x + shape.r) >= graphics.bounds.w) { shape.dx *= -1; - shape.x = graphics->bounds.w - shape.r; + shape.x = graphics.bounds.w - shape.r; } if((shape.y - shape.r) < 0) { shape.dy *= -1; shape.y = shape.r; } - if((shape.y + shape.r) >= graphics->bounds.h) { + if((shape.y + shape.r) >= graphics.bounds.h) { shape.dy *= -1; - shape.y = graphics->bounds.h - shape.r; + shape.y = graphics.bounds.h - shape.r; } - graphics->set_pen(shape.pen); - graphics->circle(Point(shape.x, shape.y), shape.r); + graphics.set_pen(shape.pen); + graphics.circle(Point(shape.x, shape.y), shape.r); } @@ -119,11 +113,11 @@ int main() { led.set_rgb(r, g, b); - graphics->set_pen(WHITE); - graphics->text("Hello World", text_location, 320); + graphics.set_pen(WHITE); + graphics.text("Hello World", text_location, 320); // update screen - st7789.update(graphics); + st7789.update(&graphics); } return 0; diff --git a/examples/pico_enc_explorer/CMakeLists.txt b/examples/pico_enc_explorer/CMakeLists.txt index 5dac8e43..0a6b4195 100644 --- a/examples/pico_enc_explorer/CMakeLists.txt +++ b/examples/pico_enc_explorer/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_encoder pico_explorer picographics_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_encoder pico_explorer pico_graphics st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/pico_enc_explorer/pico_enc_explorer.cpp b/examples/pico_enc_explorer/pico_enc_explorer.cpp index 4a7b93b9..d2e79507 100644 --- a/examples/pico_enc_explorer/pico_enc_explorer.cpp +++ b/examples/pico_enc_explorer/pico_enc_explorer.cpp @@ -6,23 +6,18 @@ #include "pico_explorer.hpp" #include "breakout_encoder.hpp" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" using namespace pimoroni; -PicoGraphicsST7789 display( - PicoExplorer::WIDTH, - PicoExplorer::HEIGHT, - ROTATE_0, // Rotation - false, // Is it round!? - nullptr, // Buffer - get_spi_pins(BG_SPI_FRONT) -); +ST7789 st7789(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); -Pen BLACK = display.create_pen(0, 0, 0); -Pen RED = display.create_pen(255, 0, 0); -Pen GREEN = display.create_pen(0, 255, 0); -Pen BLUE = display.create_pen(0, 0, 255); +Pen BLACK = graphics.create_pen(0, 0, 0); +Pen RED = graphics.create_pen(255, 0, 0); +Pen GREEN = graphics.create_pen(0, 255, 0); +Pen BLUE = graphics.create_pen(0, 0, 255); static const uint8_t STEPS_PER_REV = 24; @@ -56,49 +51,49 @@ void count_changed(int16_t count) { from_hsv(h, 1.0f, 1.0f, r, g, b); enc.set_led(r, g, b); - display.set_pen(BLACK); - display.clear(); + graphics.set_pen(BLACK); + graphics.clear(); { - display.set_pen(RED); + graphics.set_pen(RED); std::ostringstream ss; ss << "R = "; ss << (int)r; std::string s(ss.str()); - display.text(s, Point(10, 10), 220, 6); + graphics.text(s, Point(10, 10), 220, 6); } { - display.set_pen(GREEN); + graphics.set_pen(GREEN); std::ostringstream ss; ss << "G = "; ss << (int)g; std::string s(ss.str()); - display.text(s, Point(10, 70), 220, 6); + graphics.text(s, Point(10, 70), 220, 6); } { - display.set_pen(BLUE); + graphics.set_pen(BLUE); std::ostringstream ss; ss << "B = "; ss << (int)b; std::string s(ss.str()); - display.text(s, Point(10, 130), 220, 6); + graphics.text(s, Point(10, 130), 220, 6); } { // Shouldn't really use create_pen in-line. // In default (RGB332) palette mode this will lookup the nearest 8-bit colour - display.set_pen(display.create_pen(r, g, b)); + graphics.set_pen(graphics.create_pen(r, g, b)); std::ostringstream ss; ss << "#"; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)r; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)g; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)b; std::string s(ss.str()); - display.text(s, Point(10, 190), 220, 5); + graphics.text(s, Point(10, 190), 220, 5); } - display.update(); + st7789.update(&graphics); } int main() { diff --git a/examples/pico_explorer/CMakeLists.txt b/examples/pico_explorer/CMakeLists.txt index 669c2b1f..0f44144a 100644 --- a/examples/pico_explorer/CMakeLists.txt +++ b/examples/pico_explorer/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable( add_resource(pico_explorer_demo fox.tga) # Pull in pico libraries that we need -target_link_libraries(pico_explorer_demo pico_stdlib pico_explorer msa301 picographics_st7789 button motor analog) +target_link_libraries(pico_explorer_demo pico_stdlib pico_explorer msa301 pico_graphics st7789 button motor analog) # create map/bin/hex file etc. pico_add_extra_outputs(pico_explorer_demo) @@ -16,6 +16,6 @@ add_executable( text_demo.cpp ) -target_link_libraries(text_demo pico_stdlib pico_explorer msa301 picographics_st7789) +target_link_libraries(text_demo pico_stdlib pico_explorer msa301 pico_graphics st7789) pico_add_extra_outputs(text_demo) \ No newline at end of file diff --git a/examples/pico_explorer/pico_explorer_demo.cpp b/examples/pico_explorer/pico_explorer_demo.cpp index ea88ae2a..963d021f 100644 --- a/examples/pico_explorer/pico_explorer_demo.cpp +++ b/examples/pico_explorer/pico_explorer_demo.cpp @@ -4,7 +4,8 @@ #include #include "pico_explorer.hpp" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include "button.hpp" #include "motor.hpp" #include "msa301.hpp" @@ -15,14 +16,8 @@ using namespace motor; extern unsigned char _binary_fox_tga_start[]; -PicoGraphicsST7789 display( - PicoExplorer::WIDTH, - PicoExplorer::HEIGHT, - ROTATE_0, // Rotation - false, // Is it round!? - nullptr, // Buffer - get_spi_pins(BG_SPI_FRONT) -); +ST7789 st7789(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); // Buttons Button button_a(PicoExplorer::A); @@ -101,49 +96,49 @@ int main() { shape.r = (rand() % 10) + 3; shape.dx = float(rand() % 255) / 128.0f; shape.dy = float(rand() % 255) / 128.0f; - shape.pen = display.create_pen(rand() % 255, rand() % 255, rand() % 255); + shape.pen = graphics.create_pen(rand() % 255, rand() % 255, rand() % 255); shapes.push_back(shape); } - Pen BG = display.create_pen(120, 40, 60); - Pen WHITE = display.create_pen(255, 255, 255); - Pen BOX = display.create_pen(55, 65, 75); - Pen PURPLE = display.create_pen(255, 0, 255); + Pen BG = graphics.create_pen(120, 40, 60); + Pen WHITE = graphics.create_pen(255, 255, 255); + Pen BOX = graphics.create_pen(55, 65, 75); + Pen PURPLE = graphics.create_pen(255, 0, 255); uint32_t i = 0; while(true) { - display.set_pen(BG); - display.clear(); + graphics.set_pen(BG); + graphics.clear(); for(auto &shape : shapes) { shape.x += shape.dx; shape.y += shape.dy; if(shape.x < 0) shape.dx *= -1; - if(shape.x >= display.bounds.w) shape.dx *= -1; + if(shape.x >= graphics.bounds.w) shape.dx *= -1; if(shape.y < 0) shape.dy *= -1; - if(shape.y >= display.bounds.h) shape.dy *= -1; + if(shape.y >= graphics.bounds.h) shape.dy *= -1; - display.set_pen(shape.pen); - display.circle(Point(shape.x, shape.y), shape.r); + graphics.set_pen(shape.pen); + graphics.circle(Point(shape.x, shape.y), shape.r); } float rv = adc0.read_voltage() / 3.3f; - display.set_pen(WHITE); - display.circle(Point(rv * 140 + 50, 110), 20); - display.set_pen(display.create_pen(rv * 255, 0, 0)); - display.circle(Point(rv * 140 + 50, 110), 15); + graphics.set_pen(WHITE); + graphics.circle(Point(rv * 140 + 50, 110), 20); + graphics.set_pen(graphics.create_pen(rv * 255, 0, 0)); + graphics.circle(Point(rv * 140 + 50, 110), 15); float gv = adc1.read_voltage() / 3.3f; - display.set_pen(WHITE); - display.circle(Point(gv * 140 + 50, 160), 20); - display.set_pen(display.create_pen(0, gv * 255, 0)); - display.circle(Point(gv * 140 + 50, 160), 15); + graphics.set_pen(WHITE); + graphics.circle(Point(gv * 140 + 50, 160), 20); + graphics.set_pen(graphics.create_pen(0, gv * 255, 0)); + graphics.circle(Point(gv * 140 + 50, 160), 15); float bv = adc2.read_voltage() / 3.3f; - display.set_pen(WHITE); - display.circle(Point(bv * 140 + 50, 210), 20); - display.set_pen(display.create_pen(0, 0, bv * 255)); - display.circle(Point(bv * 140 + 50, 210), 15); + graphics.set_pen(WHITE); + graphics.circle(Point(bv * 140 + 50, 210), 20); + graphics.set_pen(graphics.create_pen(0, 0, bv * 255)); + graphics.circle(Point(bv * 140 + 50, 210), 15); motor1.speed(bv); motor2.speed(rv); @@ -152,98 +147,66 @@ int main() { // display.set_tone(440, 0.5); if(button_a.read()) { - display.set_pen(WHITE); - display.character('A', Point(120, 180), 5); + graphics.set_pen(WHITE); + graphics.character('A', Point(120, 180), 5); } if(button_b.read()) { - display.set_pen(WHITE); - display.character('B', Point(120, 180), 5); + graphics.set_pen(WHITE); + graphics.character('B', Point(120, 180), 5); } if(button_x.read()) { - display.set_pen(WHITE); - display.character('X', Point(120, 180), 5); + graphics.set_pen(WHITE); + graphics.character('X', Point(120, 180), 5); } if(button_y.read()) { - display.set_pen(WHITE); - display.character('Y', Point(120, 180), 5); + graphics.set_pen(WHITE); + graphics.character('Y', Point(120, 180), 5); } float tyoff = cos(i / 20.0f) * 50.0f - 50.0f; Rect text_box(10, 10, 150, 150); - display.set_pen(BOX); - display.rectangle(text_box); + graphics.set_pen(BOX); + graphics.rectangle(text_box); text_box.deflate(10); - display.set_clip(text_box); - display.set_pen(WHITE); - display.text("This is a test of some text data that should wrap nicely onto multiple lines which is dead useful like.", Point(text_box.x, text_box.y + tyoff), 100); + graphics.set_clip(text_box); + graphics.set_pen(WHITE); + graphics.text("This is a test of some text data that should wrap nicely onto multiple lines which is dead useful like.", Point(text_box.x, text_box.y + tyoff), 100); float xoff = sin(i / 20.0f) * 50.0f; xoff += 120 - (81 / 2); float yoff = cos(i / 20.0f) * 50.0f; yoff += 120 - (68 / 2); for(int y = 0; y < 68; y++) { - // uint16_t *dest = display.frame_buffer + (y * 240); uint8_t *src = _binary_fox_tga_start + 18 + (y * 81 * 3); for(int x = 0; x < 81; x++) { uint8_t b = *src++; uint8_t g = *src++; uint8_t r = *src++; - display.set_pen(display.create_pen(r, g, b)); - display.pixel(Point(x + xoff, 68 - y + yoff)); + graphics.set_pen(graphics.create_pen(r, g, b)); + graphics.pixel(Point(x + xoff, 68 - y + yoff)); } } - display.remove_clip(); + graphics.remove_clip(); - display.set_pen(WHITE); - display.text("x: " + std::to_string(int(msa301.get_axis(msa301.X, 16) * 100)), Point(10, 190), 100); - display.text("y: " + std::to_string(int(msa301.get_axis(msa301.Y, 16) * 100)), Point(10, 205), 100); - display.text("z: " + std::to_string(int(msa301.get_axis(msa301.Z, 16) * 100)), Point(10, 220), 100); + graphics.set_pen(WHITE); + graphics.text("x: " + std::to_string(int(msa301.get_axis(msa301.X, 16) * 100)), Point(10, 190), 100); + graphics.text("y: " + std::to_string(int(msa301.get_axis(msa301.Y, 16) * 100)), Point(10, 205), 100); + graphics.text("z: " + std::to_string(int(msa301.get_axis(msa301.Z, 16) * 100)), Point(10, 220), 100); uint16_t xpos = (msa301.get_axis(msa301.X, 16) * 120) + 120; uint16_t ypos = (msa301.get_axis(msa301.Z, 16) * 120) + 120; - display.set_pen(WHITE); - display.circle(Point(xpos, ypos), 20); - display.set_pen(PURPLE); - display.circle(Point(xpos, ypos), 15); + graphics.set_pen(WHITE); + graphics.circle(Point(xpos, ypos), 20); + graphics.set_pen(PURPLE); + graphics.circle(Point(xpos, ypos), 15); - -/* - if(pico_display.is_pressed(pico_display.A)) { - pico_display.rectangle(0, 0, 18, 18); - //sprite(tick, 5, 5, true, green); - }else{ - //sprite(arrow, 10 + bounce, 10, true, white); - } - - if(pico_display.is_pressed(pico_display.B)) { - pico_display.rectangle(0, 49, 18, 18); - //sprite(tick, 5, 54, true, green); - }else{ - //sprite(arrow, 10 - bounce, 50, true, white); - } - - - if(pico_display.is_pressed(pico_display.X)) { - pico_display.rectangle(102, 0, 18, 18); - //sprite(tick, 107, 5, true, green); - }else{ - //sprite(arrow, 102 - bounce, 10, false, white); - } - - if(pico_display.is_pressed(pico_display.Y)) { - pico_display.rectangle(102, 49, 18, 18); - //sprite(tick, 107, 54, true, green); - }else{ - //sprite(arrow, 102 + bounce, 50, false, white); - } -*/ // update screen - display.update(); + st7789.update(&graphics); i++; } diff --git a/examples/pico_explorer/text_demo.cpp b/examples/pico_explorer/text_demo.cpp index 6aa0ff79..e5f63da7 100644 --- a/examples/pico_explorer/text_demo.cpp +++ b/examples/pico_explorer/text_demo.cpp @@ -4,6 +4,9 @@ #include #include "pico_explorer.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" + #include "font6_data.hpp" #include "font8_data.hpp" #include "msa301.hpp" @@ -12,32 +15,32 @@ using namespace pimoroni; extern unsigned char _binary_fox_tga_start[]; -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_explorer(buffer); +ST7789 st7789(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); + MSA301 msa301; int main() { - pico_explorer.init(); - pico_explorer.set_font(&font8); + graphics.set_font(&font8); msa301.init(); - Pen BG = pico_explorer.create_pen(120, 40, 60); - Pen WHITE = pico_explorer.create_pen(255, 255, 255); + Pen BG = graphics.create_pen(120, 40, 60); + Pen WHITE = graphics.create_pen(255, 255, 255); uint32_t i = 0; while(true) { - pico_explorer.set_pen(BG); - pico_explorer.clear(); + graphics.set_pen(BG); + graphics.clear(); - pico_explorer.set_pen(WHITE); - pico_explorer.set_font(&font6); - pico_explorer.text("6x6: The quick, brown fox jumps over the lazy dog! UPPER. lower.", Point(10, 10), 220); - pico_explorer.text("0123456789 !$%^&*()", Point(10, 70), 220); - pico_explorer.set_font(&font8); - pico_explorer.text("6x8: The quick, brown fox jumps over the lazy dog! UPPER. lower.", Point(10, 120), 220); - pico_explorer.text("0123456789 !$%^&*()", Point(10, 180), 220); + graphics.set_pen(WHITE); + graphics.set_font(&font6); + graphics.text("6x6: The quick, brown fox jumps over the lazy dog! UPPER. lower.", Point(10, 10), 220); + graphics.text("0123456789 !$%^&*()", Point(10, 70), 220); + graphics.set_font(&font8); + graphics.text("6x8: The quick, brown fox jumps over the lazy dog! UPPER. lower.", Point(10, 120), 220); + graphics.text("0123456789 !$%^&*()", Point(10, 180), 220); - pico_explorer.update(); + st7789.update(&graphics); i++; } diff --git a/examples/pico_explorer_encoder/CMakeLists.txt b/examples/pico_explorer_encoder/CMakeLists.txt index bfc53d45..dba74a85 100644 --- a/examples/pico_explorer_encoder/CMakeLists.txt +++ b/examples/pico_explorer_encoder/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable( pico_generate_pio_header(pico_explorer_encoder ${CMAKE_CURRENT_LIST_DIR}/quadrature_out.pio) # Pull in pico libraries that we need -target_link_libraries(pico_explorer_encoder pico_stdlib pico_explorer encoder button motor picographics_st7789) +target_link_libraries(pico_explorer_encoder pico_stdlib pico_explorer encoder button motor pico_graphics st7789) # create map/bin/hex file etc. pico_add_extra_outputs(pico_explorer_encoder) \ No newline at end of file diff --git a/examples/pico_explorer_encoder/pico_explorer_encoder.cpp b/examples/pico_explorer_encoder/pico_explorer_encoder.cpp index d95afb68..61cafc02 100644 --- a/examples/pico_explorer_encoder/pico_explorer_encoder.cpp +++ b/examples/pico_explorer_encoder/pico_explorer_encoder.cpp @@ -4,7 +4,8 @@ #include "pico/stdlib.h" #include "encoder.hpp" #include "quadrature_out.pio.h" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include "button.hpp" /* @@ -93,14 +94,8 @@ enum DrawState { //-------------------------------------------------- // Variables //-------------------------------------------------- -PicoGraphicsST7789 display( - PicoExplorer::WIDTH, - PicoExplorer::HEIGHT, - ROTATE_0, // Rotation - false, // Is it round!? - nullptr, // Buffer - get_spi_pins(BG_SPI_FRONT) -); +ST7789 st7789(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); Button button_a(PicoExplorer::A); Button button_b(PicoExplorer::B); @@ -182,13 +177,13 @@ uint32_t draw_plot(Point p1, Point p2, volatile bool (&readings)[READINGS_SIZE], switch(draw_state) { case DRAW_TRANSITION: for(uint8_t y = p1.y; y < p2.y; y++) - display.pixel(Point(x + p1.x, y)); + graphics.pixel(Point(x + p1.x, y)); break; case DRAW_HIGH: - display.pixel(Point(x + p1.x, p1.y)); + graphics.pixel(Point(x + p1.x, p1.y)); break; case DRAW_LOW: - display.pixel(Point(x + p1.x, p2.y - 1)); + graphics.pixel(Point(x + p1.x, p2.y - 1)); break; } } @@ -255,7 +250,7 @@ void setup() { // MAIN //////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - Pen WHITE = display.create_pen(255, 255, 255); + Pen WHITE = graphics.create_pen(255, 255, 255); // Perform the main setup for the demo setup(); @@ -321,16 +316,16 @@ int main() { //-------------------------------------------------- // Draw the encoder readings to the screen as a signal plot - display.set_pen(display.create_pen(0, 0, 0)); - display.clear(); + graphics.set_pen(graphics.create_pen(0, 0, 0)); + graphics.clear(); drawing_to_screen = true; - display.set_pen(display.create_pen(255, 255, 0)); + graphics.set_pen(graphics.create_pen(255, 255, 0)); uint32_t local_pos = next_reading_index; uint32_t alignment_offset = draw_plot(Point(0, 10), Point(PicoExplorer::WIDTH, 10 + 50), enc_a_readings, local_pos, current_zoom_level > EDGE_ALIGN_ABOVE_ZOOM); - display.set_pen(display.create_pen(0, 255, 255)); + graphics.set_pen(graphics.create_pen(0, 255, 255)); draw_plot(Point(0, 80), Point(PicoExplorer::WIDTH, 80 + 50), enc_b_readings, (local_pos + (READINGS_SIZE - alignment_offset)) % READINGS_SIZE, false); // Copy values that may have been stored in the scratch buffers, back into the main buffers @@ -346,49 +341,49 @@ int main() { drawing_to_screen = false; next_scratch_index = 0; - display.set_pen(WHITE); - display.character('A', Point(5, 10 + 15), 3); - display.character('B', Point(5, 80 + 15), 3); + graphics.set_pen(WHITE); + graphics.character('A', Point(5, 10 + 15), 3); + graphics.character('B', Point(5, 80 + 15), 3); if(current_zoom_level < 10) - display.text("x" + std::to_string(current_zoom_level), Point(220, 62), 200, 2); + graphics.text("x" + std::to_string(current_zoom_level), Point(220, 62), 200, 2); else if(current_zoom_level < 100) - display.text("x" + std::to_string(current_zoom_level), Point(210, 62), 200, 2); + graphics.text("x" + std::to_string(current_zoom_level), Point(210, 62), 200, 2); else - display.text("x" + std::to_string(current_zoom_level), Point(200, 62), 200, 2); + graphics.text("x" + std::to_string(current_zoom_level), Point(200, 62), 200, 2); //-------------------------------------------------- // Write out the count, frequency and rpm of the encoder - display.set_pen(display.create_pen(8, 8, 8)); - display.rectangle(Rect(0, 140, PicoExplorer::WIDTH, PicoExplorer::HEIGHT - 140)); + graphics.set_pen(graphics.create_pen(8, 8, 8)); + graphics.rectangle(Rect(0, 140, PicoExplorer::WIDTH, PicoExplorer::HEIGHT - 140)); - display.set_pen(display.create_pen(64, 64, 64)); - display.rectangle(Rect(0, 140, PicoExplorer::WIDTH, 2)); + graphics.set_pen(graphics.create_pen(64, 64, 64)); + graphics.rectangle(Rect(0, 140, PicoExplorer::WIDTH, 2)); { std::stringstream sstream; sstream << capture.count(); - display.set_pen(WHITE); display.text("Count:", Point(10, 150), 200, 3); - display.set_pen(display.create_pen(255, 128, 255)); display.text(sstream.str(), Point(110, 150), 200, 3); + graphics.set_pen(WHITE); graphics.text("Count:", Point(10, 150), 200, 3); + graphics.set_pen(graphics.create_pen(255, 128, 255)); graphics.text(sstream.str(), Point(110, 150), 200, 3); } { std::stringstream sstream; sstream << std::fixed << std::setprecision(1) << capture.frequency() << "hz"; - display.set_pen(WHITE); display.text("Freq: ", Point(10, 180), 220, 3); - display.set_pen(display.create_pen(128, 255, 255)); display.text(sstream.str(), Point(90, 180), 220, 3); + graphics.set_pen(WHITE); graphics.text("Freq: ", Point(10, 180), 220, 3); + graphics.set_pen(graphics.create_pen(128, 255, 255)); graphics.text(sstream.str(), Point(90, 180), 220, 3); } { std::stringstream sstream; sstream << std::fixed << std::setprecision(1) << capture.revolutions_per_minute(); - display.set_pen(WHITE); display.text("RPM: ", Point(10, 210), 220, 3); - display.set_pen(display.create_pen(255, 255, 128)); display.text(sstream.str(), Point(80, 210), 220, 3); + graphics.set_pen(WHITE); graphics.text("RPM: ", Point(10, 210), 220, 3); + graphics.set_pen(graphics.create_pen(255, 255, 128)); graphics.text(sstream.str(), Point(80, 210), 220, 3); } - display.update(); // Refresh the screen + st7789.update(&graphics); // Refresh the screen gpio_put(PICO_DEFAULT_LED_PIN, false); // Show the screen refresh has ended } } diff --git a/examples/pico_pot_explorer/CMakeLists.txt b/examples/pico_pot_explorer/CMakeLists.txt index f2b47485..433e6096 100644 --- a/examples/pico_pot_explorer/CMakeLists.txt +++ b/examples/pico_pot_explorer/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_potentiometer pico_explorer picographics_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_potentiometer pico_explorer pico_graphics st7789) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/pico_pot_explorer/pico_pot_explorer.cpp b/examples/pico_pot_explorer/pico_pot_explorer.cpp index 49f4f067..a375b8f0 100644 --- a/examples/pico_pot_explorer/pico_pot_explorer.cpp +++ b/examples/pico_pot_explorer/pico_pot_explorer.cpp @@ -7,23 +7,18 @@ #include "common/pimoroni_i2c.hpp" #include "pico_explorer.hpp" #include "breakout_potentiometer.hpp" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" using namespace pimoroni; -PicoGraphicsST7789 display( - PicoExplorer::WIDTH, - PicoExplorer::HEIGHT, - ROTATE_0, // Rotation - false, // Is it round!? - nullptr, // Buffer - get_spi_pins(BG_SPI_FRONT) -); +ST7789 st7789(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); -Pen BLACK = display.create_pen(0, 0, 0); -Pen RED = display.create_pen(255, 0, 0); -Pen GREEN = display.create_pen(0, 255, 0); -Pen BLUE = display.create_pen(0, 0, 255); +Pen BLACK = graphics.create_pen(0, 0, 0); +Pen RED = graphics.create_pen(255, 0, 0); +Pen GREEN = graphics.create_pen(0, 255, 0); +Pen BLUE = graphics.create_pen(0, 0, 255); I2C i2c(PICO_EXPLORER); BreakoutPotentiometer pot(&i2c); @@ -71,49 +66,49 @@ int main() { from_hsv(percent, 1.0f, 1.0f, r, g, b); pot.set_led(r, g, b); - display.set_pen(BLACK); - display.clear(); + graphics.set_pen(BLACK); + graphics.clear(); { - display.set_pen(RED); + graphics.set_pen(RED); std::ostringstream ss; ss << "R = "; ss << (int)r; std::string s(ss.str()); - display.text(s, Point(10, 10), 220, 6); + graphics.text(s, Point(10, 10), 220, 6); } { - display.set_pen(GREEN); + graphics.set_pen(GREEN); std::ostringstream ss; ss << "G = "; ss << (int)g; std::string s(ss.str()); - display.text(s, Point(10, 70), 220, 6); + graphics.text(s, Point(10, 70), 220, 6); } { - display.set_pen(BLUE); + graphics.set_pen(BLUE); std::ostringstream ss; ss << "B = "; ss << (int)b; std::string s(ss.str()); - display.text(s, Point(10, 130), 220, 6); + graphics.text(s, Point(10, 130), 220, 6); } { // Shouldn't really use create_pen in-line. // In default (RGB332) palette mode this will lookup the nearest 8-bit colour - display.set_pen(display.create_pen(r, g, b)); + graphics.set_pen(graphics.create_pen(r, g, b)); std::ostringstream ss; ss << "#"; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)r; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)g; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)b; std::string s(ss.str()); - display.text(s, Point(10, 190), 220, 5); + graphics.text(s, Point(10, 190), 220, 5); } - display.update(); + st7789.update(&graphics); } } else { diff --git a/examples/pico_rtc_display/CMakeLists.txt b/examples/pico_rtc_display/CMakeLists.txt index 7b2f6207..df7cba8c 100644 --- a/examples/pico_rtc_display/CMakeLists.txt +++ b/examples/pico_rtc_display/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_explorer pico_display breakout_rtc picographics_st7789 button rgbled) +target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_explorer pico_display breakout_rtc pico_graphics st7789 button rgbled) # create map/bin/hex file etc. pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/pico_rtc_display/pico_rtc_display.cpp b/examples/pico_rtc_display/pico_rtc_display.cpp index eee36499..2a3db860 100644 --- a/examples/pico_rtc_display/pico_rtc_display.cpp +++ b/examples/pico_rtc_display/pico_rtc_display.cpp @@ -27,7 +27,8 @@ #endif #include "breakout_rtc.hpp" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include "drivers/button/button.hpp" #include "drivers/rgbled/rgbled.hpp" @@ -60,7 +61,8 @@ Button button_y(PicoDisplay::Y); RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); #endif -PicoGraphicsST7789 display(screen_width, screen_height, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); +ST7789 st7789(screen_width, screen_height, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); BreakoutRTC rtc; @@ -94,10 +96,10 @@ void flash_led(uint32_t curr_count) { } int main() { - Pen WHITE = display.create_pen(255, 255, 255); - Pen BG = display.create_pen(55, 65, 75); - Pen RED = display.create_pen(255, 0, 0); - Pen GREEN = display.create_pen(0, 255, 0); + Pen WHITE = graphics.create_pen(255, 255, 255); + Pen BG = graphics.create_pen(55, 65, 75); + Pen RED = graphics.create_pen(255, 0, 0); + Pen GREEN = graphics.create_pen(0, 255, 0); rtc.init(); // rtc.setup(false); @@ -208,77 +210,77 @@ int main() { } Rect text_box(5, 5, screen_width-10, screen_height-10); - display.set_pen(BG); - display.rectangle(text_box); + graphics.set_pen(BG); + graphics.rectangle(text_box); // text_box.deflate(10); - display.set_clip(text_box); - display.set_pen(WHITE); + graphics.set_clip(text_box); + graphics.set_pen(WHITE); switch(display_mode) { case MODE_DISP_CLOCK: // Show the clock face flash_led(0); if(rtc.update_time()) { - display.text("Set Timer", + graphics.text("Set Timer", Point(text_box.x, text_box.y+2), 230, 1); - display.set_pen(GREEN); - display.text(rtc.string_date(), + graphics.set_pen(GREEN); + graphics.text(rtc.string_date(), Point(text_box.x, text_box.y+20), 230, 4); - display.set_pen(RED); - display.text(rtc.string_time(), + graphics.set_pen(RED); + graphics.text(rtc.string_time(), Point(text_box.x, text_box.y+60), 230, 6); - display.set_pen(WHITE); - display.text("Clock", + graphics.set_pen(WHITE); + graphics.text("Clock", Point(text_box.x, text_box.y+screen_height-20), 230, 1); } else { sprintf(buf, "Time: rtc.updateTime() ret err"); - display.text(buf, + graphics.text(buf, Point(text_box.x, text_box.y), 30, 2); } break; case MODE_DISP_TIMER: - display.text("Set Timer", + graphics.text("Set Timer", Point(text_box.x, text_box.y+2), 230, 1); if(rtc.read_timer_interrupt_flag()) { // Go periodic time interupt - say loop ended - display.set_pen(RED); + graphics.set_pen(RED); sprintf(buf, "%s", "Timer complete"); - display.text(buf, + graphics.text(buf, Point(text_box.x, text_box.y+30), 230, 4); - display.set_pen(WHITE); + graphics.set_pen(WHITE); flash_led(i); } else { sprintf(buf, "%s %d", "Timer running", rtc.get_timer_count()); - display.text(buf, + graphics.text(buf, Point(text_box.x, text_box.y+30), 230, 3); } - display.text("Clock", + graphics.text("Clock", Point(text_box.x, text_box.y+screen_height-20), 230, 1); break; case MODE_SET_TIMER: flash_led(0); - display.text("Run Timer", + graphics.text("Run Timer", Point(text_box.x, text_box.y+2), 230, 1); - display.text("+ Time", + graphics.text("+ Time", Point(text_box.x+screen_width-42, text_box.y+2), 230, 1); sprintf(buf, "Time %d secs", timer_count); - display.text(buf, + graphics.text(buf, Point(text_box.x, text_box.y+30), 230, 3); - display.text("Clock", + graphics.text("Clock", Point(text_box.x, text_box.y+screen_height-20), 230, 1); - display.text("- Time", + graphics.text("- Time", Point(text_box.x+screen_width-42, text_box.y+screen_height-20), 230, 1); break; } - display.remove_clip(); + graphics.remove_clip(); // update screen - display.update(); + st7789.update(&graphics); i++; } diff --git a/examples/pico_tof_display/CMakeLists.txt b/examples/pico_tof_display/CMakeLists.txt index 06a8417a..16b4c9b4 100644 --- a/examples/pico_tof_display/CMakeLists.txt +++ b/examples/pico_tof_display/CMakeLists.txt @@ -4,7 +4,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(tof_display pico_stdlib pico_explorer pico_display vl53l1x picographics_st7789 button) +target_link_libraries(tof_display pico_stdlib pico_explorer pico_display vl53l1x pico_graphics st7789 button) pico_enable_stdio_uart(tof_display 1) diff --git a/examples/pico_tof_display/pico_tof_display.cpp b/examples/pico_tof_display/pico_tof_display.cpp index 86bacb2f..4b60b93e 100644 --- a/examples/pico_tof_display/pico_tof_display.cpp +++ b/examples/pico_tof_display/pico_tof_display.cpp @@ -26,19 +26,13 @@ #include "vl53l1x.hpp" #include "drivers/button/button.hpp" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" using namespace pimoroni; #ifdef USE_PICO_EXPLORER -PicoGraphicsST7789 pico_display( - PicoExplorer::WIDTH, - PicoExplorer::HEIGHT, - ROTATE_0, // Rotation - false, // Is it round!? - nullptr, // Buffer - get_spi_pins(BG_SPI_FRONT) -); +ST7789 st7789(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); Button button_a(PicoExplorer::A); Button button_b(PicoExplorer::B); @@ -59,14 +53,7 @@ uint16_t disptext_dist_xoff = 10; uint16_t disptext_dist_yoff = 90; uint16_t disptext_dist_size = 6; #else -PicoGraphicsST7789 pico_display( - PicoDisplay::WIDTH, - PicoDisplay::HEIGHT, - ROTATE_0, // Rotation - false, // Is it round!? - nullptr, // Buffer - get_spi_pins(BG_SPI_FRONT) -); +ST7789 st7789(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); Button button_a(PicoDisplay::A); Button button_b(PicoDisplay::B); @@ -88,9 +75,10 @@ uint16_t disptext_dist_yoff = 45; uint16_t disptext_dist_size = 4; #endif +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); -uint16_t screen_width = pico_display.bounds.w; -uint16_t screen_height = pico_display.bounds.h; +uint16_t screen_width = graphics.bounds.w; +uint16_t screen_height = graphics.bounds.h; #define MM_TO_INCH 25.4 @@ -110,10 +98,10 @@ void flash_led(uint32_t curr_count) { #ifndef USE_PICO_EXPLORER if ((curr_count % FLASH_MOD) < (FLASH_MOD / 2)) { // value less than half modded number - LED off - pico_display.set_led(0, 0, 0); + //pico_display.set_led(0, 0, 0); // TODO use RGBLED } else { // value more than half modded number - LED on - pico_display.set_led(128, 128, 128); + //pico_display.set_led(128, 128, 128); // TODO use RGBLED } #endif } @@ -141,9 +129,9 @@ int main() { // Whether the display is being held bool dist_held = false; - Pen WHITE = pico_display.create_pen(255, 255, 255); - Pen REDDISH = pico_display.create_pen(255, 64, 64); - Pen BG = pico_display.create_pen(55, 65, 75); + Pen WHITE = graphics.create_pen(255, 255, 255); + Pen REDDISH = graphics.create_pen(255, 64, 64); + Pen BG = graphics.create_pen(55, 65, 75); while(true) { // bool a_pressed = button_a.read(); @@ -168,30 +156,30 @@ int main() { } Rect text_box(5, 5, screen_width-10, screen_height-10); - pico_display.set_pen(BG); - pico_display.rectangle(text_box); + graphics.set_pen(BG); + graphics.rectangle(text_box); // text_box.deflate(10); - pico_display.set_clip(text_box); - pico_display.set_pen(WHITE); + graphics.set_clip(text_box); + graphics.set_pen(WHITE); // Show the current distance flash_led(0); if (vl53_present) { - pico_display.text("Units", + graphics.text("Units", Point(text_box.x+disptext_x_reminder_xoff, text_box.y+disptext_x_reminder_yoff), 230, disptext_reminder_size); - pico_display.text("+Mode", + graphics.text("+Mode", Point(text_box.x+disptext_y_reminder_xoff, text_box.y+disptext_y_reminder_yoff), 230, disptext_reminder_size); if(dist_held) { - pico_display.set_pen(REDDISH); + graphics.set_pen(REDDISH); } - pico_display.text("Hold", + graphics.text("Hold", Point(text_box.x+disptext_b_reminder_xoff, text_box.y+disptext_b_reminder_yoff), 230, disptext_reminder_size); - pico_display.set_pen(WHITE); + graphics.set_pen(WHITE); sprintf(buf, "Mode: %s", mode_to_text[vl53_mode]); - pico_display.text(buf, + graphics.text(buf, Point(text_box.x+disptext_mode_xoff, text_box.y+disptext_mode_yoff), 230, disptext_mode_size); @@ -204,19 +192,19 @@ int main() { sprintf(buf, "%dft %.1fin", ft, ((float)dist/MM_TO_INCH)-ft*12.0); } - pico_display.text(buf, + graphics.text(buf, Point(text_box.x+disptext_dist_xoff, text_box.y+disptext_dist_yoff), 120, disptext_dist_size); } else { - pico_display.text("VL53L1X Missing", + graphics.text("VL53L1X Missing", Point(text_box.x+disptext_dist_xoff, text_box.y+disptext_dist_yoff), 230, disptext_dist_size); } - pico_display.remove_clip(); + graphics.remove_clip(); // update screen - pico_display.update(); + st7789.update(&graphics); i++; } diff --git a/examples/pico_trackball_display/CMakeLists.txt b/examples/pico_trackball_display/CMakeLists.txt index dc065c5e..ac18ef67 100644 --- a/examples/pico_trackball_display/CMakeLists.txt +++ b/examples/pico_trackball_display/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_explorer pico_display breakout_trackball picographics_st7789) +target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_explorer pico_display breakout_trackball pico_graphics st7789) pico_enable_stdio_uart(${OUTPUT_NAME} 1) diff --git a/examples/pico_trackball_display/pico_trackball_display.cpp b/examples/pico_trackball_display/pico_trackball_display.cpp index b045b899..bdb5e27d 100644 --- a/examples/pico_trackball_display/pico_trackball_display.cpp +++ b/examples/pico_trackball_display/pico_trackball_display.cpp @@ -21,11 +21,12 @@ #ifdef USE_PICO_EXPLORER #include "pico_explorer.hpp" #else -#include "display.hpp" +#include "pico_display.hpp" #endif #include "breakout_trackball.hpp" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" using namespace pimoroni; @@ -44,7 +45,8 @@ const uint16_t screen_width = PicoDisplay::WIDTH; const uint16_t screen_height = PicoDisplay::HEIGHT; #endif -PicoGraphicsST7789 display(screen_width, screen_height, ROTATE_0, false, nullptr, get_spi_pins(BG_SPI_FRONT)); +ST7789 st7789(screen_width, screen_height, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); const Point screen_centre(screen_width / 2, screen_height / 2); const uint16_t circle_radius = std::min(screen_centre.x, screen_centre.y) / 4; @@ -84,10 +86,10 @@ int main() { positions[i] = pos; } - Pen WHITE = display.create_pen(255, 255, 255); - Pen BLACK = display.create_pen(0, 0, 0); - Pen LIGHT_GREY = display.create_pen(212, 212, 212); - Pen MID_GREY = display.create_pen(128, 128, 128); + Pen WHITE = graphics.create_pen(255, 255, 255); + Pen BLACK = graphics.create_pen(0, 0, 0); + Pen LIGHT_GREY = graphics.create_pen(212, 212, 212); + Pen MID_GREY = graphics.create_pen(128, 128, 128); while(true) { Trackball::State state = trackball.read(); @@ -95,46 +97,46 @@ int main() { y = std::min(std::max(y - state.up + state.down, 0), (int)screen_height); Point cursor_pos(x, y); - display.set_pen(BLACK); - display.clear(); + graphics.set_pen(BLACK); + graphics.clear(); //Draw a set of circles in a ring around the screen centre for(uint8_t i = 0; i < NUM_CIRCLES; i++) { TrackballColour col = colour_circles[i]; if(circle_states[i]) { - display.set_pen(display.create_pen(col.r, col.g, col.b)); - display.circle(positions[i], circle_radius + circle_border); - display.set_pen(display.create_pen(col.r >> 1, col.g >> 1, col.b >> 1)); - display.circle(positions[i], circle_radius); + graphics.set_pen(graphics.create_pen(col.r, col.g, col.b)); + graphics.circle(positions[i], circle_radius + circle_border); + graphics.set_pen(graphics.create_pen(col.r >> 1, col.g >> 1, col.b >> 1)); + graphics.circle(positions[i], circle_radius); } else { - display.set_pen(display.create_pen(col.r >> 1, col.g >> 1, col.b >> 1)); - display.circle(positions[i], circle_radius + circle_border); - display.set_pen(display.create_pen(col.r, col.g, col.b)); - display.circle(positions[i], circle_radius); + graphics.set_pen(graphics.create_pen(col.r >> 1, col.g >> 1, col.b >> 1)); + graphics.circle(positions[i], circle_radius + circle_border); + graphics.set_pen(graphics.create_pen(col.r, col.g, col.b)); + graphics.circle(positions[i], circle_radius); } } //Draw a centre circle if(centre_circle_state) { - display.set_pen(WHITE); - display.circle(screen_centre, circle_radius + circle_border); - display.set_pen(MID_GREY); - display.circle(screen_centre, circle_radius); + graphics.set_pen(WHITE); + graphics.circle(screen_centre, circle_radius + circle_border); + graphics.set_pen(MID_GREY); + graphics.circle(screen_centre, circle_radius); } else { - display.set_pen(MID_GREY); - display.circle(screen_centre, circle_radius + circle_border); - display.set_pen(WHITE); - display.circle(screen_centre, circle_radius); + graphics.set_pen(MID_GREY); + graphics.circle(screen_centre, circle_radius + circle_border); + graphics.set_pen(WHITE); + graphics.circle(screen_centre, circle_radius); } //Draw the cursor - display.set_pen(BLACK); - display.circle(cursor_pos, cursor_radius + cursor_border); - display.set_pen(LIGHT_GREY); - display.circle(cursor_pos, cursor_radius); + graphics.set_pen(BLACK); + graphics.circle(cursor_pos, cursor_radius + cursor_border); + graphics.set_pen(LIGHT_GREY); + graphics.circle(cursor_pos, cursor_radius); int16_t x_diff = cursor_pos.x - screen_centre.x; int16_t y_diff = cursor_pos.y - screen_centre.y; @@ -166,7 +168,7 @@ int main() { } // update screen - display.update(); + st7789.update(&graphics); } return 0; diff --git a/examples/tufty2040/tufty2040_drawing.cmake b/examples/tufty2040/tufty2040_drawing.cmake index ff63d762..17dee086 100644 --- a/examples/tufty2040/tufty2040_drawing.cmake +++ b/examples/tufty2040/tufty2040_drawing.cmake @@ -4,7 +4,8 @@ add_executable(${OUTPUT_NAME} tufty2040_drawing.cpp) target_link_libraries(${OUTPUT_NAME} tufty2040 hardware_spi - picographics_st7789 + pico_graphics + st7789 button ) diff --git a/examples/tufty2040/tufty2040_drawing.cpp b/examples/tufty2040/tufty2040_drawing.cpp index 63ced2c4..48f68e2b 100644 --- a/examples/tufty2040/tufty2040_drawing.cpp +++ b/examples/tufty2040/tufty2040_drawing.cpp @@ -7,7 +7,8 @@ #include "pico/platform.h" #include "common/pimoroni_common.hpp" -#include "picographics_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include "tufty2040.hpp" #include "button.hpp" @@ -15,8 +16,10 @@ using namespace pimoroni; Tufty2040 tufty; -PicoGraphicsST7789 display( - Tufty2040::WIDTH, Tufty2040::HEIGHT, ROTATE_0, nullptr, +ST7789 st7789( + Tufty2040::WIDTH, + Tufty2040::HEIGHT, + ROTATE_0, ParallelPins{ Tufty2040::LCD_CS, Tufty2040::LCD_DC, @@ -27,6 +30,8 @@ PicoGraphicsST7789 display( } ); +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); + Button button_a(Tufty2040::A); Button button_b(Tufty2040::B); Button button_c(Tufty2040::C); @@ -59,10 +64,10 @@ void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { } int main() { - display.set_backlight(255); + st7789.set_backlight(255); - Pen WHITE = display.create_pen(255, 255, 255); - Pen BG = display.create_pen(120, 40, 60); + Pen WHITE = graphics.create_pen(255, 255, 255); + Pen BG = graphics.create_pen(120, 40, 60); struct pt { float x; @@ -76,12 +81,12 @@ int main() { std::vector shapes; for(int i = 0; i < 100; i++) { pt shape; - shape.x = rand() % display.bounds.w; - shape.y = rand() % display.bounds.h; + shape.x = rand() % graphics.bounds.w; + shape.y = rand() % graphics.bounds.h; shape.r = (rand() % 10) + 3; shape.dx = float(rand() % 255) / 64.0f; shape.dy = float(rand() % 255) / 64.0f; - shape.pen = display.create_pen(rand() % 255, rand() % 255, rand() % 255); + shape.pen = graphics.create_pen(rand() % 255, rand() % 255, rand() % 255); shapes.push_back(shape); } @@ -90,8 +95,8 @@ int main() { while(true) { - display.set_pen(BG); - display.clear(); + graphics.set_pen(BG); + graphics.clear(); for(auto &shape : shapes) { shape.x += shape.dx; @@ -100,30 +105,30 @@ int main() { shape.dx *= -1; shape.x = shape.r; } - if((shape.x + shape.r) >= display.bounds.w) { + if((shape.x + shape.r) >= graphics.bounds.w) { shape.dx *= -1; - shape.x = display.bounds.w - shape.r; + shape.x = graphics.bounds.w - shape.r; } if((shape.y - shape.r) < 0) { shape.dy *= -1; shape.y = shape.r; } - if((shape.y + shape.r) >= display.bounds.h) { + if((shape.y + shape.r) >= graphics.bounds.h) { shape.dy *= -1; - shape.y = display.bounds.h - shape.r; + shape.y = graphics.bounds.h - shape.r; } - display.set_pen(shape.pen); - display.circle(Point(shape.x, shape.y), shape.r); + graphics.set_pen(shape.pen); + graphics.circle(Point(shape.x, shape.y), shape.r); } - display.set_pen(WHITE); - display.text("Hello World", text_location, 320); + graphics.set_pen(WHITE); + graphics.text("Hello World", text_location, 320); // update screen - display.update(); + st7789.update(&graphics); i+=10; tufty.led(i); diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 4eb2dcd8..a7498a1a 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -4,7 +4,6 @@ add_subdirectory(breakout_dotmatrix) add_subdirectory(breakout_encoder) add_subdirectory(breakout_ioexpander) add_subdirectory(breakout_ltr559) -add_subdirectory(breakout_colourlcd160x80) add_subdirectory(breakout_rgbmatrix5x5) add_subdirectory(breakout_matrix11x7) add_subdirectory(breakout_mics6814) @@ -17,7 +16,6 @@ add_subdirectory(breakout_sgp30) add_subdirectory(breakout_as7262) add_subdirectory(breakout_msa301) add_subdirectory(breakout_bh1745) -add_subdirectory(picographics_st7789) add_subdirectory(pico_graphics) add_subdirectory(pico_display) add_subdirectory(pico_display_2) diff --git a/libraries/breakout_colourlcd160x80/CMakeLists.txt b/libraries/breakout_colourlcd160x80/CMakeLists.txt deleted file mode 100644 index d855c97b..00000000 --- a/libraries/breakout_colourlcd160x80/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -include(breakout_colourlcd160x80.cmake) diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cmake b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cmake deleted file mode 100644 index ece9be90..00000000 --- a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cmake +++ /dev/null @@ -1,11 +0,0 @@ -set(LIB_NAME breakout_colourlcd160x80) -add_library(${LIB_NAME} INTERFACE) - -target_sources(${LIB_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp -) - -target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) - -# Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib st7735 pico_graphics hardware_spi) diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp deleted file mode 100644 index d35e831e..00000000 --- a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "breakout_colourlcd160x80.hpp" - -namespace pimoroni { - - -} \ No newline at end of file diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp deleted file mode 100644 index b2eadd27..00000000 --- a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "drivers/st7735/st7735.hpp" -#include "libraries/pico_graphics/pico_graphics.hpp" -#include "common/pimoroni_common.hpp" -#include "common/pimoroni_bus.hpp" - -namespace pimoroni { - - class BreakoutColourLCD160x80 : public PicoGraphics_PenRGB565 { - //-------------------------------------------------- - // Constants - //-------------------------------------------------- - public: - static const int WIDTH = 160; - static const int HEIGHT = 80; - - //-------------------------------------------------- - // Variables - //-------------------------------------------------- - private: - ST7735 screen; - - - //-------------------------------------------------- - // Constructors/Destructor - //-------------------------------------------------- - public: - - BreakoutColourLCD160x80(void *frame_buffer) - : BreakoutColourLCD160x80(frame_buffer, get_spi_pins(BG_SPI_FRONT)) { - } - - BreakoutColourLCD160x80(void *frame_buffer, SPIPins bus_pins) - : PicoGraphics_PenRGB565(WIDTH, HEIGHT, frame_buffer), screen(WIDTH, HEIGHT, bus_pins){ - } - - void update() { - screen.update(this); - } - - void set_backlight(uint8_t brightness) { - screen.set_backlight(brightness); - } - }; - -} diff --git a/libraries/breakout_colourlcd240x240/CMakeLists.txt b/libraries/breakout_colourlcd240x240/CMakeLists.txt deleted file mode 100644 index 2c234a7d..00000000 --- a/libraries/breakout_colourlcd240x240/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -set(LIB_NAME breakout_colourlcd240x240) -add_library(${LIB_NAME} INTERFACE) - -target_sources(${LIB_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp -) - -target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) - -# Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib st7789 pico_graphics) \ No newline at end of file diff --git a/libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.cmake b/libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.cmake deleted file mode 100644 index cf2f3148..00000000 --- a/libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.cmake +++ /dev/null @@ -1,14 +0,0 @@ -include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/st7789/st7789.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/../pico_graphics/pico_graphics.cmake) - -set(LIB_NAME breakout_colourlcd240x240) -add_library(${LIB_NAME} INTERFACE) - -target_sources(${LIB_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp -) - -target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) - -# Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib st7789 pico_graphics) diff --git a/libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp b/libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp deleted file mode 100644 index f24f0e70..00000000 --- a/libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "breakout_colourlcd240x240.hpp" - -namespace pimoroni { - - BreakoutColourLCD240x240::BreakoutColourLCD240x240(uint16_t *buf) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, - PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) { - __fb = buf; - } - - BreakoutColourLCD240x240::BreakoutColourLCD240x240(uint16_t *buf, spi_inst_t *spi, - uint cs, uint dc, uint sck, uint mosi, uint bl) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, spi, cs, dc, sck, mosi, bl) { - __fb = buf; - } - - BreakoutColourLCD240x240::BreakoutColourLCD240x240(uint16_t *buf, BG_SPI_SLOT slot) - : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf, - PIMORONI_SPI_DEFAULT_INSTANCE, screen.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, screen.get_slot_bl(slot)) { - __fb = buf; - } - - void BreakoutColourLCD240x240::init() { - } - - spi_inst_t* BreakoutColourLCD240x240::get_spi() const { - return screen.get_spi(); - } - - int BreakoutColourLCD240x240::get_cs() const { - return screen.get_cs(); - } - - int BreakoutColourLCD240x240::get_dc() const { - return screen.get_dc(); - } - - int BreakoutColourLCD240x240::get_sck() const { - return screen.get_sck(); - } - - int BreakoutColourLCD240x240::get_mosi() const { - return screen.get_mosi(); - } - - int BreakoutColourLCD240x240::get_bl() const { - return screen.get_bl(); - } - - void BreakoutColourLCD240x240::update() { - screen.update(); - } - - void BreakoutColourLCD240x240::set_backlight(uint8_t brightness) { - screen.set_backlight(brightness); - } - -} \ No newline at end of file diff --git a/libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.hpp b/libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.hpp deleted file mode 100644 index 67588696..00000000 --- a/libraries/breakout_colourlcd240x240/breakout_colourlcd240x240.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "drivers/st7789/st7789.hpp" -#include "libraries/pico_graphics/pico_graphics.hpp" -#include "common/pimoroni_common.hpp" - -namespace pimoroni { - - class BreakoutColourLCD240x240 : public PicoGraphics { - //-------------------------------------------------- - // Constants - //-------------------------------------------------- - public: - static const int WIDTH = 240; - static const int HEIGHT = 240; - - //-------------------------------------------------- - // Variables - //-------------------------------------------------- - public: - uint16_t *__fb; - private: - ST7789 screen; - - - //-------------------------------------------------- - // Constructors/Destructor - //-------------------------------------------------- - public: - BreakoutColourLCD240x240(uint16_t *buf); - BreakoutColourLCD240x240(uint16_t *buf, spi_inst_t *spi, - uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED); - BreakoutColourLCD240x240(uint16_t *buf, BG_SPI_SLOT slot); - - - //-------------------------------------------------- - // Methods - //-------------------------------------------------- - public: - void init(); - - spi_inst_t* get_spi() const; - int get_cs() const; - int get_dc() const; - int get_sck() const; - int get_mosi() const; - int get_bl() const; - - void update(); - void set_backlight(uint8_t brightness); - }; - -} diff --git a/libraries/breakout_roundlcd/CMakeLists.txt b/libraries/breakout_roundlcd/CMakeLists.txt deleted file mode 100644 index 46e19eb2..00000000 --- a/libraries/breakout_roundlcd/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -set(LIB_NAME breakout_roundlcd) -add_library(${LIB_NAME} INTERFACE) - -target_sources(${LIB_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp -) - -target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) - -# Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib st7789 pico_graphics) \ No newline at end of file diff --git a/libraries/breakout_roundlcd/breakout_roundlcd.cmake b/libraries/breakout_roundlcd/breakout_roundlcd.cmake deleted file mode 100644 index b4a2c5ec..00000000 --- a/libraries/breakout_roundlcd/breakout_roundlcd.cmake +++ /dev/null @@ -1,14 +0,0 @@ -include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/st7789/st7789.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/../pico_graphics/pico_graphics.cmake) - -set(LIB_NAME breakout_roundlcd) -add_library(${LIB_NAME} INTERFACE) - -target_sources(${LIB_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp -) - -target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) - -# Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib st7789 pimoroni_bus pico_graphics) \ No newline at end of file diff --git a/libraries/breakout_roundlcd/breakout_roundlcd.cpp b/libraries/breakout_roundlcd/breakout_roundlcd.cpp deleted file mode 100644 index c46f8cbb..00000000 --- a/libraries/breakout_roundlcd/breakout_roundlcd.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "breakout_roundlcd.hpp" - -namespace pimoroni { - - BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf) - : PicoGraphics(WIDTH, HEIGHT, buf), - screen(WIDTH, HEIGHT, ROTATE_0, true, buf, get_spi_pins(BG_SPI_FRONT)) { - __fb = buf; - } - - BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf, spi_inst_t *spi, - uint cs, uint dc, uint sck, uint mosi, uint bl) - : PicoGraphics(WIDTH, HEIGHT, buf), - screen(WIDTH, HEIGHT, ROTATE_0, true, buf, SPIPins{spi, cs sck, mosi, PIN_UNUSED, dc, bl}) { - __fb = buf; - } - - BreakoutRoundLCD::BreakoutRoundLCD(uint16_t *buf, BG_SPI_SLOT slot) - : PicoGraphics(WIDTH, HEIGHT, buf), - screen(WIDTH, HEIGHT, ROTATE_0, true, buf, get_spi_pins(slot)) { { - __fb = buf; - } - - void BreakoutRoundLCD::init() { - } - - spi_inst_t* BreakoutRoundLCD::get_spi() const { - return screen.get_spi(); - } - - int BreakoutRoundLCD::get_cs() const { - return screen.get_cs(); - } - - int BreakoutRoundLCD::get_dc() const { - return screen.get_dc(); - } - - int BreakoutRoundLCD::get_sck() const { - return screen.get_sck(); - } - - int BreakoutRoundLCD::get_mosi() const { - return screen.get_mosi(); - } - - int BreakoutRoundLCD::get_bl() const { - return screen.get_bl(); - } - - void BreakoutRoundLCD::update() { - screen.update(); - } - - void BreakoutRoundLCD::set_backlight(uint8_t brightness) { - screen.set_backlight(brightness); - } - -} \ No newline at end of file diff --git a/libraries/breakout_roundlcd/breakout_roundlcd.hpp b/libraries/breakout_roundlcd/breakout_roundlcd.hpp deleted file mode 100644 index 8c990b05..00000000 --- a/libraries/breakout_roundlcd/breakout_roundlcd.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "drivers/st7789/st7789.hpp" -#include "libraries/pico_graphics/pico_graphics.hpp" - -namespace pimoroni { - - class BreakoutRoundLCD : public PicoGraphics { - //-------------------------------------------------- - // Constants - //-------------------------------------------------- - public: - static const int WIDTH = 240; - static const int HEIGHT = 240; - - static const uint8_t PIN_UNUSED = UINT8_MAX; - - - //-------------------------------------------------- - // Variables - //-------------------------------------------------- - public: - uint16_t *__fb; - private: - ST7789 screen; - - - //-------------------------------------------------- - // Constructors/Destructor - //-------------------------------------------------- - public: - BreakoutRoundLCD(uint16_t *buf); - BreakoutRoundLCD(uint16_t *buf, spi_inst_t *spi, - uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED); - BreakoutRoundLCD(uint16_t *buf, BG_SPI_SLOT slot); - - - //-------------------------------------------------- - // Methods - //-------------------------------------------------- - public: - void init(); - - spi_inst_t* get_spi() const; - int get_cs() const; - int get_dc() const; - int get_sck() const; - int get_mosi() const; - int get_bl() const; - - void update(); - void set_backlight(uint8_t brightness); - }; - -} diff --git a/libraries/pico_explorer/pico_explorer.cpp b/libraries/pico_explorer/pico_explorer.cpp index ccd07c69..be8dfc6b 100644 --- a/libraries/pico_explorer/pico_explorer.cpp +++ b/libraries/pico_explorer/pico_explorer.cpp @@ -1,122 +1 @@ -#include -#include - -#include "hardware/gpio.h" -#include "hardware/pwm.h" -#include "hardware/adc.h" - -#include "pico_explorer.hpp" - -const uint8_t MOTOR1N = 8; -const uint8_t MOTOR1P = 9; -const uint8_t MOTOR2N = 10; -const uint8_t MOTOR2P = 11; - -namespace pimoroni { - - PicoExplorer::PicoExplorer(void *buf) - : PicoGraphics(WIDTH, HEIGHT, buf), - screen(WIDTH, HEIGHT, ROTATE_0, false, buf, get_spi_pins(PICO_EXPLORER_ONBOARD)) { - __fb = buf; - } - - void PicoExplorer::init() { - // setup button inputs - gpio_set_function(A, GPIO_FUNC_SIO); gpio_set_dir(A, GPIO_IN); gpio_pull_up(A); - gpio_set_function(B, GPIO_FUNC_SIO); gpio_set_dir(B, GPIO_IN); gpio_pull_up(B); - gpio_set_function(X, GPIO_FUNC_SIO); gpio_set_dir(X, GPIO_IN); gpio_pull_up(X); - gpio_set_function(Y, GPIO_FUNC_SIO); gpio_set_dir(Y, GPIO_IN); gpio_pull_up(Y); - - // setup ADC channels - adc_init(); - const uint8_t ADC_BASE_PIN = 26; - adc_gpio_init(ADC0 + ADC_BASE_PIN); - adc_gpio_init(ADC1 + ADC_BASE_PIN); - adc_gpio_init(ADC2 + ADC_BASE_PIN); - - // setup motor pins - pwm_config motor_pwm_cfg = pwm_get_default_config(); - pwm_config_set_wrap(&motor_pwm_cfg, 5500); - - pwm_init(pwm_gpio_to_slice_num(MOTOR1N), &motor_pwm_cfg, true); - gpio_set_function(MOTOR1N, GPIO_FUNC_PWM); - - pwm_init(pwm_gpio_to_slice_num(MOTOR1P), &motor_pwm_cfg, true); - gpio_set_function(MOTOR1P, GPIO_FUNC_PWM); - - pwm_init(pwm_gpio_to_slice_num(MOTOR2N), &motor_pwm_cfg, true); - gpio_set_function(MOTOR2N, GPIO_FUNC_PWM); - - pwm_init(pwm_gpio_to_slice_num(MOTOR2P), &motor_pwm_cfg, true); - gpio_set_function(MOTOR2P, GPIO_FUNC_PWM); - } - - void PicoExplorer::update() { - screen.update(palette); - } - - [[deprecated("Use Button(uint pin).")]] - bool PicoExplorer::is_pressed(uint8_t button) { - return !gpio_get(button); - } - - [[deprecated("Use Analog(uint pin).")]] - float PicoExplorer::get_adc(uint8_t channel) { - adc_select_input(channel); - // scale raw 12-bit adc value to 0 .. 1 float - float result = float(adc_read()) / (1 << 12); - // clamp result to 0 .. 1 - result = std::min(1.0f, std::max(0.0f, result)); - return result; - } - - [[deprecated("Use Motor(pin_pair pins).")]] - void PicoExplorer::set_motor(uint8_t channel, uint8_t action, float speed) { - uint8_t p = channel == MOTOR1 ? MOTOR1P : MOTOR2P; - uint8_t n = channel == MOTOR1 ? MOTOR1N : MOTOR2N; - - switch(action) { - case FORWARD: { - pwm_set_gpio_level(n, (1 - speed) * 5500); - pwm_set_gpio_level(p, 5500); - break; - } - - case REVERSE: { - pwm_set_gpio_level(n, 5500); - pwm_set_gpio_level(p, (1 - speed) * 5500); - break; - } - - case STOP: { - pwm_set_gpio_level(p, 5500); - pwm_set_gpio_level(n, 5500); - break; - } - } - } - - [[deprecated("Use Buzzer(uint pin).")]] - void PicoExplorer::set_audio_pin(uint pin) { - pwm_config tone_pwm_cfg = pwm_get_default_config(); - - // calculate the pwm wrap value for this frequency - // first we set the clock divider to give us exactly - // ten thousand cycles per second - pwm_config_set_clkdiv(&tone_pwm_cfg, 255); - pwm_init(pwm_gpio_to_slice_num(pin), &tone_pwm_cfg, true); - gpio_set_function(pin, GPIO_FUNC_PWM); - audio_pin = pin; - } - - [[deprecated("Use Buzzer(uint pin).set_tone().")]] - void PicoExplorer::set_tone(uint16_t frequency, float duty) { - // output a square wave, so 50% duty cycle - if(audio_pin != -1) { - uint16_t pwm_wrap = 490196 / frequency; - pwm_set_wrap(audio_pin, pwm_wrap); - pwm_set_gpio_level(audio_pin, pwm_wrap * duty); - } - } - -} +#include "pico_explorer.hpp" \ No newline at end of file diff --git a/libraries/pico_explorer/pico_explorer.hpp b/libraries/pico_explorer/pico_explorer.hpp index b1d0d51b..3468831a 100644 --- a/libraries/pico_explorer/pico_explorer.hpp +++ b/libraries/pico_explorer/pico_explorer.hpp @@ -1,12 +1,10 @@ #pragma once -#include "drivers/st7789/st7789.hpp" -#include "libraries/pico_graphics/pico_graphics.hpp" #include "drivers/motor/motor.hpp" namespace pimoroni { - class PicoExplorer : public PicoGraphics { + class PicoExplorer { public: static const int WIDTH = 240; static const int HEIGHT = 240; @@ -41,25 +39,6 @@ namespace pimoroni { static const uint GP5 = 5; static const uint GP6 = 6; static const uint GP7 = 7; - - void *__fb; - private: - ST7789 screen; - int8_t audio_pin = -1; - - public: - PicoExplorer(void *buf); - - void init(); - void update(); - bool is_pressed(uint8_t button); - - float get_adc(uint8_t channel); - - void set_motor(uint8_t channel, uint8_t action, float speed = 0.0f); - - void set_audio_pin(uint pin); - void set_tone(uint16_t frequency, float duty = 0.2f); }; } \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.cmake b/libraries/pico_graphics/pico_graphics.cmake index a77cd83f..e5320dd2 100644 --- a/libraries/pico_graphics/pico_graphics.cmake +++ b/libraries/pico_graphics/pico_graphics.cmake @@ -5,4 +5,4 @@ add_library(pico_graphics target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR}) -target_link_libraries(pico_graphics bitmap_fonts) \ No newline at end of file +target_link_libraries(pico_graphics bitmap_fonts pico_stdlib) \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index b4462748..954d7733 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -320,8 +320,8 @@ namespace pimoroni { DisplayDriver(uint16_t width, uint16_t height, Rotation rotation) : width(width), height(height), rotation(rotation) {}; - virtual void update(PicoGraphics *display); - virtual void set_backlight(uint8_t brightness); + virtual void update(PicoGraphics *display) {}; + virtual void set_backlight(uint8_t brightness) {}; }; } diff --git a/libraries/picographics_st7789/CMakeLists.txt b/libraries/picographics_st7789/CMakeLists.txt deleted file mode 100644 index 89a60659..00000000 --- a/libraries/picographics_st7789/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -include(picographics_st7789.cmake) \ No newline at end of file diff --git a/libraries/picographics_st7789/README.md b/libraries/picographics_st7789/README.md deleted file mode 100644 index 98d1bb82..00000000 --- a/libraries/picographics_st7789/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# Pico Graphics ST7789 - Pico Display Pack & Pico Display Pack 2.0" and 240x240 Square & Round LCD Breakouts - -Our Pico Display Packs offers a vibrant 1.14" (240x135) or 2.0" (320x240) IPS LCD screen for your Raspberry Pi Pico it also includes four switches and and an RGB LED! - -We've included helper functions to handle every aspect of drawing to the screen and interfacing with the buttons and LED. See the [function reference](#function-reference) for details. - -- [Example Program](#example-program) -- [Function Reference](#function-reference) - - [PicoGraphics](#picographics) - - [set_backlight](#set_backlight) - - [update](#update) - -## Example Program - -The following example sets up Pico Display, displays some basic demo text and graphics and will illuminate the RGB LED green if the A button is pressed. - -```c++ -#include "pico_display.hpp" -#include "picographics_st7789.hpp" -#include "rgbled.hpp" -#include "button.hpp" - -using namespace pimoroni; - -// Swap WIDTH and HEIGHT to rotate 90 degrees -PicoGraphicsST7789 pico_display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0); - -// RGB LED controller -RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); - -// Buttons -Button button_a(PicoDisplay::A); -Button button_b(PicoDisplay::B); -Button button_x(PicoDisplay::X); -Button button_y(PicoDisplay::Y); - -int main() { - // set the backlight to a value between 0 and 255 - // the backlight is driven via PWM and is gamma corrected by our - // library to give a gorgeous linear brightness range. - pico_display.set_backlight(100); - - // Create pens for the colours we want to use - // parameters are red, green, blue all between 0 and 255 - // By default these are crushed to RGB332 so only the upper bits of each are used! - int BG_COLOR = pico_display.create_pen(30, 40, 50); - int BOX_COLOR = pico_display.create_pen(10, 20, 30); - int TEXT_COLOR = pico_display.create_pen(110, 120, 130); - - while(true) { - // detect if the A button is pressed (could be A, B, X, or Y) - if(button_a.raw()) { - // make the led glow green - // parameters are red, green, blue all between 0 and 255 - // these are also gamma corrected - led.set_rgb(0, 255, 0); - } - - // set the colour of the pen - pico_display.set_pen(BG_COLOR); - - // fill the screen with the current pen colour - pico_display.clear(); - - // draw a box to put some text in - pico_display.set_pen(BOX_COLOR); - Rect text_rect(10, 10, 150, 150); - pico_display.rectangle(text_rect); - - // write some text inside the box with 10 pixels of margin - // automatically word wrapping - text_rect.deflate(10); - pico_display.set_pen(TEXT_COLOR); - pico_display.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w); - - // now we've done our drawing let's update the screen - pico_display.update(); - } -} -``` - -## Function Reference - -### PicoGraphics - -The Pico Graphics ST7789 driver uses our Pico Graphics library to draw graphics and text. For more information [read the Pico Graphics function reference.](../pico_graphics/README.md#function-reference). - -You will also need to use the RGBLED library to drive the RGB LED, and the Button library for the four buttons. - -### set_backlight - -Set the display backlight from 0-255. - -```c++ -pico_display.set_backlight(brightness); -``` - -Uses hardware PWM to dim the display backlight, dimming values are gamma-corrected to provide smooth brightness transitions across the full range of intensity. This may result in some low values mapping as "off." - -### update - -To display your changes on Pico Display's screen you need to call `update`: - -```c++ -pico_display.update(); -``` diff --git a/libraries/picographics_st7789/picographics_st7789.cmake b/libraries/picographics_st7789/picographics_st7789.cmake deleted file mode 100644 index 1196c95c..00000000 --- a/libraries/picographics_st7789/picographics_st7789.cmake +++ /dev/null @@ -1,11 +0,0 @@ -set(LIB_NAME picographics_st7789) -add_library(${LIB_NAME} INTERFACE) - -target_sources(${LIB_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp -) - -target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) - -# Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma pimoroni_bus st7789 pico_graphics) \ No newline at end of file diff --git a/libraries/picographics_st7789/picographics_st7789.cpp b/libraries/picographics_st7789/picographics_st7789.cpp deleted file mode 100644 index 5bd9bd69..00000000 --- a/libraries/picographics_st7789/picographics_st7789.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -#include "picographics_st7789.hpp" - - -namespace pimoroni { - -} diff --git a/libraries/picographics_st7789/picographics_st7789.hpp b/libraries/picographics_st7789/picographics_st7789.hpp deleted file mode 100644 index 96ec537f..00000000 --- a/libraries/picographics_st7789/picographics_st7789.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "drivers/st7789/st7789.hpp" -#include "libraries/pico_graphics/pico_graphics.hpp" -#include "common/pimoroni_bus.hpp" - -namespace pimoroni { - - class PicoGraphicsST7789 : public PicoGraphics_PenRGB565 { - private: - ST7789 st7789; - - public: - PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) : - PicoGraphics_PenRGB565(width, height, frame_buffer), - st7789(width, height, rotation, round, get_spi_pins(BG_SPI_FRONT)) { - common_init(); - }; - - PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) : - PicoGraphics_PenRGB565(width, height, frame_buffer), - st7789(width, height, rotation, round, bus_pins) { - common_init(); - }; - - PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) : - PicoGraphics_PenRGB565(width, height, frame_buffer), - st7789(width, height, rotation, bus_pins) { - common_init(); - }; - - void common_init() { - this->set_dimensions(st7789.width, st7789.height); - st7789.update(this); - } - - void update() { - st7789.update(this); - } - - void set_backlight(uint8_t brightness) { - st7789.set_backlight(brightness); - } - - void set_framebuffer(void* frame_buffer) { - this->frame_buffer = frame_buffer; - } - }; - -} From d1b7639e8adcecbf648e2551da261ab08fd2d7ea Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Jun 2022 19:18:18 +0100 Subject: [PATCH 32/84] PicoGraphics: Update README. --- libraries/pico_graphics/README.md | 101 ++++++++++++++++-------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/libraries/pico_graphics/README.md b/libraries/pico_graphics/README.md index e2e74f2d..b6696b10 100644 --- a/libraries/pico_graphics/README.md +++ b/libraries/pico_graphics/README.md @@ -1,9 +1,12 @@ # Pico Graphics -Pico Graphics is a tiny graphics library for 16-bit RGB565 displays. +Pico Graphics is a tiny graphics library supporting a number of underlying buffer formats including 8-bit paletted (256 colour), 8-bit RGB332 (256 colour), 16-bit RGB565 (65K colour) and 4-bit packed (8 colour). It supports drawing text, primitive and individual pixels and includes basic types such as `rect` and `point` brimming with methods to help you develop games and applications. +- [Overview](#overview) + - [Pen Types](#pen-types) + - [Creating A Pico Graphics Instance](#creating-a-pico-graphics-instance) - [Function Reference](#function-reference) - [Types](#types) - [rect](#rect) @@ -14,16 +17,13 @@ It supports drawing text, primitive and individual pixels and includes basic typ - [rect.inflate & rect.deflate](#rectinflate--rectdeflate) - [point](#point) - [point.clamp](#pointclamp) - - [operators](#operators) - [Pens & Clipping](#pens--clipping) - [set_pen](#set_pen) - [create_pen](#create_pen) - [set_clip & remove_clip](#set_clip--remove_clip) - [Palette](#palette) - - [set_palette_mode](#set_palette_mode) - - [reserve_palette](#reserve_palette) - - [set_palette](#set_palette) - - [RGB565 and RGB332](#rgb565-and-rgb332) + - [update_pen](#update_pen) + - [reset_pen](#reset_pen) - [Pixels](#pixels) - [pixel](#pixel) - [pixel_span](#pixel_span) @@ -33,6 +33,45 @@ It supports drawing text, primitive and individual pixels and includes basic typ - [Text](#text) - [Change Font](#change-font) + +## Overview + +Pico Graphics comes in multiple flavours depending on which underlying buffer type you wish to work with. + +Your buffer doesn't have to be native to your display. For example a 16-bit ST7789 display can work with P4, P8, RGB332 and RGB565 buffers, with palette lookups handled for you on the fly. + +### Pen Types + +* `P4` - 4-bit packed, with an 8 colour palette. This is commonly used for 7/8-colour e-ink displays or driving large displays with few colours. +* `P8` - 8-bit, with a 256 colour palette. Great balance of memory usage versus available colours. You can replace palette entries on the fly. +* `RGB332` - 8-bit, with a fixed 256 colour RGB332 palette. Great for quickly porting an RGB565 app to use less RAM. Limits your colour choices, but is easier to grok. +* `RGB565` - 16-bit, 65K "True Colour." Great for rainbows, gradients and images but comes at the cost of RAM! + +### Creating A Pico Graphics Instance + +To create a Pico Graphics instance to draw into, you should construct an instance of the Pen type class you want to use: + +```c++ +PicoGraphics_PenP4 graphics(WITH, HEIGHT, nullptr); +PicoGraphics_PenP8 graphics(WITH, HEIGHT, nullptr); +PicoGraphics_PenRGB332 graphics(WITH, HEIGHT, nullptr); +PicoGraphics_PenRGB565 graphics(WITH, HEIGHT, nullptr); +``` + +To draw something to a display you should create a display driver instance, eg: + +```c++ +ST7789 st7789(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +``` + +And then send it the Pico Graphics instance to draw: + +```c++ +st7789.update(&graphics); +``` + +The driver will check your graphics type and act accordingly. + ## Function Reference ### Types @@ -152,13 +191,9 @@ A point can be clamped within the confines of a `rect`. This is useful for keepi ```c++ point cursor(10, 1000); // A point, far outside the bounds of our screen -cursor.clamp(screen.bounds)); // Clamp to the screen +cursor.clamp(screen.bounds); // Clamp to the screen ``` -##### operators - -TODO - ### Pens & Clipping #### set_pen @@ -199,52 +234,22 @@ By default Pico Graphics uses an `RGB332` palette and clamps all pens to their ` Alternatively `set_palette_mode()` lets you switch into an RGB565 `USER` palette which gives you up to 256 16-bit colours of your choice. -#### set_palette_mode +#### update_pen ```c++ -void PicoGraphics::set_palette_mode(PALETTE_USER); +int PicoGraphics::update_pen(uint8_t index, uint8_t r, uint8_t g, uint8_t b); ``` -Clears the default `RGB332` palette and switches into `USER` mode. +Modify a palette entry to the given RGB colour (or nearest supported equivilent.) -Pens created with `create_pen()` will use 16-bit `RGB565` resolution and you have up to 256 palette entries to use. + +#### reset_pen ```c++ -void PicoGraphics::set_palette_mode(PALETTE_RGB332); +void PicoGraphics::reset_pen(uint8_t index); ``` -Clears any `USER` assigned palettes and returns to `RGB332` mode. - -#### reserve_palette - -```c++ -int PicoGraphics::reserve_palette(); -``` - -Marks the first empty palette entry as reserved and return its index. - - -#### set_palette - -```c++ -void PicoGraphics::set_palette(uint8_t index, RGB565 color); -``` - -#### RGB565 and RGB332 - -```c++ -int RGB565(uint8_t r, uint8_t g, uint8_t b); -``` - -Creates and returns an RGB565 colour, using the five/six/five most significant bits of each channel in turn. - -```c++ -int RGB332(uint8_t, uint8_t g, uint8_t b); -``` - -Creates and returns an RGB565 colour, using the three/three/two most significant bits of each channel in turn. - -IE: This clips the colour to RGB332. +Return a palette entry to its default value. Usually black and marked unused. ### Pixels From 7cc0cd2930e07b1dc9f9830a106526bb6efeb47b Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Jun 2022 19:18:32 +0100 Subject: [PATCH 33/84] Update tof display demo. --- examples/pico_tof_display/CMakeLists.txt | 2 +- examples/pico_tof_display/pico_tof_display.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/pico_tof_display/CMakeLists.txt b/examples/pico_tof_display/CMakeLists.txt index 16b4c9b4..90c9d20a 100644 --- a/examples/pico_tof_display/CMakeLists.txt +++ b/examples/pico_tof_display/CMakeLists.txt @@ -4,7 +4,7 @@ add_executable( ) # Pull in pico libraries that we need -target_link_libraries(tof_display pico_stdlib pico_explorer pico_display vl53l1x pico_graphics st7789 button) +target_link_libraries(tof_display pico_stdlib pico_explorer pico_display vl53l1x pico_graphics st7789 rgbled button) pico_enable_stdio_uart(tof_display 1) diff --git a/examples/pico_tof_display/pico_tof_display.cpp b/examples/pico_tof_display/pico_tof_display.cpp index 4b60b93e..f70219b2 100644 --- a/examples/pico_tof_display/pico_tof_display.cpp +++ b/examples/pico_tof_display/pico_tof_display.cpp @@ -25,6 +25,7 @@ #endif #include "vl53l1x.hpp" #include "drivers/button/button.hpp" +#include "drivers/rgbled/rgbled.hpp" #include "drivers/st7789/st7789.hpp" #include "libraries/pico_graphics/pico_graphics.hpp" @@ -55,6 +56,8 @@ uint16_t disptext_dist_size = 6; #else ST7789 st7789(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +RGBLED rgbled(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); + Button button_a(PicoDisplay::A); Button button_b(PicoDisplay::B); Button button_x(PicoDisplay::X); @@ -98,10 +101,10 @@ void flash_led(uint32_t curr_count) { #ifndef USE_PICO_EXPLORER if ((curr_count % FLASH_MOD) < (FLASH_MOD / 2)) { // value less than half modded number - LED off - //pico_display.set_led(0, 0, 0); // TODO use RGBLED + rgbled.set_rgb(0, 0, 0); } else { // value more than half modded number - LED on - //pico_display.set_led(128, 128, 128); // TODO use RGBLED + rgbled.set_rgb(128, 128, 128); } #endif } From b13470b4fbc3de2b41cb996067eb7d011f66d9c7 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 7 Jun 2022 20:19:16 +0100 Subject: [PATCH 34/84] PicoGraphics: Add set_palette and set_font. --- libraries/pico_graphics/pico_graphics.cpp | 10 ++++ libraries/pico_graphics/pico_graphics.hpp | 47 ++++++++++------ .../modules/picographics/picographics.c | 21 +++++--- .../modules/picographics/picographics.cpp | 54 +++++++++++++++++++ .../modules/picographics/picographics.h | 2 + 5 files changed, 109 insertions(+), 25 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 6b38fe08..ca4bf156 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -29,6 +29,16 @@ namespace pimoroni { this->font = font; } + void PicoGraphics::set_font(std::string font){ + if (font == "bitmap6") { + this->font = &font6; + } else if (font == "bitmap8") { + this->font = &font8; + } else if (font == "bitmap14_outline") { + this->font = &font14_outline; + } + } + void PicoGraphics::set_clip(const Rect &r) { clip = bounds.intersection(r); } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 954d7733..965ce77e 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -5,6 +5,8 @@ #include #include #include "libraries/bitmap_fonts/font6_data.hpp" +#include "libraries/bitmap_fonts/font8_data.hpp" +#include "libraries/bitmap_fonts/font14_outline_data.hpp" #include "common/pimoroni_common.hpp" // A tiny graphics library for our Pico products @@ -105,6 +107,7 @@ namespace pimoroni { virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length); void set_font(const bitmap::font_t *font); + void set_font(std::string font); void set_dimensions(int width, int height); @@ -132,20 +135,26 @@ namespace pimoroni { public: uint8_t color; PaletteEntry palette[8]; + const RGB565 default_palette[8] = { + rgb_to_rgb565(57, 48, 57), // Black + rgb_to_rgb565(255, 255, 255), // White + rgb_to_rgb565(58, 91, 70), // Green + rgb_to_rgb565(61, 59, 94), // Blue + rgb_to_rgb565(156, 72, 75), // Red + rgb_to_rgb565(208, 190, 71), // Yellow + rgb_to_rgb565(177, 106, 73), // Orange + rgb_to_rgb565(255, 255, 255) // Clear + }; PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer) : PicoGraphics(width, height, frame_buffer) { this->pen_type = PEN_P4; if(this->frame_buffer == nullptr) { this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); } - palette[0].color = rgb_to_rgb565(57, 48, 57); // Black - palette[1].color = rgb_to_rgb565(255, 255, 255); // White - palette[2].color = rgb_to_rgb565(58, 91, 70); // Green - palette[3].color = rgb_to_rgb565(61, 59, 94); // Blue - palette[4].color = rgb_to_rgb565(156, 72, 75); // Red - palette[5].color = rgb_to_rgb565(208, 190, 71); // Yellow - palette[6].color = rgb_to_rgb565(177, 106, 73); // Orange - palette[7].color = rgb_to_rgb565(255, 255, 255); // Clear + for(auto i = 0u; i < 8; i++) { + palette[i].color = default_palette[i]; + palette[i].used = true; + } } void set_pen(uint c) { color = c & 0xf; @@ -153,6 +162,15 @@ namespace pimoroni { void set_pen(uint8_t r, uint8_t g, uint8_t b) override { // TODO look up closest palette colour, or just NOOP? } + void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { + i &= 0xf; + palette[i].color = rgb_to_rgb565(r, g, b); + palette[i].used = true; + } + void reset_pen(uint8_t i) override { + i &= 0xf; + palette[i].color = default_palette[i]; + } void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { // pointer to byte in framebuffer that contains this pixel uint8_t *buf = (uint8_t *)frame_buffer; @@ -201,10 +219,12 @@ namespace pimoroni { // TODO look up closest palette colour, or just NOOP? } void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { + i &= 0xff; palette[i].color = rgb_to_rgb565(r, g, b); palette[i].used = true; } void reset_pen(uint8_t i) override { + i &= 0xff; palette[i].color = 0; palette[i].used = false; } @@ -247,7 +267,8 @@ namespace pimoroni { this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); } for(auto i = 0u; i < 256; i++) { - reset_pen(i); + palette[i].color = rgb332_to_rgb565(i); + palette[i].used = true; } } void set_pen(uint c) override { @@ -256,14 +277,6 @@ namespace pimoroni { void set_pen(uint8_t r, uint8_t g, uint8_t b) override { color = rgb_to_rgb332(r, g, b); } - void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { - palette[i].color = rgb_to_rgb565(r, g, b); - palette[i].used = true; - } - void reset_pen(uint8_t i) override { - palette[i].color = rgb332_to_rgb565(i); - palette[i].used = true; - } int create_pen(uint8_t r, uint8_t g, uint8_t b) override { return rgb_to_rgb332(r, g, b); } diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 11b6a31d..523ac5e7 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -7,11 +7,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_module_RGB565_obj, ModPicoGraph // Class Methods MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_update_obj, ModPicoGraphics_update); MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_backlight_obj, ModPicoGraphics_set_backlight); -MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_framebuffer_obj, ModPicoGraphics_set_framebuffer); // Palette management MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_update_pen_obj, 5, 5, ModPicoGraphics_update_pen); MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_reset_pen_obj, ModPicoGraphics_reset_pen); +MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_set_palette_obj, 2, ModPicoGraphics_set_palette); // Pen MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_pen_obj, ModPicoGraphics_set_pen); @@ -34,20 +34,17 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_line_obj, 5, 5, ModPicoGraph // Utility MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_get_bounds_obj, ModPicoGraphics_get_bounds); +MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_font_obj, ModPicoGraphics_set_font); +MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_framebuffer_obj, ModPicoGraphics_set_framebuffer); STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&ModPicoGraphics_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&ModPicoGraphics_set_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&ModPicoGraphics_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&ModPicoGraphics_update_obj) }, - - { MP_ROM_QSTR(MP_QSTR_update_pen), MP_ROM_PTR(&ModPicoGraphics_update_pen_obj) }, - { MP_ROM_QSTR(MP_QSTR_reset_pen), MP_ROM_PTR(&ModPicoGraphics_reset_pen_obj) }, - - { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&ModPicoGraphics_set_backlight_obj) }, - { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&ModPicoGraphics_create_pen_obj) }, { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&ModPicoGraphics_set_clip_obj) }, { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&ModPicoGraphics_remove_clip_obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&ModPicoGraphics_clear_obj) }, { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&ModPicoGraphics_pixel_span_obj) }, { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&ModPicoGraphics_rectangle_obj) }, { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&ModPicoGraphics_circle_obj) }, @@ -58,7 +55,15 @@ STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&ModPicoGraphics_triangle_obj) }, { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&ModPicoGraphics_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&ModPicoGraphics_create_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_update_pen), MP_ROM_PTR(&ModPicoGraphics_update_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_pen), MP_ROM_PTR(&ModPicoGraphics_reset_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_palette), MP_ROM_PTR(&ModPicoGraphics_set_palette_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&ModPicoGraphics_set_backlight_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_bounds), MP_ROM_PTR(&ModPicoGraphics_get_bounds_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_font), MP_ROM_PTR(&ModPicoGraphics_set_font_obj) }, { MP_ROM_QSTR(MP_QSTR_set_framebuffer), MP_ROM_PTR(&ModPicoGraphics_set_framebuffer_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ModPicoGraphics_locals_dict, ModPicoGraphics_locals_dict_table); diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 329f2977..0bf41566 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -12,6 +12,14 @@ extern "C" { #include "picographics.h" #include "micropython/modules/pimoroni_bus/pimoroni_bus.h" +std::string 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; + } + mp_raise_TypeError("can't convert object to str implicitly"); +} + typedef struct _ModPicoGraphics_obj_t { mp_obj_base_t base; PicoGraphics *graphics; @@ -166,6 +174,12 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size return MP_OBJ_FROM_PTR(self); } +mp_obj_t ModPicoGraphics_set_font(mp_obj_t self_in, mp_obj_t font) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); + self->graphics->set_font(mp_obj_to_string_r(font)); + return mp_const_none; +} + mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) { (void)self_in; (void)framebuffer; @@ -277,6 +291,46 @@ mp_obj_t ModPicoGraphics_create_pen(size_t n_args, const mp_obj_t *args) { return mp_obj_new_int(result); } +mp_obj_t ModPicoGraphics_set_palette(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + size_t num_tuples = n_args - 1; + const mp_obj_t *tuples = pos_args + 1; + + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], ModPicoGraphics_obj_t); + + // Check if there is only one argument, which might be a list + if(n_args == 2) { + if(mp_obj_is_type(pos_args[1], &mp_type_list)) { + mp_obj_list_t *points = MP_OBJ_TO_PTR2(pos_args[1], mp_obj_list_t); + + if(points->len <= 0) mp_raise_ValueError("set_palette(): cannot provide an empty list"); + + num_tuples = points->len; + tuples = points->items; + } + else { + mp_raise_TypeError("set_palette(): can't convert object to list"); + } + } + + for(size_t i = 0; i < num_tuples; i++) { + mp_obj_t obj = tuples[i]; + if(!mp_obj_is_type(obj, &mp_type_tuple)) mp_raise_ValueError("set_palette(): can't convert object to tuple"); + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(obj, mp_obj_tuple_t); + + if(tuple->len != 3) mp_raise_ValueError("set_palette(): tuple must contain R, G, B values"); + + self->graphics->update_pen( + i, + mp_obj_get_int(tuple->items[0]), + mp_obj_get_int(tuple->items[1]), + mp_obj_get_int(tuple->items[2]) + ); + } + + return mp_const_none; +} + mp_obj_t ModPicoGraphics_set_clip(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index c6e55ee0..066e5126 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -36,6 +36,7 @@ extern mp_obj_t ModPicoGraphics_set_backlight(mp_obj_t self_in, mp_obj_t brightn // Palette management extern mp_obj_t ModPicoGraphics_update_pen(size_t n_args, const mp_obj_t *args); extern mp_obj_t ModPicoGraphics_reset_pen(mp_obj_t self_in, mp_obj_t pen); +extern mp_obj_t ModPicoGraphics_set_palette(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); // Pen extern mp_obj_t ModPicoGraphics_set_pen(mp_obj_t self_in, mp_obj_t pen); @@ -57,5 +58,6 @@ extern mp_obj_t ModPicoGraphics_triangle(size_t n_args, const mp_obj_t *args); extern mp_obj_t ModPicoGraphics_line(size_t n_args, const mp_obj_t *args); // Utility +extern mp_obj_t ModPicoGraphics_set_font(mp_obj_t self_in, mp_obj_t font); extern mp_obj_t ModPicoGraphics_get_bounds(mp_obj_t self_in); extern mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); \ No newline at end of file From 4585e5ec0fb6364646d397e7f57454e43b93096e Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 8 Jun 2022 13:01:08 +0100 Subject: [PATCH 35/84] ST7789: Fix 240x240 display rotations. --- drivers/st7789/st7789.cpp | 49 ++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index f432e793..99361f1f 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -119,18 +119,45 @@ namespace pimoroni { // 240x240 Square and Round LCD Breakouts if(width == 240 && height == 240) { - caset[0] = 0; - caset[1] = 239; - if(round) { - raset[0] = 40; - raset[1] = 279; - } else { - raset[0] = rotate180 ? 80 : 0; - raset[1] = rotate180 ? 329 : 239; + int row_offset = round ? 40 : 80; + int col_offset = 0; + + switch(rotate) { + case ROTATE_0: + if (!round) row_offset = 0; + caset[0] = col_offset; + caset[1] = width + col_offset - 1; + raset[0] = row_offset; + raset[1] = width + row_offset - 1; + + madctl = MADCTL::HORIZ_ORDER; + break; + case ROTATE_90: + if (!round) row_offset = 0; + caset[0] = row_offset; + caset[1] = width + row_offset - 1; + raset[0] = col_offset; + raset[1] = width + col_offset - 1; + + madctl = MADCTL::HORIZ_ORDER | MADCTL::COL_ORDER | MADCTL::SWAP_XY; + break; + case ROTATE_180: + caset[0] = col_offset; + caset[1] = width + col_offset - 1; + raset[0] = row_offset; + raset[1] = width + row_offset - 1; + + madctl = MADCTL::HORIZ_ORDER | MADCTL::COL_ORDER | MADCTL::ROW_ORDER; + break; + case ROTATE_270: + caset[0] = row_offset; + caset[1] = width + row_offset - 1; + raset[0] = col_offset; + raset[1] = width + col_offset - 1; + + madctl = MADCTL::ROW_ORDER | MADCTL::SWAP_XY; + break; } - madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0; - if (rotate == ROTATE_90) madctl |= MADCTL::SWAP_XY; - madctl |= MADCTL::HORIZ_ORDER; } // Pico Display From 8efe23fb5bcb74ad16d45521a5fb7cd5177666b1 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 8 Jun 2022 13:01:26 +0100 Subject: [PATCH 36/84] Round LCD: Set to round in demo. --- examples/breakout_roundlcd/roundlcd_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/breakout_roundlcd/roundlcd_demo.cpp b/examples/breakout_roundlcd/roundlcd_demo.cpp index 54b7fcc8..4761c240 100644 --- a/examples/breakout_roundlcd/roundlcd_demo.cpp +++ b/examples/breakout_roundlcd/roundlcd_demo.cpp @@ -15,7 +15,7 @@ using namespace pimoroni; const int WIDTH = 240; const int HEIGHT = 240; -ST7789 st7789(WIDTH, HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); +ST7789 st7789(WIDTH, HEIGHT, ROTATE_0, true, get_spi_pins(BG_SPI_FRONT)); PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); constexpr float RADIUS = WIDTH / 2; From 3d489a93834b5c9354f7172a62305cdd810cdd76 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 8 Jun 2022 13:11:37 +0100 Subject: [PATCH 37/84] ST7789: 240x240 Handle unsupported rotations gracefully. --- drivers/st7789/st7789.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 99361f1f..4a9d2430 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -123,15 +123,6 @@ namespace pimoroni { int col_offset = 0; switch(rotate) { - case ROTATE_0: - if (!round) row_offset = 0; - caset[0] = col_offset; - caset[1] = width + col_offset - 1; - raset[0] = row_offset; - raset[1] = width + row_offset - 1; - - madctl = MADCTL::HORIZ_ORDER; - break; case ROTATE_90: if (!round) row_offset = 0; caset[0] = row_offset; @@ -157,6 +148,15 @@ namespace pimoroni { madctl = MADCTL::ROW_ORDER | MADCTL::SWAP_XY; break; + default: // ROTATE_0 (and for any smart-alec who tries to rotate 45 degrees or something...) + if (!round) row_offset = 0; + caset[0] = col_offset; + caset[1] = width + col_offset - 1; + raset[0] = row_offset; + raset[1] = width + row_offset - 1; + + madctl = MADCTL::HORIZ_ORDER; + break; } } From fc1561e54b22e46669faf97726782efa390083b3 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 8 Jun 2022 13:23:53 +0100 Subject: [PATCH 38/84] PicoGraphics: Fix set_framebuffer. --- libraries/pico_graphics/pico_graphics.cpp | 9 +++++---- libraries/pico_graphics/pico_graphics.hpp | 1 + micropython/modules/picographics/picographics.cpp | 11 +++++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index ca4bf156..ed10231c 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -11,10 +11,11 @@ namespace pimoroni { void PicoGraphics::palette_lookup(void *frame_buffer, void *result, uint offset, uint length) {}; void PicoGraphics::set_dimensions(int width, int height) { - bounds.w = width; - bounds.h = height; - clip.w = width; - clip.h = height; + bounds = clip = {0, 0, width, height}; + } + + void PicoGraphics::set_framebuffer(void *frame_buffer) { + this->frame_buffer = frame_buffer; } void *PicoGraphics::get_data() { diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 965ce77e..83c413ae 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -110,6 +110,7 @@ namespace pimoroni { void set_font(std::string font); void set_dimensions(int width, int height); + void set_framebuffer(void *frame_buffer); void *get_data(); void get_data(uint y, void *row_buf); diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 0bf41566..f1c3e2f0 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -181,9 +181,6 @@ mp_obj_t ModPicoGraphics_set_font(mp_obj_t self_in, mp_obj_t font) { } mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) { - (void)self_in; - (void)framebuffer; - /* ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); if (framebuffer == mp_const_none) { @@ -193,10 +190,16 @@ mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) } else { mp_buffer_info_t bufinfo; mp_get_buffer_raise(framebuffer, &bufinfo, MP_BUFFER_RW); + + // This should have no effect if you try to replace the framebuffer with itself + // but it will free up a buffer that has no other references + if(self->buffer != nullptr) { + m_del(uint8_t, self->buffer, self->graphics->bounds.w * self->graphics->bounds.h); + } + self->buffer = bufinfo.buf; self->graphics->set_framebuffer(self->buffer); } - */ return mp_const_none; } From 49b62515c291d9bfa640d5fb98f1ba64828a8573 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 8 Jun 2022 16:37:09 +0100 Subject: [PATCH 39/84] PicoGraphicS: Hershey support, bugfixes, tidyup. --- libraries/pico_graphics/pico_graphics.cmake | 2 +- libraries/pico_graphics/pico_graphics.cpp | 102 ++++++++++++------ libraries/pico_graphics/pico_graphics.hpp | 58 +++++----- micropython/modules/micropython-common.cmake | 1 + .../modules/picographics/picographics.cpp | 22 ++-- 5 files changed, 121 insertions(+), 64 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cmake b/libraries/pico_graphics/pico_graphics.cmake index e5320dd2..c69eb7d7 100644 --- a/libraries/pico_graphics/pico_graphics.cmake +++ b/libraries/pico_graphics/pico_graphics.cmake @@ -5,4 +5,4 @@ add_library(pico_graphics target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR}) -target_link_libraries(pico_graphics bitmap_fonts pico_stdlib) \ No newline at end of file +target_link_libraries(pico_graphics bitmap_fonts hershey_fonts pico_stdlib) \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index ed10231c..263ffed7 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -4,10 +4,10 @@ namespace pimoroni { void PicoGraphics::set_pen(uint c) {}; void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) {}; - void PicoGraphics::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {}; - void PicoGraphics::reset_pen(uint8_t i) {}; + int PicoGraphics::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {return -1;}; + int PicoGraphics::reset_pen(uint8_t i) {return -1;}; int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;}; - void PicoGraphics::set_pixel(void *frame_buffer, uint x, uint y, uint stride) {}; + void PicoGraphics::set_pixel(const Point &p) {}; void PicoGraphics::palette_lookup(void *frame_buffer, void *result, uint offset, uint length) {}; void PicoGraphics::set_dimensions(int width, int height) { @@ -27,16 +27,27 @@ namespace pimoroni { } void PicoGraphics::set_font(const bitmap::font_t *font){ - this->font = font; + this->bitmap_font = font; + this->hershey_font = nullptr; } - void PicoGraphics::set_font(std::string font){ - if (font == "bitmap6") { - this->font = &font6; - } else if (font == "bitmap8") { - this->font = &font8; - } else if (font == "bitmap14_outline") { - this->font = &font14_outline; + void PicoGraphics::set_font(const hershey::font_t *font){ + this->bitmap_font = nullptr; + this->hershey_font = font; + } + + void PicoGraphics::set_font(std::string name){ + if (name == "bitmap6") { + set_font(&font6); + } else if (name == "bitmap8") { + set_font(&font8); + } else if (name == "bitmap14_outline") { + 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]); + } } } @@ -54,7 +65,7 @@ namespace pimoroni { void PicoGraphics::pixel(const Point &p) { if(!clip.contains(p)) return; - set_pixel(frame_buffer, p.x, p.y, bounds.w); + set_pixel(p); } void PicoGraphics::pixel_span(const Point &p, int32_t l) { @@ -69,7 +80,7 @@ namespace pimoroni { Point dest(clipped.x, clipped.y); while(l--) { - set_pixel(frame_buffer, dest.x, dest.y, bounds.w); + set_pixel(dest); dest.x++; } } @@ -117,20 +128,42 @@ namespace pimoroni { } } - void PicoGraphics::character(const char c, const Point &p, uint8_t scale) { - bitmap::character(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){ - rectangle(Rect(x, y, w, h)); - }, c, p.x, p.y, scale); + void PicoGraphics::character(const char c, const Point &p, float s, float a) { + if (bitmap_font) { + bitmap::character(bitmap_font, [this](int32_t x, int32_t y, int32_t w, int32_t h) { + rectangle(Rect(x, y, w, h)); + }, c, p.x, p.y, std::max(1.0f, s)); + return; + } + + if (hershey_font) { + hershey::glyph(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) { + line(Point(x1, y1), Point(x2, y2)); + }, c, p.x, p.y, s, a); + return; + } } - void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) { - bitmap::text(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){ - rectangle(Rect(x, y, w, h)); - }, t, p.x, p.y, wrap, scale); + void PicoGraphics::text(const std::string &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)); + }, t, p.x, p.y, wrap, std::max(1.0f, s), letter_spacing); + return; + } + + if (hershey_font) { + hershey::text(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) { + line(Point(x1, y1), Point(x2, y2)); + }, t, p.x, p.y, s, a); + return; + } } - int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) { - return bitmap::measure_text(font, t, scale); + int32_t PicoGraphics::measure_text(const std::string &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; } int32_t orient2d(Point p1, Point p2, Point p3) { @@ -186,7 +219,7 @@ namespace pimoroni { Point dest = Point(triangle_bounds.x, triangle_bounds.y + y); for (int32_t x = 0; x < triangle_bounds.w; x++) { if ((w0 | w1 | w2) >= 0) { - set_pixel(frame_buffer, dest.x, dest.y, bounds.w); + set_pixel(dest); } dest.x++; @@ -251,24 +284,29 @@ namespace pimoroni { void PicoGraphics::line(Point p1, Point p2) { // fast horizontal line if(p1.y == p2.y) { - int32_t start = std::max(clip.x, std::min(p1.x, p2.x)); - int32_t end = std::min(clip.x + clip.w, std::max(p1.x, p2.x)); + p1 = p1.clamp(clip); + p2 = p2.clamp(clip); + int32_t start = std::min(p1.x, p2.x); + int32_t end = std::max(p1.x, p2.x); pixel_span(Point(start, p1.y), end - start); return; } // fast vertical line if(p1.x == p2.x) { - int32_t start = std::max(clip.y, std::min(p1.y, p2.y)); - int32_t length = std::min(clip.y + clip.h, std::max(p1.y, p2.y)) - start; + p1 = p1.clamp(clip); + p2 = p2.clamp(clip); + int32_t start = std::min(p1.y, p2.y); + int32_t length = std::max(p1.y, p2.y) - start; Point dest(p1.x, start); while(length--) { - set_pixel(frame_buffer, dest.x, dest.y, bounds.w); + set_pixel(dest); dest.y++; } return; } + // general purpose line // lines are either "shallow" or "steep" based on whether the x delta // is greater than the y delta @@ -283,7 +321,8 @@ namespace pimoroni { int32_t x = p1.x; int32_t y = p1.y << 16; while(s--) { - set_pixel(frame_buffer, x, y >> 16, bounds.w); + Point p(x, y >> 16); + if(clip.contains(p)) set_pixel(p); y += sy; x += sx; } @@ -295,7 +334,8 @@ namespace pimoroni { int32_t y = p1.y; int32_t x = p1.x << 16; while(s--) { - set_pixel(frame_buffer, x >> 16, y, bounds.w); + Point p(x >> 16, y); + if(clip.contains(p)) set_pixel(p); y += sy; x += sx; } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 83c413ae..b7246aa2 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -4,9 +4,13 @@ #include #include #include + +#include "libraries/hershey_fonts/hershey_fonts.hpp" +#include "libraries/bitmap_fonts/bitmap_fonts.hpp" #include "libraries/bitmap_fonts/font6_data.hpp" #include "libraries/bitmap_fonts/font8_data.hpp" #include "libraries/bitmap_fonts/font14_outline_data.hpp" + #include "common/pimoroni_common.hpp" // A tiny graphics library for our Pico products @@ -72,7 +76,8 @@ namespace pimoroni { Rect bounds; Rect clip; - const bitmap::font_t *font; + const bitmap::font_t *bitmap_font; + const hershey::font_t *hershey_font; static constexpr RGB332 rgb_to_rgb332(uint8_t r, uint8_t g, uint8_t b) { return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); @@ -100,13 +105,14 @@ namespace pimoroni { virtual void set_pen(uint c); virtual void set_pen(uint8_t r, uint8_t g, uint8_t b); - virtual void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b); - virtual void reset_pen(uint8_t i); + virtual int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b); + virtual int reset_pen(uint8_t i); virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); - virtual void set_pixel(void *frame_buffer, uint x, uint y, uint stride); + virtual void set_pixel(const Point &p); virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length); void set_font(const bitmap::font_t *font); + void set_font(const hershey::font_t *font); void set_font(std::string font); void set_dimensions(int width, int height); @@ -123,9 +129,9 @@ namespace pimoroni { void pixel_span(const Point &p, int32_t l); void rectangle(const Rect &r); void circle(const Point &p, int32_t r); - void character(const char c, const Point &p, uint8_t scale = 2); - void text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale = 2); - int32_t measure_text(const std::string &t, uint8_t scale = 2); + 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 polygon(const std::vector &points); void triangle(Point p1, Point p2, Point p3); void line(Point p1, Point p2); @@ -163,26 +169,28 @@ namespace pimoroni { void set_pen(uint8_t r, uint8_t g, uint8_t b) override { // TODO look up closest palette colour, or just NOOP? } - void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { + int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { i &= 0xf; palette[i].color = rgb_to_rgb565(r, g, b); palette[i].used = true; + return i; } - void reset_pen(uint8_t i) override { + int reset_pen(uint8_t i) override { i &= 0xf; palette[i].color = default_palette[i]; + return i; } - void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { + void set_pixel(const Point &p) override { // pointer to byte in framebuffer that contains this pixel uint8_t *buf = (uint8_t *)frame_buffer; - uint8_t *p = &buf[(x / 2) + (y * stride / 2)]; + uint8_t *f = &buf[(p.x / 2) + (p.y * bounds.w / 2)]; - uint8_t o = (~x & 0b1) * 4; // bit offset within byte - uint8_t m = ~(0b1111 << o); // bit mask for byte - uint8_t b = color << o; // bit value shifted to position + uint8_t o = (~p.x & 0b1) * 4; // bit offset within byte + uint8_t m = ~(0b1111 << o); // bit mask for byte + uint8_t b = color << o; // bit value shifted to position - *p &= m; // clear bits - *p |= b; // set value + *f &= m; // clear bits + *f |= b; // set value } void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { uint8_t *src = (uint8_t *)frame_buffer; @@ -219,15 +227,17 @@ namespace pimoroni { void set_pen(uint8_t r, uint8_t g, uint8_t b) override { // TODO look up closest palette colour, or just NOOP? } - void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { + int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { i &= 0xff; palette[i].color = rgb_to_rgb565(r, g, b); palette[i].used = true; + return i; } - void reset_pen(uint8_t i) override { + int reset_pen(uint8_t i) override { i &= 0xff; palette[i].color = 0; palette[i].used = false; + return i; } int create_pen(uint8_t r, uint8_t g, uint8_t b) override { // Create a colour and place it in the palette if there's space @@ -241,9 +251,9 @@ namespace pimoroni { } return -1; } - void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { + void set_pixel(const Point &p) override { uint8_t *buf = (uint8_t *)frame_buffer; - buf[y * stride + x] = color; + buf[p.y * bounds.w + p.x] = color; } void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { uint8_t *src = (uint8_t *)frame_buffer; @@ -281,9 +291,9 @@ namespace pimoroni { int create_pen(uint8_t r, uint8_t g, uint8_t b) override { return rgb_to_rgb332(r, g, b); } - void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { + void set_pixel(const Point &p) override { uint8_t *buf = (uint8_t *)frame_buffer; - buf[y * stride + x] = color; + buf[p.y * bounds.w + p.x] = color; } void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { uint8_t *src = (uint8_t *)frame_buffer; @@ -316,9 +326,9 @@ namespace pimoroni { int create_pen(uint8_t r, uint8_t g, uint8_t b) override { return rgb_to_rgb565(r, g, b); } - void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { + void set_pixel(const Point &p) override { uint16_t *buf = (uint16_t *)frame_buffer; - buf[y * stride + x] = color; + buf[p.y * bounds.w + p.x] = color; } static size_t buffer_size(uint w, uint h) { return w * h * sizeof(RGB565); diff --git a/micropython/modules/micropython-common.cmake b/micropython/modules/micropython-common.cmake index 949a3133..29ec616d 100644 --- a/micropython/modules/micropython-common.cmake +++ b/micropython/modules/micropython-common.cmake @@ -29,6 +29,7 @@ include(pico_unicorn/micropython) include(pico_wireless/micropython) include(pico_explorer/micropython) +include(hershey_fonts/micropython) include(bitmap_fonts/micropython) include(plasma/micropython) diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index f1c3e2f0..46c7eef3 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -443,14 +443,16 @@ mp_obj_t ModPicoGraphics_character(size_t n_args, const mp_obj_t *pos_args, mp_m } mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale }; + enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale, ARG_angle, ARG_spacing }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_wordwrap, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, + { MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_angle, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_spacing, MP_ARG_INT, {.u_int = 1} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -469,19 +471,22 @@ mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t int x = args[ARG_x].u_int; int y = args[ARG_y].u_int; int wrap = args[ARG_wrap].u_int; - int scale = args[ARG_scale].u_int; + float scale = args[ARG_scale].u_obj == mp_const_none ? 2.0f : mp_obj_get_float(args[ARG_scale].u_obj); + int angle = args[ARG_angle].u_int; + int letter_spacing = args[ARG_spacing].u_int; - self->graphics->text(t, Point(x, y), wrap, scale); + self->graphics->text(t, Point(x, y), wrap, scale, angle, letter_spacing); return mp_const_none; } mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_self, ARG_text, ARG_scale }; + enum { ARG_self, ARG_text, ARG_scale, ARG_spacing }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, + { MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_spacing, MP_ARG_INT, {.u_int = 1} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -497,9 +502,10 @@ mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, m std::string t((const char*)str); - int scale = args[ARG_scale].u_int; + 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; - int width = self->graphics->measure_text(t, scale); + int width = self->graphics->measure_text(t, scale, letter_spacing); return mp_obj_new_int(width); } From 4500497e3cc98ad8ec4c3dc4a5f81fb337f81ab5 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 8 Jun 2022 17:14:28 +0100 Subject: [PATCH 40/84] PicoGraphics: Add get_buffer_size. Take the guesswork out of correctly sizing a bytearray. Accepts a display and pen type. --- .../modules/picographics/picographics.c | 2 + .../modules/picographics/picographics.cpp | 114 ++++++++++-------- .../modules/picographics/picographics.h | 1 + 3 files changed, 67 insertions(+), 50 deletions(-) diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 523ac5e7..c8e00cc2 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -3,6 +3,7 @@ // Module functions STATIC MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_module_RGB332_obj, ModPicoGraphics_module_RGB332); STATIC MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_module_RGB565_obj, ModPicoGraphics_module_RGB565); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_get_required_buffer_size_obj, ModPicoGraphics_get_required_buffer_size); // Class Methods MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_update_obj, ModPicoGraphics_update); @@ -80,6 +81,7 @@ const mp_obj_type_t ModPicoGraphics_type = { STATIC const mp_map_elem_t picographics_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_picographics) }, { MP_ROM_QSTR(MP_QSTR_PicoGraphics), (mp_obj_t)&ModPicoGraphics_type }, + { MP_ROM_QSTR(MP_QSTR_get_buffer_size), MP_ROM_PTR(&ModPicoGraphics_get_required_buffer_size_obj) }, { MP_ROM_QSTR(MP_QSTR_RGB332), MP_ROM_PTR(&ModPicoGraphics_module_RGB332_obj) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&ModPicoGraphics_module_RGB565_obj) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 46c7eef3..4d79c1e9 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -27,6 +27,52 @@ typedef struct _ModPicoGraphics_obj_t { void *buffer; } ModPicoGraphics_obj_t; +bool get_display_resolution(PicoGraphicsDisplay display, int &width, int &height) { + switch(display) { + case DISPLAY_PICO_DISPLAY: + width = 240; + height = 135; + break; + case DISPLAY_PICO_DISPLAY_2: + case DISPLAY_TUFTY_2040: + width = 320; + height = 240; + break; + case DISPLAY_PICO_EXPLORER: + case DISPLAY_LCD_240X240: + case DISPLAY_ENVIRO_PLUS: + width = 240; + height = 240; + break; + case DISPLAY_ROUND_LCD_240X240: + width = 240; + height = 240; + break; + case DISPLAY_LCD_160X80: + width = 160; + height = 80; + break; + default: + return false; + } + return true; +} + +size_t get_required_buffer_size(PicoGraphicsPenType pen_type, uint width, uint height) { + switch(pen_type) { + case PEN_P4: + return PicoGraphics_PenP4::buffer_size(width, height); + case PEN_P8: + return PicoGraphics_PenP8::buffer_size(width, height); + case PEN_RGB332: + return PicoGraphics_PenRGB332::buffer_size(width, height); + case PEN_RGB565: + return PicoGraphics_PenRGB565::buffer_size(width, height); + default: + return 0; + } +} + mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { ModPicoGraphics_obj_t *self = nullptr; @@ -47,42 +93,14 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size self->base.type = &ModPicoGraphics_type; Rotation rotate = (Rotation)args[ARG_rotate].u_int; - bool round = false; - int width = 0; - int height = 0; PicoGraphicsPenType pen_type = (PicoGraphicsPenType)args[ARG_pen_type].u_int; PicoGraphicsDisplay display = (PicoGraphicsDisplay)args[ARG_display].u_int; - switch(display) { - case DISPLAY_PICO_DISPLAY: - width = 240; - height = 135; - break; - case DISPLAY_PICO_DISPLAY_2: - case DISPLAY_TUFTY_2040: - width = 320; - height = 240; - break; - case DISPLAY_PICO_EXPLORER: - case DISPLAY_LCD_240X240: - case DISPLAY_ENVIRO_PLUS: - width = 240; - height = 240; - break; - case DISPLAY_ROUND_LCD_240X240: - width = 240; - height = 240; - round = true; - break; - case DISPLAY_LCD_160X80: - width = 160; - height = 80; - break; - default: - mp_raise_ValueError("Unsupported display!"); - break; // unreachable - } + bool round = display == DISPLAY_ROUND_LCD_240X240; + int width = 0; + int height = 0; + if(!get_display_resolution(display, width, height)) mp_raise_ValueError("Unsupported display!"); // Try to create an appropriate display driver if (display == DISPLAY_TUFTY_2040) { @@ -115,24 +133,8 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size } // Create or fetch buffer - size_t required_size = 0; - switch(pen_type) { - case PEN_P4: - required_size = PicoGraphics_PenP4::buffer_size(width, height); - break; - case PEN_P8: - required_size = PicoGraphics_PenP8::buffer_size(width, height); - break; - case PEN_RGB332: - required_size = PicoGraphics_PenRGB332::buffer_size(width, height); - break; - case PEN_RGB565: - required_size = PicoGraphics_PenRGB565::buffer_size(width, height); - break; - default: - mp_raise_ValueError("Unsupported display!"); - break; // unreachable - } + size_t required_size = get_required_buffer_size(pen_type, width, height); + if(required_size == 0) mp_raise_ValueError("Unsupported pen type!"); if (args[ARG_buffer].u_obj != mp_const_none) { mp_buffer_info_t bufinfo; @@ -203,6 +205,18 @@ mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) return mp_const_none; } +mp_obj_t ModPicoGraphics_get_required_buffer_size(mp_obj_t display_in, mp_obj_t pen_type_in) { + PicoGraphicsPenType pen_type = (PicoGraphicsPenType)mp_obj_get_int(pen_type_in); + PicoGraphicsDisplay display = (PicoGraphicsDisplay)mp_obj_get_int(display_in); + int width = 0; + int height = 0; + if(!get_display_resolution(display, width, height)) mp_raise_ValueError("Unsupported display!"); + size_t required_size = get_required_buffer_size(pen_type, width, height); + if(required_size == 0) mp_raise_ValueError("Unsupported pen type!"); + + return mp_obj_new_int(required_size); +} + mp_obj_t ModPicoGraphics_get_bounds(mp_obj_t self_in) { ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); mp_obj_t tuple[2] = { diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index 066e5126..ded38c35 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -26,6 +26,7 @@ extern const mp_obj_type_t ModPicoGraphics_type; // Module functions extern mp_obj_t ModPicoGraphics_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b); extern mp_obj_t ModPicoGraphics_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); +extern mp_obj_t ModPicoGraphics_get_required_buffer_size(mp_obj_t display_in, mp_obj_t pen_type_in); // Class methods extern mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); From bfea30b66235362332a1a63313e8e9c07fe97b4e Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 12:22:42 +0100 Subject: [PATCH 41/84] Pimoroni Bus: Allow SPIBus to take mosi arg, no backlight by default. --- micropython/modules/pimoroni_bus/pimoroni_bus.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/micropython/modules/pimoroni_bus/pimoroni_bus.cpp b/micropython/modules/pimoroni_bus/pimoroni_bus.cpp index 6a5cf874..095de541 100644 --- a/micropython/modules/pimoroni_bus/pimoroni_bus.cpp +++ b/micropython/modules/pimoroni_bus/pimoroni_bus.cpp @@ -47,13 +47,14 @@ void PimoroniBus_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ } mp_obj_t SPIPins_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; + enum { ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_miso, ARG_bl }; static const mp_arg_t allowed_args[] = { { MP_QSTR_cs, MP_ARG_INT, {.u_int = SPI_BG_FRONT_CS} }, { MP_QSTR_dc, MP_ARG_INT, {.u_int = SPI_DEFAULT_MISO} }, { MP_QSTR_sck, MP_ARG_INT, {.u_int = SPI_DEFAULT_SCK} }, { MP_QSTR_mosi, MP_ARG_INT, {.u_int = SPI_DEFAULT_MOSI} }, - { MP_QSTR_bl, MP_ARG_INT, {.u_int = SPI_BG_FRONT_PWM} }, + { MP_QSTR_miso, MP_ARG_INT, {.u_int = PIN_UNUSED} }, + { MP_QSTR_bl, MP_ARG_INT, {.u_int = PIN_UNUSED} }, }; // Parse args. @@ -67,9 +68,9 @@ mp_obj_t SPIPins_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, (uint)args[ARG_cs].u_int, (uint)args[ARG_sck].u_int, (uint)args[ARG_mosi].u_int, - PIN_UNUSED, + (uint)args[ARG_miso].u_int, (uint)args[ARG_dc].u_int, - args[ARG_bl].u_int == -1 ? PIN_UNUSED : (uint)args[ARG_bl].u_int + (uint)args[ARG_bl].u_int }; return MP_OBJ_FROM_PTR(self); From 1d32b967c23fd6ceb2a12dbb1e95982777516723 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 12:23:32 +0100 Subject: [PATCH 42/84] ST7789: Separate code paths for future DMA/PIO support. --- drivers/st7789/st7789.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 4a9d2430..4fbee353 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -245,33 +245,35 @@ namespace pimoroni { } void ST7789::update(PicoGraphics *graphics) { - if(graphics->pen_type == PicoGraphics::PEN_RGB565) { - command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); - } else { - uint8_t command = reg::RAMWR; + uint8_t cmd = reg::RAMWR; + if(graphics->pen_type == PicoGraphics::PEN_RGB565) { // Display buffer is screen native + command(cmd, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); + } else if(spi) { // SPI Bus gpio_put(dc, 0); // command mode - gpio_put(cs, 0); - - if(spi) { - spi_write_blocking(spi, &command, 1); - } else { - write_blocking_parallel(&command, 1); - } - + spi_write_blocking(spi, &cmd, 1); gpio_put(dc, 1); // data mode uint16_t row_buf[width]; - for(auto y = 0u; y < height; y++) { graphics->get_data(y, &row_buf); // TODO: Add DMA->SPI / PIO while we prep the next row - if(spi) { - spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); - } else { - write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); - } + spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); + } + + gpio_put(cs, 1); + } else { // Parallel Bus + gpio_put(dc, 0); // command mode + gpio_put(cs, 0); + write_blocking_parallel(&cmd, 1); + gpio_put(dc, 1); // data mode + + uint16_t row_buf[width]; + for(auto y = 0u; y < height; y++) { + graphics->get_data(y, &row_buf); + // TODO: Add DMA->SPI / PIO while we prep the next row + write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); } gpio_put(cs, 1); From a558d35cabb3e2fbe67c99b21f8ffb877e4972d5 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 13:45:52 +0100 Subject: [PATCH 43/84] PicoGraphics: Remove last vestiges of template approach. --- drivers/st7735/st7735.cpp | 4 ++-- drivers/st7789/st7789.cpp | 6 +++--- libraries/pico_graphics/pico_graphics.cpp | 10 +--------- libraries/pico_graphics/pico_graphics.hpp | 10 +++++----- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/st7735/st7735.cpp b/drivers/st7735/st7735.cpp index ee306bb9..c257020d 100644 --- a/drivers/st7735/st7735.cpp +++ b/drivers/st7735/st7735.cpp @@ -166,7 +166,7 @@ namespace pimoroni { // Native 16-bit framebuffer update void ST7735::update(PicoGraphics *graphics) { if(graphics->pen_type == PicoGraphics::PEN_RGB565) { - command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); + command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer); } else { command(reg::RAMWR); gpio_put(dc, 1); // data mode @@ -174,7 +174,7 @@ namespace pimoroni { uint16_t row_buf[width]; for(auto y = 0u; y < height; y++) { - graphics->get_data(y, &row_buf); + graphics->get_row_rgb565(&row_buf, width * y, width); // TODO: Add DMA->SPI / PIO while we prep the next row spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); } diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 4fbee353..be275016 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -248,7 +248,7 @@ namespace pimoroni { uint8_t cmd = reg::RAMWR; if(graphics->pen_type == PicoGraphics::PEN_RGB565) { // Display buffer is screen native - command(cmd, width * height * sizeof(uint16_t), (const char*)graphics->get_data()); + command(cmd, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer); } else if(spi) { // SPI Bus gpio_put(dc, 0); // command mode gpio_put(cs, 0); @@ -257,7 +257,7 @@ namespace pimoroni { uint16_t row_buf[width]; for(auto y = 0u; y < height; y++) { - graphics->get_data(y, &row_buf); + graphics->get_row_rgb565(&row_buf, width * y, width); // TODO: Add DMA->SPI / PIO while we prep the next row spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); } @@ -271,7 +271,7 @@ namespace pimoroni { uint16_t row_buf[width]; for(auto y = 0u; y < height; y++) { - graphics->get_data(y, &row_buf); + graphics->get_row_rgb565(&row_buf, width * y, width); // TODO: Add DMA->SPI / PIO while we prep the next row write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); } diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 263ffed7..a9b9ff30 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -8,7 +8,7 @@ namespace pimoroni { int PicoGraphics::reset_pen(uint8_t i) {return -1;}; int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;}; void PicoGraphics::set_pixel(const Point &p) {}; - void PicoGraphics::palette_lookup(void *frame_buffer, void *result, uint offset, uint length) {}; + void PicoGraphics::get_row_rgb565(void *result, uint offset, uint length) {}; void PicoGraphics::set_dimensions(int width, int height) { bounds = clip = {0, 0, width, height}; @@ -18,14 +18,6 @@ namespace pimoroni { this->frame_buffer = frame_buffer; } - void *PicoGraphics::get_data() { - return frame_buffer; - } - - void PicoGraphics::get_data(uint y, void *row_buf) { - palette_lookup(frame_buffer, row_buf, y * bounds.w, bounds.w); - } - void PicoGraphics::set_font(const bitmap::font_t *font){ this->bitmap_font = font; this->hershey_font = nullptr; diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index b7246aa2..49b11142 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -109,7 +109,7 @@ namespace pimoroni { virtual int reset_pen(uint8_t i); virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); virtual void set_pixel(const Point &p); - virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length); + virtual void get_row_rgb565(void *result, uint offset, uint length); void set_font(const bitmap::font_t *font); void set_font(const hershey::font_t *font); @@ -119,7 +119,7 @@ namespace pimoroni { void set_framebuffer(void *frame_buffer); void *get_data(); - void get_data(uint y, void *row_buf); + void get_data(PenType type, uint y, void *row_buf); void set_clip(const Rect &r); void remove_clip(); @@ -192,7 +192,7 @@ namespace pimoroni { *f &= m; // clear bits *f |= b; // set value } - void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { + void get_row_rgb565(void *result, uint offset, uint length) override { uint8_t *src = (uint8_t *)frame_buffer; uint16_t *dst = (uint16_t *)result; for(auto x = 0u; x < length; x++) { @@ -255,7 +255,7 @@ namespace pimoroni { uint8_t *buf = (uint8_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } - void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { + void get_row_rgb565(void *result, uint offset, uint length) override { uint8_t *src = (uint8_t *)frame_buffer; uint16_t *dst = (uint16_t *)result; for(auto x = 0u; x < length; x++) { @@ -295,7 +295,7 @@ namespace pimoroni { uint8_t *buf = (uint8_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } - void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { + void get_row_rgb565(void *result, uint offset, uint length) override { uint8_t *src = (uint8_t *)frame_buffer; uint16_t *dst = (uint16_t *)result; for(auto x = 0u; x < length; x++) { From 024518ed9a2751da2de17bacf7410f1ba0263db5 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 13:46:21 +0100 Subject: [PATCH 44/84] PicoGraphics: Don't require wordwrap. --- micropython/modules/picographics/picographics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 4d79c1e9..33a15cf9 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -463,7 +463,7 @@ mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_wordwrap, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_wordwrap, MP_ARG_INT, {.u_int = __INT32_MAX__} }, // Sort-of a fudge, but wide-enough to avoid wrapping on any display size { MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_angle, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_spacing, MP_ARG_INT, {.u_int = 1} }, From 1a9ebb7b6ef8c24b363b61638e177f5035e291e5 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 16:52:06 +0100 Subject: [PATCH 45/84] PicoGraphics: More pen conversion, better names. --- libraries/pico_graphics/pico_graphics.hpp | 35 +++++++++++++++---- .../modules/picographics/picographics.c | 14 +++++--- .../modules/picographics/picographics.cpp | 35 +++++++++++++++++-- .../modules/picographics/picographics.h | 10 ++++-- 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 49b11142..b0d81f30 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -85,19 +85,39 @@ namespace pimoroni { static constexpr RGB565 rgb332_to_rgb565(RGB332 c) { uint16_t p = ((c & 0b11100000) << 8) | - ((c & 0b00011100) << 6) | - ((c & 0b00000011) << 3); + ((c & 0b00011100) << 6) | + ((c & 0b00000011) << 3); return __builtin_bswap16(p); } + static constexpr RGB565 rgb565_to_rgb332(RGB565 c) { + c = __builtin_bswap16(c); + return ((c & 0b1110000000000000) >> 8) | + ((c & 0b0000011100000000) >> 6) | + ((c & 0b0000000000011000) >> 3); + } + static constexpr RGB565 rgb_to_rgb565(uint8_t r, uint8_t g, uint8_t b) { uint16_t p = ((r & 0b11111000) << 8) | - ((g & 0b11111100) << 3) | - ((b & 0b11111000) >> 3); + ((g & 0b11111100) << 3) | + ((b & 0b11111000) >> 3); return __builtin_bswap16(p); } + static constexpr void rgb332_to_rgb(RGB332 c, uint8_t &r, uint8_t &g, uint8_t &b) { + r = (c & 0b11100000) >> 0; + g = (c & 0b00011100) << 3; + b = (c & 0b00000011) << 6; + }; + + static constexpr void rgb565_to_rgb(RGB565 c, uint8_t &r, uint8_t &g, uint8_t &b) { + c = __builtin_bswap16(c); + r = (c & 0b1111100000000000) >> 8; + g = (c & 0b0000011111100000) >> 3; + b = (c & 0b0000000000011111) << 3; + }; + PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) : frame_buffer(frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) { set_font(&font6); @@ -141,8 +161,8 @@ namespace pimoroni { class PicoGraphics_PenP4 : public PicoGraphics { public: uint8_t color; - PaletteEntry palette[8]; - const RGB565 default_palette[8] = { + PaletteEntry palette[16]; + const RGB565 default_palette[16] = { rgb_to_rgb565(57, 48, 57), // Black rgb_to_rgb565(255, 255, 255), // White rgb_to_rgb565(58, 91, 70), // Green @@ -158,6 +178,9 @@ namespace pimoroni { if(this->frame_buffer == nullptr) { this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); } + for(auto i = 0u; i < 16; i++) { + palette[i].used = false; + } for(auto i = 0u; i < 8; i++) { palette[i].color = default_palette[i]; palette[i].used = true; diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index c8e00cc2..c42c804b 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -1,8 +1,10 @@ #include "picographics.h" // Module functions -STATIC MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_module_RGB332_obj, ModPicoGraphics_module_RGB332); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_module_RGB565_obj, ModPicoGraphics_module_RGB565); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_module_RGB_to_RGB332_obj, ModPicoGraphics_module_RGB_to_RGB332); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(ModPicoGraphics_module_RGB_to_RGB565_obj, ModPicoGraphics_module_RGB_to_RGB565); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_module_RGB332_to_RGB_obj, ModPicoGraphics_module_RGB332_to_RGB); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_module_RGB565_to_RGB_obj, ModPicoGraphics_module_RGB565_to_RGB); STATIC MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_get_required_buffer_size_obj, ModPicoGraphics_get_required_buffer_size); // Class Methods @@ -74,6 +76,7 @@ const mp_obj_type_t ModPicoGraphics_type = { { &mp_type_type }, .name = MP_QSTR_picographics, .make_new = ModPicoGraphics_make_new, + .buffer_p = { .get_buffer = ModPicoGraphics_get_framebuffer }, .locals_dict = (mp_obj_dict_t*)&ModPicoGraphics_locals_dict, }; @@ -83,8 +86,11 @@ STATIC const mp_map_elem_t picographics_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PicoGraphics), (mp_obj_t)&ModPicoGraphics_type }, { MP_ROM_QSTR(MP_QSTR_get_buffer_size), MP_ROM_PTR(&ModPicoGraphics_get_required_buffer_size_obj) }, - { MP_ROM_QSTR(MP_QSTR_RGB332), MP_ROM_PTR(&ModPicoGraphics_module_RGB332_obj) }, - { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&ModPicoGraphics_module_RGB565_obj) }, + // Colour conversion + { MP_ROM_QSTR(MP_QSTR_RGB_to_RGB332), MP_ROM_PTR(&ModPicoGraphics_module_RGB_to_RGB332_obj) }, + { MP_ROM_QSTR(MP_QSTR_RGB_to_RGB565), MP_ROM_PTR(&ModPicoGraphics_module_RGB_to_RGB565_obj) }, + { MP_ROM_QSTR(MP_QSTR_RGB332_to_RGB), MP_ROM_PTR(&ModPicoGraphics_module_RGB332_to_RGB_obj) }, + { MP_ROM_QSTR(MP_QSTR_RGB565_to_RGB), MP_ROM_PTR(&ModPicoGraphics_module_RGB565_to_RGB_obj) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_240X240), MP_ROM_INT(DISPLAY_LCD_240X240) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_ROUND_LCD_240X240), MP_ROM_INT(DISPLAY_ROUND_LCD_240X240) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 33a15cf9..fb108a63 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -182,6 +182,15 @@ mp_obj_t ModPicoGraphics_set_font(mp_obj_t self_in, mp_obj_t font) { return mp_const_none; } +mp_int_t ModPicoGraphics_get_framebuffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); + (void)flags; + bufinfo->buf = self->graphics->frame_buffer; + bufinfo->len = get_required_buffer_size((PicoGraphicsPenType)self->graphics->pen_type, self->graphics->bounds.w, self->graphics->bounds.h); + bufinfo->typecode = 'B'; + return 0; +} + mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer) { ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); @@ -245,7 +254,29 @@ mp_obj_t ModPicoGraphics_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { return mp_const_none; } -mp_obj_t ModPicoGraphics_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { +mp_obj_t ModPicoGraphics_module_RGB332_to_RGB(mp_obj_t rgb332) { + uint8_t r, g, b; + PicoGraphics::rgb332_to_rgb(mp_obj_get_int(rgb332), r, g, b); + mp_obj_t t[] = { + mp_obj_new_int(r), + mp_obj_new_int(g), + mp_obj_new_int(b), + }; + return mp_obj_new_tuple(3, t); +} + +mp_obj_t ModPicoGraphics_module_RGB565_to_RGB(mp_obj_t rgb565) { + uint8_t r, g, b; + PicoGraphics::rgb565_to_rgb(mp_obj_get_int(rgb565), r, g, b); + mp_obj_t t[] = { + mp_obj_new_int(r), + mp_obj_new_int(g), + mp_obj_new_int(b), + }; + return mp_obj_new_tuple(3, t); +} + +mp_obj_t ModPicoGraphics_module_RGB_to_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { return mp_obj_new_int(PicoGraphics::rgb_to_rgb332( mp_obj_get_int(r), mp_obj_get_int(g), @@ -253,7 +284,7 @@ mp_obj_t ModPicoGraphics_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { )); } -mp_obj_t ModPicoGraphics_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { +mp_obj_t ModPicoGraphics_module_RGB_to_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { return mp_obj_new_int(PicoGraphics::rgb_to_rgb565( mp_obj_get_int(r), mp_obj_get_int(g), diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index ded38c35..9f18fdcb 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -24,8 +24,10 @@ enum PicoGraphicsPenType { extern const mp_obj_type_t ModPicoGraphics_type; // Module functions -extern mp_obj_t ModPicoGraphics_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b); -extern mp_obj_t ModPicoGraphics_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); +extern mp_obj_t ModPicoGraphics_module_RGB_to_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b); +extern mp_obj_t ModPicoGraphics_module_RGB_to_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b); +extern mp_obj_t ModPicoGraphics_module_RGB332_to_RGB(mp_obj_t rgb332); +extern mp_obj_t ModPicoGraphics_module_RGB565_to_RGB(mp_obj_t rgb565); extern mp_obj_t ModPicoGraphics_get_required_buffer_size(mp_obj_t display_in, mp_obj_t pen_type_in); // Class methods @@ -61,4 +63,6 @@ extern mp_obj_t ModPicoGraphics_line(size_t n_args, const mp_obj_t *args); // Utility extern mp_obj_t ModPicoGraphics_set_font(mp_obj_t self_in, mp_obj_t font); extern mp_obj_t ModPicoGraphics_get_bounds(mp_obj_t self_in); -extern mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); \ No newline at end of file +extern mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); + +extern mp_int_t ModPicoGraphics_get_framebuffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); \ No newline at end of file From 7f0fe44881b196793f3aa6858fbea581c1d6dcb9 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 16:52:44 +0100 Subject: [PATCH 46/84] JPEGDEC: Move to libraries, use C++, draw into PicoGraphics. --- libraries/jpegdec/JPEGDEC.cpp | 199 ++++++++++++++++++ .../modules => libraries}/jpegdec/JPEGDEC.h | 0 .../jpeg.c => libraries/jpegdec/jpeg.inl | 0 micropython/modules/jpegdec/jpegdec.c | 87 +------- micropython/modules/jpegdec/jpegdec.cpp | 161 ++++++++++++++ micropython/modules/jpegdec/jpegdec.h | 11 + micropython/modules/jpegdec/micropython.cmake | 5 +- 7 files changed, 378 insertions(+), 85 deletions(-) create mode 100644 libraries/jpegdec/JPEGDEC.cpp rename {micropython/modules => libraries}/jpegdec/JPEGDEC.h (100%) rename micropython/modules/jpegdec/jpeg.c => libraries/jpegdec/jpeg.inl (100%) create mode 100644 micropython/modules/jpegdec/jpegdec.cpp create mode 100644 micropython/modules/jpegdec/jpegdec.h diff --git a/libraries/jpegdec/JPEGDEC.cpp b/libraries/jpegdec/JPEGDEC.cpp new file mode 100644 index 00000000..39e33a4b --- /dev/null +++ b/libraries/jpegdec/JPEGDEC.cpp @@ -0,0 +1,199 @@ +// +// JPEG Decoder +// +// written by Larry Bank +// bitbank@pobox.com +// Arduino port started 8/2/2020 +// Original JPEG code written 26+ years ago :) +// The goal of this code is to decode baseline JPEG images +// using no more than 18K of RAM (if sent directly to an LCD display) +// +// Copyright 2020 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +// +#include "JPEGDEC.h" + +// forward references +JPEG_STATIC int JPEGInit(JPEGIMAGE *pJPEG); +JPEG_STATIC int JPEGParseInfo(JPEGIMAGE *pPage, int bExtractThumb); +JPEG_STATIC void JPEGGetMoreData(JPEGIMAGE *pPage); +JPEG_STATIC int DecodeJPEG(JPEGIMAGE *pImage); + +// Include the C code which does the actual work +#include "jpeg.inl" + +void JPEGDEC::setPixelType(int iType) +{ + if (iType >= 0 && iType < INVALID_PIXEL_TYPE) + _jpeg.ucPixelType = (uint8_t)iType; + else + _jpeg.iError = JPEG_INVALID_PARAMETER; +} /* setPixelType() */ + +void JPEGDEC::setMaxOutputSize(int iMaxMCUs) +{ + if (iMaxMCUs < 1) + iMaxMCUs = 1; // don't allow invalid value + _jpeg.iMaxMCUs = iMaxMCUs; +} /* setMaxOutputSize() */ +// +// Memory initialization +// +int JPEGDEC::openRAM(uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(&_jpeg, 0, sizeof(JPEGIMAGE)); + _jpeg.ucMemType = JPEG_MEM_RAM; + _jpeg.pfnRead = readRAM; + _jpeg.pfnSeek = seekMem; + _jpeg.pfnDraw = pfnDraw; + _jpeg.pfnOpen = NULL; + _jpeg.pfnClose = NULL; + _jpeg.JPEGFile.iSize = iDataSize; + _jpeg.JPEGFile.pData = pData; + _jpeg.iMaxMCUs = 1000; // set to an unnaturally high value to start + return JPEGInit(&_jpeg); +} /* openRAM() */ + +int JPEGDEC::openFLASH(uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(&_jpeg, 0, sizeof(JPEGIMAGE)); + _jpeg.ucMemType = JPEG_MEM_FLASH; + _jpeg.pfnRead = readFLASH; + _jpeg.pfnSeek = seekMem; + _jpeg.pfnDraw = pfnDraw; + _jpeg.pfnOpen = NULL; + _jpeg.pfnClose = NULL; + _jpeg.JPEGFile.iSize = iDataSize; + _jpeg.JPEGFile.pData = pData; + _jpeg.iMaxMCUs = 1000; // set to an unnaturally high value to start + return JPEGInit(&_jpeg); +} /* openRAM() */ + +int JPEGDEC::getOrientation() +{ + return (int)_jpeg.ucOrientation; +} /* getOrientation() */ + +int JPEGDEC::getLastError() +{ + return _jpeg.iError; +} /* getLastError() */ + +int JPEGDEC::getWidth() +{ + return _jpeg.iWidth; +} /* getWidth() */ + +int JPEGDEC::getHeight() +{ + return _jpeg.iHeight; +} /* getHeight() */ + +int JPEGDEC::hasThumb() +{ + return (int)_jpeg.ucHasThumb; +} /* hasThumb() */ + +int JPEGDEC::getThumbWidth() +{ + return _jpeg.iThumbWidth; +} /* getThumbWidth() */ + +int JPEGDEC::getThumbHeight() +{ + return _jpeg.iThumbHeight; +} /* getThumbHeight() */ + +int JPEGDEC::getBpp() +{ + return (int)_jpeg.ucBpp; +} /* getBpp() */ + +int JPEGDEC::getSubSample() +{ + return (int)_jpeg.ucSubSample; +} /* getSubSample() */ + +// +// File (SD/MMC) based initialization +// +int JPEGDEC::open(const char *szFilename, JPEG_OPEN_CALLBACK *pfnOpen, JPEG_CLOSE_CALLBACK *pfnClose, JPEG_READ_CALLBACK *pfnRead, JPEG_SEEK_CALLBACK *pfnSeek, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(&_jpeg, 0, sizeof(JPEGIMAGE)); + _jpeg.pfnRead = pfnRead; + _jpeg.pfnSeek = pfnSeek; + _jpeg.pfnDraw = pfnDraw; + _jpeg.pfnOpen = pfnOpen; + _jpeg.pfnClose = pfnClose; + _jpeg.iMaxMCUs = 1000; // set to an unnaturally high value to start + _jpeg.JPEGFile.fHandle = (*pfnOpen)(szFilename, &_jpeg.JPEGFile.iSize); + if (_jpeg.JPEGFile.fHandle == NULL) + return 0; + return JPEGInit(&_jpeg); + +} /* open() */ + +#ifdef FS_H +static int32_t FileRead(JPEGFILE *handle, uint8_t *buffer, int32_t length) +{ + return ((File *)(handle->fHandle))->read(buffer, length); +} +static int32_t FileSeek(JPEGFILE *handle, int32_t position) +{ + return ((File *)(handle->fHandle))->seek(position); +} +static void FileClose(void *handle) +{ + ((File *)handle)->close(); +} + +int JPEGDEC::open(File &file, JPEG_DRAW_CALLBACK *pfnDraw) +{ + if (!file) return 0; + memset(&_jpeg, 0, sizeof(JPEGIMAGE)); + _jpeg.pfnRead = FileRead; + _jpeg.pfnSeek = FileSeek; + _jpeg.pfnClose = FileClose; + _jpeg.pfnDraw = pfnDraw; + _jpeg.iMaxMCUs = 1000; + _jpeg.JPEGFile.fHandle = &file; + _jpeg.JPEGFile.iSize = file.size(); + return JPEGInit(&_jpeg); +} +#endif // FS_H + +void JPEGDEC::close() +{ + if (_jpeg.pfnClose) + (*_jpeg.pfnClose)(_jpeg.JPEGFile.fHandle); +} /* close() */ + +// +// Decode the image +// returns: +// 1 = good result +// 0 = error +// +int JPEGDEC::decode(int x, int y, int iOptions) +{ + _jpeg.iXOffset = x; + _jpeg.iYOffset = y; + _jpeg.iOptions = iOptions; + return DecodeJPEG(&_jpeg); +} /* decode() */ + +int JPEGDEC::decodeDither(uint8_t *pDither, int iOptions) +{ + _jpeg.iOptions = iOptions; + _jpeg.pDitherBuffer = pDither; + return DecodeJPEG(&_jpeg); +} diff --git a/micropython/modules/jpegdec/JPEGDEC.h b/libraries/jpegdec/JPEGDEC.h similarity index 100% rename from micropython/modules/jpegdec/JPEGDEC.h rename to libraries/jpegdec/JPEGDEC.h diff --git a/micropython/modules/jpegdec/jpeg.c b/libraries/jpegdec/jpeg.inl similarity index 100% rename from micropython/modules/jpegdec/jpeg.c rename to libraries/jpegdec/jpeg.inl diff --git a/micropython/modules/jpegdec/jpegdec.c b/micropython/modules/jpegdec/jpegdec.c index 1b24bddf..394ecd65 100644 --- a/micropython/modules/jpegdec/jpegdec.c +++ b/micropython/modules/jpegdec/jpegdec.c @@ -1,90 +1,9 @@ -#include "py/runtime.h" -#include "py/objstr.h" -#include "JPEGDEC.h" +#include "jpegdec.h" -const mp_obj_type_t JPEG_type; - -typedef struct _JPEG_obj_t { - mp_obj_base_t base; - JPEGIMAGE *jpeg; - mp_obj_t callback; -} _JPEG_obj_t; - -mp_obj_t current_callback = mp_const_none; - -int JPEGDraw(JPEGDRAW *pDraw) { - for(int y = 0; y < pDraw->iHeight; y++) { - for(int x = 0; x < pDraw->iWidth; x++) { - int i = y * pDraw->iWidth + x; - mp_obj_t args[] = { - mp_obj_new_int(pDraw->x + x), - mp_obj_new_int(pDraw->y + y), - mp_obj_new_int(pDraw->pPixels[i]) - }; - mp_call_function_n_kw(current_callback, MP_ARRAY_SIZE(args), 0, args); - } - } - return 1; -} - -STATIC mp_obj_t _JPEG_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { - ARG_callback - }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - _JPEG_obj_t *self = m_new_obj_with_finaliser(_JPEG_obj_t); - self->base.type = &JPEG_type; - self->jpeg = m_new(JPEGIMAGE, 1); - self->callback = args[ARG_callback].u_obj; - return self; -} - -STATIC mp_obj_t _JPEG_del(mp_obj_t self_in) { - _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); - m_del(JPEGIMAGE, self->jpeg, 1); - return mp_const_none; -} STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_del_obj, _JPEG_del); - -// open_RAM -STATIC mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer) { - _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); - int result = JPEG_openRAM(self->jpeg, bufinfo.buf, bufinfo.len, JPEGDraw); - JPEG_setPixelType(self->jpeg, RGB565_BIG_ENDIAN); - return result == 1 ? mp_const_true : mp_const_false; -} STATIC MP_DEFINE_CONST_FUN_OBJ_2(JPEG_openRAM_obj, _JPEG_openRAM); - -// decode -STATIC mp_obj_t _JPEG_decode(mp_obj_t self_in, mp_obj_t flags) { - _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); - int x = 0; - int y = 0; - int f = mp_obj_get_int(flags); - current_callback = self->callback; - return JPEG_decode(self->jpeg, x, y, f) == 1 ? mp_const_true : mp_const_false; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(JPEG_decode_obj, _JPEG_decode); - -// get_width -STATIC mp_obj_t _JPEG_getWidth(mp_obj_t self_in) { - _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(JPEG_getWidth(self->jpeg)); -} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(JPEG_decode_obj, 1, _JPEG_decode); STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_getWidth_obj, _JPEG_getWidth); - -// get_height -STATIC mp_obj_t _JPEG_getHeight(mp_obj_t self_in) { - _JPEG_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(JPEG_getHeight(self->jpeg)); -} STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_getHeight_obj, _JPEG_getHeight); // class @@ -112,10 +31,12 @@ STATIC const mp_map_elem_t JPEG_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_jpegdec) }, { MP_OBJ_NEW_QSTR(MP_QSTR_JPEG), (mp_obj_t)&JPEG_type }, }; + STATIC MP_DEFINE_CONST_DICT(mp_module_JPEG_globals, JPEG_globals_table); const mp_obj_module_t JPEG_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_JPEG_globals, }; + MP_REGISTER_MODULE(MP_QSTR_jpegdec, JPEG_user_cmodule, MODULE_JPEGDEC_ENABLED); \ No newline at end of file diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp new file mode 100644 index 00000000..8a155165 --- /dev/null +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -0,0 +1,161 @@ +#include "libraries/jpegdec/JPEGDEC.h" + +#include "micropython/modules/util.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" + +using namespace pimoroni; + +extern "C" { +#include "jpegdec.h" +#include "micropython/modules/picographics/picographics.h" + +typedef struct _ModPicoGraphics_obj_t { + mp_obj_base_t base; + PicoGraphics *graphics; + DisplayDriver *display; + void *buffer; +} ModPicoGraphics_obj_t; + +typedef struct _JPEG_obj_t { + mp_obj_base_t base; + JPEGDEC *jpeg; + mp_obj_t callback; + ModPicoGraphics_obj_t *graphics; +} _JPEG_obj_t; + +PicoGraphics *current_graphics = nullptr; + +int JPEGDraw(JPEGDRAW *pDraw) { + // "pixel" is slow and clipped, + // guaranteeing we wont draw jpeg data out of the framebuffer.. + // Can we clip beforehand and make this faster? + if(pDraw->iBpp == 4) { // TODO 4-bit pixel unpacking isn't working. What's up? + uint8_t *pixels = (uint8_t *)pDraw->pPixels; + for(int y = 0; y < pDraw->iHeight; y++) { + for(int x = 0; x < pDraw->iWidth; x++) { + int i = y * pDraw->iWidth + x; + uint8_t p = pixels[i / 2]; + p >>= (i & 0b1) * 4; + p &= 0xf; + current_graphics->set_pen(p); + current_graphics->pixel({pDraw->x + x, pDraw->y + y}); + } + } + } else if(pDraw->iBpp == 8) { + uint8_t *pixels = (uint8_t *)pDraw->pPixels; + for(int y = 0; y < pDraw->iHeight; y++) { + for(int x = 0; x < pDraw->iWidth; x++) { + int i = y * pDraw->iWidth + x; + current_graphics->set_pen(pixels[i] >> (current_graphics->pen_type == PicoGraphics::PEN_P4 ? 4 : 0)); + current_graphics->pixel({pDraw->x + x, pDraw->y + y}); + } + } + } else { + for(int y = 0; y < pDraw->iHeight; y++) { + for(int x = 0; x < pDraw->iWidth; x++) { + int i = y * pDraw->iWidth + x; + if (current_graphics->pen_type == PicoGraphics::PEN_RGB332) { + current_graphics->set_pen(PicoGraphics::rgb565_to_rgb332(pDraw->pPixels[i])); + } else { + current_graphics->set_pen(pDraw->pPixels[i]); + } + current_graphics->pixel({pDraw->x + x, pDraw->y + y}); + } + } + } + return 1; +} + +mp_obj_t _JPEG_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { + ARG_picographics + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_picographics, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!MP_OBJ_IS_TYPE(args[ARG_picographics].u_obj, &ModPicoGraphics_type)) mp_raise_ValueError(MP_ERROR_TEXT("PicoGraphics Object Required")); + + _JPEG_obj_t *self = m_new_obj_with_finaliser(_JPEG_obj_t); + self->base.type = &JPEG_type; + self->jpeg = m_new_class(JPEGDEC); + self->graphics = (ModPicoGraphics_obj_t *)MP_OBJ_TO_PTR(args[ARG_picographics].u_obj); + return self; +} + +mp_obj_t _JPEG_del(mp_obj_t self_in) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t); + (void)self; + return mp_const_none; +} + +// open_RAM +mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + int result = self->jpeg->openRAM((uint8_t *)bufinfo.buf, bufinfo.len, JPEGDraw); + if (result == 1) { + switch(self->graphics->graphics->pen_type) { + case PicoGraphics::PEN_RGB332: + case PicoGraphics::PEN_RGB565: + self->jpeg->setPixelType(RGB565_BIG_ENDIAN); + break; + case PicoGraphics::PEN_P8: + self->jpeg->setPixelType(EIGHT_BIT_GRAYSCALE); + break; + // TODO currently uses EIGHT_BIT_GREYSCALE and shifts down should this use a 4-bit dither? + case PicoGraphics::PEN_P4: + self->jpeg->setPixelType(EIGHT_BIT_GRAYSCALE); + break; + // TODO 2-bit is currently unsupported + case PicoGraphics::PEN_P2: + self->jpeg->setPixelType(TWO_BIT_DITHERED); + break; + } + } + return result == 1 ? mp_const_true : mp_const_false; +} + +// decode +mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_x, ARG_y, ARG_scale }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_scale, MP_ARG_INT, {.u_int = 0} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _JPEG_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _JPEG_obj_t); + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + int f = args[ARG_scale].u_int; + + // We need to store a pointer to the PicoGraphics surface + // since the JPEGDRAW struct has no userdata + current_graphics = self->graphics->graphics; + int result = self->jpeg->decode(x, y, f); + current_graphics = nullptr; + return result == 1 ? mp_const_true : mp_const_false; +} + +// get_width +mp_obj_t _JPEG_getWidth(mp_obj_t self_in) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t); + return mp_obj_new_int(self->jpeg->getWidth()); +} + +// get_height +mp_obj_t _JPEG_getHeight(mp_obj_t self_in) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t); + return mp_obj_new_int(self->jpeg->getHeight()); +} + +} \ No newline at end of file diff --git a/micropython/modules/jpegdec/jpegdec.h b/micropython/modules/jpegdec/jpegdec.h new file mode 100644 index 00000000..d8d9b26f --- /dev/null +++ b/micropython/modules/jpegdec/jpegdec.h @@ -0,0 +1,11 @@ +#include "py/runtime.h" +#include "py/objstr.h" + +extern const mp_obj_type_t JPEG_type; + +extern mp_obj_t _JPEG_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 _JPEG_del(mp_obj_t self_in); +extern mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer); +extern mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t _JPEG_getWidth(mp_obj_t self_in); +extern mp_obj_t _JPEG_getHeight(mp_obj_t self_in); \ No newline at end of file diff --git a/micropython/modules/jpegdec/micropython.cmake b/micropython/modules/jpegdec/micropython.cmake index feaa331a..2defc4da 100644 --- a/micropython/modules/jpegdec/micropython.cmake +++ b/micropython/modules/jpegdec/micropython.cmake @@ -2,7 +2,8 @@ add_library(usermod_jpegdec INTERFACE) target_sources(usermod_jpegdec INTERFACE ${CMAKE_CURRENT_LIST_DIR}/jpegdec.c - ${CMAKE_CURRENT_LIST_DIR}/jpeg.c + ${CMAKE_CURRENT_LIST_DIR}/jpegdec.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/jpegdec/JPEGDEC.cpp ) target_include_directories(usermod_jpegdec INTERFACE @@ -15,4 +16,4 @@ target_compile_definitions(usermod_jpegdec INTERFACE target_link_libraries(usermod INTERFACE usermod_jpegdec) -set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/jpeg.c PROPERTIES COMPILE_FLAGS "-Wno-error=unused-function") +set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/../../../libraries/jpegdec/JPEGDEC.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=unused-function") From 891750517527f0ad62e547fe2982883bfba029e6 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 17:39:20 +0100 Subject: [PATCH 47/84] JPEGDEC: Add open_file. --- micropython/modules/jpegdec/jpegdec.c | 2 + micropython/modules/jpegdec/jpegdec.cpp | 51 ++++++++++++++++++++----- micropython/modules/jpegdec/jpegdec.h | 1 + 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/micropython/modules/jpegdec/jpegdec.c b/micropython/modules/jpegdec/jpegdec.c index 394ecd65..ab4e221e 100644 --- a/micropython/modules/jpegdec/jpegdec.c +++ b/micropython/modules/jpegdec/jpegdec.c @@ -2,6 +2,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_del_obj, _JPEG_del); STATIC MP_DEFINE_CONST_FUN_OBJ_2(JPEG_openRAM_obj, _JPEG_openRAM); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(JPEG_openFILE_obj, _JPEG_openFILE); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(JPEG_decode_obj, 1, _JPEG_decode); STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_getWidth_obj, _JPEG_getWidth); STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_getHeight_obj, _JPEG_getHeight); @@ -10,6 +11,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(JPEG_getHeight_obj, _JPEG_getHeight); STATIC const mp_rom_map_elem_t JPEG_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&JPEG_del_obj) }, { MP_ROM_QSTR(MP_QSTR_open_RAM), MP_ROM_PTR(&JPEG_openRAM_obj) }, + { MP_ROM_QSTR(MP_QSTR_open_file), MP_ROM_PTR(&JPEG_openFILE_obj) }, { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&JPEG_decode_obj) }, { MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&JPEG_getWidth_obj) }, { MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&JPEG_getHeight_obj) }, diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index 8a155165..baa9d561 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -8,6 +8,9 @@ using namespace pimoroni; extern "C" { #include "jpegdec.h" #include "micropython/modules/picographics/picographics.h" +#include "py/stream.h" +#include "py/reader.h" +#include "extmod/vfs.h" typedef struct _ModPicoGraphics_obj_t { mp_obj_base_t base; @@ -19,7 +22,7 @@ typedef struct _ModPicoGraphics_obj_t { typedef struct _JPEG_obj_t { mp_obj_base_t base; JPEGDEC *jpeg; - mp_obj_t callback; + void *buf; ModPicoGraphics_obj_t *graphics; } _JPEG_obj_t; @@ -87,16 +90,13 @@ mp_obj_t _JPEG_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, c mp_obj_t _JPEG_del(mp_obj_t self_in) { _JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t); - (void)self; + self->jpeg->close(); return mp_const_none; } -// open_RAM -mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer) { - _JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); - int result = self->jpeg->openRAM((uint8_t *)bufinfo.buf, bufinfo.len, JPEGDraw); +static int _open(_JPEG_obj_t *self, void *buf, size_t len) { + self->buf = buf; // Store a pointer to this buffer so GC doesn't eat it + int result = self->jpeg->openRAM((uint8_t *)buf, len, JPEGDraw); if (result == 1) { switch(self->graphics->graphics->pen_type) { case PicoGraphics::PEN_RGB332: @@ -116,7 +116,40 @@ mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer) { break; } } - return result == 1 ? mp_const_true : mp_const_false; + return result; +} + +// open_FILE +mp_obj_t _JPEG_openFILE(mp_obj_t self_in, mp_obj_t filename) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t); + mp_obj_t args[2] = { + filename, + MP_OBJ_NEW_QSTR(MP_QSTR_r), + }; + + // Stat the file to get its size + // example tuple response: (32768, 0, 0, 0, 0, 0, 5153, 1654709815, 1654709815, 1654709815) + mp_obj_t stat = mp_vfs_stat(filename); + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(stat, mp_obj_tuple_t); + size_t filesize = mp_obj_get_int(tuple->items[6]); + + mp_buffer_info_t bufinfo; + bufinfo.buf = (void *)m_new(uint8_t, filesize); + mp_obj_t file = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map); + int errcode; + bufinfo.len = mp_stream_rw(file, bufinfo.buf, filesize, &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + if (errcode != 0) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Failed to open file!")); + } + return _open(self, bufinfo.buf, bufinfo.len) == 1 ? mp_const_true : mp_const_false; +} + +// open_RAM +mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer) { + _JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + return _open(self, bufinfo.buf, bufinfo.len) == 1 ? mp_const_true : mp_const_false; } // decode diff --git a/micropython/modules/jpegdec/jpegdec.h b/micropython/modules/jpegdec/jpegdec.h index d8d9b26f..fd1a59de 100644 --- a/micropython/modules/jpegdec/jpegdec.h +++ b/micropython/modules/jpegdec/jpegdec.h @@ -6,6 +6,7 @@ extern const mp_obj_type_t JPEG_type; extern mp_obj_t _JPEG_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 _JPEG_del(mp_obj_t self_in); extern mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer); +extern mp_obj_t _JPEG_openFILE(mp_obj_t self_in, mp_obj_t filename); extern mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t _JPEG_getWidth(mp_obj_t self_in); extern mp_obj_t _JPEG_getHeight(mp_obj_t self_in); \ No newline at end of file From 62818a5f4944048313abb93e392818e3677fa7cc Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 20:21:46 +0100 Subject: [PATCH 48/84] PicoGraphics: Palettes as RGB, Scanline convert with callback. --- drivers/st7735/st7735.cpp | 10 +- drivers/st7789/st7789.cpp | 22 +- libraries/pico_graphics/pico_graphics.cpp | 2 +- libraries/pico_graphics/pico_graphics.hpp | 239 ++++++++++++------ .../modules/picographics/picographics.cpp | 26 +- 5 files changed, 182 insertions(+), 117 deletions(-) diff --git a/drivers/st7735/st7735.cpp b/drivers/st7735/st7735.cpp index c257020d..aac94901 100644 --- a/drivers/st7735/st7735.cpp +++ b/drivers/st7735/st7735.cpp @@ -172,12 +172,10 @@ namespace pimoroni { gpio_put(dc, 1); // data mode gpio_put(cs, 0); - uint16_t row_buf[width]; - for(auto y = 0u; y < height; y++) { - graphics->get_row_rgb565(&row_buf, width * y, width); - // TODO: Add DMA->SPI / PIO while we prep the next row - spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); - } + graphics->scanline_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) { + spi_write_blocking(spi, (const uint8_t*)data, length); + }); + gpio_put(cs, 1); } } diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index be275016..688e008f 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -13,7 +13,7 @@ namespace pimoroni { COL_ORDER = 0b01000000, SWAP_XY = 0b00100000, // AKA "MV" SCAN_ORDER = 0b00010000, - RGB = 0b00001000, + RGB_BGR = 0b00001000, HORIZ_ORDER = 0b00000100 }; @@ -255,13 +255,10 @@ namespace pimoroni { spi_write_blocking(spi, &cmd, 1); gpio_put(dc, 1); // data mode - uint16_t row_buf[width]; - for(auto y = 0u; y < height; y++) { - graphics->get_row_rgb565(&row_buf, width * y, width); - // TODO: Add DMA->SPI / PIO while we prep the next row - spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t)); - } - + graphics->scanline_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) { + spi_write_blocking(spi, (const uint8_t*)data, length); + }); + gpio_put(cs, 1); } else { // Parallel Bus gpio_put(dc, 0); // command mode @@ -269,12 +266,9 @@ namespace pimoroni { write_blocking_parallel(&cmd, 1); gpio_put(dc, 1); // data mode - uint16_t row_buf[width]; - for(auto y = 0u; y < height; y++) { - graphics->get_row_rgb565(&row_buf, width * y, width); - // TODO: Add DMA->SPI / PIO while we prep the next row - write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t)); - } + graphics->scanline_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) { + write_blocking_parallel((const uint8_t*)data, length); + }); gpio_put(cs, 1); } diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index a9b9ff30..9e690a0e 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -8,7 +8,7 @@ namespace pimoroni { int PicoGraphics::reset_pen(uint8_t i) {return -1;}; int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;}; void PicoGraphics::set_pixel(const Point &p) {}; - void PicoGraphics::get_row_rgb565(void *result, uint offset, uint length) {}; + void PicoGraphics::scanline_convert(PenType type, conversion_callback_func callback) {}; void PicoGraphics::set_dimensions(int width, int height) { bounds = clip = {0, 0, width, height}; diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index b0d81f30..c0062394 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "libraries/hershey_fonts/hershey_fonts.hpp" #include "libraries/bitmap_fonts/bitmap_fonts.hpp" @@ -22,6 +23,60 @@ namespace pimoroni { typedef uint8_t RGB332; typedef uint16_t RGB565; + struct RGB { + uint8_t r, g, b; + + constexpr RGB() : r(0), g(0), b(0) {} + constexpr RGB(RGB332 c) : + r((c & 0b11100000) >> 0), + g((c & 0b00011100) << 3), + b((c & 0b00000011) << 6) {} + constexpr RGB(RGB565 c) : + r((__builtin_bswap16(c) & 0b1111100000000000) >> 8), + g((__builtin_bswap16(c) & 0b0000011111100000) >> 3), + b((__builtin_bswap16(c) & 0b0000000000011111) << 3) {} + constexpr RGB(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {} + + // a rough approximation of how bright a colour is used to compare the + // relative brightness of two colours + int luminance() { + // weights based on https://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/ + return r * 21 + g * 72 * b * 7; + } + + // a relatively low cost approximation of how "different" two colours are + // perceived which avoids expensive colour space conversions. + // described in detail at https://www.compuphase.com/cmetric.htm + int distance(RGB c) { + int rmean = ((int)r + c.r) / 2; + int rx = (int)r - c.r, gx = (int)g - c.g, bx = (int)b - c.b; + return abs((int)( + (((512 + rmean) * rx * rx) >> 8) + 4 * gx * gx + (((767 - rmean) * bx * bx) >> 8) + )); + } + + int closest(const RGB *palette, size_t len) { + int d = INT_MAX, m = -1; + for(size_t i = 0; i < len; i++) { + int dc = distance(palette[i]); + if(dc < d) {m = i; d = dc;} + } + return m; + } + + constexpr RGB565 to_rgb565() { + uint16_t p = ((r & 0b11111000) << 8) | + ((g & 0b11111100) << 3) | + ((b & 0b11111000) >> 3); + + return __builtin_bswap16(p); + } + + constexpr RGB565 to_rgb332() { + return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); + } + }; + typedef int Pen; struct Rect; @@ -57,11 +112,6 @@ namespace pimoroni { class PicoGraphics { public: - struct PaletteEntry { - RGB565 color; - bool used; - }; - enum PenType { PEN_P2 = 0, PEN_P4, @@ -76,11 +126,13 @@ namespace pimoroni { Rect bounds; Rect clip; + typedef std::function conversion_callback_func; + const bitmap::font_t *bitmap_font; const hershey::font_t *hershey_font; static constexpr RGB332 rgb_to_rgb332(uint8_t r, uint8_t g, uint8_t b) { - return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); + return RGB(r, g, b).to_rgb332(); } static constexpr RGB565 rgb332_to_rgb565(RGB332 c) { @@ -98,24 +150,15 @@ namespace pimoroni { } static constexpr RGB565 rgb_to_rgb565(uint8_t r, uint8_t g, uint8_t b) { - uint16_t p = ((r & 0b11111000) << 8) | - ((g & 0b11111100) << 3) | - ((b & 0b11111000) >> 3); - - return __builtin_bswap16(p); + return RGB(r, g, b).to_rgb565(); } - static constexpr void rgb332_to_rgb(RGB332 c, uint8_t &r, uint8_t &g, uint8_t &b) { - r = (c & 0b11100000) >> 0; - g = (c & 0b00011100) << 3; - b = (c & 0b00000011) << 6; + static constexpr RGB rgb332_to_rgb(RGB332 c) { + return RGB((RGB332)c); }; - static constexpr void rgb565_to_rgb(RGB565 c, uint8_t &r, uint8_t &g, uint8_t &b) { - c = __builtin_bswap16(c); - r = (c & 0b1111100000000000) >> 8; - g = (c & 0b0000011111100000) >> 3; - b = (c & 0b0000000000011111) << 3; + static constexpr RGB rgb565_to_rgb(RGB565 c) { + return RGB((RGB565)c); }; PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer) @@ -129,7 +172,7 @@ namespace pimoroni { virtual int reset_pen(uint8_t i); virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); virtual void set_pixel(const Point &p); - virtual void get_row_rgb565(void *result, uint offset, uint length); + virtual void scanline_convert(PenType type, conversion_callback_func callback); void set_font(const bitmap::font_t *font); void set_font(const hershey::font_t *font); @@ -161,17 +204,8 @@ namespace pimoroni { class PicoGraphics_PenP4 : public PicoGraphics { public: uint8_t color; - PaletteEntry palette[16]; - const RGB565 default_palette[16] = { - rgb_to_rgb565(57, 48, 57), // Black - rgb_to_rgb565(255, 255, 255), // White - rgb_to_rgb565(58, 91, 70), // Green - rgb_to_rgb565(61, 59, 94), // Blue - rgb_to_rgb565(156, 72, 75), // Red - rgb_to_rgb565(208, 190, 71), // Yellow - rgb_to_rgb565(177, 106, 73), // Orange - rgb_to_rgb565(255, 255, 255) // Clear - }; + RGB palette[16]; + PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer) : PicoGraphics(width, height, frame_buffer) { this->pen_type = PEN_P4; @@ -179,28 +213,23 @@ namespace pimoroni { this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); } for(auto i = 0u; i < 16; i++) { - palette[i].used = false; - } - for(auto i = 0u; i < 8; i++) { - palette[i].color = default_palette[i]; - palette[i].used = true; + palette[i] = { + uint8_t(i << 4), + uint8_t(i << 4), + uint8_t(i << 4) + }; } } void set_pen(uint c) { color = c & 0xf; } void set_pen(uint8_t r, uint8_t g, uint8_t b) override { - // TODO look up closest palette colour, or just NOOP? + int pen = RGB(r, g, b).closest(palette, 16); + if(pen != -1) color = pen; } int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { i &= 0xf; - palette[i].color = rgb_to_rgb565(r, g, b); - palette[i].used = true; - return i; - } - int reset_pen(uint8_t i) override { - i &= 0xf; - palette[i].color = default_palette[i]; + palette[i] = {r, g, b}; return i; } void set_pixel(const Point &p) override { @@ -215,14 +244,29 @@ namespace pimoroni { *f &= m; // clear bits *f |= b; // set value } - void get_row_rgb565(void *result, uint offset, uint length) override { - uint8_t *src = (uint8_t *)frame_buffer; - uint16_t *dst = (uint16_t *)result; - for(auto x = 0u; x < length; x++) { - uint8_t c = src[(offset / 2) + (x / 2)]; - uint8_t o = (~x & 0b1) * 4; // bit offset within byte - uint8_t b = (c >> o) & 0xf; // bit value shifted to position - dst[x] = palette[b].color; + void scanline_convert(PenType type, conversion_callback_func callback) override { + if(type == PEN_RGB565) { + // Cache the RGB888 palette as RGB565 + RGB565 cache[16]; + for(auto i = 0u; i < 16; i++) { + cache[i] = palette[i].to_rgb565(); + } + + // Treat our void* frame_buffer as uint8_t + uint8_t *src = (uint8_t *)frame_buffer; + + // Allocate a per-row temporary buffer + uint16_t row_buf[bounds.w]; + for(auto y = 0; y < bounds.h; y++) { + for(auto x = 0; x < bounds.w; x++) { + uint8_t c = src[(bounds.w * y / 2) + (x / 2)]; + uint8_t o = (~x & 0b1) * 4; // bit offset within byte + uint8_t b = (c >> o) & 0xf; // bit value shifted to position + row_buf[x] = cache[b]; + } + // Callback to the driver with the row data + callback(row_buf, bounds.w * sizeof(RGB565)); + } } } static size_t buffer_size(uint w, uint h) { @@ -233,7 +277,8 @@ namespace pimoroni { class PicoGraphics_PenP8 : public PicoGraphics { public: uint8_t color; - PaletteEntry palette[256]; + RGB palette[256]; + bool used[256]; PicoGraphics_PenP8(uint16_t width, uint16_t height, void *frame_buffer) : PicoGraphics(width, height, frame_buffer) { this->pen_type = PEN_P8; @@ -241,48 +286,62 @@ namespace pimoroni { this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); } for(auto i = 0u; i < 256; i++) { - reset_pen(i); + palette[i] = {0, 0, 0}; + used[i] = false; } } void set_pen(uint c) override { color = c; } void set_pen(uint8_t r, uint8_t g, uint8_t b) override { - // TODO look up closest palette colour, or just NOOP? + int pen = RGB(r, g, b).closest(palette, 16); + if(pen != -1) color = pen; } int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { i &= 0xff; - palette[i].color = rgb_to_rgb565(r, g, b); - palette[i].used = true; - return i; - } - int reset_pen(uint8_t i) override { - i &= 0xff; - palette[i].color = 0; - palette[i].used = false; + palette[i] = {r, g, b}; return i; } int create_pen(uint8_t r, uint8_t g, uint8_t b) override { // Create a colour and place it in the palette if there's space - RGB565 c = rgb_to_rgb565(r, g, b); for(auto i = 0u; i < 256u; i++) { - if(!palette[i].used) { - palette[i].color = c; - palette[i].used = true; + if(!used[i]) { + palette[i] = {r, g, b}; + used[i] = true; return i; } } return -1; } + int reset_pen(uint8_t i) { + palette[i] = {0, 0, 0}; + used[i] = false; + return i; + } void set_pixel(const Point &p) override { uint8_t *buf = (uint8_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } - void get_row_rgb565(void *result, uint offset, uint length) override { - uint8_t *src = (uint8_t *)frame_buffer; - uint16_t *dst = (uint16_t *)result; - for(auto x = 0u; x < length; x++) { - dst[x] = palette[src[offset + x]].color; + void scanline_convert(PenType type, conversion_callback_func callback) override { + if(type == PEN_RGB565) { + // Cache the RGB888 palette as RGB565 + RGB565 cache[256]; + for(auto i = 0u; i < 256; i++) { + cache[i] = palette[i].to_rgb565(); + } + + // Treat our void* frame_buffer as uint8_t + uint8_t *src = (uint8_t *)frame_buffer; + + // Allocate a per-row temporary buffer + uint16_t row_buf[bounds.w]; + for(auto y = 0; y < bounds.h; y++) { + for(auto x = 0; x < bounds.w; x++) { + row_buf[x] = cache[src[bounds.w * y + x]]; + } + // Callback to the driver with the row data + callback(row_buf, bounds.w * sizeof(RGB565)); + } } } static size_t buffer_size(uint w, uint h) { @@ -293,7 +352,7 @@ namespace pimoroni { class PicoGraphics_PenRGB332 : public PicoGraphics { public: RGB332 color; - PaletteEntry palette[256]; + RGB palette[256]; PicoGraphics_PenRGB332(uint16_t width, uint16_t height, void *frame_buffer) : PicoGraphics(width, height, frame_buffer) { this->pen_type = PEN_RGB332; @@ -301,8 +360,7 @@ namespace pimoroni { this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); } for(auto i = 0u; i < 256; i++) { - palette[i].color = rgb332_to_rgb565(i); - palette[i].used = true; + palette[i] = RGB((RGB332)i); } } void set_pen(uint c) override { @@ -318,11 +376,26 @@ namespace pimoroni { uint8_t *buf = (uint8_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } - void get_row_rgb565(void *result, uint offset, uint length) override { - uint8_t *src = (uint8_t *)frame_buffer; - uint16_t *dst = (uint16_t *)result; - for(auto x = 0u; x < length; x++) { - dst[x] = palette[src[offset + x]].color; + void scanline_convert(PenType type, conversion_callback_func callback) override { + if(type == PEN_RGB565) { + // Cache the RGB888 palette as RGB565 + RGB565 cache[256]; + for(auto i = 0u; i < 256; i++) { + cache[i] = palette[i].to_rgb565(); + } + + // Treat our void* frame_buffer as uint8_t + uint8_t *src = (uint8_t *)frame_buffer; + + // Allocate a per-row temporary buffer + uint16_t row_buf[bounds.w]; + for(auto y = 0; y < bounds.h; y++) { + for(auto x = 0; x < bounds.w; x++) { + row_buf[x] = cache[src[bounds.w * y + x]]; + } + // Callback to the driver with the row data + callback(row_buf, bounds.w * sizeof(RGB565)); + } } } static size_t buffer_size(uint w, uint h) { @@ -332,6 +405,7 @@ namespace pimoroni { class PicoGraphics_PenRGB565 : public PicoGraphics { public: + RGB src_color; RGB565 color; PicoGraphics_PenRGB565(uint16_t width, uint16_t height, void *frame_buffer) : PicoGraphics(width, height, frame_buffer) { @@ -344,7 +418,8 @@ namespace pimoroni { color = c; } void set_pen(uint8_t r, uint8_t g, uint8_t b) override { - color = rgb_to_rgb565(r, g, b); + src_color = {r, g, b}; + color = src_color.to_rgb565(); } int create_pen(uint8_t r, uint8_t g, uint8_t b) override { return rgb_to_rgb565(r, g, b); diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index fb108a63..d185e136 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -255,41 +255,39 @@ mp_obj_t ModPicoGraphics_set_backlight(mp_obj_t self_in, mp_obj_t brightness) { } mp_obj_t ModPicoGraphics_module_RGB332_to_RGB(mp_obj_t rgb332) { - uint8_t r, g, b; - PicoGraphics::rgb332_to_rgb(mp_obj_get_int(rgb332), r, g, b); + RGB c((RGB332)mp_obj_get_int(rgb332)); mp_obj_t t[] = { - mp_obj_new_int(r), - mp_obj_new_int(g), - mp_obj_new_int(b), + mp_obj_new_int(c.r), + mp_obj_new_int(c.g), + mp_obj_new_int(c.b), }; return mp_obj_new_tuple(3, t); } mp_obj_t ModPicoGraphics_module_RGB565_to_RGB(mp_obj_t rgb565) { - uint8_t r, g, b; - PicoGraphics::rgb565_to_rgb(mp_obj_get_int(rgb565), r, g, b); + RGB c((RGB565)mp_obj_get_int(rgb565)); mp_obj_t t[] = { - mp_obj_new_int(r), - mp_obj_new_int(g), - mp_obj_new_int(b), + mp_obj_new_int(c.r), + mp_obj_new_int(c.g), + mp_obj_new_int(c.b), }; return mp_obj_new_tuple(3, t); } mp_obj_t ModPicoGraphics_module_RGB_to_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(PicoGraphics::rgb_to_rgb332( + return mp_obj_new_int(RGB( mp_obj_get_int(r), mp_obj_get_int(g), mp_obj_get_int(b) - )); + ).to_rgb332()); } mp_obj_t ModPicoGraphics_module_RGB_to_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) { - return mp_obj_new_int(PicoGraphics::rgb_to_rgb565( + return mp_obj_new_int(RGB( mp_obj_get_int(r), mp_obj_get_int(g), mp_obj_get_int(b) - )); + ).to_rgb565()); } mp_obj_t ModPicoGraphics_set_pen(mp_obj_t self_in, mp_obj_t pen) { From d2b065d2da7ad6bf2e916a6aaffef7a5d64b617a Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 20:32:18 +0100 Subject: [PATCH 49/84] JPEGDEC: Use 4-bit dither. --- libraries/jpegdec/JPEGDEC.cpp | 5 ++++- libraries/jpegdec/JPEGDEC.h | 2 +- micropython/modules/jpegdec/jpegdec.cpp | 14 +++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/libraries/jpegdec/JPEGDEC.cpp b/libraries/jpegdec/JPEGDEC.cpp index 39e33a4b..5ac0d1d4 100644 --- a/libraries/jpegdec/JPEGDEC.cpp +++ b/libraries/jpegdec/JPEGDEC.cpp @@ -188,11 +188,14 @@ int JPEGDEC::decode(int x, int y, int iOptions) _jpeg.iXOffset = x; _jpeg.iYOffset = y; _jpeg.iOptions = iOptions; + _jpeg.pDitherBuffer = nullptr; return DecodeJPEG(&_jpeg); } /* decode() */ -int JPEGDEC::decodeDither(uint8_t *pDither, int iOptions) +int JPEGDEC::decodeDither(int x, int y, uint8_t *pDither, int iOptions) { + _jpeg.iXOffset = x; + _jpeg.iYOffset = y; _jpeg.iOptions = iOptions; _jpeg.pDitherBuffer = pDither; return DecodeJPEG(&_jpeg); diff --git a/libraries/jpegdec/JPEGDEC.h b/libraries/jpegdec/JPEGDEC.h index 38c92a3a..8f88ff33 100644 --- a/libraries/jpegdec/JPEGDEC.h +++ b/libraries/jpegdec/JPEGDEC.h @@ -213,7 +213,7 @@ class JPEGDEC #endif void close(); int decode(int x, int y, int iOptions); - int decodeDither(uint8_t *pDither, int iOptions); + int decodeDither(int x, int y, uint8_t *pDither, int iOptions); int getOrientation(); int getWidth(); int getHeight(); diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index baa9d561..6a124bd3 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -38,7 +38,7 @@ int JPEGDraw(JPEGDRAW *pDraw) { for(int x = 0; x < pDraw->iWidth; x++) { int i = y * pDraw->iWidth + x; uint8_t p = pixels[i / 2]; - p >>= (i & 0b1) * 4; + p >>= (i & 0b1) ? 0 : 4; p &= 0xf; current_graphics->set_pen(p); current_graphics->pixel({pDraw->x + x, pDraw->y + y}); @@ -108,7 +108,7 @@ static int _open(_JPEG_obj_t *self, void *buf, size_t len) { break; // TODO currently uses EIGHT_BIT_GREYSCALE and shifts down should this use a 4-bit dither? case PicoGraphics::PEN_P4: - self->jpeg->setPixelType(EIGHT_BIT_GRAYSCALE); + self->jpeg->setPixelType(FOUR_BIT_DITHERED); break; // TODO 2-bit is currently unsupported case PicoGraphics::PEN_P2: @@ -174,7 +174,15 @@ mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args // We need to store a pointer to the PicoGraphics surface // since the JPEGDRAW struct has no userdata current_graphics = self->graphics->graphics; - int result = self->jpeg->decode(x, y, f); + int result = -1; + + if(self->graphics->graphics->pen_type == PicoGraphics::PEN_P4) { + uint8_t *buf = new uint8_t[1024]; + result = self->jpeg->decodeDither(x, y, buf, f); + delete[] buf; + } else { + result = self->jpeg->decode(x, y, f); + } current_graphics = nullptr; return result == 1 ? mp_const_true : mp_const_false; } From 656d69399a998a47b8172f7253a88b47a6f027e9 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Jun 2022 20:37:41 +0100 Subject: [PATCH 50/84] JPEGDEC: Fix dither buffer size --- libraries/jpegdec/JPEGDEC.cpp | 1 + micropython/modules/jpegdec/jpegdec.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/jpegdec/JPEGDEC.cpp b/libraries/jpegdec/JPEGDEC.cpp index 5ac0d1d4..fd3c82e0 100644 --- a/libraries/jpegdec/JPEGDEC.cpp +++ b/libraries/jpegdec/JPEGDEC.cpp @@ -192,6 +192,7 @@ int JPEGDEC::decode(int x, int y, int iOptions) return DecodeJPEG(&_jpeg); } /* decode() */ +// TODO PR these tweaks to https://github.com/bitbank2/JPEGDEC int JPEGDEC::decodeDither(int x, int y, uint8_t *pDither, int iOptions) { _jpeg.iXOffset = x; diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index 6a124bd3..bc333202 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -177,7 +177,7 @@ mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args int result = -1; if(self->graphics->graphics->pen_type == PicoGraphics::PEN_P4) { - uint8_t *buf = new uint8_t[1024]; + uint8_t *buf = new uint8_t[2048]; result = self->jpeg->decodeDither(x, y, buf, f); delete[] buf; } else { From 602d1b41dd8a78a2aabc2e600d3e49ad4508524f Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 10 Jun 2022 00:58:54 +0100 Subject: [PATCH 51/84] PicoGraphics: Attempt at dither and scanline interrupts. Currently both unused and both very slow. Dither may only be feasible for <=8 colour displays. JPEGDEC will dither to 4-bit greyscale quite happily. --- libraries/pico_graphics/pico_graphics.cpp | 16 ++++ libraries/pico_graphics/pico_graphics.hpp | 80 +++++++++++++++++-- micropython/modules/jpegdec/jpegdec.cpp | 13 ++- .../modules/picographics/picographics.c | 2 + .../modules/picographics/picographics.cpp | 23 ++++++ .../modules/picographics/picographics.h | 1 + 6 files changed, 124 insertions(+), 11 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 9e690a0e..abcfa1e8 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -8,6 +8,7 @@ namespace pimoroni { int PicoGraphics::reset_pen(uint8_t i) {return -1;}; int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;}; void PicoGraphics::set_pixel(const Point &p) {}; + void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {}; void PicoGraphics::scanline_convert(PenType type, conversion_callback_func callback) {}; void PicoGraphics::set_dimensions(int width, int height) { @@ -51,6 +52,21 @@ namespace pimoroni { clip = bounds; } + void PicoGraphics::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates) { + RGB error; + for(size_t i = 0; i < candidates.size(); i++) { + candidates[i] = (col + error).closest(palette, len); + error += (col - palette[candidates[i]]); + } + + // sort by a rough approximation of luminance, this ensures that neighbouring + // pixels in the dither matrix are at extreme opposites of luminence + // giving a more balanced output + std::sort(candidates.begin(), candidates.end(), [palette](int a, int b) { + return palette[a].luminance() > palette[b].luminance(); + }); + } + void PicoGraphics::clear() { rectangle(clip); } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index c0062394..38204988 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 @@ -24,7 +25,7 @@ namespace pimoroni { typedef uint8_t RGB332; typedef uint16_t RGB565; struct RGB { - uint8_t r, g, b; + int16_t r, g, b; constexpr RGB() : r(0), g(0), b(0) {} constexpr RGB(RGB332 c) : @@ -37,25 +38,31 @@ namespace pimoroni { b((__builtin_bswap16(c) & 0b0000000000011111) << 3) {} constexpr RGB(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {} + constexpr RGB operator+ (const RGB& c) const {return RGB(r + c.r, g + c.g, b + c.b);} + constexpr RGB& operator+=(const RGB& c) {r += c.r; g += c.g; b += c.b; return *this;} + constexpr RGB operator- (const RGB& c) const {return RGB(r - c.r, g - c.g, b - c.b);} + // a rough approximation of how bright a colour is used to compare the // relative brightness of two colours - int luminance() { + int luminance() const { // weights based on https://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/ - return r * 21 + g * 72 * b * 7; + return r * 21 + g * 72 + b * 7; } // a relatively low cost approximation of how "different" two colours are // perceived which avoids expensive colour space conversions. // described in detail at https://www.compuphase.com/cmetric.htm - int distance(RGB c) { - int rmean = ((int)r + c.r) / 2; - int rx = (int)r - c.r, gx = (int)g - c.g, bx = (int)b - c.b; + int distance(const RGB& c) const { + int rmean = (r + c.r) / 2; + int rx = r - c.r; + int gx = g - c.g; + int bx = b - c.b; return abs((int)( (((512 + rmean) * rx * rx) >> 8) + 4 * gx * gx + (((767 - rmean) * bx * bx) >> 8) )); } - int closest(const RGB *palette, size_t len) { + int closest(const RGB *palette, size_t len) const { int d = INT_MAX, m = -1; for(size_t i = 0; i < len; i++) { int dc = distance(palette[i]); @@ -127,6 +134,9 @@ namespace pimoroni { Rect clip; typedef std::function conversion_callback_func; + //typedef std::function scanline_interrupt_func; + + //scanline_interrupt_func scanline_interrupt = nullptr; const bitmap::font_t *bitmap_font; const hershey::font_t *hershey_font; @@ -172,6 +182,7 @@ namespace pimoroni { virtual int reset_pen(uint8_t i); virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); virtual void set_pixel(const Point &p); + virtual void set_pixel_dither(const Point &p, const RGB &c); virtual void scanline_convert(PenType type, conversion_callback_func callback); void set_font(const bitmap::font_t *font); @@ -187,6 +198,8 @@ namespace pimoroni { void set_clip(const Rect &r); void remove_clip(); + void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); + void clear(); void pixel(const Point &p); void pixel_span(const Point &p, int32_t l); @@ -244,6 +257,21 @@ namespace pimoroni { *f &= m; // clear bits *f |= b; // set value } + void set_pixel_dither(const Point &p, const RGB &c) override { + if(!bounds.contains(p)) return; + static uint pattern[16] = // dither pattern + {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; + + static std::array candidates; + get_dither_candidates(c, palette, 256, candidates); + + // find the pattern coordinate offset + uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); + + // set the pixel + color = candidates[pattern[pattern_index]]; + set_pixel(p); + } void scanline_convert(PenType type, conversion_callback_func callback) override { if(type == PEN_RGB565) { // Cache the RGB888 palette as RGB565 @@ -258,6 +286,14 @@ namespace pimoroni { // Allocate a per-row temporary buffer uint16_t row_buf[bounds.w]; for(auto y = 0; y < bounds.h; y++) { + /*if(scanline_interrupt != nullptr) { + scanline_interrupt(y); + // Cache the RGB888 palette as RGB565 + for(auto i = 0u; i < 16; i++) { + cache[i] = palette[i].to_rgb565(); + } + }*/ + for(auto x = 0; x < bounds.w; x++) { uint8_t c = src[(bounds.w * y / 2) + (x / 2)]; uint8_t o = (~x & 0b1) * 4; // bit offset within byte @@ -322,6 +358,21 @@ namespace pimoroni { uint8_t *buf = (uint8_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } + void set_pixel_dither(const Point &p, const RGB &c) override { + if(!bounds.contains(p)) return; + static uint pattern[16] = // dither pattern + {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; + + static std::array candidates; + get_dither_candidates(c, palette, 256, candidates); + + // find the pattern coordinate offset + uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); + + // set the pixel + color = candidates[pattern[pattern_index]]; + set_pixel(p); + } void scanline_convert(PenType type, conversion_callback_func callback) override { if(type == PEN_RGB565) { // Cache the RGB888 palette as RGB565 @@ -376,6 +427,21 @@ namespace pimoroni { uint8_t *buf = (uint8_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } + void set_pixel_dither(const Point &p, const RGB &c) override { + if(!bounds.contains(p)) return; + static uint pattern[16] = // dither pattern + {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; + + static std::array candidates; + get_dither_candidates(c, palette, 256, candidates); + + // find the pattern coordinate offset + uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); + + // set the pixel + color = candidates[pattern[pattern_index]]; + set_pixel(p); + } void scanline_convert(PenType type, conversion_callback_func callback) override { if(type == PEN_RGB565) { // Cache the RGB888 palette as RGB565 diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index bc333202..2d1136d5 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -29,10 +29,13 @@ typedef struct _JPEG_obj_t { PicoGraphics *current_graphics = nullptr; int JPEGDraw(JPEGDRAW *pDraw) { +#ifdef MICROPY_EVENT_POLL_HOOK +MICROPY_EVENT_POLL_HOOK +#endif // "pixel" is slow and clipped, // guaranteeing we wont draw jpeg data out of the framebuffer.. // Can we clip beforehand and make this faster? - if(pDraw->iBpp == 4) { // TODO 4-bit pixel unpacking isn't working. What's up? + if(pDraw->iBpp == 4) { uint8_t *pixels = (uint8_t *)pDraw->pPixels; for(int y = 0; y < pDraw->iHeight; y++) { for(int x = 0; x < pDraw->iWidth; x++) { @@ -58,11 +61,14 @@ int JPEGDraw(JPEGDRAW *pDraw) { for(int x = 0; x < pDraw->iWidth; x++) { int i = y * pDraw->iWidth + x; if (current_graphics->pen_type == PicoGraphics::PEN_RGB332) { - current_graphics->set_pen(PicoGraphics::rgb565_to_rgb332(pDraw->pPixels[i])); + current_graphics->set_pen(RGB((RGB565)pDraw->pPixels[i]).to_rgb332()); + current_graphics->pixel({pDraw->x + x, pDraw->y + y}); + // FIXME VERY, VERY SLOW! + //current_graphics->set_pixel_dither({pDraw->x + x, pDraw->y + y}, RGB((RGB565)(pDraw->pPixels[i]))); } else { current_graphics->set_pen(pDraw->pPixels[i]); + current_graphics->pixel({pDraw->x + x, pDraw->y + y}); } - current_graphics->pixel({pDraw->x + x, pDraw->y + y}); } } } @@ -106,7 +112,6 @@ static int _open(_JPEG_obj_t *self, void *buf, size_t len) { case PicoGraphics::PEN_P8: self->jpeg->setPixelType(EIGHT_BIT_GRAYSCALE); break; - // TODO currently uses EIGHT_BIT_GREYSCALE and shifts down should this use a 4-bit dither? case PicoGraphics::PEN_P4: self->jpeg->setPixelType(FOUR_BIT_DITHERED); break; diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index c42c804b..bd2253b9 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -36,6 +36,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_triangle_obj, 7, 7, ModPicoG MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_line_obj, 5, 5, ModPicoGraphics_line); // Utility +//MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_scanline_callback_obj, ModPicoGraphics_set_scanline_callback); MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_get_bounds_obj, ModPicoGraphics_get_bounds); MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_font_obj, ModPicoGraphics_set_font); MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_framebuffer_obj, ModPicoGraphics_set_framebuffer); @@ -65,6 +66,7 @@ STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&ModPicoGraphics_set_backlight_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_set_scanline_callback), MP_ROM_PTR(&ModPicoGraphics_set_scanline_callback_obj) }, { MP_ROM_QSTR(MP_QSTR_get_bounds), MP_ROM_PTR(&ModPicoGraphics_get_bounds_obj) }, { MP_ROM_QSTR(MP_QSTR_set_font), MP_ROM_PTR(&ModPicoGraphics_set_font_obj) }, { MP_ROM_QSTR(MP_QSTR_set_framebuffer), MP_ROM_PTR(&ModPicoGraphics_set_framebuffer_obj) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index d185e136..5cb9b85f 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -25,6 +25,7 @@ typedef struct _ModPicoGraphics_obj_t { PicoGraphics *graphics; DisplayDriver *display; void *buffer; + //mp_obj_t scanline_callback; // Not really feasible in MicroPython } ModPicoGraphics_obj_t; bool get_display_resolution(PicoGraphicsDisplay display, int &width, int &height) { @@ -166,6 +167,8 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size break; } + //self->scanline_callback = mp_const_none; + // Clear the buffer self->graphics->set_pen(0); self->graphics->clear(); @@ -235,8 +238,28 @@ mp_obj_t ModPicoGraphics_get_bounds(mp_obj_t self_in) { return mp_obj_new_tuple(2, tuple); } +/* +mp_obj_t ModPicoGraphics_set_scanline_callback(mp_obj_t self_in, mp_obj_t cb_in) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); + self->scanline_callback = cb_in; + return mp_const_none; +} +*/ + mp_obj_t ModPicoGraphics_update(mp_obj_t self_in) { ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); +/* + if(self->scanline_callback != mp_const_none) { + self->graphics->scanline_interrupt = [self](int y){ + mp_obj_t args[] = { + mp_obj_new_int(y) + }; + mp_call_function_n_kw(self->scanline_callback, MP_ARRAY_SIZE(args), 0, args); + }; + } else { + self->graphics->scanline_interrupt = nullptr; + } +*/ self->display->update(self->graphics); return mp_const_none; diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index 9f18fdcb..62955a96 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -61,6 +61,7 @@ extern mp_obj_t ModPicoGraphics_triangle(size_t n_args, const mp_obj_t *args); extern mp_obj_t ModPicoGraphics_line(size_t n_args, const mp_obj_t *args); // Utility +//extern mp_obj_t ModPicoGraphics_set_scanline_callback(mp_obj_t self_in, mp_obj_t cb_in); extern mp_obj_t ModPicoGraphics_set_font(mp_obj_t self_in, mp_obj_t font); extern mp_obj_t ModPicoGraphics_get_bounds(mp_obj_t self_in); extern mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); From 2419f0ef45dc22233bdfcb2c56768ba407a5ebfc Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 10 Jun 2022 10:00:35 +0100 Subject: [PATCH 52/84] PicoGraphics/JPEGDEC: RGB332 per channel fast dither. --- libraries/pico_graphics/pico_graphics.cpp | 1 + libraries/pico_graphics/pico_graphics.hpp | 62 ++++++++++++++++++++--- micropython/modules/jpegdec/jpegdec.cpp | 8 +-- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index abcfa1e8..551fb34d 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -9,6 +9,7 @@ namespace pimoroni { int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;}; void PicoGraphics::set_pixel(const Point &p) {}; void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {}; + void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {}; void PicoGraphics::scanline_convert(PenType type, conversion_callback_func callback) {}; void PicoGraphics::set_dimensions(int width, int height) { diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 38204988..3163926d 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -183,6 +183,7 @@ namespace pimoroni { virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); virtual void set_pixel(const Point &p); virtual void set_pixel_dither(const Point &p, const RGB &c); + virtual void set_pixel_dither(const Point &p, const RGB565 &c); virtual void scanline_convert(PenType type, conversion_callback_func callback); void set_font(const bitmap::font_t *font); @@ -429,17 +430,62 @@ namespace pimoroni { } void set_pixel_dither(const Point &p, const RGB &c) override { if(!bounds.contains(p)) return; - static uint pattern[16] = // dither pattern - {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; + static uint8_t _odm[16] = { + 0, 8, 2, 10, + 12, 4, 14, 6, + 3, 11, 1, 9, + 15, 7, 13, 5 + }; - static std::array candidates; - get_dither_candidates(c, palette, 256, candidates); + uint8_t _dmv = _odm[(p.x & 0b11) | ((p.y & 0b11) << 2)]; - // find the pattern coordinate offset - uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); + uint8_t red = c.r & 0b11000000; // Two bits red + uint8_t red_r = c.r & 0b111111; // Remaining six bits red + red_r >>= 2; // Discard down to four bit + + uint8_t grn = (c.g & 0b11000000) >> 3; // Two bits green + uint8_t grn_r = c.g & 0b111111; // Remaining six bits green + grn_r >>= 2; // Discard down to four bit + + uint8_t blu = (c.b & 0b10000000) >> 6; // One bit blue + uint8_t blu_r = c.b & 0b1111111; // Remaining seven bits green + blu_r >>= 3; // Discard down to four bit + + color = red | grn | blu; + if(red_r > _dmv) color |= 0b00100000; + if(grn_r > _dmv) color |= 0b00000100; + if(blu_r > _dmv) color |= 0b00000001; + + set_pixel(p); + } + void set_pixel_dither(const Point &p, const RGB565 &c) override { + if(!bounds.contains(p)) return; + RGB565 cs = __builtin_bswap16(c); + static uint8_t _odm[16] = { + 0, 8, 2, 10, + 12, 4, 14, 6, + 3, 11, 1, 9, + 15, 7, 13, 5 + }; + + uint8_t _dmv = _odm[(p.x & 0b11) | ((p.y & 0b11) << 2)]; + + // RRRRRGGGGGGBBBBB + uint8_t red = (cs & 0b1100000000000000) >> 8; // Two bits grn + uint8_t red_r = (cs & 0b0011100000000000) >> 10; // Four bits cmp + + uint8_t grn = (cs & 0b0000011000000000) >> 6; // Two bit grn + uint8_t grn_r = (cs & 0b0000000111100000) >> 5; // Four bit cmp + + uint8_t blu = (cs & 0b0000000000010000) >> 3; // Two bit blu + uint8_t blu_r = (cs & 0b0000000000001111); // Four bit cmp + + color = red | grn | blu; + // RRRGGGBB + if(red_r > _dmv) color |= 0b00100000; + if(grn_r > _dmv) color |= 0b00000100; + if(blu_r > _dmv) color |= 0b00000001; - // set the pixel - color = candidates[pattern[pattern_index]]; set_pixel(p); } void scanline_convert(PenType type, conversion_callback_func callback) override { diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index 2d1136d5..123d47e7 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -61,10 +61,10 @@ MICROPY_EVENT_POLL_HOOK for(int x = 0; x < pDraw->iWidth; x++) { int i = y * pDraw->iWidth + x; if (current_graphics->pen_type == PicoGraphics::PEN_RGB332) { - current_graphics->set_pen(RGB((RGB565)pDraw->pPixels[i]).to_rgb332()); - current_graphics->pixel({pDraw->x + x, pDraw->y + y}); - // FIXME VERY, VERY SLOW! - //current_graphics->set_pixel_dither({pDraw->x + x, pDraw->y + y}, RGB((RGB565)(pDraw->pPixels[i]))); + //current_graphics->set_pen(RGB((RGB565)pDraw->pPixels[i]).to_rgb332()); + //current_graphics->pixel({pDraw->x + x, pDraw->y + y}); + // TODO make dither optional + current_graphics->set_pixel_dither({pDraw->x + x, pDraw->y + y}, (RGB565)(pDraw->pPixels[i])); } else { current_graphics->set_pen(pDraw->pPixels[i]); current_graphics->pixel({pDraw->x + x, pDraw->y + y}); From 582c67570a53abed0295fa39ed5b804fdf895672 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Jun 2022 11:26:21 +0100 Subject: [PATCH 53/84] PicoGraphics: Refactor pen types into their own cpp files. --- libraries/pico_graphics/pico_graphics.cmake | 4 + libraries/pico_graphics/pico_graphics.hpp | 322 ++---------------- .../pico_graphics/pico_graphics_pen_p4.cpp | 90 +++++ .../pico_graphics/pico_graphics_pen_p8.cpp | 69 ++++ .../pico_graphics_pen_rgb332.cpp | 109 ++++++ .../pico_graphics_pen_rgb565.cpp | 25 ++ .../modules/picographics/micropython.cmake | 4 + 7 files changed, 330 insertions(+), 293 deletions(-) create mode 100644 libraries/pico_graphics/pico_graphics_pen_p4.cpp create mode 100644 libraries/pico_graphics/pico_graphics_pen_p8.cpp create mode 100644 libraries/pico_graphics/pico_graphics_pen_rgb332.cpp create mode 100644 libraries/pico_graphics/pico_graphics_pen_rgb565.cpp diff --git a/libraries/pico_graphics/pico_graphics.cmake b/libraries/pico_graphics/pico_graphics.cmake index c69eb7d7..e06ea5d7 100644 --- a/libraries/pico_graphics/pico_graphics.cmake +++ b/libraries/pico_graphics/pico_graphics.cmake @@ -1,6 +1,10 @@ add_library(pico_graphics ${CMAKE_CURRENT_LIST_DIR}/types.cpp ${CMAKE_CURRENT_LIST_DIR}/pico_graphics.cpp + ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_p4.cpp + ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_p8.cpp + ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb332.cpp + ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb565.cpp ) target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 3163926d..e3bcad8f 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -220,94 +220,15 @@ namespace pimoroni { uint8_t color; RGB palette[16]; - PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer) - : PicoGraphics(width, height, frame_buffer) { - this->pen_type = PEN_P4; - if(this->frame_buffer == nullptr) { - this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); - } - for(auto i = 0u; i < 16; i++) { - palette[i] = { - uint8_t(i << 4), - uint8_t(i << 4), - uint8_t(i << 4) - }; - } - } - void set_pen(uint c) { - color = c & 0xf; - } - void set_pen(uint8_t r, uint8_t g, uint8_t b) override { - int pen = RGB(r, g, b).closest(palette, 16); - if(pen != -1) color = pen; - } - int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { - i &= 0xf; - palette[i] = {r, g, b}; - return i; - } - void set_pixel(const Point &p) override { - // pointer to byte in framebuffer that contains this pixel - uint8_t *buf = (uint8_t *)frame_buffer; - uint8_t *f = &buf[(p.x / 2) + (p.y * bounds.w / 2)]; - - uint8_t o = (~p.x & 0b1) * 4; // bit offset within byte - uint8_t m = ~(0b1111 << o); // bit mask for byte - uint8_t b = color << o; // bit value shifted to position - - *f &= m; // clear bits - *f |= b; // set value - } - void set_pixel_dither(const Point &p, const RGB &c) override { - if(!bounds.contains(p)) return; - static uint pattern[16] = // dither pattern - {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; - - static std::array candidates; - get_dither_candidates(c, palette, 256, candidates); - - // find the pattern coordinate offset - uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); - - // set the pixel - color = candidates[pattern[pattern_index]]; - set_pixel(p); - } - void scanline_convert(PenType type, conversion_callback_func callback) override { - if(type == PEN_RGB565) { - // Cache the RGB888 palette as RGB565 - RGB565 cache[16]; - for(auto i = 0u; i < 16; i++) { - cache[i] = palette[i].to_rgb565(); - } - - // Treat our void* frame_buffer as uint8_t - uint8_t *src = (uint8_t *)frame_buffer; - - // Allocate a per-row temporary buffer - uint16_t row_buf[bounds.w]; - for(auto y = 0; y < bounds.h; y++) { - /*if(scanline_interrupt != nullptr) { - scanline_interrupt(y); - // Cache the RGB888 palette as RGB565 - for(auto i = 0u; i < 16; i++) { - cache[i] = palette[i].to_rgb565(); - } - }*/ - - for(auto x = 0; x < bounds.w; x++) { - uint8_t c = src[(bounds.w * y / 2) + (x / 2)]; - uint8_t o = (~x & 0b1) * 4; // bit offset within byte - uint8_t b = (c >> o) & 0xf; // bit value shifted to position - row_buf[x] = cache[b]; - } - // Callback to the driver with the row data - callback(row_buf, bounds.w * sizeof(RGB565)); - } - } - } + PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer); + void set_pen(uint c) override; + void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override; + void set_pixel(const Point &p) override; + void set_pixel_dither(const Point &p, const RGB &c) override; + void scanline_convert(PenType type, conversion_callback_func callback) override; static size_t buffer_size(uint w, uint h) { - return w * h / 2; + return w * h / 2; } }; @@ -316,86 +237,14 @@ namespace pimoroni { uint8_t color; RGB palette[256]; bool used[256]; - PicoGraphics_PenP8(uint16_t width, uint16_t height, void *frame_buffer) - : PicoGraphics(width, height, frame_buffer) { - this->pen_type = PEN_P8; - if(this->frame_buffer == nullptr) { - this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); - } - for(auto i = 0u; i < 256; i++) { - palette[i] = {0, 0, 0}; - used[i] = false; - } - } - void set_pen(uint c) override { - color = c; - } - void set_pen(uint8_t r, uint8_t g, uint8_t b) override { - int pen = RGB(r, g, b).closest(palette, 16); - if(pen != -1) color = pen; - } - int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { - i &= 0xff; - palette[i] = {r, g, b}; - return i; - } - int create_pen(uint8_t r, uint8_t g, uint8_t b) override { - // Create a colour and place it in the palette if there's space - for(auto i = 0u; i < 256u; i++) { - if(!used[i]) { - palette[i] = {r, g, b}; - used[i] = true; - return i; - } - } - return -1; - } - int reset_pen(uint8_t i) { - palette[i] = {0, 0, 0}; - used[i] = false; - return i; - } - void set_pixel(const Point &p) override { - uint8_t *buf = (uint8_t *)frame_buffer; - buf[p.y * bounds.w + p.x] = color; - } - void set_pixel_dither(const Point &p, const RGB &c) override { - if(!bounds.contains(p)) return; - static uint pattern[16] = // dither pattern - {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; - - static std::array candidates; - get_dither_candidates(c, palette, 256, candidates); - - // find the pattern coordinate offset - uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); - - // set the pixel - color = candidates[pattern[pattern_index]]; - set_pixel(p); - } - void scanline_convert(PenType type, conversion_callback_func callback) override { - if(type == PEN_RGB565) { - // Cache the RGB888 palette as RGB565 - RGB565 cache[256]; - for(auto i = 0u; i < 256; i++) { - cache[i] = palette[i].to_rgb565(); - } - - // Treat our void* frame_buffer as uint8_t - uint8_t *src = (uint8_t *)frame_buffer; - - // Allocate a per-row temporary buffer - uint16_t row_buf[bounds.w]; - for(auto y = 0; y < bounds.h; y++) { - for(auto x = 0; x < bounds.w; x++) { - row_buf[x] = cache[src[bounds.w * y + x]]; - } - // Callback to the driver with the row data - callback(row_buf, bounds.w * sizeof(RGB565)); - } - } - } + PicoGraphics_PenP8(uint16_t width, uint16_t height, void *frame_buffer); + void set_pen(uint c) override; + void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override; + int create_pen(uint8_t r, uint8_t g, uint8_t b) override; + int reset_pen(uint8_t i) override; + void set_pixel(const Point &p) override; + void scanline_convert(PenType type, conversion_callback_func callback) override; static size_t buffer_size(uint w, uint h) { return w * h; } @@ -405,111 +254,14 @@ namespace pimoroni { public: RGB332 color; RGB palette[256]; - PicoGraphics_PenRGB332(uint16_t width, uint16_t height, void *frame_buffer) - : PicoGraphics(width, height, frame_buffer) { - this->pen_type = PEN_RGB332; - if(this->frame_buffer == nullptr) { - this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); - } - for(auto i = 0u; i < 256; i++) { - palette[i] = RGB((RGB332)i); - } - } - void set_pen(uint c) override { - color = c; - } - void set_pen(uint8_t r, uint8_t g, uint8_t b) override { - color = rgb_to_rgb332(r, g, b); - } - int create_pen(uint8_t r, uint8_t g, uint8_t b) override { - return rgb_to_rgb332(r, g, b); - } - void set_pixel(const Point &p) override { - uint8_t *buf = (uint8_t *)frame_buffer; - buf[p.y * bounds.w + p.x] = color; - } - void set_pixel_dither(const Point &p, const RGB &c) override { - if(!bounds.contains(p)) return; - static uint8_t _odm[16] = { - 0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5 - }; - - uint8_t _dmv = _odm[(p.x & 0b11) | ((p.y & 0b11) << 2)]; - - uint8_t red = c.r & 0b11000000; // Two bits red - uint8_t red_r = c.r & 0b111111; // Remaining six bits red - red_r >>= 2; // Discard down to four bit - - uint8_t grn = (c.g & 0b11000000) >> 3; // Two bits green - uint8_t grn_r = c.g & 0b111111; // Remaining six bits green - grn_r >>= 2; // Discard down to four bit - - uint8_t blu = (c.b & 0b10000000) >> 6; // One bit blue - uint8_t blu_r = c.b & 0b1111111; // Remaining seven bits green - blu_r >>= 3; // Discard down to four bit - - color = red | grn | blu; - if(red_r > _dmv) color |= 0b00100000; - if(grn_r > _dmv) color |= 0b00000100; - if(blu_r > _dmv) color |= 0b00000001; - - set_pixel(p); - } - void set_pixel_dither(const Point &p, const RGB565 &c) override { - if(!bounds.contains(p)) return; - RGB565 cs = __builtin_bswap16(c); - static uint8_t _odm[16] = { - 0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5 - }; - - uint8_t _dmv = _odm[(p.x & 0b11) | ((p.y & 0b11) << 2)]; - - // RRRRRGGGGGGBBBBB - uint8_t red = (cs & 0b1100000000000000) >> 8; // Two bits grn - uint8_t red_r = (cs & 0b0011100000000000) >> 10; // Four bits cmp - - uint8_t grn = (cs & 0b0000011000000000) >> 6; // Two bit grn - uint8_t grn_r = (cs & 0b0000000111100000) >> 5; // Four bit cmp - - uint8_t blu = (cs & 0b0000000000010000) >> 3; // Two bit blu - uint8_t blu_r = (cs & 0b0000000000001111); // Four bit cmp - - color = red | grn | blu; - // RRRGGGBB - if(red_r > _dmv) color |= 0b00100000; - if(grn_r > _dmv) color |= 0b00000100; - if(blu_r > _dmv) color |= 0b00000001; - - set_pixel(p); - } - void scanline_convert(PenType type, conversion_callback_func callback) override { - if(type == PEN_RGB565) { - // Cache the RGB888 palette as RGB565 - RGB565 cache[256]; - for(auto i = 0u; i < 256; i++) { - cache[i] = palette[i].to_rgb565(); - } - - // Treat our void* frame_buffer as uint8_t - uint8_t *src = (uint8_t *)frame_buffer; - - // Allocate a per-row temporary buffer - uint16_t row_buf[bounds.w]; - for(auto y = 0; y < bounds.h; y++) { - for(auto x = 0; x < bounds.w; x++) { - row_buf[x] = cache[src[bounds.w * y + x]]; - } - // Callback to the driver with the row data - callback(row_buf, bounds.w * sizeof(RGB565)); - } - } - } + PicoGraphics_PenRGB332(uint16_t width, uint16_t height, void *frame_buffer); + void set_pen(uint c) override; + void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + int create_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_pixel(const Point &p) override; + void set_pixel_dither(const Point &p, const RGB &c) override; + void set_pixel_dither(const Point &p, const RGB565 &c) override; + void scanline_convert(PenType type, conversion_callback_func callback) override; static size_t buffer_size(uint w, uint h) { return w * h; } @@ -519,27 +271,11 @@ namespace pimoroni { public: RGB src_color; RGB565 color; - PicoGraphics_PenRGB565(uint16_t width, uint16_t height, void *frame_buffer) - : PicoGraphics(width, height, frame_buffer) { - this->pen_type = PEN_RGB565; - if(this->frame_buffer == nullptr) { - this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); - } - } - void set_pen(uint c) override { - color = c; - } - void set_pen(uint8_t r, uint8_t g, uint8_t b) override { - src_color = {r, g, b}; - color = src_color.to_rgb565(); - } - int create_pen(uint8_t r, uint8_t g, uint8_t b) override { - return rgb_to_rgb565(r, g, b); - } - void set_pixel(const Point &p) override { - uint16_t *buf = (uint16_t *)frame_buffer; - buf[p.y * bounds.w + p.x] = color; - } + PicoGraphics_PenRGB565(uint16_t width, uint16_t height, void *frame_buffer); + void set_pen(uint c) override; + void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + int create_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_pixel(const Point &p) override; static size_t buffer_size(uint w, uint h) { return w * h * sizeof(RGB565); } diff --git a/libraries/pico_graphics/pico_graphics_pen_p4.cpp b/libraries/pico_graphics/pico_graphics_pen_p4.cpp new file mode 100644 index 00000000..10f54241 --- /dev/null +++ b/libraries/pico_graphics/pico_graphics_pen_p4.cpp @@ -0,0 +1,90 @@ +#include "pico_graphics.hpp" + +namespace pimoroni { + PicoGraphics_PenP4::PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer) + : PicoGraphics(width, height, frame_buffer) { + this->pen_type = PEN_P4; + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); + } + for(auto i = 0u; i < 16; i++) { + palette[i] = { + uint8_t(i << 4), + uint8_t(i << 4), + uint8_t(i << 4) + }; + } + } + void PicoGraphics_PenP4::set_pen(uint c) { + color = c & 0xf; + } + void PicoGraphics_PenP4::set_pen(uint8_t r, uint8_t g, uint8_t b) { + int pen = RGB(r, g, b).closest(palette, 16); + if(pen != -1) color = pen; + } + int PicoGraphics_PenP4::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { + i &= 0xf; + palette[i] = {r, g, b}; + return i; + } + void PicoGraphics_PenP4::set_pixel(const Point &p) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + uint8_t *f = &buf[(p.x / 2) + (p.y * bounds.w / 2)]; + + uint8_t o = (~p.x & 0b1) * 4; // bit offset within byte + uint8_t m = ~(0b1111 << o); // bit mask for byte + uint8_t b = color << o; // bit value shifted to position + + *f &= m; // clear bits + *f |= b; // set value + } + void PicoGraphics_PenP4::set_pixel_dither(const Point &p, const RGB &c) { + if(!bounds.contains(p)) return; + static uint pattern[16] = // dither pattern + {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; + + static std::array candidates; + get_dither_candidates(c, palette, 256, candidates); + + // find the pattern coordinate offset + uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); + + // set the pixel + color = candidates[pattern[pattern_index]]; + set_pixel(p); + } + void PicoGraphics_PenP4::scanline_convert(PenType type, conversion_callback_func callback) { + if(type == PEN_RGB565) { + // Cache the RGB888 palette as RGB565 + RGB565 cache[16]; + for(auto i = 0u; i < 16; i++) { + cache[i] = palette[i].to_rgb565(); + } + + // Treat our void* frame_buffer as uint8_t + uint8_t *src = (uint8_t *)frame_buffer; + + // Allocate a per-row temporary buffer + uint16_t row_buf[bounds.w]; + for(auto y = 0; y < bounds.h; y++) { + /*if(scanline_interrupt != nullptr) { + scanline_interrupt(y); + // Cache the RGB888 palette as RGB565 + for(auto i = 0u; i < 16; i++) { + cache[i] = palette[i].to_rgb565(); + } + }*/ + + for(auto x = 0; x < bounds.w; x++) { + uint8_t c = src[(bounds.w * y / 2) + (x / 2)]; + uint8_t o = (~x & 0b1) * 4; // bit offset within byte + uint8_t b = (c >> o) & 0xf; // bit value shifted to position + row_buf[x] = cache[b]; + } + // Callback to the driver with the row data + callback(row_buf, bounds.w * sizeof(RGB565)); + } + } + } +} \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics_pen_p8.cpp b/libraries/pico_graphics/pico_graphics_pen_p8.cpp new file mode 100644 index 00000000..da0729bf --- /dev/null +++ b/libraries/pico_graphics/pico_graphics_pen_p8.cpp @@ -0,0 +1,69 @@ +#include "pico_graphics.hpp" + +namespace pimoroni { + PicoGraphics_PenP8::PicoGraphics_PenP8(uint16_t width, uint16_t height, void *frame_buffer) + : PicoGraphics(width, height, frame_buffer) { + this->pen_type = PEN_P8; + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); + } + for(auto i = 0u; i < 256; i++) { + palette[i] = {0, 0, 0}; + used[i] = false; + } + } + void PicoGraphics_PenP8::set_pen(uint c) { + color = c; + } + void PicoGraphics_PenP8::set_pen(uint8_t r, uint8_t g, uint8_t b) { + int pen = RGB(r, g, b).closest(palette, 16); + if(pen != -1) color = pen; + } + int PicoGraphics_PenP8::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { + i &= 0xff; + palette[i] = {r, g, b}; + return i; + } + int PicoGraphics_PenP8::create_pen(uint8_t r, uint8_t g, uint8_t b) { + // Create a colour and place it in the palette if there's space + for(auto i = 0u; i < 256u; i++) { + if(!used[i]) { + palette[i] = {r, g, b}; + used[i] = true; + return i; + } + } + return -1; + } + int PicoGraphics_PenP8::reset_pen(uint8_t i) { + palette[i] = {0, 0, 0}; + used[i] = false; + return i; + } + void PicoGraphics_PenP8::set_pixel(const Point &p) { + uint8_t *buf = (uint8_t *)frame_buffer; + buf[p.y * bounds.w + p.x] = color; + } + void PicoGraphics_PenP8::scanline_convert(PenType type, conversion_callback_func callback) { + if(type == PEN_RGB565) { + // Cache the RGB888 palette as RGB565 + RGB565 cache[256]; + for(auto i = 0u; i < 256; i++) { + cache[i] = palette[i].to_rgb565(); + } + + // Treat our void* frame_buffer as uint8_t + uint8_t *src = (uint8_t *)frame_buffer; + + // Allocate a per-row temporary buffer + uint16_t row_buf[bounds.w]; + for(auto y = 0; y < bounds.h; y++) { + for(auto x = 0; x < bounds.w; x++) { + row_buf[x] = cache[src[bounds.w * y + x]]; + } + // Callback to the driver with the row data + callback(row_buf, bounds.w * sizeof(RGB565)); + } + } + } +} \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp new file mode 100644 index 00000000..8141e430 --- /dev/null +++ b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp @@ -0,0 +1,109 @@ +#include "pico_graphics.hpp" + +namespace pimoroni { + PicoGraphics_PenRGB332::PicoGraphics_PenRGB332(uint16_t width, uint16_t height, void *frame_buffer) + : PicoGraphics(width, height, frame_buffer) { + this->pen_type = PEN_RGB332; + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); + } + for(auto i = 0u; i < 256; i++) { + palette[i] = RGB((RGB332)i); + } + } + void PicoGraphics_PenRGB332::set_pen(uint c) { + color = c; + } + void PicoGraphics_PenRGB332::set_pen(uint8_t r, uint8_t g, uint8_t b) { + color = rgb_to_rgb332(r, g, b); + } + int PicoGraphics_PenRGB332::create_pen(uint8_t r, uint8_t g, uint8_t b) { + return rgb_to_rgb332(r, g, b); + } + void PicoGraphics_PenRGB332::set_pixel(const Point &p) { + uint8_t *buf = (uint8_t *)frame_buffer; + buf[p.y * bounds.w + p.x] = color; + } + void PicoGraphics_PenRGB332::set_pixel_dither(const Point &p, const RGB &c) { + if(!bounds.contains(p)) return; + static uint8_t _odm[16] = { + 0, 8, 2, 10, + 12, 4, 14, 6, + 3, 11, 1, 9, + 15, 7, 13, 5 + }; + + uint8_t _dmv = _odm[(p.x & 0b11) | ((p.y & 0b11) << 2)]; + + uint8_t red = c.r & 0b11000000; // Two bits red + uint8_t red_r = c.r & 0b111111; // Remaining six bits red + red_r >>= 2; // Discard down to four bit + + uint8_t grn = (c.g & 0b11000000) >> 3; // Two bits green + uint8_t grn_r = c.g & 0b111111; // Remaining six bits green + grn_r >>= 2; // Discard down to four bit + + uint8_t blu = (c.b & 0b10000000) >> 6; // One bit blue + uint8_t blu_r = c.b & 0b1111111; // Remaining seven bits green + blu_r >>= 3; // Discard down to four bit + + color = red | grn | blu; + if(red_r > _dmv) color |= 0b00100000; + if(grn_r > _dmv) color |= 0b00000100; + if(blu_r > _dmv) color |= 0b00000001; + + set_pixel(p); + } + void PicoGraphics_PenRGB332::set_pixel_dither(const Point &p, const RGB565 &c) { + if(!bounds.contains(p)) return; + RGB565 cs = __builtin_bswap16(c); + static uint8_t _odm[16] = { + 0, 8, 2, 10, + 12, 4, 14, 6, + 3, 11, 1, 9, + 15, 7, 13, 5 + }; + + uint8_t _dmv = _odm[(p.x & 0b11) | ((p.y & 0b11) << 2)]; + + // RRRRRGGGGGGBBBBB + uint8_t red = (cs & 0b1100000000000000) >> 8; // Two bits grn + uint8_t red_r = (cs & 0b0011100000000000) >> 10; // Four bits cmp + + uint8_t grn = (cs & 0b0000011000000000) >> 6; // Two bit grn + uint8_t grn_r = (cs & 0b0000000111100000) >> 5; // Four bit cmp + + uint8_t blu = (cs & 0b0000000000010000) >> 3; // Two bit blu + uint8_t blu_r = (cs & 0b0000000000001111); // Four bit cmp + + color = red | grn | blu; + // RRRGGGBB + if(red_r > _dmv) color |= 0b00100000; + if(grn_r > _dmv) color |= 0b00000100; + if(blu_r > _dmv) color |= 0b00000001; + + set_pixel(p); + } + void PicoGraphics_PenRGB332::scanline_convert(PenType type, conversion_callback_func callback) { + if(type == PEN_RGB565) { + // Cache the RGB888 palette as RGB565 + RGB565 cache[256]; + for(auto i = 0u; i < 256; i++) { + cache[i] = palette[i].to_rgb565(); + } + + // Treat our void* frame_buffer as uint8_t + uint8_t *src = (uint8_t *)frame_buffer; + + // Allocate a per-row temporary buffer + uint16_t row_buf[bounds.w]; + for(auto y = 0; y < bounds.h; y++) { + for(auto x = 0; x < bounds.w; x++) { + row_buf[x] = cache[src[bounds.w * y + x]]; + } + // Callback to the driver with the row data + callback(row_buf, bounds.w * sizeof(RGB565)); + } + } + } +} \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp new file mode 100644 index 00000000..cdfa0b32 --- /dev/null +++ b/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp @@ -0,0 +1,25 @@ +#include "pico_graphics.hpp" + +namespace pimoroni { + PicoGraphics_PenRGB565::PicoGraphics_PenRGB565(uint16_t width, uint16_t height, void *frame_buffer) + : PicoGraphics(width, height, frame_buffer) { + this->pen_type = PEN_RGB565; + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); + } + } + void PicoGraphics_PenRGB565::set_pen(uint c) { + color = c; + } + void PicoGraphics_PenRGB565::set_pen(uint8_t r, uint8_t g, uint8_t b) { + src_color = {r, g, b}; + color = src_color.to_rgb565(); + } + int PicoGraphics_PenRGB565::create_pen(uint8_t r, uint8_t g, uint8_t b) { + return RGB(r, g, b).to_rgb565(); + } + void PicoGraphics_PenRGB565::set_pixel(const Point &p) { + uint16_t *buf = (uint16_t *)frame_buffer; + buf[p.y * bounds.w + p.x] = color; + } +} \ No newline at end of file diff --git a/micropython/modules/picographics/micropython.cmake b/micropython/modules/picographics/micropython.cmake index d1f6dc11..fb692169 100644 --- a/micropython/modules/picographics/micropython.cmake +++ b/micropython/modules/picographics/micropython.cmake @@ -8,6 +8,10 @@ target_sources(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7735/st7735.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_p4.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_p8.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_rgb332.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_rgb565.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp ) From 03dc1e994162ca7ebbce9a4fd5a11229b4218717 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Jun 2022 14:05:51 +0100 Subject: [PATCH 54/84] PicoGraphics: Support sensible default rotations. Rotate Tufty to 180 degrees by default. Rotate Pico Display to 270 degrees by default. --- .../modules/picographics/picographics.cpp | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 5cb9b85f..6888b286 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -28,16 +28,20 @@ typedef struct _ModPicoGraphics_obj_t { //mp_obj_t scanline_callback; // Not really feasible in MicroPython } ModPicoGraphics_obj_t; -bool get_display_resolution(PicoGraphicsDisplay display, int &width, int &height) { +bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height, int &rotate) { switch(display) { case DISPLAY_PICO_DISPLAY: width = 240; height = 135; + // Portrait to match labelling + if(rotate == -1) rotate = (int)Rotation::ROTATE_270; break; case DISPLAY_PICO_DISPLAY_2: case DISPLAY_TUFTY_2040: width = 320; height = 240; + // Tufty display is upside-down + if(rotate == -1) rotate = (int)Rotation::ROTATE_180; break; case DISPLAY_PICO_EXPLORER: case DISPLAY_LCD_240X240: @@ -80,7 +84,7 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size enum { ARG_display, ARG_rotate, ARG_bus, ARG_buffer, ARG_pen_type }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_rotate, MP_ARG_INT, { .u_int = Rotation::ROTATE_0 } }, + { MP_QSTR_rotate, MP_ARG_INT, { .u_int = -1 } }, { MP_QSTR_bus, MP_ARG_OBJ, { .u_obj = mp_const_none } }, { MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, { MP_QSTR_pen_type, MP_ARG_INT, { .u_int = PEN_RGB332 } }, @@ -93,7 +97,6 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size self = m_new_obj(ModPicoGraphics_obj_t); self->base.type = &ModPicoGraphics_type; - Rotation rotate = (Rotation)args[ARG_rotate].u_int; PicoGraphicsPenType pen_type = (PicoGraphicsPenType)args[ARG_pen_type].u_int; PicoGraphicsDisplay display = (PicoGraphicsDisplay)args[ARG_display].u_int; @@ -101,15 +104,17 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size bool round = display == DISPLAY_ROUND_LCD_240X240; int width = 0; int height = 0; - if(!get_display_resolution(display, width, height)) mp_raise_ValueError("Unsupported display!"); + int rotate = args[ARG_rotate].u_int; + if(!get_display_settings(display, width, height, rotate)) mp_raise_ValueError("Unsupported display!"); + if(rotate == -1) rotate = (int)Rotation::ROTATE_0; // Try to create an appropriate display driver if (display == DISPLAY_TUFTY_2040) { if (args[ARG_bus].u_obj == mp_const_none) { - self->display = m_new_class(ST7789, width, height, rotate, {10, 11, 12, 13, 14, 2}); + self->display = m_new_class(ST7789, width, height, (Rotation)rotate, {10, 11, 12, 13, 14, 2}); } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) { _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); - self->display = m_new_class(ST7789, width, height, rotate, *(ParallelPins *)(bus->pins)); + self->display = m_new_class(ST7789, width, height, (Rotation)rotate, *(ParallelPins *)(bus->pins)); } else { mp_raise_ValueError("ParallelBus expected!"); } @@ -124,10 +129,10 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size } } else { if (args[ARG_bus].u_obj == mp_const_none) { - self->display = m_new_class(ST7789, width, height, rotate, round, get_spi_pins(BG_SPI_FRONT)); + self->display = m_new_class(ST7789, width, height, (Rotation)rotate, round, get_spi_pins(BG_SPI_FRONT)); } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) { _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj); - self->display = m_new_class(ST7789, width, height, rotate, round, *(SPIPins *)(bus->pins)); + self->display = m_new_class(ST7789, width, height, (Rotation)rotate, round, *(SPIPins *)(bus->pins)); } else { mp_raise_ValueError("SPIBus expected!"); } @@ -222,7 +227,8 @@ mp_obj_t ModPicoGraphics_get_required_buffer_size(mp_obj_t display_in, mp_obj_t PicoGraphicsDisplay display = (PicoGraphicsDisplay)mp_obj_get_int(display_in); int width = 0; int height = 0; - if(!get_display_resolution(display, width, height)) mp_raise_ValueError("Unsupported display!"); + int rotation = 0; + if(!get_display_settings(display, width, height, rotation)) mp_raise_ValueError("Unsupported display!"); size_t required_size = get_required_buffer_size(pen_type, width, height); if(required_size == 0) mp_raise_ValueError("Unsupported pen type!"); From 1b68e498d4e7353093ba92a3dc7c63fae480fecc Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Jun 2022 14:43:08 +0100 Subject: [PATCH 55/84] ST7789/PicoGraphics: Update docs. --- drivers/st7789/README.md | 58 +++++++++ libraries/pico_display/README.md | 64 +++------ libraries/pico_display_2/README.md | 99 +++++--------- libraries/pico_explorer/README.md | 201 ++++++++++++++++------------- 4 files changed, 217 insertions(+), 205 deletions(-) create mode 100644 drivers/st7789/README.md diff --git a/drivers/st7789/README.md b/drivers/st7789/README.md new file mode 100644 index 00000000..b9e92b4b --- /dev/null +++ b/drivers/st7789/README.md @@ -0,0 +1,58 @@ +# ST7789 Display Driver for Pimoroni LCDs + +The ST7789 driver supports both Parallel and Serial (SPI) ST7789 displays and is intended for use with: + +* Pico Display +* Pico Display 2.0 +* Tufty 2040 +* Pico Explorer +* 240x240 Round & Square SPI LCD Breakouts + +## Setup + +Construct an instance of the ST7789 driver with either Parallel or SPI pins. + +Parallel: + +```c++ +ST7789 st7789(WIDTH, HEIGHT, ROTATE_0, { + Tufty2040::LCD_CS, // Chip-Select + Tufty2040::LCD_DC, // Data-Command + Tufty2040::LCD_WR, // Write + Tufty2040::LCD_RD, // Read + Tufty2040::LCD_D0, // Data 0 (start of a bank of 8 pins) + Tufty2040::BACKLIGHT // Backlight +}); +``` + +SPI: + +```c++ +ST7789 st7789(WIDTH, HEIGHT, ROTATE_0, false, { + PIMORONI_SPI_DEFAULT_INSTANCE, // SPI instance + SPI_BG_FRONT_CS, // Chip-select + SPI_DEFAULT_SCK, // SPI Clock + SPI_DEFAULT_MOSI, // SPI Out + PIN_UNUSED, // SPI In + SPI_DEFAULT_DC, // SPI Data/Command + PIN_UNUSED // Backlight +}); +``` + +## Reference + +### Update + +ST7789's `update` accepts an instance of `PicoGraphics` in any colour mode: + +```c++ +st7789.update(&graphics); +``` + +### Set Backlight + +If a backlight pin has been configured, you can set the backlight from 0 to 255: + +```c++ +st7789.set_backlight(128) +``` \ No newline at end of file diff --git a/libraries/pico_display/README.md b/libraries/pico_display/README.md index 92400654..648df9ce 100644 --- a/libraries/pico_display/README.md +++ b/libraries/pico_display/README.md @@ -7,11 +7,7 @@ We've included helper functions to handle every aspect of drawing to the screen - [Example Program](#example-program) - [Function Reference](#function-reference) - [PicoGraphics](#picographics) - - [init](#init) - - [set_backlight](#set_backlight) - - [set_led](#set_led) - - [is_pressed](#is_pressed) - - [update](#update) + - [ST7789](#st7789) ## Example Program @@ -19,16 +15,18 @@ The following example sets up Pico Display, displays some basic demo text and gr ```c++ #include "pico_display.hpp" -#include "generic_st7789.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" #include "rgbled.hpp" #include "button.hpp" -uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT]; +// Display driver +ST7789 st7789(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); -// Swap WIDTH and HEIGHT to rotate 90 degrees -ST7789Generic display(PicoDisplay::WIDTH, PicoDisplay::HEIGHT, buffer); +// Graphics library - in RGB332 mode you get 256 colours and optional dithering for ~32K RAM. +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); -// Create an RGB LED +// RGB LED RGBLED led(PicoDisplay::LED_R, PicoDisplay::LED_G, PicoDisplay::LED_B); // And each button @@ -42,7 +40,7 @@ int main() { // set the backlight to a value between 0 and 255 // the backlight is driven via PWM and is gamma corrected by our // library to give a gorgeous linear brightness range. - display.set_backlight(100); + st7789.set_backlight(100); while(true) { // detect if the A button is pressed (could be A, B, X, or Y) @@ -55,24 +53,24 @@ int main() { // set the colour of the pen // parameters are red, green, blue all between 0 and 255 - display.set_pen(30, 40, 50); + graphics.set_pen(30, 40, 50); // fill the screen with the current pen colour - display.clear(); + graphics.clear(); // draw a box to put some text in - display.set_pen(10, 20, 30); + graphics.set_pen(10, 20, 30); Rect text_rect(10, 10, 150, 150); - display.rectangle(text_rect); + graphics.rectangle(text_rect); // write some text inside the box with 10 pixels of margin // automatically word wrapping text_rect.deflate(10); - display.set_pen(110, 120, 130); - display.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w); + graphics.set_pen(110, 120, 130); + graphics.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w); // now we've done our drawing let's update the screen - display.update(); + st7789.update(&graphics); } } ``` @@ -83,32 +81,6 @@ int main() { Pico Display uses our Pico Graphics library to draw graphics and text. For more information [read the Pico Graphics function reference.](../pico_graphics/README.md#function-reference). -### configure_display +### ST7789 -Configures an ST7789 display. Done by default, but you can use this to set 180 degree rotation like so: - -```c++ -display.configure_display(true); -``` - -### flip - -Deprecated: calls `configure_display(true);` - -### set_backlight - -Set the display backlight from 0-255. - -```c++ -display.set_backlight(brightness); -``` - -Uses hardware PWM to dim the display backlight, dimming values are gamma-corrected to provide smooth brightness transitions across the full range of intensity. This may result in some low values mapping as "off." - -### update - -To display your changes on Pico Display's screen you need to call `update`: - -```c++ -display.update(); -``` +Pico Display uses the ST7789 display driver to handle the LCD. For more information [read the ST7789 README.](../../drivers/st7789/README.md). \ No newline at end of file diff --git a/libraries/pico_display_2/README.md b/libraries/pico_display_2/README.md index ee454773..18ad905c 100644 --- a/libraries/pico_display_2/README.md +++ b/libraries/pico_display_2/README.md @@ -2,16 +2,10 @@ Our Pico Display Pack offers a vibrant 1.14" (240x135) IPS LCD screen for your Raspberry Pi Pico it also includes four switches and and an RGB LED! -We've included helper functions to handle every aspect of drawing to the screen and interfacing with the buttons and LED. See the [function reference](#function-reference) for details. - - [Example Program](#example-program) - [Function Reference](#function-reference) - [PicoGraphics](#picographics) - - [init](#init) - - [set_backlight](#set_backlight) - - [set_led](#set_led) - - [is_pressed](#is_pressed) - - [update](#update) + - [ST7789](#st7789) ## Example Program @@ -19,49 +13,62 @@ The following example sets up Pico Display, displays some basic demo text and gr ```c++ #include "pico_display_2.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" +#include "rgbled.hpp" +#include "button.hpp" -using namespace pimoroni; +// Display driver +ST7789 st7789(PicoDisplay2::WIDTH, PicoDisplay2::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); -uint16_t buffer[PicoDisplay2::WIDTH * PicoDisplay2::HEIGHT]; -PicoDisplay2 pico_display(buffer); +// Graphics library - in RGB332 mode you get 256 colours and optional dithering for 75K RAM. +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); + +// RGB LED +RGBLED led(PicoDisplay2::LED_R, PicoDisplay2::LED_G, PicoDisplay2::LED_B); + +// And each button +Button button_a(PicoDisplay2::A); +Button button_b(PicoDisplay2::B); +Button button_x(PicoDisplay2::X); +Button button_y(PicoDisplay2::Y); int main() { - pico_display.init(); // set the backlight to a value between 0 and 255 // the backlight is driven via PWM and is gamma corrected by our // library to give a gorgeous linear brightness range. - pico_display.set_backlight(100); + st7789.set_backlight(100); while(true) { // detect if the A button is pressed (could be A, B, X, or Y) - if(pico_display.is_pressed(pico_display.A)) { + if(button_a.raw(display.A)) { // make the led glow green // parameters are red, green, blue all between 0 and 255 // these are also gamma corrected - pico_display.set_led(0, 255, 0); + led.set_rgb(0, 255, 0); } // set the colour of the pen // parameters are red, green, blue all between 0 and 255 - pico_display.set_pen(30, 40, 50); + graphics.set_pen(30, 40, 50); // fill the screen with the current pen colour - pico_display.clear(); + graphics.clear(); // draw a box to put some text in - pico_display.set_pen(10, 20, 30); + graphics.set_pen(10, 20, 30); Rect text_rect(10, 10, 150, 150); - pico_display.rectangle(text_rect); + graphics.rectangle(text_rect); // write some text inside the box with 10 pixels of margin // automatically word wrapping text_rect.deflate(10); - pico_display.set_pen(110, 120, 130); - pico_display.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w); + graphics.set_pen(110, 120, 130); + graphics.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w); // now we've done our drawing let's update the screen - pico_display.update(); + st7789.update(&graphics); } } ``` @@ -72,52 +79,6 @@ int main() { Pico Display uses our Pico Graphics library to draw graphics and text. For more information [read the Pico Graphics function reference.](../pico_graphics/README.md#function-reference). -### init +### ST7789 -Sets up Pico Display. `init` must be called before any other functions since it configures the required PWM and GPIO: - -```c++ -pico_display.init(); -``` - -### set_backlight - -Set the display backlight from 0-255. - -```c++ -pico_display.set_backlight(brightness); -``` - -Uses hardware PWM to dim the display backlight, dimming values are gamma-corrected to provide smooth brightness transitions across the full range of intensity. This may result in some low values mapping as "off." - -### set_led - -Sets the RGB LED on Pico Display with an RGB triplet: - -```c++ -pico_display.set_led(r, g, b); -``` - -Uses hardware PWM to drive the LED. Values are automatically gamma-corrected to provide smooth brightness transitions and low values may map as "off." - -### is_pressed - -Reads the GPIO pin connected to one of Pico Display's buttons, returning a `bool` - `true` if it's pressed and `false` if it is released. - -```c++ -pico_display.is_pressed(button); -``` - -The button vaule should be a `uint8_t` denoting a pin, and constants `A`, `B`, `X` and `Y` are supplied to make it easier. e: - -```c++ -bool is_a_button_pressed = pico_display.is_pressed(PicoDisplay2::A) -``` - -### update - -To display your changes on Pico Display's screen you need to call `update`: - -```c++ -pico_display.update(); -``` +Pico Display uses the ST7789 display driver to handle the LCD. For more information [read the ST7789 README.](../../drivers/st7789/README.md). \ No newline at end of file diff --git a/libraries/pico_explorer/README.md b/libraries/pico_explorer/README.md index 91589cdd..6c9b0a25 100644 --- a/libraries/pico_explorer/README.md +++ b/libraries/pico_explorer/README.md @@ -11,35 +11,59 @@ We've included helper functions to handle every aspect of drawing to the screen - [Buttons](#buttons) - [ADC Channels](#adc-channels) - [GPIO](#gpio) + - [Motors](#motors) - [Functions](#functions) - - [init](#init) - - [set_motor](#set_motor) - - [get_adc](#get_adc) - - [set_audio_pin](#set_audio_pin) - - [set_tone](#set_tone) - - [is_pressed](#is_pressed) - - [update](#update) + - [Motors](#motors-1) + - [Analog](#analog) + - [Buzzer](#buzzer) + - [Buttons](#buttons-1) + - [ST7789](#st7789) + ## Example Program -The following example sets up Pico Explorer, displays some basic demo text and graphics and will illuminate the RGB LED green if the A button is pressed. +The following example shows how to set up all of Pico Explorers functions: ```c++ #include "pico_explorer.hpp" +#include "drivers/st7789/st7789.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" +#include "button.hpp" +#include "motor.hpp" +#include "analog.hpp" using namespace pimoroni; -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_explorer(buffer); +// Display driver +ST7789 st7789(PicoExplorer::WIDTH, PicoExplorer::HEIGHT, ROTATE_0, false, get_spi_pins(BG_SPI_FRONT)); + +// Graphics library - in RGB332 mode you get 256 colours and optional dithering for ~56K RAM. +PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr); + +// Buttons +Button button_a(PicoExplorer::A); +Button button_b(PicoExplorer::B); +Button button_x(PicoExplorer::X); +Button button_y(PicoExplorer::Y); + +// Motors +Motor motor1(PicoExplorer::MOTOR1_PINS); +Motor motor2(PicoExplorer::MOTOR2_PINS); + +// Analog +Analog adc0(PicoExplorer::ADC0_PIN); +Analog adc1(PicoExplorer::ADC1_PIN); +Analog adc2(PicoExplorer::ADC2_PIN); + int main() { - pico_explorer.init(); + motor1.init(); + motor2.init(); - while(true) { - - // now we've done our drawing let's update the screen - pico_explorer.update(); - } + while(true) { + // update screen + st7789.update(&graphics); + } } ``` @@ -55,132 +79,129 @@ Please note that the backlight on Pico Explorer is not dimmable (we needed the p #### Buttons -The four buttons, A, B, X and Y have corresponding constants set to their respective GPIO pins. For example: +The four buttons, A, B, X and Y have corresponding constants set to their respective GPIO pins. ```c++ -bool a_is_pressed = pico_explorer.is_pressed(pico_explorer.A); +PicoExplorer::A = 12; +PicoExplorer::B = 13; +PicoExplorer::X = 14; +PicoExplorer::Y = 15; ``` #### ADC Channels -The three ADC channels are defined as `ADC0`, `ADC1` and `ADC2`, and should be used with `get_adc`, eg: +The three ADC channels are defined as `ADC0_PIN`, `ADC1_PIN` and `ADC2_PIN`, and should be used with an instance of the `Analog` class: ```c++ -float adc0_reading = pico_explorer.get_adc(pico_explorer.ADC0); +PicoExplorer::ADC0_PIN = 26; +PicoExplorer::ADC1_PIN = 27; +PicoExplorer::ADC2_PIN = 28; ``` #### GPIO -The 8 general purpose IO pins on the lower Pico Explorer are GP0 through GP7, we've created constants for you to identify them easily. You should use Pico SDK's `gpio_get` to read a pin, eg: +The 8 general purpose IO pins on the lower Pico Explorer are GP0 through GP7, we've created constants for you to identify them easily. + +```c++ +PicoExplorer::GP0 = 0; +PicoExplorer::GP1 = 1; +PicoExplorer::GP2 = 2; +PicoExplorer::GP3 = 3; +PicoExplorer::GP4 = 4; +PicoExplorer::GP5 = 5; +PicoExplorer::GP6 = 6; +PicoExplorer::GP7 = 7; +``` + +You should use Pico SDK's `gpio_get` to read a pin, eg: ```c++ bool pin_state = gpio_get(pico_explorer.GP0); ``` +#### Motors + +The two motor channels are defined as pin pairs, and should be used with an instance of the `Motor` class: + +```c++ + PicoExplorer::MOTOR1_PINS = {9, 8}; + PicoExplorer::MOTOR2_PINS = {11, 10}; +``` + ### Functions -#### init +#### Motors -Sets up Pico Explorer. `init` must be called before any other functions since it configures the required PWM and GPIO: +Pico Explorer uses our `Motor` library to drive motors. Motors are driven by PWM via an onboard DRV8833. Constants are provided for both motors, so setup is as easy as: ```c++ -pico_explorer.init(); +#include "motor.hpp" + +using namespace motor; + +Motor motor1(PicoExplorer::MOTOR1_PINS); +Motor motor2(PicoExplorer::MOTOR2_PINS); ``` -#### set_motor +You should also init your motors to set up the required GPIO/PWM on their pins: ```c++ -void PicoExplorer::set_motor(uint8_t channel, uint8_t action, float speed); +motor1.init(); +motor2.init(); ``` -Motors are driven by PWM via an onboard DRV8833, `set_motor` will set the PWM values for the corresponding channel. - -Channel should be one of `MOTOR1` or `MOTOR2`. - -Action should be `FORWARD`, `REVERSE` or `STOP`. - -Speed should be given as a float between `0.0` and `1.0`, eg: +Speed should be given as a float between `-1.0` and `1.0`, eg: ```c++ -pico_explorer.set_motor(pico_explorer.MOTOR1, pico_explorer.FORWARD, 0.5f); -pico_explorer.set_motor(pico_explorer.MOTOR2, pico_explorer.REVERSE, 0.5f); +motor1.speed(1.0) // Full-speed forward +motor1.speed(-1.0) // Full-speed backward ``` And to stop the motor: ```c++ -pico_explorer.set_motor(pico_explorer.MOTOR1, pico_explorer.STOP); -pico_explorer.set_motor(pico_explorer.MOTOR2, pico_explorer.STOP); +motor1.stop() ``` -#### get_adc +#### Analog ```c++ float get_adc(uint8_t channel); ``` -Pico Explorer's ADC channels are connected to Pico's ADC-capable pins 26, 27 and 28 which correspond to channels 0, 1 and 2 respectively. eg: +Pico Explorer's ADC channels are connected to Pico's ADC-capable pins 26, 27 and 28 which correspond to channels 0, 1 and 2 respectively. + +Constants are supplied for these in the PicoExplorer library, so you can create an Analog instance for each: ```c++ -float reading = pico_explorer.get_adc(pico_explorer.ADC0); +#include "analog.hpp" +Analog adc0(PicoExplorer::ADC0_PIN); +Analog adc1(PicoExplorer::ADC1_PIN); +Analog adc2(PicoExplorer::ADC2_PIN); ``` -Will perform a 12-bit ADC read and return the result as a float scaled from `0.0f` to `1.0f`. This value can be plugged directly into a motor, eg: +And read a voltage with: ```c++ -float reading = pico_explorer.get_adc(pico_explorer.ADC0); -pico_explorer.set_motor(pico_explorer.MOTOR1, pico_explorer.FORWARD, reading); +adc0.read_voltage(); ``` -#### set_audio_pin +#### Buzzer + +Note: You must bridge the pin you use over to the `AUDIO` pin on the Pico Explorer header in order to drive the onboard Piezo. + +TODO document buzzer + +#### Buttons ```c++ -void set_audio_pin(uint8_t p); +#include "button.hpp" +Button button_a(PicoExplorer::A); +Button button_b(PicoExplorer::B); +Button button_x(PicoExplorer::X); +Button button_y(PicoExplorer::Y); ``` -`set_audio_pin` configures the PIN that Pico Explorer uses for audio output. It should be one of `GP0` through `GP7`, eg: +### ST7789 -```c++ -pico_explorer.set_audio_pin(pico_explorer.GP0); -``` - -Note: You must bridge this pin over to the `AUDIO` pin on the Pico Explorer header in order to drive the onboard Piezo, eg: - -#### set_tone - -```c++ -void set_tone(uint16_t frequency, float duty = 0.2f); -``` - -`set_tone` will play an audio tone out of your chosen audio pin, if you have bridged that pin to "AUDIO" on the Pico Explorer header then it will sound the onboard Piezo. - -```c++ -uint16_t frequency = 440; -pico_explorer.set_tone(frequency); -``` - -#### is_pressed - -```c++ -bool is_pressed(uint8_t button); -``` - -Reads the GPIO pin connected to one of Pico Explorer's buttons, returning a `bool` - `true` if it's pressed and `false` if it is released. - -```c++ -pico_explorer.is_pressed(button); -``` - -The button vaule should be a `uint8_t` denoting a pin, and constants `A`, `B`, `X` and `Y` are supplied to make it easier. e: - -```c++ -bool is_a_button_pressed = pico_explorer.is_pressed(PicoDisplay::A) -``` - -#### update - -To display your changes on Pico Explorer's screen you need to call `update`: - -```c++ -pico_explorer.update(); -``` \ No newline at end of file +Pico Explorer uses the ST7789 display driver to handle the LCD. For more information [read the ST7789 README.](../../drivers/st7789/README.md). \ No newline at end of file From ce9aa019ecb0d1df8665a7d6ee26739de4f35077 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Jun 2022 15:45:47 +0100 Subject: [PATCH 56/84] PicoGraphics: Fix P8 buffer size. --- libraries/pico_graphics/pico_graphics_pen_p8.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/pico_graphics/pico_graphics_pen_p8.cpp b/libraries/pico_graphics/pico_graphics_pen_p8.cpp index da0729bf..201d3277 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p8.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p8.cpp @@ -62,7 +62,7 @@ namespace pimoroni { row_buf[x] = cache[src[bounds.w * y + x]]; } // Callback to the driver with the row data - callback(row_buf, bounds.w * sizeof(RGB565)); + callback(row_buf, bounds.w * sizeof(uint8_t)); } } } From e480620e9f0dd31588996de6f7025051000329ef Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Jun 2022 15:46:16 +0100 Subject: [PATCH 57/84] Tufty2040: Drop rogue pin. --- libraries/tufty2040/tufty2040.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/tufty2040/tufty2040.hpp b/libraries/tufty2040/tufty2040.hpp index dca2283f..5798171f 100644 --- a/libraries/tufty2040/tufty2040.hpp +++ b/libraries/tufty2040/tufty2040.hpp @@ -15,7 +15,6 @@ namespace pimoroni { static const uint8_t A = 7; static const uint8_t B = 8; static const uint8_t C = 9; - static const uint8_t Y = 15; static const uint8_t UP = 22; static const uint8_t DOWN = 6; static const uint8_t LED = 25; From c66a5901423336e11a95e0b8af559dc99eadde63 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Jun 2022 15:47:00 +0100 Subject: [PATCH 58/84] Tufty2040: Solarized example. --- .../examples/tufty2040/tufty2040_solarized.py | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 micropython/examples/tufty2040/tufty2040_solarized.py diff --git a/micropython/examples/tufty2040/tufty2040_solarized.py b/micropython/examples/tufty2040/tufty2040_solarized.py new file mode 100644 index 00000000..3c97d9b7 --- /dev/null +++ b/micropython/examples/tufty2040/tufty2040_solarized.py @@ -0,0 +1,119 @@ +from picographics import PicoGraphics, DISPLAY_TUFTY_2040, PEN_P4 +from pimoroni import Button +import math +import time + +""" +Tufty2040: Solarized + +Sets up Tufty 2040 in 4-bit colour mode and fills the +16-bit palette with some nice Solarized colours. + +See: https://ethanschoonover.com/solarized/ +""" + + +# Background & Content Tones +BASE_03 = 0 +BASE_02 = 1 +BASE_01 = 2 +BASE_00 = 3 +BASE_0 = 4 +BASE_1 = 5 +BASE_2 = 6 +BASE_3 = 7 + +# Accent Colours +YELLOW = 8 +ORANGE = 9 +RED = 10 +MAGENTA = 11 +VIOLET = 12 +BLUE = 13 +CYAN = 14 +GREEN = 15 + +# Friendly names for light/dark backgrounds +BG_DARK = BASE_03 +BG_LIGHT = BASE_2 + + +def bargraph(ox, oy, w, h, value, colors, pips=32): + step = int(pips / len(colors)) + filled = int(value * pips) + pip_width = int(w / pips) + for i in range(pips): + p = colors[int(i / step)] + lcd.set_pen(p) + x = i * pip_width + if i > filled: + lcd.rectangle(ox + x, oy + h - 1, pip_width - 2, 1) + else: + lcd.rectangle(ox + x, oy, pip_width - 2, h) + + +lcd = PicoGraphics(DISPLAY_TUFTY_2040, pen_type=PEN_P4) + +lcd.set_backlight(0.8) +lcd.set_font("bitmap8") + +button_up = Button(22, invert=False) +button_down = Button(6, invert=False) + + +# Prime the palette with Solarized 16-colours! +lcd.set_palette([ + (0x00, 0x2b, 0x36), # Base 03 + (0x07, 0x36, 0x42), # Base 02 + (0x58, 0x6e, 0x75), # base 01 + (0x65, 0x7b, 0x83), # Base 00 + (0x83, 0x94, 0x96), # Base 0 + (0x93, 0xa1, 0xa1), # Base 1 + (0xee, 0xe8, 0xd5), # Base 2 + (0xfd, 0xf6, 0xe3), # Base 3 + (0xb5, 0x89, 0x00), # Yellow + (0xcb, 0x4b, 0x16), # Orange + (0xdc, 0x32, 0x2f), # Red + (0xd3, 0x36, 0x82), # Magenta + (0x6c, 0x71, 0xc4), # Violet + (0x26, 0x8b, 0xd2), # Blue + (0x2a, 0xa1, 0x98), # Cyan + (0x85, 0x99, 0x00), # Green +]) + +dark_mode = True + + +while True: + if button_down.is_pressed: + dark_mode = True + if button_up.is_pressed: + dark_mode = False + + lcd.set_pen(BG_DARK if dark_mode else BG_LIGHT) + lcd.clear() + + texts = [ + "Vær sÃ¥ god", + "Testing. Testing. 123.", + "Helló Világ", + "Comment ça va", + "meine Straße hinauf", + "It's a spicy 25°C", + "What do you think?", + "éphéméréité" + ] + + for i, pen in enumerate([YELLOW, ORANGE, RED, MAGENTA, VIOLET, BLUE, CYAN, GREEN]): + lcd.set_pen(pen) + lcd.text(texts[i], 10, i * 22 + 10, 320) + + v1 = (math.sin(time.ticks_ms() / 400.0 / math.pi) + 1.0) / 2.0 + v2 = (math.sin(time.ticks_ms() / 650.0 / math.pi) + 1.0) / 2.0 + v3 = (math.sin(time.ticks_ms() / 900.0 / math.pi) + 1.0) / 2.0 + + bargraph(10, 188, 300, 8, v1, [VIOLET, BLUE, CYAN, GREEN]) + bargraph(10, 200, 300, 8, v2, [GREEN, YELLOW, RED, MAGENTA]) + bargraph(10, 212, 300, 8, v3, [CYAN, GREEN, YELLOW, ORANGE]) + + lcd.update() From 24f4b6fc8300d314f48274d23a051373172f9caa Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Jun 2022 15:53:22 +0100 Subject: [PATCH 59/84] MicroPython: Drop crummy PicoSystem module. Saves about 1.5k. --- micropython/modules_py/modules_py.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/modules_py/modules_py.cmake b/micropython/modules_py/modules_py.cmake index 3b18ff34..a3b0e7c8 100644 --- a/micropython/modules_py/modules_py.cmake +++ b/micropython/modules_py/modules_py.cmake @@ -16,5 +16,5 @@ add_library(usermod_modules_py INTERFACE) target_link_libraries(usermod INTERFACE usermod_modules_py) # .py files to copy from modules_py to ports/rp2/modules -copy_module(usermod_modules_py ${CMAKE_CURRENT_LIST_DIR}/picosystem.py picosystem) +#copy_module(usermod_modules_py ${CMAKE_CURRENT_LIST_DIR}/picosystem.py picosystem) copy_module(usermod_modules_py ${CMAKE_CURRENT_LIST_DIR}/pimoroni.py pimoroni) From 5d7113e8c948c1986bfe609d32ba37e6e76179c4 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Jun 2022 17:54:12 +0100 Subject: [PATCH 60/84] PicoGraphics: Basic 128x128 RGB332 spritesheet support. --- libraries/pico_graphics/pico_graphics.cpp | 1 + libraries/pico_graphics/pico_graphics.hpp | 8 ++++ .../pico_graphics_pen_rgb332.cpp | 16 ++++++++ libraries/pico_graphics/types.cpp | 14 ------- .../modules/picographics/picographics.c | 7 ++++ .../modules/picographics/picographics.cpp | 41 ++++++++++++++++++- .../modules/picographics/picographics.h | 4 ++ 7 files changed, 76 insertions(+), 15 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 551fb34d..3cde4729 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -11,6 +11,7 @@ namespace pimoroni { void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {}; void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {}; void PicoGraphics::scanline_convert(PenType type, conversion_callback_func callback) {}; + void PicoGraphics::sprite(void* data, const Point &sprite, const Point &dest, const int transparent) {}; void PicoGraphics::set_dimensions(int width, int height) { bounds = clip = {0, 0, width, height}; diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index e3bcad8f..23c94ae3 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -100,6 +100,12 @@ namespace pimoroni { Point clamp(const Rect &r) const; }; + inline bool operator== (const Point &lhs, const Point &rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } + inline bool operator!= (const Point &lhs, const Point &rhs) { return !(lhs == rhs); } + inline Point operator- (Point lhs, const Point &rhs) { lhs -= rhs; return lhs; } + inline Point operator- (const Point &rhs) { return Point(-rhs.x, -rhs.y); } + inline Point operator+ (Point lhs, const Point &rhs) { lhs += rhs; return lhs; } + struct Rect { int32_t x = 0, y = 0, w = 0, h = 0; @@ -185,6 +191,7 @@ namespace pimoroni { virtual void set_pixel_dither(const Point &p, const RGB &c); virtual void set_pixel_dither(const Point &p, const RGB565 &c); virtual void scanline_convert(PenType type, conversion_callback_func callback); + virtual void sprite(void* data, const Point &sprite, const Point &dest, const int transparent); void set_font(const bitmap::font_t *font); void set_font(const hershey::font_t *font); @@ -262,6 +269,7 @@ namespace pimoroni { void set_pixel_dither(const Point &p, const RGB &c) override; void set_pixel_dither(const Point &p, const RGB565 &c) override; void scanline_convert(PenType type, conversion_callback_func callback) override; + void sprite(void* data, const Point &sprite, const Point &dest, const int transparent) override; static size_t buffer_size(uint w, uint h) { return w * h; } diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp index 8141e430..9b21f894 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp @@ -106,4 +106,20 @@ namespace pimoroni { } } } + void PicoGraphics_PenRGB332::sprite(void* data, const Point &sprite, const Point &dest, const int transparent) { + //int sprite_x = (sprite & 0x0f) << 3; + //int sprite_y = (sprite & 0xf0) >> 1; + Point s { + sprite.x << 3, + sprite.y << 3 + }; + RGB332 *ptr = (RGB332 *)data; + Point o = {0, 0}; + for(o.y = 0; o.y < 8; o.y++) { + for(o.x = 0; o.x < 8; o.x++) { + color = ptr[(s.y + o.y) * 128 + (s.x + o.x)]; + if(color != transparent) set_pixel(dest + o); + } + } + } } \ No newline at end of file diff --git a/libraries/pico_graphics/types.cpp b/libraries/pico_graphics/types.cpp index 91d8fb27..53dac95e 100644 --- a/libraries/pico_graphics/types.cpp +++ b/libraries/pico_graphics/types.cpp @@ -12,20 +12,6 @@ namespace pimoroni { ); } - Point operator- (Point lhs, const Point &rhs) { - lhs -= rhs; - return lhs; - } - - Point operator- (const Point &rhs) { - return Point(-rhs.x, -rhs.y); - } - - Point operator+ (Point lhs, const Point &rhs) { - lhs += rhs; - return lhs; - } - bool Rect::empty() const { return w <= 0 || h <= 0; } diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index bd2253b9..158e0655 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -35,6 +35,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_polygon_obj, 2, ModPicoGraphics_polyg MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_triangle_obj, 7, 7, ModPicoGraphics_triangle); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_line_obj, 5, 5, ModPicoGraphics_line); +// Sprites +MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_spritesheet_obj, ModPicoGraphics_set_spritesheet); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_sprite_obj, 6, 6, ModPicoGraphics_sprite); + // Utility //MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_scanline_callback_obj, ModPicoGraphics_set_scanline_callback); MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_get_bounds_obj, ModPicoGraphics_get_bounds); @@ -59,6 +63,9 @@ STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&ModPicoGraphics_triangle_obj) }, { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&ModPicoGraphics_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_spritesheet), MP_ROM_PTR(&ModPicoGraphics_set_spritesheet_obj) }, + { MP_ROM_QSTR(MP_QSTR_sprite), MP_ROM_PTR(&ModPicoGraphics_sprite_obj) }, + { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&ModPicoGraphics_create_pen_obj) }, { MP_ROM_QSTR(MP_QSTR_update_pen), MP_ROM_PTR(&ModPicoGraphics_update_pen_obj) }, { MP_ROM_QSTR(MP_QSTR_reset_pen), MP_ROM_PTR(&ModPicoGraphics_reset_pen_obj) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 6888b286..8d4a9c27 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -24,6 +24,7 @@ typedef struct _ModPicoGraphics_obj_t { mp_obj_base_t base; PicoGraphics *graphics; DisplayDriver *display; + void *spritedata; void *buffer; //mp_obj_t scanline_callback; // Not really feasible in MicroPython } ModPicoGraphics_obj_t; @@ -139,7 +140,7 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size } // Create or fetch buffer - size_t required_size = get_required_buffer_size(pen_type, width, height); + size_t required_size = get_required_buffer_size((PicoGraphicsPenType)pen_type, width, height); if(required_size == 0) mp_raise_ValueError("Unsupported pen type!"); if (args[ARG_buffer].u_obj != mp_const_none) { @@ -174,6 +175,8 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size //self->scanline_callback = mp_const_none; + self->spritedata = nullptr; + // Clear the buffer self->graphics->set_pen(0); self->graphics->clear(); @@ -184,6 +187,42 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size return MP_OBJ_FROM_PTR(self); } +mp_obj_t ModPicoGraphics_set_spritesheet(mp_obj_t self_in, mp_obj_t spritedata) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); + if(spritedata == mp_const_none) { + self->spritedata = nullptr; + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(spritedata, &bufinfo, MP_BUFFER_RW); + + int required_size = get_required_buffer_size((PicoGraphicsPenType)self->graphics->pen_type, 128, 128); + + if(bufinfo.len != (size_t)(required_size)) { + mp_raise_ValueError("Spritesheet the wrong size!"); + } + + self->spritedata = bufinfo.buf; + } + return mp_const_none; +} + +mp_obj_t ModPicoGraphics_sprite(size_t n_args, const mp_obj_t *args) { + enum { ARG_self, ARG_sprite_x, ARG_sprite_y, ARG_x, ARG_y, ARG_transparent }; + + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); + + if(self->spritedata == nullptr) return mp_const_false; + + self->graphics->sprite( + self->spritedata, + {mp_obj_get_int(args[ARG_sprite_x]), mp_obj_get_int(args[ARG_sprite_y])}, + {mp_obj_get_int(args[ARG_x]), mp_obj_get_int(args[ARG_y])}, + mp_obj_get_int(args[ARG_transparent]) + ); + + return mp_const_true; +} + mp_obj_t ModPicoGraphics_set_font(mp_obj_t self_in, mp_obj_t font) { ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); self->graphics->set_font(mp_obj_to_string_r(font)); diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index 62955a96..0ee79823 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -60,6 +60,10 @@ extern mp_obj_t ModPicoGraphics_polygon(size_t n_args, const mp_obj_t *pos_args, extern mp_obj_t ModPicoGraphics_triangle(size_t n_args, const mp_obj_t *args); extern mp_obj_t ModPicoGraphics_line(size_t n_args, const mp_obj_t *args); +// Sprites +extern mp_obj_t ModPicoGraphics_set_spritesheet(mp_obj_t self_in, mp_obj_t spritedata); +extern mp_obj_t ModPicoGraphics_sprite(size_t n_args, const mp_obj_t *args); + // Utility //extern mp_obj_t ModPicoGraphics_set_scanline_callback(mp_obj_t self_in, mp_obj_t cb_in); extern mp_obj_t ModPicoGraphics_set_font(mp_obj_t self_in, mp_obj_t font); From e63a0e7da73802d59cbeb9b2c23a29fed6b10ae2 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 13 Jun 2022 20:17:59 +0100 Subject: [PATCH 61/84] AS7262: Update MicroPython example. --- .../breakout_as7262/pico_explorer_graph.py | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/micropython/examples/breakout_as7262/pico_explorer_graph.py b/micropython/examples/breakout_as7262/pico_explorer_graph.py index 43246936..3b46a144 100644 --- a/micropython/examples/breakout_as7262/pico_explorer_graph.py +++ b/micropython/examples/breakout_as7262/pico_explorer_graph.py @@ -1,17 +1,16 @@ from pimoroni_i2c import PimoroniI2C from breakout_as7262 import BreakoutAS7262 -import picoexplorer as display +import picographics import time -width = display.get_width() -height = display.get_height() + +display = picographics.PicoGraphics(picographics.DISPLAY_PICO_EXPLORER) + +width, height = display.get_bounds() bar_width = width // 6 bar_height = height -display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565) -display.init(display_buffer) - i2c = PimoroniI2C(20, 21) as7 = BreakoutAS7262(i2c) @@ -31,35 +30,44 @@ def draw_bar(v, i): display.rectangle(i * bar_width, current_bar_top, bar_width, current_bar_height - 1) +BLACK = display.create_pen(0, 0, 0) +RED = display.create_pen(255, 0, 0) +ORANGE = display.create_pen(255, 128, 0) +YELLOW = display.create_pen(255, 255, 0) +GREEN = display.create_pen(0, 255, 0) +BLUE = display.create_pen(0, 0, 255) +VIOLET = display.create_pen(255, 0, 255) + + while True: r, o, y, g, b, v = as7.read() m = max(r, o, y, g, b, v) - display.set_pen(0, 0, 0) + display.set_pen(BLACK) display.clear() # Red - display.set_pen(255, 0, 0) + display.set_pen(RED) draw_bar(r / m, 0) # Orange - display.set_pen(255, 128, 0) + display.set_pen(ORANGE) draw_bar(o / m, 1) # Yellow - display.set_pen(255, 255, 0) + display.set_pen(YELLOW) draw_bar(y / m, 2) # Green - display.set_pen(0, 255, 0) + display.set_pen(GREEN) draw_bar(g / m, 3) # Blue - display.set_pen(0, 0, 255) + display.set_pen(BLUE) draw_bar(b / m, 4) # Violet - display.set_pen(255, 0, 255) + display.set_pen(VIOLET) draw_bar(v / m, 5) display.update() From 6a3ba0d42119e0cc39373407a7010d363509ddd6 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 14 Jun 2022 10:58:56 +0100 Subject: [PATCH 62/84] MicroPython: Shim MP_REGISTER_MODULE for >1.18 compat. MicroPython has changed MP_REGISTER_MODULE to use only *two* args and now runs the preprocessing stage on files before running makemoduledefs.py. This change avoids the build exploding, since the new regex matches the last two args as a single argument and generates a malformed module defs include. The pattern here exploits the fact that 1.18 and below do not preprocess files, so *both* MP_REGISTER_MODULE lines are included in the source, but *only* the three arg version is matched by regex. In >1.18 the files will be processed and the three arg version removed before makemoduledefs.py processes it. --- micropython/modules/adcfft/adcfft.c | 6 +- micropython/modules/badger2040/badger2040.c | 4 ++ .../modules/breakout_as7262/breakout_as7262.c | 4 ++ .../modules/breakout_bh1745/breakout_bh1745.c | 4 ++ .../modules/breakout_bme280/breakout_bme280.c | 4 ++ .../modules/breakout_bme68x/breakout_bme68x.c | 4 ++ .../modules/breakout_bmp280/breakout_bmp280.c | 4 ++ .../breakout_dotmatrix/breakout_dotmatrix.c | 4 ++ .../breakout_encoder/breakout_encoder.c | 4 ++ .../breakout_icp10125/breakout_icp10125.c | 4 ++ .../breakout_ioexpander/breakout_ioexpander.c | 4 ++ .../modules/breakout_ltr559/breakout_ltr559.c | 4 ++ .../breakout_matrix11x7/breakout_matrix11x7.c | 4 ++ .../breakout_mics6814/breakout_mics6814.c | 4 ++ .../modules/breakout_msa301/breakout_msa301.c | 4 ++ .../breakout_pmw3901/breakout_paa5100.c | 64 +++++++++++++++++++ .../breakout_pmw3901/breakout_pmw3901.c | 40 ++---------- .../breakout_pmw3901/micropython.cmake | 3 +- .../breakout_potentiometer.c | 4 ++ .../breakout_rgbmatrix5x5.c | 4 ++ .../modules/breakout_rtc/breakout_rtc.c | 4 ++ .../modules/breakout_scd41/breakout_scd41.c | 4 ++ .../modules/breakout_sgp30/breakout_sgp30.c | 4 ++ .../breakout_trackball/breakout_trackball.c | 4 ++ .../modules/breakout_vl53l5cx/vl53l5cx.c | 4 ++ micropython/modules/encoder/encoder.c | 4 ++ micropython/modules/hub75/hub75.c | 6 +- micropython/modules/jpegdec/jpegdec.c | 6 +- micropython/modules/motor/motor.c | 4 ++ micropython/modules/pcf85063a/pcf85063a.c | 4 ++ .../modules/pico_explorer/pico_explorer.c | 6 +- .../modules/pico_rgb_keypad/pico_rgb_keypad.c | 4 ++ micropython/modules/pico_scroll/pico_scroll.c | 4 ++ .../modules/pico_unicorn/pico_unicorn.c | 4 ++ .../modules/pico_wireless/pico_wireless.c | 4 ++ .../modules/picographics/picographics.c | 6 +- .../modules/pimoroni_bus/pimoroni_bus.c | 6 +- .../modules/pimoroni_i2c/pimoroni_i2c.c | 4 ++ micropython/modules/plasma/plasma.c | 4 ++ micropython/modules/servo/servo.c | 4 ++ 40 files changed, 225 insertions(+), 42 deletions(-) create mode 100644 micropython/modules/breakout_pmw3901/breakout_paa5100.c diff --git a/micropython/modules/adcfft/adcfft.c b/micropython/modules/adcfft/adcfft.c index 11319a93..669150a2 100644 --- a/micropython/modules/adcfft/adcfft.c +++ b/micropython/modules/adcfft/adcfft.c @@ -33,4 +33,8 @@ const mp_obj_module_t adcfft_user_cmodule = { .globals = (mp_obj_dict_t*)&mp_module_adcfft_globals, }; -MP_REGISTER_MODULE(MP_QSTR_adcfft, adcfft_user_cmodule, MODULE_ADCFFT_ENABLED); \ No newline at end of file +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_adcfft, adcfft_user_cmodule, MODULE_ADCFFT_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_adcfft, adcfft_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/badger2040/badger2040.c b/micropython/modules/badger2040/badger2040.c index c95627d5..4aa0dfed 100644 --- a/micropython/modules/badger2040/badger2040.c +++ b/micropython/modules/badger2040/badger2040.c @@ -137,4 +137,8 @@ const mp_obj_module_t badger2040_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_badger2040_globals, }; +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_badger2040, badger2040_user_cmodule, MODULE_BADGER2040_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_badger2040, badger2040_user_cmodule); +#endif diff --git a/micropython/modules/breakout_as7262/breakout_as7262.c b/micropython/modules/breakout_as7262/breakout_as7262.c index 654765df..27e2dd60 100644 --- a/micropython/modules/breakout_as7262/breakout_as7262.c +++ b/micropython/modules/breakout_as7262/breakout_as7262.c @@ -83,6 +83,10 @@ const mp_obj_module_t breakout_as7262_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_as7262, breakout_as7262_user_cmodule, MODULE_BREAKOUT_AS7262_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_as7262, breakout_as7262_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_bh1745/breakout_bh1745.c b/micropython/modules/breakout_bh1745/breakout_bh1745.c index af4d4f8c..5ad5d233 100644 --- a/micropython/modules/breakout_bh1745/breakout_bh1745.c +++ b/micropython/modules/breakout_bh1745/breakout_bh1745.c @@ -57,6 +57,10 @@ const mp_obj_module_t breakout_bh1745_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_bh1745, breakout_bh1745_user_cmodule, MODULE_BREAKOUT_LTR559_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_bh1745, breakout_bh1745_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_bme280/breakout_bme280.c b/micropython/modules/breakout_bme280/breakout_bme280.c index 5495d18e..3e45e8c0 100644 --- a/micropython/modules/breakout_bme280/breakout_bme280.c +++ b/micropython/modules/breakout_bme280/breakout_bme280.c @@ -68,6 +68,10 @@ const mp_obj_module_t breakout_bme280_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_bme280, breakout_bme280_user_cmodule, MODULE_BREAKOUT_BME280_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_bme280, breakout_bme280_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_bme68x/breakout_bme68x.c b/micropython/modules/breakout_bme68x/breakout_bme68x.c index caffab88..2090c572 100644 --- a/micropython/modules/breakout_bme68x/breakout_bme68x.c +++ b/micropython/modules/breakout_bme68x/breakout_bme68x.c @@ -80,6 +80,10 @@ const mp_obj_module_t breakout_bme68x_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_bme68x, breakout_bme68x_user_cmodule, MODULE_BREAKOUT_BME68X_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_bme68x, breakout_bme68x_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_bmp280/breakout_bmp280.c b/micropython/modules/breakout_bmp280/breakout_bmp280.c index d70c59b0..06cc2e2c 100644 --- a/micropython/modules/breakout_bmp280/breakout_bmp280.c +++ b/micropython/modules/breakout_bmp280/breakout_bmp280.c @@ -68,6 +68,10 @@ const mp_obj_module_t breakout_bmp280_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_bmp280, breakout_bmp280_user_cmodule, MODULE_BREAKOUT_BMP280_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_bmp280, breakout_bmp280_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_dotmatrix/breakout_dotmatrix.c b/micropython/modules/breakout_dotmatrix/breakout_dotmatrix.c index b1d6a6e9..96814529 100644 --- a/micropython/modules/breakout_dotmatrix/breakout_dotmatrix.c +++ b/micropython/modules/breakout_dotmatrix/breakout_dotmatrix.c @@ -54,6 +54,10 @@ const mp_obj_module_t breakout_dotmatrix_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_dotmatrix, breakout_dotmatrix_user_cmodule, MODULE_BREAKOUT_DOTMATRIX_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_dotmatrix, breakout_dotmatrix_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_encoder/breakout_encoder.c b/micropython/modules/breakout_encoder/breakout_encoder.c index 2db2e1f6..35823915 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.c +++ b/micropython/modules/breakout_encoder/breakout_encoder.c @@ -60,6 +60,10 @@ const mp_obj_module_t breakout_encoder_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_encoder, breakout_encoder_user_cmodule, MODULE_BREAKOUT_ENCODER_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_encoder, breakout_encoder_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_icp10125/breakout_icp10125.c b/micropython/modules/breakout_icp10125/breakout_icp10125.c index bc3c415e..2946ab3e 100644 --- a/micropython/modules/breakout_icp10125/breakout_icp10125.c +++ b/micropython/modules/breakout_icp10125/breakout_icp10125.c @@ -48,6 +48,10 @@ const mp_obj_module_t breakout_icp10125_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_icp10125, breakout_icp10125_user_cmodule, MODULE_BREAKOUT_SGP30_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_icp10125, breakout_icp10125_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_ioexpander/breakout_ioexpander.c b/micropython/modules/breakout_ioexpander/breakout_ioexpander.c index 5e990c97..a9dc0852 100644 --- a/micropython/modules/breakout_ioexpander/breakout_ioexpander.c +++ b/micropython/modules/breakout_ioexpander/breakout_ioexpander.c @@ -89,6 +89,10 @@ const mp_obj_module_t breakout_ioexpander_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_ioexpander, breakout_ioexpander_user_cmodule, MODULE_BREAKOUT_IOEXPANDER_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_ioexpander, breakout_ioexpander_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_ltr559/breakout_ltr559.c b/micropython/modules/breakout_ltr559/breakout_ltr559.c index 6236cf24..6c8a66bc 100644 --- a/micropython/modules/breakout_ltr559/breakout_ltr559.c +++ b/micropython/modules/breakout_ltr559/breakout_ltr559.c @@ -71,6 +71,10 @@ const mp_obj_module_t breakout_ltr559_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_ltr559, breakout_ltr559_user_cmodule, MODULE_BREAKOUT_LTR559_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_ltr559, breakout_ltr559_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_matrix11x7/breakout_matrix11x7.c b/micropython/modules/breakout_matrix11x7/breakout_matrix11x7.c index eb17b3e1..ea20a079 100644 --- a/micropython/modules/breakout_matrix11x7/breakout_matrix11x7.c +++ b/micropython/modules/breakout_matrix11x7/breakout_matrix11x7.c @@ -46,6 +46,10 @@ const mp_obj_module_t breakout_matrix11x7_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_matrix11x7, breakout_matrix11x7_user_cmodule, MODULE_BREAKOUT_MATRIX11X7_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_matrix11x7, breakout_matrix11x7_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.c b/micropython/modules/breakout_mics6814/breakout_mics6814.c index 9af5f684..11cb785e 100644 --- a/micropython/modules/breakout_mics6814/breakout_mics6814.c +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.c @@ -74,6 +74,10 @@ const mp_obj_module_t breakout_mics6814_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_mics6814, breakout_mics6814_user_cmodule, MODULE_BREAKOUT_MICS6814_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_mics6814, breakout_mics6814_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_msa301/breakout_msa301.c b/micropython/modules/breakout_msa301/breakout_msa301.c index 86fad45d..4dc01d7f 100644 --- a/micropython/modules/breakout_msa301/breakout_msa301.c +++ b/micropython/modules/breakout_msa301/breakout_msa301.c @@ -107,6 +107,10 @@ const mp_obj_module_t breakout_msa301_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_msa301, breakout_msa301_user_cmodule, MODULE_BREAKOUT_MSA301_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_msa301, breakout_msa301_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_pmw3901/breakout_paa5100.c b/micropython/modules/breakout_pmw3901/breakout_paa5100.c new file mode 100644 index 00000000..3935c00e --- /dev/null +++ b/micropython/modules/breakout_pmw3901/breakout_paa5100.c @@ -0,0 +1,64 @@ +#include "breakout_pmw3901.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BreakoutPMW3901 Class +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Methods *****/ +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPAA5100_get_id_obj, BreakoutPMW3901_get_id); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPAA5100_get_revision_obj, BreakoutPMW3901_get_revision); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPAA5100_set_rotation_obj, 1, BreakoutPMW3901_set_rotation); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPAA5100_set_orientation_obj, 1, BreakoutPMW3901_set_orientation); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPAA5100_get_motion_obj, 1, BreakoutPMW3901_get_motion); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPAA5100_get_motion_slow_obj, 1, BreakoutPMW3901_get_motion_slow); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPAA5100_frame_capture_obj, 2, BreakoutPMW3901_frame_capture); + +/***** Binding of Methods *****/ +STATIC const mp_rom_map_elem_t BreakoutPAA5100_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_get_id), MP_ROM_PTR(&BreakoutPAA5100_get_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_revision), MP_ROM_PTR(&BreakoutPAA5100_get_revision_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_rotation), MP_ROM_PTR(&BreakoutPAA5100_set_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_orientation), MP_ROM_PTR(&BreakoutPAA5100_set_orientation_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_motion), MP_ROM_PTR(&BreakoutPAA5100_get_motion_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_motion_slow), MP_ROM_PTR(&BreakoutPAA5100_get_motion_slow_obj) }, + { MP_ROM_QSTR(MP_QSTR_frame_capture), MP_ROM_PTR(&BreakoutPAA5100_frame_capture_obj) }, + { MP_ROM_QSTR(MP_QSTR_DEGREES_0), MP_ROM_INT(0x00) }, + { MP_ROM_QSTR(MP_QSTR_DEGREES_90), MP_ROM_INT(0x01) }, + { MP_ROM_QSTR(MP_QSTR_DEGREES_180), MP_ROM_INT(0x02) }, + { MP_ROM_QSTR(MP_QSTR_DEGREES_270), MP_ROM_INT(0x03) }, + { MP_ROM_QSTR(MP_QSTR_FRAME_SIZE), MP_ROM_INT(35) }, + { MP_ROM_QSTR(MP_QSTR_FRAME_BYTES), MP_ROM_INT(1225) }, +}; +STATIC MP_DEFINE_CONST_DICT(BreakoutPAA5100_locals_dict, BreakoutPAA5100_locals_dict_table); + +/***** Class Definition *****/ +const mp_obj_type_t breakout_paa5100_BreakoutPAA5100_type = { + { &mp_type_type }, + .name = MP_QSTR_BreakoutPAA5100, + .print = BreakoutPMW3901_print, + .make_new = BreakoutPAA5100_make_new, + .locals_dict = (mp_obj_dict_t*)&BreakoutPAA5100_locals_dict, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// breakout_paa5100 Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Globals Table *****/ +STATIC const mp_map_elem_t breakout_paa5100_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_paa5100) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutPAA5100), (mp_obj_t)&breakout_paa5100_BreakoutPAA5100_type }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_paa5100_globals, breakout_paa5100_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t breakout_paa5100_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_breakout_paa5100_globals, +}; + +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_breakout_paa5100, breakout_paa5100_user_cmodule, MODULE_BREAKOUT_PMW3901_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_paa5100, breakout_paa5100_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/breakout_pmw3901/breakout_pmw3901.c b/micropython/modules/breakout_pmw3901/breakout_pmw3901.c index fabf33fa..24e7382d 100644 --- a/micropython/modules/breakout_pmw3901/breakout_pmw3901.c +++ b/micropython/modules/breakout_pmw3901/breakout_pmw3901.c @@ -57,38 +57,8 @@ const mp_obj_module_t breakout_pmw3901_user_cmodule = { .globals = (mp_obj_dict_t*)&mp_module_breakout_pmw3901_globals, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -MP_REGISTER_MODULE(MP_QSTR_breakout_pmw3901, breakout_pmw3901_user_cmodule, MODULE_BREAKOUT_PMW3901_ENABLED); -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Class Definition *****/ -const mp_obj_type_t breakout_paa5100_BreakoutPAA5100_type = { - { &mp_type_type }, - .name = MP_QSTR_BreakoutPAA5100, - .print = BreakoutPMW3901_print, - .make_new = BreakoutPAA5100_make_new, - .locals_dict = (mp_obj_dict_t*)&BreakoutPMW3901_locals_dict, -}; - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// breakout_paa5100 Module -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/***** Globals Table *****/ -STATIC const mp_map_elem_t breakout_paa5100_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_paa5100) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutPAA5100), (mp_obj_t)&breakout_paa5100_BreakoutPAA5100_type }, -}; -STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_paa5100_globals, breakout_paa5100_globals_table); - -/***** Module Definition *****/ -const mp_obj_module_t breakout_paa5100_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_breakout_paa5100_globals, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -MP_REGISTER_MODULE(MP_QSTR_breakout_paa5100, breakout_paa5100_user_cmodule, MODULE_BREAKOUT_PMW3901_ENABLED); -//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_breakout_pmw3901, breakout_pmw3901_user_cmodule, MODULE_BREAKOUT_PMW3901_ENABLED);//, +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_pmw3901, breakout_pmw3901_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/breakout_pmw3901/micropython.cmake b/micropython/modules/breakout_pmw3901/micropython.cmake index ae38c6df..4bc80ae6 100644 --- a/micropython/modules/breakout_pmw3901/micropython.cmake +++ b/micropython/modules/breakout_pmw3901/micropython.cmake @@ -3,7 +3,8 @@ string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) add_library(usermod_${MOD_NAME} INTERFACE) target_sources(usermod_${MOD_NAME} INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + ${CMAKE_CURRENT_LIST_DIR}/breakout_pmw3901.c + ${CMAKE_CURRENT_LIST_DIR}/breakout_paa5100.c ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/pmw3901/pmw3901.cpp diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.c b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c index 9315f1c7..70d81af4 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.c +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c @@ -58,6 +58,10 @@ const mp_obj_module_t breakout_potentiometer_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_potentiometer, breakout_potentiometer_user_cmodule, MODULE_BREAKOUT_POTENTIOMETER_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_potentiometer, breakout_potentiometer_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_rgbmatrix5x5/breakout_rgbmatrix5x5.c b/micropython/modules/breakout_rgbmatrix5x5/breakout_rgbmatrix5x5.c index 3d8df2f5..f4322a2c 100644 --- a/micropython/modules/breakout_rgbmatrix5x5/breakout_rgbmatrix5x5.c +++ b/micropython/modules/breakout_rgbmatrix5x5/breakout_rgbmatrix5x5.c @@ -46,6 +46,10 @@ const mp_obj_module_t breakout_rgbmatrix5x5_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_rgbmatrix5x5, breakout_rgbmatrix5x5_user_cmodule, MODULE_BREAKOUT_RGBMATRIX5X5_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_rgbmatrix5x5, breakout_rgbmatrix5x5_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_rtc/breakout_rtc.c b/micropython/modules/breakout_rtc/breakout_rtc.c index 358c25d4..c91a420d 100644 --- a/micropython/modules/breakout_rtc/breakout_rtc.c +++ b/micropython/modules/breakout_rtc/breakout_rtc.c @@ -161,6 +161,10 @@ const mp_obj_module_t breakout_rtc_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_rtc, breakout_rtc_user_cmodule, MODULE_BREAKOUT_RTC_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_rtc, breakout_rtc_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_scd41/breakout_scd41.c b/micropython/modules/breakout_scd41/breakout_scd41.c index d8a78021..61a0d8b9 100755 --- a/micropython/modules/breakout_scd41/breakout_scd41.c +++ b/micropython/modules/breakout_scd41/breakout_scd41.c @@ -49,6 +49,10 @@ const mp_obj_module_t scd41_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_scd41, scd41_user_cmodule, MODULE_BREAKOUT_SCD41_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_scd41, scd41_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/micropython/modules/breakout_sgp30/breakout_sgp30.c b/micropython/modules/breakout_sgp30/breakout_sgp30.c index 6b3677bd..39ad456f 100644 --- a/micropython/modules/breakout_sgp30/breakout_sgp30.c +++ b/micropython/modules/breakout_sgp30/breakout_sgp30.c @@ -60,6 +60,10 @@ const mp_obj_module_t breakout_sgp30_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_sgp30, breakout_sgp30_user_cmodule, MODULE_BREAKOUT_SGP30_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_sgp30, breakout_sgp30_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_trackball/breakout_trackball.c b/micropython/modules/breakout_trackball/breakout_trackball.c index fe66ea26..ee118231 100644 --- a/micropython/modules/breakout_trackball/breakout_trackball.c +++ b/micropython/modules/breakout_trackball/breakout_trackball.c @@ -62,6 +62,10 @@ const mp_obj_module_t breakout_trackball_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_trackball, breakout_trackball_user_cmodule, MODULE_BREAKOUT_TRACKBALL_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_trackball, breakout_trackball_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_vl53l5cx/vl53l5cx.c b/micropython/modules/breakout_vl53l5cx/vl53l5cx.c index fa0725e0..7700add3 100644 --- a/micropython/modules/breakout_vl53l5cx/vl53l5cx.c +++ b/micropython/modules/breakout_vl53l5cx/vl53l5cx.c @@ -80,4 +80,8 @@ const mp_obj_module_t vl53l5cx_user_cmodule = { }; /***** Module Registration: as "breakout_vl53l5cx" *****/ +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_breakout_vl53l5cx, vl53l5cx_user_cmodule, MODULE_VL53L5CX_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_breakout_vl53l5cx, vl53l5cx_user_cmodule); +#endif diff --git a/micropython/modules/encoder/encoder.c b/micropython/modules/encoder/encoder.c index 2fedf54f..52f389b2 100644 --- a/micropython/modules/encoder/encoder.c +++ b/micropython/modules/encoder/encoder.c @@ -63,4 +63,8 @@ const mp_obj_module_t encoder_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_encoder_globals, }; +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_encoder, encoder_user_cmodule, MODULE_ENCODER_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_encoder, encoder_user_cmodule); +#endif diff --git a/micropython/modules/hub75/hub75.c b/micropython/modules/hub75/hub75.c index cf11a8eb..39d49f80 100644 --- a/micropython/modules/hub75/hub75.c +++ b/micropython/modules/hub75/hub75.c @@ -74,4 +74,8 @@ const mp_obj_module_t hub75_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_hub75_globals, }; -MP_REGISTER_MODULE(MP_QSTR_hub75, hub75_user_cmodule, MODULE_HUB75_ENABLED); \ No newline at end of file +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_hub75, hub75_user_cmodule, MODULE_HUB75_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_hub75, hub75_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/jpegdec/jpegdec.c b/micropython/modules/jpegdec/jpegdec.c index ab4e221e..4e31764c 100644 --- a/micropython/modules/jpegdec/jpegdec.c +++ b/micropython/modules/jpegdec/jpegdec.c @@ -41,4 +41,8 @@ const mp_obj_module_t JPEG_user_cmodule = { .globals = (mp_obj_dict_t*)&mp_module_JPEG_globals, }; -MP_REGISTER_MODULE(MP_QSTR_jpegdec, JPEG_user_cmodule, MODULE_JPEGDEC_ENABLED); \ No newline at end of file +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_jpegdec, JPEG_user_cmodule, MODULE_JPEGDEC_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_jpegdec, JPEG_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/motor/motor.c b/micropython/modules/motor/motor.c index e1d1731d..aef5c0a3 100644 --- a/micropython/modules/motor/motor.c +++ b/micropython/modules/motor/motor.c @@ -270,4 +270,8 @@ const mp_obj_module_t motor_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_motor_globals, }; +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_motor, motor_user_cmodule, MODULE_MOTOR_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_motor, motor_user_cmodule); +#endif diff --git a/micropython/modules/pcf85063a/pcf85063a.c b/micropython/modules/pcf85063a/pcf85063a.c index 14489f15..971240c1 100644 --- a/micropython/modules/pcf85063a/pcf85063a.c +++ b/micropython/modules/pcf85063a/pcf85063a.c @@ -93,6 +93,10 @@ const mp_obj_module_t pcf85063a_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_pcf85063a, pcf85063a_user_cmodule, MODULE_BREAKOUT_RTC_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_pcf85063a, pcf85063a_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/pico_explorer/pico_explorer.c b/micropython/modules/pico_explorer/pico_explorer.c index 9070e817..1db88642 100644 --- a/micropython/modules/pico_explorer/pico_explorer.c +++ b/micropython/modules/pico_explorer/pico_explorer.c @@ -39,4 +39,8 @@ const mp_obj_module_t picoexplorer_user_cmodule = { .globals = (mp_obj_dict_t*)&mp_module_picoexplorer_globals, }; -MP_REGISTER_MODULE(MP_QSTR_picoexplorer, picoexplorer_user_cmodule, MODULE_PICOEXPLORER_ENABLED); \ No newline at end of file +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_picoexplorer, picoexplorer_user_cmodule, MODULE_PICOEXPLORER_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_picoexplorer, picoexplorer_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.c b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.c index f9bf8778..dfe3967a 100644 --- a/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.c +++ b/micropython/modules/pico_rgb_keypad/pico_rgb_keypad.c @@ -39,6 +39,10 @@ const mp_obj_module_t picokeypad_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_picokeypad, picokeypad_user_cmodule, MODULE_PICOKEYPAD_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_picokeypad, picokeypad_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/micropython/modules/pico_scroll/pico_scroll.c b/micropython/modules/pico_scroll/pico_scroll.c index f9412abd..7727a9a4 100644 --- a/micropython/modules/pico_scroll/pico_scroll.c +++ b/micropython/modules/pico_scroll/pico_scroll.c @@ -55,6 +55,10 @@ const mp_obj_module_t picoscroll_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_picoscroll, picoscroll_user_cmodule, MODULE_PICOSCROLL_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_picoscroll, picoscroll_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/micropython/modules/pico_unicorn/pico_unicorn.c b/micropython/modules/pico_unicorn/pico_unicorn.c index b3cad262..6b4ad999 100755 --- a/micropython/modules/pico_unicorn/pico_unicorn.c +++ b/micropython/modules/pico_unicorn/pico_unicorn.c @@ -50,6 +50,10 @@ const mp_obj_module_t picounicorn_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_picounicorn, picounicorn_user_cmodule, MODULE_PICOUNICORN_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_picounicorn, picounicorn_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/pico_wireless/pico_wireless.c b/micropython/modules/pico_wireless/pico_wireless.c index 4863580e..55d2e81d 100644 --- a/micropython/modules/pico_wireless/pico_wireless.c +++ b/micropython/modules/pico_wireless/pico_wireless.c @@ -177,6 +177,10 @@ const mp_obj_module_t picowireless_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_picowireless, picowireless_user_cmodule, MODULE_PICO_WIRELESS_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_picowireless, picowireless_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 158e0655..1d04c250 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -123,4 +123,8 @@ const mp_obj_module_t picographics_user_cmodule = { .globals = (mp_obj_dict_t*)&mp_module_picographics_globals, }; -MP_REGISTER_MODULE(MP_QSTR_picographics, picographics_user_cmodule, MODULE_PICOGRAPHICS_ENABLED); \ No newline at end of file +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_picographics, picographics_user_cmodule, MODULE_PICOGRAPHICS_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_picographics, picographics_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/pimoroni_bus/pimoroni_bus.c b/micropython/modules/pimoroni_bus/pimoroni_bus.c index aba4341c..ac336e0b 100644 --- a/micropython/modules/pimoroni_bus/pimoroni_bus.c +++ b/micropython/modules/pimoroni_bus/pimoroni_bus.c @@ -29,4 +29,8 @@ const mp_obj_module_t pimoroni_bus_user_cmodule = { .globals = (mp_obj_dict_t*)&mp_module_pimoroni_bus_globals, }; -MP_REGISTER_MODULE(MP_QSTR_pimoroni_bus, pimoroni_bus_user_cmodule, MODULE_PIMORONI_BUS_ENABLED); \ No newline at end of file +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_pimoroni_bus, pimoroni_bus_user_cmodule, MODULE_PIMORONI_BUS_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_pimoroni_bus, pimoroni_bus_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.c b/micropython/modules/pimoroni_i2c/pimoroni_i2c.c index 6070e51f..69550bc8 100644 --- a/micropython/modules/pimoroni_i2c/pimoroni_i2c.c +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.c @@ -49,6 +49,10 @@ const mp_obj_module_t pimoroni_i2c_user_cmodule = { }; //////////////////////////////////////////////////////////////////////////////////////////////////// +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_pimoroni_i2c, pimoroni_i2c_user_cmodule, MODULE_PIMORONI_I2C_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_pimoroni_i2c, pimoroni_i2c_user_cmodule); +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/plasma/plasma.c b/micropython/modules/plasma/plasma.c index 8d473061..80d94c2a 100644 --- a/micropython/modules/plasma/plasma.c +++ b/micropython/modules/plasma/plasma.c @@ -111,4 +111,8 @@ const mp_obj_module_t plasma_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_plasma_globals, }; +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_plasma, plasma_user_cmodule, MODULE_PLASMA_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_plasma, plasma_user_cmodule); +#endif diff --git a/micropython/modules/servo/servo.c b/micropython/modules/servo/servo.c index c3ee6d83..9e393f4a 100644 --- a/micropython/modules/servo/servo.c +++ b/micropython/modules/servo/servo.c @@ -256,4 +256,8 @@ const mp_obj_module_t servo_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_servo_globals, }; +#if MICROPY_VERSION <= 70144 MP_REGISTER_MODULE(MP_QSTR_servo, servo_user_cmodule, MODULE_SERVO_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_servo, servo_user_cmodule); +#endif From f3d3dde04f62dd7adabe81b3b62dfff9b02a4239 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 14 Jun 2022 12:33:07 +0100 Subject: [PATCH 63/84] PicoGraphics: Fix PEN_P8 scanline callback. --- libraries/pico_graphics/pico_graphics_pen_p8.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/pico_graphics/pico_graphics_pen_p8.cpp b/libraries/pico_graphics/pico_graphics_pen_p8.cpp index 201d3277..da0729bf 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p8.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p8.cpp @@ -62,7 +62,7 @@ namespace pimoroni { row_buf[x] = cache[src[bounds.w * y + x]]; } // Callback to the driver with the row data - callback(row_buf, bounds.w * sizeof(uint8_t)); + callback(row_buf, bounds.w * sizeof(RGB565)); } } } From eb303ae811baa58306978c26e9e5da2ea0a6ad26 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 14 Jun 2022 13:20:27 +0100 Subject: [PATCH 64/84] PicoGraphics: Integer sprite scaling. --- libraries/pico_graphics/pico_graphics.cpp | 2 +- libraries/pico_graphics/pico_graphics.hpp | 6 ++++-- .../pico_graphics/pico_graphics_pen_rgb332.cpp | 15 ++++++++++----- micropython/modules/picographics/picographics.c | 2 +- micropython/modules/picographics/picographics.cpp | 11 +++++++++-- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 3cde4729..fb4ab288 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -11,7 +11,7 @@ namespace pimoroni { void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {}; void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {}; void PicoGraphics::scanline_convert(PenType type, conversion_callback_func callback) {}; - void PicoGraphics::sprite(void* data, const Point &sprite, const Point &dest, const int transparent) {}; + void PicoGraphics::sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) {}; void PicoGraphics::set_dimensions(int width, int height) { bounds = clip = {0, 0, width, height}; diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 23c94ae3..933638b8 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -96,6 +96,7 @@ namespace pimoroni { inline Point& operator-= (const Point &a) { x -= a.x; y -= a.y; return *this; } inline Point& operator+= (const Point &a) { x += a.x; y += a.y; return *this; } + inline Point& operator/= (const int32_t a) { x /= a; y /= a; return *this; } Point clamp(const Rect &r) const; }; @@ -105,6 +106,7 @@ namespace pimoroni { inline Point operator- (Point lhs, const Point &rhs) { lhs -= rhs; return lhs; } inline Point operator- (const Point &rhs) { return Point(-rhs.x, -rhs.y); } inline Point operator+ (Point lhs, const Point &rhs) { lhs += rhs; return lhs; } + inline Point operator/ (Point lhs, const int32_t a) { lhs /= a; return lhs; } struct Rect { int32_t x = 0, y = 0, w = 0, h = 0; @@ -191,7 +193,7 @@ namespace pimoroni { virtual void set_pixel_dither(const Point &p, const RGB &c); virtual void set_pixel_dither(const Point &p, const RGB565 &c); virtual void scanline_convert(PenType type, conversion_callback_func callback); - virtual void sprite(void* data, const Point &sprite, const Point &dest, const int transparent); + virtual void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent); void set_font(const bitmap::font_t *font); void set_font(const hershey::font_t *font); @@ -269,7 +271,7 @@ namespace pimoroni { void set_pixel_dither(const Point &p, const RGB &c) override; void set_pixel_dither(const Point &p, const RGB565 &c) override; void scanline_convert(PenType type, conversion_callback_func callback) override; - void sprite(void* data, const Point &sprite, const Point &dest, const int transparent) override; + void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) override; static size_t buffer_size(uint w, uint h) { return w * h; } diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp index 9b21f894..d8389229 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp @@ -106,7 +106,7 @@ namespace pimoroni { } } } - void PicoGraphics_PenRGB332::sprite(void* data, const Point &sprite, const Point &dest, const int transparent) { + void PicoGraphics_PenRGB332::sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) { //int sprite_x = (sprite & 0x0f) << 3; //int sprite_y = (sprite & 0xf0) >> 1; Point s { @@ -115,10 +115,15 @@ namespace pimoroni { }; RGB332 *ptr = (RGB332 *)data; Point o = {0, 0}; - for(o.y = 0; o.y < 8; o.y++) { - for(o.x = 0; o.x < 8; o.x++) { - color = ptr[(s.y + o.y) * 128 + (s.x + o.x)]; - if(color != transparent) set_pixel(dest + o); + for(o.y = 0; o.y < 8 * scale; o.y++) { + Point so = { + 0, + o.y / scale + }; + for(o.x = 0; o.x < 8 * scale; o.x++) { + so.x = o.x / scale; + color = ptr[(s.y + so.y) * 128 + (s.x + so.x)]; + if(color != transparent) pixel(dest + o); } } } diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 1d04c250..99fe8d9d 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -37,7 +37,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_line_obj, 5, 5, ModPicoGraph // Sprites MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_spritesheet_obj, ModPicoGraphics_set_spritesheet); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_sprite_obj, 6, 6, ModPicoGraphics_sprite); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_sprite_obj, 5, 7, ModPicoGraphics_sprite); // Utility //MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_scanline_callback_obj, ModPicoGraphics_set_scanline_callback); diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 8d4a9c27..b49b3c5a 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -207,17 +207,24 @@ mp_obj_t ModPicoGraphics_set_spritesheet(mp_obj_t self_in, mp_obj_t spritedata) } mp_obj_t ModPicoGraphics_sprite(size_t n_args, const mp_obj_t *args) { - enum { ARG_self, ARG_sprite_x, ARG_sprite_y, ARG_x, ARG_y, ARG_transparent }; + enum { ARG_self, ARG_sprite_x, ARG_sprite_y, ARG_x, ARG_y, ARG_scale, ARG_transparent }; ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t); if(self->spritedata == nullptr) return mp_const_false; + int scale = 1; + int transparent = 0; + + if(n_args >= 6) scale = mp_obj_get_int(args[ARG_scale]); + if(n_args >= 7) transparent = mp_obj_get_int(args[ARG_transparent]); + self->graphics->sprite( self->spritedata, {mp_obj_get_int(args[ARG_sprite_x]), mp_obj_get_int(args[ARG_sprite_y])}, {mp_obj_get_int(args[ARG_x]), mp_obj_get_int(args[ARG_y])}, - mp_obj_get_int(args[ARG_transparent]) + scale, + transparent ); return mp_const_true; From b9ca8ec7793805e1639283072e655dc3acfded69 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 14 Jun 2022 14:15:27 +0100 Subject: [PATCH 65/84] PicoGraphics: Add load_spritesheet. --- .../modules/picographics/picographics.c | 2 ++ .../modules/picographics/picographics.cpp | 30 +++++++++++++++++++ .../modules/picographics/picographics.h | 1 + 3 files changed, 33 insertions(+) diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 99fe8d9d..40b5175b 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -37,6 +37,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_line_obj, 5, 5, ModPicoGraph // Sprites MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_spritesheet_obj, ModPicoGraphics_set_spritesheet); +MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_load_spritesheet_obj, ModPicoGraphics_load_spritesheet); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_sprite_obj, 5, 7, ModPicoGraphics_sprite); // Utility @@ -64,6 +65,7 @@ STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&ModPicoGraphics_line_obj) }, { MP_ROM_QSTR(MP_QSTR_set_spritesheet), MP_ROM_PTR(&ModPicoGraphics_set_spritesheet_obj) }, + { MP_ROM_QSTR(MP_QSTR_load_spritesheet), MP_ROM_PTR(&ModPicoGraphics_load_spritesheet_obj) }, { MP_ROM_QSTR(MP_QSTR_sprite), MP_ROM_PTR(&ModPicoGraphics_sprite_obj) }, { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&ModPicoGraphics_create_pen_obj) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index b49b3c5a..81f375fd 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -11,6 +11,9 @@ using namespace pimoroni; extern "C" { #include "picographics.h" #include "micropython/modules/pimoroni_bus/pimoroni_bus.h" +#include "py/stream.h" +#include "py/reader.h" +#include "extmod/vfs.h" std::string mp_obj_to_string_r(const mp_obj_t &obj) { if(mp_obj_is_str_or_bytes(obj)) { @@ -206,6 +209,33 @@ mp_obj_t ModPicoGraphics_set_spritesheet(mp_obj_t self_in, mp_obj_t spritedata) return mp_const_none; } +mp_obj_t ModPicoGraphics_load_spritesheet(mp_obj_t self_in, mp_obj_t filename) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); + mp_obj_t args[2] = { + filename, + MP_OBJ_NEW_QSTR(MP_QSTR_r), + }; + + // Stat the file to get its size + // example tuple response: (32768, 0, 0, 0, 0, 0, 5153, 1654709815, 1654709815, 1654709815) + mp_obj_t stat = mp_vfs_stat(filename); + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(stat, mp_obj_tuple_t); + size_t filesize = mp_obj_get_int(tuple->items[6]); + + mp_buffer_info_t bufinfo; + bufinfo.buf = (void *)m_new(uint8_t, filesize); + mp_obj_t file = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map); + int errcode; + bufinfo.len = mp_stream_rw(file, bufinfo.buf, filesize, &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + if (errcode != 0) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Failed to open sprite file!")); + } + + self->spritedata = bufinfo.buf; + + return mp_const_none; +} + mp_obj_t ModPicoGraphics_sprite(size_t n_args, const mp_obj_t *args) { enum { ARG_self, ARG_sprite_x, ARG_sprite_y, ARG_x, ARG_y, ARG_scale, ARG_transparent }; diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index 0ee79823..3e0a56d5 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -62,6 +62,7 @@ extern mp_obj_t ModPicoGraphics_line(size_t n_args, const mp_obj_t *args); // Sprites extern mp_obj_t ModPicoGraphics_set_spritesheet(mp_obj_t self_in, mp_obj_t spritedata); +extern mp_obj_t ModPicoGraphics_load_spritesheet(mp_obj_t self_in, mp_obj_t filename); extern mp_obj_t ModPicoGraphics_sprite(size_t n_args, const mp_obj_t *args); // Utility From 27d571b473cecd749adba6cb8fb39ea971a55665 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 14 Jun 2022 15:06:44 +0100 Subject: [PATCH 66/84] PicoGraphics: Tidy up dithering. --- libraries/pico_graphics/pico_graphics.cpp | 17 +----- libraries/pico_graphics/pico_graphics.hpp | 38 ++++++++++-- .../pico_graphics/pico_graphics_pen_p4.cpp | 58 ++++++++++++++++--- .../pico_graphics/pico_graphics_pen_p8.cpp | 49 ++++++++++++++-- micropython/modules/jpegdec/jpegdec.c | 5 ++ micropython/modules/jpegdec/jpegdec.cpp | 17 +----- 6 files changed, 134 insertions(+), 50 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index fb4ab288..8bdd2eb3 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -53,22 +53,7 @@ namespace pimoroni { void PicoGraphics::remove_clip() { clip = bounds; } - - void PicoGraphics::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates) { - RGB error; - for(size_t i = 0; i < candidates.size(); i++) { - candidates[i] = (col + error).closest(palette, len); - error += (col - palette[candidates[i]]); - } - - // sort by a rough approximation of luminance, this ensures that neighbouring - // pixels in the dither matrix are at extreme opposites of luminence - // giving a more balanced output - std::sort(candidates.begin(), candidates.end(), [palette](int a, int b) { - return palette[a].luminance() > palette[b].luminance(); - }); - } - + void PicoGraphics::clear() { rectangle(clip); } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 933638b8..765573e3 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -208,8 +208,6 @@ namespace pimoroni { void set_clip(const Rect &r); void remove_clip(); - void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); - void clear(); void pixel(const Point &p); void pixel_span(const Point &p, int32_t l); @@ -226,15 +224,28 @@ namespace pimoroni { class PicoGraphics_PenP4 : public PicoGraphics { public: + static const uint palette_size = 16; uint8_t color; - RGB palette[16]; + RGB palette[palette_size]; + bool used[palette_size]; + + const uint pattern[16] = // dither pattern + {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; + std::array, 512> candidate_cache; + bool cache_built = false; + std::array candidates; PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override; + int create_pen(uint8_t r, uint8_t g, uint8_t b) override; + int reset_pen(uint8_t i) override; + void set_pixel(const Point &p) override; + void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); void set_pixel_dither(const Point &p, const RGB &c) override; + void scanline_convert(PenType type, conversion_callback_func callback) override; static size_t buffer_size(uint w, uint h) { return w * h / 2; @@ -243,16 +254,28 @@ namespace pimoroni { class PicoGraphics_PenP8 : public PicoGraphics { public: + static const uint palette_size = 256; uint8_t color; - RGB palette[256]; - bool used[256]; + RGB palette[palette_size]; + bool used[palette_size]; + + const uint pattern[16] = // dither pattern + {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; + std::array, 512> candidate_cache; + bool cache_built = false; + std::array candidates; + PicoGraphics_PenP8(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override; int create_pen(uint8_t r, uint8_t g, uint8_t b) override; int reset_pen(uint8_t i) override; + void set_pixel(const Point &p) override; + void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); + void set_pixel_dither(const Point &p, const RGB &c) override; + void scanline_convert(PenType type, conversion_callback_func callback) override; static size_t buffer_size(uint w, uint h) { return w * h; @@ -267,11 +290,14 @@ namespace pimoroni { void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; int create_pen(uint8_t r, uint8_t g, uint8_t b) override; + void set_pixel(const Point &p) override; void set_pixel_dither(const Point &p, const RGB &c) override; void set_pixel_dither(const Point &p, const RGB565 &c) override; - void scanline_convert(PenType type, conversion_callback_func callback) override; + void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) override; + + void scanline_convert(PenType type, conversion_callback_func callback) override; static size_t buffer_size(uint w, uint h) { return w * h; } diff --git a/libraries/pico_graphics/pico_graphics_pen_p4.cpp b/libraries/pico_graphics/pico_graphics_pen_p4.cpp index 10f54241..4a6d76c4 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p4.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p4.cpp @@ -7,19 +7,20 @@ namespace pimoroni { if(this->frame_buffer == nullptr) { this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); } - for(auto i = 0u; i < 16; i++) { + for(auto i = 0u; i < palette_size; i++) { palette[i] = { uint8_t(i << 4), uint8_t(i << 4), uint8_t(i << 4) }; + used[i] = false; } } void PicoGraphics_PenP4::set_pen(uint c) { color = c & 0xf; } void PicoGraphics_PenP4::set_pen(uint8_t r, uint8_t g, uint8_t b) { - int pen = RGB(r, g, b).closest(palette, 16); + int pen = RGB(r, g, b).closest(palette, palette_size); if(pen != -1) color = pen; } int PicoGraphics_PenP4::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { @@ -27,6 +28,22 @@ namespace pimoroni { palette[i] = {r, g, b}; return i; } + int PicoGraphics_PenP4::create_pen(uint8_t r, uint8_t g, uint8_t b) { + // Create a colour and place it in the palette if there's space + for(auto i = 0u; i < palette_size; i++) { + if(!used[i]) { + palette[i] = {r, g, b}; + used[i] = true; + return i; + } + } + return -1; + } + int PicoGraphics_PenP4::reset_pen(uint8_t i) { + palette[i] = {0, 0, 0}; + used[i] = false; + return i; + } void PicoGraphics_PenP4::set_pixel(const Point &p) { // pointer to byte in framebuffer that contains this pixel uint8_t *buf = (uint8_t *)frame_buffer; @@ -39,26 +56,49 @@ namespace pimoroni { *f &= m; // clear bits *f |= b; // set value } + + void PicoGraphics_PenP4::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates) { + RGB error; + for(size_t i = 0; i < candidates.size(); i++) { + candidates[i] = (col + error).closest(palette, len); + error += (col - palette[candidates[i]]); + } + + // sort by a rough approximation of luminance, this ensures that neighbouring + // pixels in the dither matrix are at extreme opposites of luminence + // giving a more balanced output + std::sort(candidates.begin(), candidates.end(), [palette](int a, int b) { + return palette[a].luminance() > palette[b].luminance(); + }); + } + void PicoGraphics_PenP4::set_pixel_dither(const Point &p, const RGB &c) { if(!bounds.contains(p)) return; - static uint pattern[16] = // dither pattern - {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; - static std::array candidates; - get_dither_candidates(c, palette, 256, candidates); + if(!cache_built) { + for(uint i = 0; i < 512; i++) { + RGB cache_col((i & 0x1C0) >> 1, (i & 0x38) << 2, (i & 0x7) << 5); + get_dither_candidates(cache_col, palette, palette_size, candidate_cache[i]); + } + cache_built = true; + } + + uint cache_key = ((c.r & 0xE0) << 1) | ((c.g & 0xE0) >> 2) | ((c.b & 0xE0) >> 5); + //get_dither_candidates(c, palette, 256, candidates); // find the pattern coordinate offset uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); // set the pixel - color = candidates[pattern[pattern_index]]; + //color = candidates[pattern[pattern_index]]; + color = candidate_cache[cache_key][pattern[pattern_index]]; set_pixel(p); } void PicoGraphics_PenP4::scanline_convert(PenType type, conversion_callback_func callback) { if(type == PEN_RGB565) { // Cache the RGB888 palette as RGB565 - RGB565 cache[16]; - for(auto i = 0u; i < 16; i++) { + RGB565 cache[palette_size]; + for(auto i = 0u; i < palette_size; i++) { cache[i] = palette[i].to_rgb565(); } diff --git a/libraries/pico_graphics/pico_graphics_pen_p8.cpp b/libraries/pico_graphics/pico_graphics_pen_p8.cpp index da0729bf..0cac304a 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p8.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p8.cpp @@ -7,8 +7,8 @@ namespace pimoroni { if(this->frame_buffer == nullptr) { this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); } - for(auto i = 0u; i < 256; i++) { - palette[i] = {0, 0, 0}; + for(auto i = 0u; i < palette_size; i++) { + palette[i] = {uint8_t(i), uint8_t(i), uint8_t(i)}; used[i] = false; } } @@ -26,7 +26,7 @@ namespace pimoroni { } int PicoGraphics_PenP8::create_pen(uint8_t r, uint8_t g, uint8_t b) { // Create a colour and place it in the palette if there's space - for(auto i = 0u; i < 256u; i++) { + for(auto i = 0u; i < palette_size; i++) { if(!used[i]) { palette[i] = {r, g, b}; used[i] = true; @@ -44,11 +44,50 @@ namespace pimoroni { uint8_t *buf = (uint8_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } + + void PicoGraphics_PenP8::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates) { + RGB error; + for(size_t i = 0; i < candidates.size(); i++) { + candidates[i] = (col + error).closest(palette, len); + error += (col - palette[candidates[i]]); + } + + // sort by a rough approximation of luminance, this ensures that neighbouring + // pixels in the dither matrix are at extreme opposites of luminence + // giving a more balanced output + std::sort(candidates.begin(), candidates.end(), [palette](int a, int b) { + return palette[a].luminance() > palette[b].luminance(); + }); + } + + void PicoGraphics_PenP8::set_pixel_dither(const Point &p, const RGB &c) { + if(!bounds.contains(p)) return; + + if(!cache_built) { + for(uint i = 0; i < 512; i++) { + RGB cache_col((i & 0x1C0) >> 1, (i & 0x38) << 2, (i & 0x7) << 5); + get_dither_candidates(cache_col, palette, palette_size, candidate_cache[i]); + } + cache_built = true; + } + + uint cache_key = ((c.r & 0xE0) << 1) | ((c.g & 0xE0) >> 2) | ((c.b & 0xE0) >> 5); + //get_dither_candidates(c, palette, 256, candidates); + + // find the pattern coordinate offset + uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2); + + // set the pixel + //color = candidates[pattern[pattern_index]]; + color = candidate_cache[cache_key][pattern[pattern_index]]; + set_pixel(p); + } + void PicoGraphics_PenP8::scanline_convert(PenType type, conversion_callback_func callback) { if(type == PEN_RGB565) { // Cache the RGB888 palette as RGB565 - RGB565 cache[256]; - for(auto i = 0u; i < 256; i++) { + RGB565 cache[palette_size]; + for(auto i = 0u; i < palette_size; i++) { cache[i] = palette[i].to_rgb565(); } diff --git a/micropython/modules/jpegdec/jpegdec.c b/micropython/modules/jpegdec/jpegdec.c index 4e31764c..cebb6fb5 100644 --- a/micropython/modules/jpegdec/jpegdec.c +++ b/micropython/modules/jpegdec/jpegdec.c @@ -32,6 +32,11 @@ const mp_obj_type_t JPEG_type = { STATIC const mp_map_elem_t JPEG_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_jpegdec) }, { MP_OBJ_NEW_QSTR(MP_QSTR_JPEG), (mp_obj_t)&JPEG_type }, + + { MP_ROM_QSTR(MP_QSTR_JPEG_SCALE_FULL), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_JPEG_SCALE_HALF), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_JPEG_SCALE_QUARTER), MP_ROM_INT(4) }, + { MP_ROM_QSTR(MP_QSTR_JPEG_SCALE_EIGHTH), MP_ROM_INT(8) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_JPEG_globals, JPEG_globals_table); diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index 123d47e7..6bf9bc9a 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -47,15 +47,6 @@ MICROPY_EVENT_POLL_HOOK current_graphics->pixel({pDraw->x + x, pDraw->y + y}); } } - } else if(pDraw->iBpp == 8) { - uint8_t *pixels = (uint8_t *)pDraw->pPixels; - for(int y = 0; y < pDraw->iHeight; y++) { - for(int x = 0; x < pDraw->iWidth; x++) { - int i = y * pDraw->iWidth + x; - current_graphics->set_pen(pixels[i] >> (current_graphics->pen_type == PicoGraphics::PEN_P4 ? 4 : 0)); - current_graphics->pixel({pDraw->x + x, pDraw->y + y}); - } - } } else { for(int y = 0; y < pDraw->iHeight; y++) { for(int x = 0; x < pDraw->iWidth; x++) { @@ -65,6 +56,8 @@ MICROPY_EVENT_POLL_HOOK //current_graphics->pixel({pDraw->x + x, pDraw->y + y}); // TODO make dither optional current_graphics->set_pixel_dither({pDraw->x + x, pDraw->y + y}, (RGB565)(pDraw->pPixels[i])); + } else if (current_graphics->pen_type == PicoGraphics::PEN_P8 || current_graphics->pen_type == PicoGraphics::PEN_P4) { + current_graphics->set_pixel_dither({pDraw->x + x, pDraw->y + y}, RGB((RGB565)pDraw->pPixels[i])); } else { current_graphics->set_pen(pDraw->pPixels[i]); current_graphics->pixel({pDraw->x + x, pDraw->y + y}); @@ -107,13 +100,9 @@ static int _open(_JPEG_obj_t *self, void *buf, size_t len) { switch(self->graphics->graphics->pen_type) { case PicoGraphics::PEN_RGB332: case PicoGraphics::PEN_RGB565: - self->jpeg->setPixelType(RGB565_BIG_ENDIAN); - break; case PicoGraphics::PEN_P8: - self->jpeg->setPixelType(EIGHT_BIT_GRAYSCALE); - break; case PicoGraphics::PEN_P4: - self->jpeg->setPixelType(FOUR_BIT_DITHERED); + self->jpeg->setPixelType(RGB565_BIG_ENDIAN); break; // TODO 2-bit is currently unsupported case PicoGraphics::PEN_P2: From 457589aaa909f80b13819a8fee088ae0b06c237c Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 14 Jun 2022 15:25:50 +0100 Subject: [PATCH 67/84] PicoGraphics: Mark dither cache stale on pen update. --- libraries/pico_graphics/pico_graphics_pen_p4.cpp | 5 +++++ libraries/pico_graphics/pico_graphics_pen_p8.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/libraries/pico_graphics/pico_graphics_pen_p4.cpp b/libraries/pico_graphics/pico_graphics_pen_p4.cpp index 4a6d76c4..17bf6b6c 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p4.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p4.cpp @@ -15,6 +15,7 @@ namespace pimoroni { }; used[i] = false; } + cache_built = false; } void PicoGraphics_PenP4::set_pen(uint c) { color = c & 0xf; @@ -25,7 +26,9 @@ namespace pimoroni { } int PicoGraphics_PenP4::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { i &= 0xf; + used[i] = true; palette[i] = {r, g, b}; + cache_built = false; return i; } int PicoGraphics_PenP4::create_pen(uint8_t r, uint8_t g, uint8_t b) { @@ -34,6 +37,7 @@ namespace pimoroni { if(!used[i]) { palette[i] = {r, g, b}; used[i] = true; + cache_built = false; return i; } } @@ -42,6 +46,7 @@ namespace pimoroni { int PicoGraphics_PenP4::reset_pen(uint8_t i) { palette[i] = {0, 0, 0}; used[i] = false; + cache_built = false; return i; } void PicoGraphics_PenP4::set_pixel(const Point &p) { diff --git a/libraries/pico_graphics/pico_graphics_pen_p8.cpp b/libraries/pico_graphics/pico_graphics_pen_p8.cpp index 0cac304a..7f1f60c7 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p8.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p8.cpp @@ -11,6 +11,7 @@ namespace pimoroni { palette[i] = {uint8_t(i), uint8_t(i), uint8_t(i)}; used[i] = false; } + cache_built = false; } void PicoGraphics_PenP8::set_pen(uint c) { color = c; @@ -21,7 +22,9 @@ namespace pimoroni { } int PicoGraphics_PenP8::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { i &= 0xff; + used[i] = true; palette[i] = {r, g, b}; + cache_built = false; return i; } int PicoGraphics_PenP8::create_pen(uint8_t r, uint8_t g, uint8_t b) { @@ -30,6 +33,7 @@ namespace pimoroni { if(!used[i]) { palette[i] = {r, g, b}; used[i] = true; + cache_built = false; return i; } } @@ -38,6 +42,7 @@ namespace pimoroni { int PicoGraphics_PenP8::reset_pen(uint8_t i) { palette[i] = {0, 0, 0}; used[i] = false; + cache_built = false; return i; } void PicoGraphics_PenP8::set_pixel(const Point &p) { From 31ade6af722b5e15ce8f67c6ab06d2808ce6314d Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 14 Jun 2022 15:38:25 +0100 Subject: [PATCH 68/84] JPEGDEC: Open just before decode to avoid seek overrun. --- micropython/modules/jpegdec/jpegdec.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index 6bf9bc9a..ee853ae9 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -22,7 +22,7 @@ typedef struct _ModPicoGraphics_obj_t { typedef struct _JPEG_obj_t { mp_obj_base_t base; JPEGDEC *jpeg; - void *buf; + mp_buffer_info_t buf; ModPicoGraphics_obj_t *graphics; } _JPEG_obj_t; @@ -93,9 +93,8 @@ mp_obj_t _JPEG_del(mp_obj_t self_in) { return mp_const_none; } -static int _open(_JPEG_obj_t *self, void *buf, size_t len) { - self->buf = buf; // Store a pointer to this buffer so GC doesn't eat it - int result = self->jpeg->openRAM((uint8_t *)buf, len, JPEGDraw); +static int _open(_JPEG_obj_t *self) { + int result = self->jpeg->openRAM((uint8_t *)self->buf.buf, self->buf.len, JPEGDraw); if (result == 1) { switch(self->graphics->graphics->pen_type) { case PicoGraphics::PEN_RGB332: @@ -127,23 +126,21 @@ mp_obj_t _JPEG_openFILE(mp_obj_t self_in, mp_obj_t filename) { mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(stat, mp_obj_tuple_t); size_t filesize = mp_obj_get_int(tuple->items[6]); - mp_buffer_info_t bufinfo; - bufinfo.buf = (void *)m_new(uint8_t, filesize); + self->buf.buf = (void *)m_new(uint8_t, filesize); mp_obj_t file = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map); int errcode; - bufinfo.len = mp_stream_rw(file, bufinfo.buf, filesize, &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + self->buf.len = mp_stream_rw(file, self->buf.buf, filesize, &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); if (errcode != 0) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Failed to open file!")); } - return _open(self, bufinfo.buf, bufinfo.len) == 1 ? mp_const_true : mp_const_false; + return mp_const_true; } // open_RAM mp_obj_t _JPEG_openRAM(mp_obj_t self_in, mp_obj_t buffer) { _JPEG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _JPEG_obj_t); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); - return _open(self, bufinfo.buf, bufinfo.len) == 1 ? mp_const_true : mp_const_false; + mp_get_buffer_raise(buffer, &self->buf, MP_BUFFER_READ); + return mp_const_true; } // decode @@ -165,6 +162,8 @@ mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args int y = args[ARG_y].u_int; int f = args[ARG_scale].u_int; + if(_open(self) != 1) return mp_const_false; + // We need to store a pointer to the PicoGraphics surface // since the JPEGDRAW struct has no userdata current_graphics = self->graphics->graphics; From 92c8c70aaa7aa8b2d53cfd56346ed44745752e63 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 14 Jun 2022 15:51:39 +0100 Subject: [PATCH 69/84] PicoGraphics: Start README. Spritesheet converter. --- micropython/modules/picographics/README.md | 156 ++++++++++++++++++ .../picographics/spritesheet-to-rgb332.py | 37 +++++ 2 files changed, 193 insertions(+) create mode 100644 micropython/modules/picographics/README.md create mode 100644 micropython/modules/picographics/spritesheet-to-rgb332.py diff --git a/micropython/modules/picographics/README.md b/micropython/modules/picographics/README.md new file mode 100644 index 00000000..deab18fa --- /dev/null +++ b/micropython/modules/picographics/README.md @@ -0,0 +1,156 @@ +# Pico Graphics + +Pico Graphics is our unified graphics and display library for driving displays from your Pico in MicroPython. + +Pico Graphics replaces the individual drivers for displays- if you're been using breakout_colorlcd, ST7789 then you'll need to update your code! + +- [Setting up Pico Graphics](#setting-up-pico-graphics) + - [Supported Displays](#supported-displays) + - [Supported Graphics Modes (Pen Type)](#supported-graphics-modes-pen-type) + - [Supported Rotations](#supported-rotations) + - [Custom Pins](#custom-pins) +- [Function Reference](#function-reference) + - [Text](#text) + - [Sprites](#sprites) + - [Loading Sprites](#loading-sprites) + - [Drawing Sprites](#drawing-sprites) + - [JPEG Files](#jpeg-files) + +## Setting up Pico Graphics + +You must construct an instance of PicoGraphics with your desired display: + +```python +from picographics import PicoGraphics, DISPLAY_LCD_160X80 + +display = PicoGraphics(display=DISPLAY_LCD_160X80) +``` + +Bear in mind that MicroPython has only 192K of RAM available- a 320x240 pixel display in RGB565 mode uses 150K! + +### Supported Displays + +* Pico Display - 240x135 SPI LCD - `DISPLAY_PICO_DISPLAY` +* Pico Display 2 - 320x240 SPI LCD - `DISPLAY_PICO_DISPLAY_2` +* Tufty 2040 - 320x240 Parallel LCD - `DISPLAY_TUFTY_2040` +* Pico Explorer - 240x240 SPI LCD - `DISPLAY_PICO_EXPLORER` +* Enviro Plus - 240x240 SPI LCD - `DISPLAY_ENVIRO_PLUS` +* 240x240 Round SPI LCD Breakout - `DISPLAY_ROUND_LCD_240X240` +* 240x240 Square SPI LCD Breakout - `DISPLAY_LCD_240X240` +* 160x80 SPI LCD Breakout - `DISPLAY_LCD_160X80` + +### Supported Graphics Modes (Pen Type) + +* 4-bit - `PEN_P4` - 16-colour palette of your choice +* 8-bit - `PEN_P8` - 256-colour palette of your choice +* 8-bit RGB332 - `PEN_RGB332` - 256 fixed colours (3 bits red, 3 bits green, 2 bits blue) +* 16-bit RGB565 - `PEN_RGB565` - 64K colours at the cost of RAM. (5 bits red, 6 bits green, 5 bits blue) + +These offer a tradeoff between RAM usage and available colours. In most cases you would probably use `RGB332` since it offers the easiest tradeoff. It's also the default. + +Eg: + +```python +display = PicoGraphics(display=PICO_DISPLAY, pen_type=PEN_RGB332) +``` + +### Supported Rotations + +All SPI LCDs support 0, 90, 180 and 270 degree rotations. + +Eg: + +```python +display = PicoGraphics(display=PICO_DISPLAY, roation=90) +``` + +### Custom Pins + +The `pimoroni_bus` library includes `SPIBus` for SPI LCDs and `ParallelBus` for Parallel LCDs (like Tufty 2040). + +In most cases you'll never need to use these, but they come in useful if you're wiring breakouts to your Pico or using multiple LCDs. + +A custom SPI bus: + +```python +from pimoroni_bus import SPIBus +from picographics import PicoGraphics, DISPLAY_PICO_EXPLORER, PEN_RGB332 + +spibus = SPIBus(cs=17, dc=16, sck=18, mosi=19) + +display = PicoGraphics(display=DISPLAY_PICO_EXPLORER, bus=spibus, pen_type=PEN_RGB332) +``` + +## Function Reference + +### Text + +### Sprites + +Pico Display has very limited support for sprites in RGB332 mode. + +Sprites must be 8x8 pixels arranged in a 128x128 pixel spritesheet. 1-bit transparency is handled by electing a single colour to skip over. + +We've prepared some RGB332-compatible sprite assets for you, but you can use `spritesheet-to-rgb332.py ` to convert your own. + +#### Loading Sprites + +Use Thonny to upload your `spritesheet.rgb332` file onto your Pico. Then load it into Pico Graphics: + +```python +display.load_spritesheet("s4m_ur4i-dingbads.rgb332") +``` + +#### Drawing Sprites + +And finally display a sprite: + +```python +display.sprite(0, 0, 0, 0) +``` + +These arguments for `sprite` are as follows: + +1. Sprite X position (from 0-15) - this selects the horizontal location of an 8x8 sprite from your 128x128 pixel spritesheet. +2. Sprite Y position (from 0-15) +3. Destination X - where to draw on your screen horizontally +4. Destination Y = where to draw on your screen vertically +5. Scale (optional) - an integer scale value, 1 = 8x8, 2 = 16x16 etc. +6. Transparent (optional) - specify a colour to treat as transparent + +### JPEG Files + +We've included BitBank's JPEGDEC - https://github.com/bitbank2/JPEGDEC - so you can display JPEG files on your LCDs. + +Eg: + +```python +import picographics +import jpegdec + +display = picographics.PicoGraphics(display=picographics.DISPLAY_PICO_EXPLORER) + +# Create a new JPEG decoder for our PicoGraphics +j = jpegdec.JPEG(display) + +# Open the JPEG file +j.open_file("filename.jpeg") + +# Decode the JPEG +j.decode(0, 0, jpegdec.JPEG_SCALE_FULL) + +# Display the result +display.update() +``` + +JPEG files must be small enough to load into RAM for decoding, and must *not* be progressive. + +JPEG files will be automatically dithered in RGB332 mode. + +In P4 and P8 modes JPEGs are dithered to your custom colour paleete. Their appearance of an image will vary based on the colours you choose. + +The arguments for `decode` are as follows: + +1. Decode X - where to place the decoded JPEG on screen +2. Decode Y +3. Flags - one of `JPEG_SCALE_FULL`, `JPEG_SCALE_HALF`, `JPEG_SCALE_QUARTER` or `JPEG_SCALE_EIGHTH` \ No newline at end of file diff --git a/micropython/modules/picographics/spritesheet-to-rgb332.py b/micropython/modules/picographics/spritesheet-to-rgb332.py new file mode 100644 index 00000000..9eaff382 --- /dev/null +++ b/micropython/modules/picographics/spritesheet-to-rgb332.py @@ -0,0 +1,37 @@ +#!/bin/env python3 +from PIL import Image +import numpy +import sys +import pathlib + +# Run with `./filename.py source-image.jpg` +IMAGE_PATH = pathlib.Path(sys.argv[1]) +OUTPUT_PATH = IMAGE_PATH.with_suffix(".rgb332") + + +def image_to_data(image): + """Generator function to convert a PIL image to 16-bit 565 RGB bytes.""" + # NumPy is much faster at doing this. NumPy code provided by: + # Keith (https://www.blogger.com/profile/02555547344016007163) + pb = numpy.array(image.convert('RGBA')).astype('uint16') + + r = (pb[:, :, 0] & 0b11100000) >> 0 + g = (pb[:, :, 1] & 0b11100000) >> 3 + b = (pb[:, :, 2] & 0b11000000) >> 6 + a = pb[:, :, 3] # Discard + + # AAAA RRRR GGGG BBBB + color = r | g | b + return color.astype("uint8").flatten().tobytes() + + +img = Image.open(IMAGE_PATH) +w, h = img.size +data = image_to_data(img) + +print(f"Converted: {w}x{h} {len(data)} bytes") + +with open(OUTPUT_PATH, "wb") as f: + f.write(data) + +print(f"Written to: {OUTPUT_PATH}") \ No newline at end of file From 48b9e5a96e165de8af3b47da53d8f2ee23837188 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 15 Jun 2022 15:50:53 +0100 Subject: [PATCH 70/84] PicoGraphics: README --- micropython/modules/picographics/README.md | 267 +++++++++++++++++++++ 1 file changed, 267 insertions(+) diff --git a/micropython/modules/picographics/README.md b/micropython/modules/picographics/README.md index deab18fa..81bd8915 100644 --- a/micropython/modules/picographics/README.md +++ b/micropython/modules/picographics/README.md @@ -10,7 +10,24 @@ Pico Graphics replaces the individual drivers for displays- if you're been using - [Supported Rotations](#supported-rotations) - [Custom Pins](#custom-pins) - [Function Reference](#function-reference) + - [General](#general) + - [Creating & Setting Pens](#creating--setting-pens) + - [Controlling The Backlight](#controlling-the-backlight) + - [Clipping](#clipping) + - [Clear](#clear) + - [Update](#update) - [Text](#text) + - [Changing The Font](#changing-the-font) + - [Drawing Text](#drawing-text) + - [Basic Shapes](#basic-shapes) + - [Line](#line) + - [Circle](#circle) + - [Rectangle](#rectangle) + - [Triangle](#triangle) + - [Polygon](#polygon) + - [Pixels](#pixels) + - [Palette Management](#palette-management) + - [Utility Functions](#utility-functions) - [Sprites](#sprites) - [Loading Sprites](#loading-sprites) - [Drawing Sprites](#drawing-sprites) @@ -83,8 +100,258 @@ display = PicoGraphics(display=DISPLAY_PICO_EXPLORER, bus=spibus, pen_type=PEN_R ## Function Reference +### General + +#### Creating & Setting Pens + +Create a pen colour for drawing into a screen: + +```python +my_pen = display.create_pen(r, g, b) +``` + +In RGB565 and RGB332 modes this packs the given RGB into an integer representing a colour in these formats and returns the result. + +In P4 and P8 modes this will consume one palette entry, or return an error if your palette is full. Palette colours are stored as RGB and converted when they are displayed on screen. + +To tell PicoGraphics which pen to use: + +```python +display.set_pen(my_pen) +``` + +This will be either an RGB332 or RGB565 colour, or a palette index. + +#### Controlling The Backlight + +You can set the display backlight brightness between `0.0` and `1.0`: + +```python +display.set_backlight(0.5) +``` + +#### Clipping + +Set the clipping bounds for drawing: + +```python +display.set_clip(x, y, w, h) +``` + +Remove the clipping bounds: + +```python +display.remove_clip() +``` + +#### Clear + +Clear the display to the current pen colour: + +```python +display.clear() +``` + +This is equivilent to: + +```python +w, h = display.get_bounds() +display.rectangle(0, 0, w, h) +``` + +You can clear portions of the screen with rectangles to save time redrawing things like JPEGs or complex graphics. + +#### Update + +Send the contents of your Pico Graphics buffer to your screen: + +```python +display.update() +``` + ### Text +#### Changing The Font + +Change the font: + +```python +display.set_font(font) +``` + +Bitmap fonts. +These are aligned from their top-left corner. + +* `bitmap6` +* `bitmap8` +* `bitmap14_outline` + +Vector (Hershey) fonts. +These are aligned to their midline. + +* `sans` +* `gothic` +* `cursive` +* `serif_italic` +* `serif` + + +#### Drawing Text + +Write some text: + +```python +display.text(text, x, y, wordwrap, scale, angle, spacing) +``` + +* `text` - the text string to draw +* `x` - the destination X coordinate +* `y` - the destination Y coordinate +* `wordwrap` - number of pixels width before trying to break text into multiple lines +* `scale` - size +* `angle` - rotation angle (Vector only!) +* `spacing` - letter spacing + +Text scale can be a whole number (integer) for Bitmap fonts, or a decimal (float) for Vector (Hershey) fonts. + +For example: + +```python +display.set_font("bitmap8") +display.text("Hello World", 0, 0, scale=2) +``` + +Draws "Hello World" in a 16px tall, 2x scaled version of the `bitmap8` font. + +Sometimes you might want to measure a text string for centering or alignment on screen, you can do this with: + +```python +width = measure_text(text, scale, spacing) +``` + +The height of each Bitmap font is explicit in its name. + +Write a single character: + +```python +display.character(char, x, y, scale) +``` + +### Basic Shapes + +#### Line + +To draw a line: + +```python +display.line(x1, y1, x2, y2) +``` + +The X1/Y1 and X2/Y2 coordinates describe the start and end of the line repsectively. + +#### Circle + +To draw a circle: + +```python +display.circle(x, y, r) +``` + +* `x` - the destination X coordinate +* `y` - the destination Y coordinate +* `r` - the radius + +The X/Y coordinates describe the center of your circle. + +#### Rectangle + +```python +display.rectangle(x, y, w, h) +``` + +* `x` - the destination X coordinate +* `y` - the destination Y coordinate +* `w` - the width +* `h` - the eight + +#### Triangle + +```python +display.triangle(x1, y1, x2, y2, x3, y3) +``` + +The three pairs of X/Y coordinates describe each point of the triangle. + +#### Polygon + +To draw other shapes, you can provide a list of points to `polygon`: + +```python +display.polygon([ + (0, 10), + (20, 10), + (20, 0), + (30, 20), + (20, 30), + (20, 20), + (0, 20), +]) +``` + +### Pixels + +Setting individual pixels is slow, but you can do it with: + +```python +display.pixel(x, y) +``` + +You can set a horiontal span of pixels a little faster with: + +```python +pixel_span(x, y, length) +``` + +### Palette Management + +Intended for P4 and P8 modes. + +You have a 16-color and 256-color palette respectively. + +Set n elements in the palette from a list of RGB tuples: + +```python +set_palette([ + (r, g, b), + (r, g, b), + (r, g, b) +]) +``` + +Update an entry in the P4 or P8 palette with the given colour. + +```python +update_pen(index, r, g, b) +``` + +This is stored internally as RGB and converted to whatever format your screen requires when displayed. + +Reset a pen back to its default value (black, marked unused): + +```python +reset_pen(index) +``` + +#### Utility Functions + +Sometimes it can be useful to convert between colour formats: + +* `RGB332_to_RGB` +* `RGB_to_RGB332` +* `RGB565_to_RGB` +* `RGB_to_RGB565` + + ### Sprites Pico Display has very limited support for sprites in RGB332 mode. From 360bf4310cf24b150bff46f868c0d22509335e44 Mon Sep 17 00:00:00 2001 From: jon Date: Wed, 15 Jun 2022 16:37:27 +0100 Subject: [PATCH 71/84] SH1107: Add driver and example. Add 1bit pen mode to PicoGraphics. TODO: * Rotation support * Sizes other than 128x128 support --- drivers/CMakeLists.txt | 76 ++++++------- drivers/sh1107/CMakeLists.txt | 1 + drivers/sh1107/README.md | 58 ++++++++++ drivers/sh1107/sh1107.cmake | 12 ++ drivers/sh1107/sh1107.cpp | 49 +++++++++ drivers/sh1107/sh1107.hpp | 85 +++++++++++++++ examples/CMakeLists.txt | 103 +++++++++--------- examples/breakout_oled_128x128/CMakeLists.txt | 12 ++ .../oled_128x128_demo.cpp | 52 +++++++++ libraries/pico_graphics/pico_graphics.cmake | 1 + libraries/pico_graphics/pico_graphics.hpp | 18 ++- .../pico_graphics/pico_graphics_pen_1bit.cpp | 35 ++++++ micropython/modules/jpegdec/jpegdec.cpp | 5 +- 13 files changed, 417 insertions(+), 90 deletions(-) create mode 100644 drivers/sh1107/CMakeLists.txt create mode 100644 drivers/sh1107/README.md create mode 100644 drivers/sh1107/sh1107.cmake create mode 100644 drivers/sh1107/sh1107.cpp create mode 100644 drivers/sh1107/sh1107.hpp create mode 100644 examples/breakout_oled_128x128/CMakeLists.txt create mode 100644 examples/breakout_oled_128x128/oled_128x128_demo.cpp create mode 100644 libraries/pico_graphics/pico_graphics_pen_1bit.cpp diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index b5478d6d..8e4989d3 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -1,37 +1,39 @@ -add_subdirectory(analog) -add_subdirectory(analogmux) -add_subdirectory(esp32spi) -add_subdirectory(ioexpander) -add_subdirectory(ltp305) -add_subdirectory(ltr559) -add_subdirectory(pmw3901) -add_subdirectory(sgp30) -add_subdirectory(st7735) -add_subdirectory(st7789) -add_subdirectory(msa301) -add_subdirectory(rv3028) -add_subdirectory(trackball) -add_subdirectory(vl53l1x) -add_subdirectory(is31fl3731) -add_subdirectory(fatfs) -add_subdirectory(sdcard) -add_subdirectory(as7262) -add_subdirectory(bh1745) -add_subdirectory(bme68x) -add_subdirectory(bmp280) -add_subdirectory(bme280) -add_subdirectory(button) -add_subdirectory(pid) -add_subdirectory(plasma) -add_subdirectory(rgbled) -add_subdirectory(icp10125) -add_subdirectory(scd4x) -add_subdirectory(hub75) -add_subdirectory(uc8151) -add_subdirectory(pwm) -add_subdirectory(servo) -add_subdirectory(encoder) -add_subdirectory(motor) -add_subdirectory(vl53l5cx) -add_subdirectory(pcf85063a) -add_subdirectory(pms5003) +add_subdirectory(analog) +add_subdirectory(analogmux) +add_subdirectory(esp32spi) +add_subdirectory(ioexpander) +add_subdirectory(ltp305) +add_subdirectory(ltr559) +add_subdirectory(pmw3901) +add_subdirectory(sgp30) +add_subdirectory(st7735) +add_subdirectory(st7789) +add_subdirectory(msa301) +add_subdirectory(rv3028) +add_subdirectory(trackball) +add_subdirectory(vl53l1x) +add_subdirectory(is31fl3731) +add_subdirectory(fatfs) +add_subdirectory(sdcard) +add_subdirectory(as7262) +add_subdirectory(bh1745) +add_subdirectory(bme68x) +add_subdirectory(bmp280) +add_subdirectory(bme280) +add_subdirectory(button) +add_subdirectory(pid) +add_subdirectory(plasma) +add_subdirectory(rgbled) +add_subdirectory(icp10125) +add_subdirectory(scd4x) +add_subdirectory(hub75) +add_subdirectory(uc8151) +add_subdirectory(pwm) +add_subdirectory(servo) +add_subdirectory(encoder) +add_subdirectory(motor) +add_subdirectory(vl53l5cx) +add_subdirectory(pcf85063a) +add_subdirectory(pms5003) +add_subdirectory(sh1107) + diff --git a/drivers/sh1107/CMakeLists.txt b/drivers/sh1107/CMakeLists.txt new file mode 100644 index 00000000..3d2eb2bd --- /dev/null +++ b/drivers/sh1107/CMakeLists.txt @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/sh1107.cmake) \ No newline at end of file diff --git a/drivers/sh1107/README.md b/drivers/sh1107/README.md new file mode 100644 index 00000000..b9e92b4b --- /dev/null +++ b/drivers/sh1107/README.md @@ -0,0 +1,58 @@ +# ST7789 Display Driver for Pimoroni LCDs + +The ST7789 driver supports both Parallel and Serial (SPI) ST7789 displays and is intended for use with: + +* Pico Display +* Pico Display 2.0 +* Tufty 2040 +* Pico Explorer +* 240x240 Round & Square SPI LCD Breakouts + +## Setup + +Construct an instance of the ST7789 driver with either Parallel or SPI pins. + +Parallel: + +```c++ +ST7789 st7789(WIDTH, HEIGHT, ROTATE_0, { + Tufty2040::LCD_CS, // Chip-Select + Tufty2040::LCD_DC, // Data-Command + Tufty2040::LCD_WR, // Write + Tufty2040::LCD_RD, // Read + Tufty2040::LCD_D0, // Data 0 (start of a bank of 8 pins) + Tufty2040::BACKLIGHT // Backlight +}); +``` + +SPI: + +```c++ +ST7789 st7789(WIDTH, HEIGHT, ROTATE_0, false, { + PIMORONI_SPI_DEFAULT_INSTANCE, // SPI instance + SPI_BG_FRONT_CS, // Chip-select + SPI_DEFAULT_SCK, // SPI Clock + SPI_DEFAULT_MOSI, // SPI Out + PIN_UNUSED, // SPI In + SPI_DEFAULT_DC, // SPI Data/Command + PIN_UNUSED // Backlight +}); +``` + +## Reference + +### Update + +ST7789's `update` accepts an instance of `PicoGraphics` in any colour mode: + +```c++ +st7789.update(&graphics); +``` + +### Set Backlight + +If a backlight pin has been configured, you can set the backlight from 0 to 255: + +```c++ +st7789.set_backlight(128) +``` \ No newline at end of file diff --git a/drivers/sh1107/sh1107.cmake b/drivers/sh1107/sh1107.cmake new file mode 100644 index 00000000..f152c0e4 --- /dev/null +++ b/drivers/sh1107/sh1107.cmake @@ -0,0 +1,12 @@ +set(DRIVER_NAME sh1107) +add_library(${DRIVER_NAME} INTERFACE) + +target_sources(${DRIVER_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp) + +target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +target_include_directories(sh1107 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_i2c pico_graphics) diff --git a/drivers/sh1107/sh1107.cpp b/drivers/sh1107/sh1107.cpp new file mode 100644 index 00000000..9a72b514 --- /dev/null +++ b/drivers/sh1107/sh1107.cpp @@ -0,0 +1,49 @@ +#include "sh1107.hpp" + +#include +#include +#include + +namespace pimoroni { + + void SH1107::update(PicoGraphics *graphics) { + if(graphics->pen_type == PicoGraphics::PEN_1BIT) { // Display buffer is screen native + + uint8_t *p = (uint8_t *)graphics->frame_buffer; + uint framebuffer_size = PicoGraphics_Pen1Bit::buffer_size(width, height); + uint page_size = framebuffer_size / 16; + + uint8_t temp[framebuffer_size] = {0}; + uint8_t *ptemp = temp; + + for(int y = 0; y < height; y++) { + for(int x = 0; x < width; x++) { + uint bo = 7 - (x & 0b111); + uint8_t color = p[(x / 8) + (y * width / 8)] & (1U << bo); + if(color) { + temp[x + (y / 8 ) * width] |= 1 << (y % 8); + }else{ + temp[x + (y / 8 ) * width] &= ~(1 << (y % 8)); + } + } + } + + uint8_t buf[page_size + 1]; + + for(int i = 0; i < 16; i++) { + i2c.reg_write_uint8(0x3c, 0, 0xb0 + i); + i2c.reg_write_uint8(0x3c, 0, 0x00); + i2c.reg_write_uint8(0x3c, 0, 0x10); + + memcpy(buf + 1, ptemp, page_size); + buf[0] = 0x40; + + i2c.write_blocking(0x3c, buf, page_size + 1, false); + + ptemp += page_size; + } + + } + } + +} diff --git a/drivers/sh1107/sh1107.hpp b/drivers/sh1107/sh1107.hpp new file mode 100644 index 00000000..864a4631 --- /dev/null +++ b/drivers/sh1107/sh1107.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include "hardware/i2c.h" +#include "hardware/gpio.h" +#include "common/pimoroni_common.hpp" + +#include "common/pimoroni_i2c.hpp" + +#include "libraries/pico_graphics/pico_graphics.hpp" + +#include + + +namespace pimoroni { + + class SH1107 : public DisplayDriver { + I2C &i2c; + + public: + bool round; + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + + public: + // Parallel init + SH1107(uint16_t width, uint16_t height, I2C &i2c) : + DisplayDriver(width, height, ROTATE_0), + i2c(i2c) { + + + i2c.reg_write_uint8(0x3c, 0, 0xae); + + i2c.reg_write_uint8(0x3c, 0, 0x20); // set memory addressing mode + i2c.reg_write_uint8(0x3c, 0, 0x00); + + i2c.reg_write_uint8(0x3c, 0, 0xb0); // set page start address + + i2c.reg_write_uint8(0x3c, 0, 0xc0); // mirror vertically (for australian market) + + i2c.reg_write_uint8(0x3c, 0, 0x00); + i2c.reg_write_uint8(0x3c, 0, 0x10); + + i2c.reg_write_uint8(0x3c, 0, 0x40); + + i2c.reg_write_uint8(0x3c, 0, 0xa0); // mirror horizontally + + i2c.reg_write_uint8(0x3c, 0, 0xa6); // no inversion + + i2c.reg_write_uint8(0x3c, 0, 0xff); // ??????! + i2c.reg_write_uint8(0x3c, 0, 0x3f); // confusion intensifies.. + + i2c.reg_write_uint8(0x3c, 0, 0xa4); + + i2c.reg_write_uint8(0x3c, 0, 0xd3); // set display offset + i2c.reg_write_uint8(0x3c, 0, 0x00); + + i2c.reg_write_uint8(0x3c, 0, 0xd5); // set display clock divide + i2c.reg_write_uint8(0x3c, 0, 0xf0); + + i2c.reg_write_uint8(0x3c, 0, 0xd9); // set precharge period + i2c.reg_write_uint8(0x3c, 0, 0x22); + + i2c.reg_write_uint8(0x3c, 0, 0xda); // set com pins hardware configuration + i2c.reg_write_uint8(0x3c, 0, 0x12); + + i2c.reg_write_uint8(0x3c, 0, 0xdb); // set vcomh + i2c.reg_write_uint8(0x3c, 0, 0x20); + + i2c.reg_write_uint8(0x3c, 0, 0x8d); // set dc-dc enable + i2c.reg_write_uint8(0x3c, 0, 0x14); + + i2c.reg_write_uint8(0x3c, 0, 0xaf); // turn display on + } + + void update(PicoGraphics *graphics) override; + + private: + void common_init(); + void command(uint8_t command, size_t len = 0, const char *data = NULL); + }; + +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f9675d27..e741ba8a 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,51 +1,52 @@ -add_subdirectory(breakout_dotmatrix) -add_subdirectory(breakout_encoder) -add_subdirectory(breakout_ioexpander) -add_subdirectory(breakout_ltr559) -add_subdirectory(breakout_colourlcd160x80) -add_subdirectory(breakout_roundlcd) -add_subdirectory(breakout_rgbmatrix5x5) -add_subdirectory(breakout_matrix11x7) -add_subdirectory(breakout_mics6814) -add_subdirectory(breakout_pmw3901) -add_subdirectory(breakout_potentiometer) -add_subdirectory(breakout_rtc) -add_subdirectory(breakout_trackball) -add_subdirectory(breakout_sgp30) -add_subdirectory(breakout_colourlcd240x240) -add_subdirectory(breakout_msa301) -add_subdirectory(breakout_bme688) -add_subdirectory(breakout_bmp280) -add_subdirectory(breakout_bme280) -add_subdirectory(breakout_as7262) -add_subdirectory(breakout_bh1745) -add_subdirectory(breakout_icp10125) -add_subdirectory(breakout_scd41) -add_subdirectory(breakout_vl53l5cx) -add_subdirectory(breakout_pms5003) - -add_subdirectory(pico_display) -add_subdirectory(pico_display_2) -add_subdirectory(pico_unicorn) -add_subdirectory(pico_unicorn_plasma) -add_subdirectory(pico_scroll) -add_subdirectory(pico_enc_explorer) -add_subdirectory(pico_explorer) -add_subdirectory(pico_pot_explorer) -add_subdirectory(pico_explorer_encoder) -add_subdirectory(pico_motor_shim) -add_subdirectory(pico_rgb_keypad) -add_subdirectory(pico_rtc_display) -add_subdirectory(pico_rtc) -add_subdirectory(pico_tof_display) -add_subdirectory(pico_trackball_display) -add_subdirectory(pico_audio) -add_subdirectory(pico_wireless) - -add_subdirectory(plasma2040) -add_subdirectory(badger2040) -add_subdirectory(tufty2040) -add_subdirectory(interstate75) -add_subdirectory(servo2040) -add_subdirectory(motor2040) -add_subdirectory(encoder) +add_subdirectory(breakout_dotmatrix) +add_subdirectory(breakout_encoder) +add_subdirectory(breakout_ioexpander) +add_subdirectory(breakout_ltr559) +add_subdirectory(breakout_colourlcd160x80) +add_subdirectory(breakout_roundlcd) +add_subdirectory(breakout_rgbmatrix5x5) +add_subdirectory(breakout_matrix11x7) +add_subdirectory(breakout_mics6814) +add_subdirectory(breakout_pmw3901) +add_subdirectory(breakout_potentiometer) +add_subdirectory(breakout_rtc) +add_subdirectory(breakout_trackball) +add_subdirectory(breakout_sgp30) +add_subdirectory(breakout_colourlcd240x240) +add_subdirectory(breakout_msa301) +add_subdirectory(breakout_bme688) +add_subdirectory(breakout_bmp280) +add_subdirectory(breakout_bme280) +add_subdirectory(breakout_as7262) +add_subdirectory(breakout_bh1745) +add_subdirectory(breakout_icp10125) +add_subdirectory(breakout_scd41) +add_subdirectory(breakout_vl53l5cx) +add_subdirectory(breakout_pms5003) +add_subdirectory(breakout_oled_128x128) + +add_subdirectory(pico_display) +add_subdirectory(pico_display_2) +add_subdirectory(pico_unicorn) +add_subdirectory(pico_unicorn_plasma) +add_subdirectory(pico_scroll) +add_subdirectory(pico_enc_explorer) +add_subdirectory(pico_explorer) +add_subdirectory(pico_pot_explorer) +add_subdirectory(pico_explorer_encoder) +add_subdirectory(pico_motor_shim) +add_subdirectory(pico_rgb_keypad) +add_subdirectory(pico_rtc_display) +add_subdirectory(pico_rtc) +add_subdirectory(pico_tof_display) +add_subdirectory(pico_trackball_display) +add_subdirectory(pico_audio) +add_subdirectory(pico_wireless) + +add_subdirectory(plasma2040) +add_subdirectory(badger2040) +add_subdirectory(tufty2040) +add_subdirectory(interstate75) +add_subdirectory(servo2040) +add_subdirectory(motor2040) +add_subdirectory(encoder) diff --git a/examples/breakout_oled_128x128/CMakeLists.txt b/examples/breakout_oled_128x128/CMakeLists.txt new file mode 100644 index 00000000..05d4564b --- /dev/null +++ b/examples/breakout_oled_128x128/CMakeLists.txt @@ -0,0 +1,12 @@ +set(OUTPUT_NAME oled_128x128_demo) + +add_executable( + ${OUTPUT_NAME} + oled_128x128_demo.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_graphics sh1107) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) \ No newline at end of file diff --git a/examples/breakout_oled_128x128/oled_128x128_demo.cpp b/examples/breakout_oled_128x128/oled_128x128_demo.cpp new file mode 100644 index 00000000..c9d84e9c --- /dev/null +++ b/examples/breakout_oled_128x128/oled_128x128_demo.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include "drivers/sh1107/sh1107.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" +#include "time.h" + +using namespace pimoroni; + + +const int WIDTH = 128; +const int HEIGHT = 128; + +I2C i2c(4, 5); + +SH1107 sh1107(WIDTH, HEIGHT, i2c); +PicoGraphics_Pen1Bit graphics(sh1107.width, sh1107.height, nullptr); + +int main() { + + + uint i = 0; + while(true) { + // for(int y = 0; y < 128; y++) { + // for(int x = 0; x < 128; x++) { + // graphics.set_pen(((x + y + i) & 0b1111) > 8 ? 1 : 0); + // graphics.set_pixel({x, y}); + // } + // } + + graphics.set_pen(1); + graphics.clear(); + + float s = (sin(i / 10.0f) * 1.0f) + 1.5f; + float a = (cos(i / 10.0f) * 10.0f); + + graphics.set_font("gothic"); + + graphics.set_pen(0); + int w = graphics.measure_text("PIRATES!", s); + graphics.text("PIRATES!", {64 - w / 2, 60}, 0, s, a); + + sh1107.update(&graphics); + + //sleep_ms(10); + + i++; + } + +} \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.cmake b/libraries/pico_graphics/pico_graphics.cmake index e06ea5d7..71d0cf9a 100644 --- a/libraries/pico_graphics/pico_graphics.cmake +++ b/libraries/pico_graphics/pico_graphics.cmake @@ -1,6 +1,7 @@ add_library(pico_graphics ${CMAKE_CURRENT_LIST_DIR}/types.cpp ${CMAKE_CURRENT_LIST_DIR}/pico_graphics.cpp + ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_1bit.cpp ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_p4.cpp ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_p8.cpp ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb332.cpp diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 765573e3..0fddba41 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -128,7 +128,8 @@ namespace pimoroni { class PicoGraphics { public: enum PenType { - PEN_P2 = 0, + PEN_1BIT, + PEN_P2, PEN_P4, PEN_P8, PEN_RGB332, @@ -221,6 +222,21 @@ namespace pimoroni { void line(Point p1, Point p2); }; + class PicoGraphics_Pen1Bit : public PicoGraphics { + public: + uint8_t color; + + PicoGraphics_Pen1Bit(uint16_t width, uint16_t height, void *frame_buffer); + void set_pen(uint c) override; + void set_pen(uint8_t r, uint8_t g, uint8_t b) override; + + void set_pixel(const Point &p) override; + + static size_t buffer_size(uint w, uint h) { + return w * h / 8; + } + }; + class PicoGraphics_PenP4 : public PicoGraphics { public: diff --git a/libraries/pico_graphics/pico_graphics_pen_1bit.cpp b/libraries/pico_graphics/pico_graphics_pen_1bit.cpp new file mode 100644 index 00000000..af052d4b --- /dev/null +++ b/libraries/pico_graphics/pico_graphics_pen_1bit.cpp @@ -0,0 +1,35 @@ +#include "pico_graphics.hpp" + +namespace pimoroni { + + PicoGraphics_Pen1Bit::PicoGraphics_Pen1Bit(uint16_t width, uint16_t height, void *frame_buffer) + : PicoGraphics(width, height, frame_buffer) { + this->pen_type = PEN_1BIT; + if(this->frame_buffer == nullptr) { + this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); + } + } + + void PicoGraphics_Pen1Bit::set_pen(uint c) { + color = c != 0 ? 1 : 0; + } + + void PicoGraphics_Pen1Bit::set_pen(uint8_t r, uint8_t g, uint8_t b) { + color = r != 0 || g != 0 || b != 0 ? 1 : 0; + } + + void PicoGraphics_Pen1Bit::set_pixel(const Point &p) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + uint8_t *f = &buf[(p.x / 8) + (p.y * bounds.w / 8)]; + + uint bo = 7 - (p.x & 0b111); + + // forceably clear the bit + *f &= ~(1U << bo); + + // set pixel + *f |= (color << bo); + } + +} \ No newline at end of file diff --git a/micropython/modules/jpegdec/jpegdec.cpp b/micropython/modules/jpegdec/jpegdec.cpp index ee853ae9..9791aa56 100644 --- a/micropython/modules/jpegdec/jpegdec.cpp +++ b/micropython/modules/jpegdec/jpegdec.cpp @@ -107,6 +107,9 @@ static int _open(_JPEG_obj_t *self) { case PicoGraphics::PEN_P2: self->jpeg->setPixelType(TWO_BIT_DITHERED); break; + case PicoGraphics::PEN_1BIT: + self->jpeg->setPixelType(ONE_BIT_DITHERED); + break; } } return result; @@ -192,4 +195,4 @@ mp_obj_t _JPEG_getHeight(mp_obj_t self_in) { return mp_obj_new_int(self->jpeg->getHeight()); } -} \ No newline at end of file +} From 1657a970bd36d0a607eb94cc46d3dca2f57ff4e3 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 16 Jun 2022 09:23:29 +0100 Subject: [PATCH 72/84] PicoGraphics: Add SH1107 support to MMicroPython. --- .../modules/picographics/micropython.cmake | 2 ++ .../modules/picographics/picographics.c | 2 ++ .../modules/picographics/picographics.cpp | 20 +++++++++++++++++++ .../modules/picographics/picographics.h | 6 ++++-- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/micropython/modules/picographics/micropython.cmake b/micropython/modules/picographics/micropython.cmake index fb692169..e3713556 100644 --- a/micropython/modules/picographics/micropython.cmake +++ b/micropython/modules/picographics/micropython.cmake @@ -7,7 +7,9 @@ target_sources(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7735/st7735.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/sh1107/sh1107.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_1bit.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_p4.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_p8.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics_pen_rgb332.cpp diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 40b5175b..86ec0ee2 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -111,7 +111,9 @@ STATIC const mp_map_elem_t picographics_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DISPLAY_TUFTY_2040), MP_ROM_INT(DISPLAY_TUFTY_2040) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_ENVIRO_PLUS), MP_ROM_INT(DISPLAY_ENVIRO_PLUS) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY_LCD_160X80), MP_ROM_INT(DISPLAY_LCD_160X80) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_I2C_OLED_128X128), MP_ROM_INT(DISPLAY_I2C_OLED_128X128) }, + { MP_ROM_QSTR(MP_QSTR_PEN_1BIT), MP_ROM_INT(PEN_1BIT) }, { MP_ROM_QSTR(MP_QSTR_PEN_P4), MP_ROM_INT(PEN_P4) }, { MP_ROM_QSTR(MP_QSTR_PEN_P8), MP_ROM_INT(PEN_P8) }, { MP_ROM_QSTR(MP_QSTR_PEN_RGB332), MP_ROM_INT(PEN_RGB332) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 81f375fd..8626e690 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -1,8 +1,10 @@ #include "drivers/st7789/st7789.hpp" #include "drivers/st7735/st7735.hpp" +#include "drivers/sh1107/sh1107.hpp" #include "libraries/pico_graphics/pico_graphics.hpp" #include "common/pimoroni_common.hpp" #include "common/pimoroni_bus.hpp" +#include "common/pimoroni_i2c.hpp" #include "micropython/modules/util.hpp" @@ -11,6 +13,7 @@ using namespace pimoroni; extern "C" { #include "picographics.h" #include "micropython/modules/pimoroni_bus/pimoroni_bus.h" +#include "pimoroni_i2c.h" #include "py/stream.h" #include "py/reader.h" #include "extmod/vfs.h" @@ -61,6 +64,11 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height, width = 160; height = 80; break; + case DISPLAY_I2C_OLED_128X128: + width = 128; + height = 128; + if(rotate == -1) rotate = (int)Rotation::ROTATE_0; + break; default: return false; } @@ -69,6 +77,8 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height, size_t get_required_buffer_size(PicoGraphicsPenType pen_type, uint width, uint height) { switch(pen_type) { + case PEN_1BIT: + return PicoGraphics_Pen1Bit::buffer_size(width, height); case PEN_P4: return PicoGraphics_PenP4::buffer_size(width, height); case PEN_P8: @@ -131,6 +141,13 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size } else { mp_raise_ValueError("SPIBus expected!"); } + } else if (display == DISPLAY_I2C_OLED_128X128) { + if (args[ARG_bus].u_obj == mp_const_none || mp_obj_is_type(args[ARG_bus].u_obj, &PimoroniI2C_type)) { + _PimoroniI2C_obj_t *i2c = PimoroniI2C_from_machine_i2c_or_native(args[ARG_bus].u_obj); + self->display = m_new_class(SH1107, width, height, *(pimoroni::I2C *)(i2c->i2c)); + } else { + mp_raise_ValueError("I2C bus expected!"); + } } else { if (args[ARG_bus].u_obj == mp_const_none) { self->display = m_new_class(ST7789, width, height, (Rotation)rotate, round, get_spi_pins(BG_SPI_FRONT)); @@ -160,6 +177,9 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size // Create an instance of the graphics library // use the *driver* width/height because they may have been swapped due to rotation switch(pen_type) { + case PEN_1BIT: + self->graphics = m_new_class(PicoGraphics_Pen1Bit, self->display->width, self->display->height, self->buffer); + break; case PEN_P4: self->graphics = m_new_class(PicoGraphics_PenP4, self->display->width, self->display->height, self->buffer); break; diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index 3e0a56d5..01a26233 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -9,11 +9,13 @@ enum PicoGraphicsDisplay { DISPLAY_PICO_EXPLORER, DISPLAY_TUFTY_2040, DISPLAY_ENVIRO_PLUS, - DISPLAY_LCD_160X80 + DISPLAY_LCD_160X80, + DISPLAY_I2C_OLED_128X128 }; enum PicoGraphicsPenType { - PEN_P2 = 0, + PEN_1BIT = 0, + PEN_P2, PEN_P4, PEN_P8, PEN_RGB332, From 92397693680139eb6c1694d87ad76d90f1b79513 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 16 Jun 2022 10:56:17 +0100 Subject: [PATCH 73/84] QRCode: Support for MicroPython v1.19. --- micropython/modules/qrcode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/modules/qrcode b/micropython/modules/qrcode index b5afd3c0..db9477e1 160000 --- a/micropython/modules/qrcode +++ b/micropython/modules/qrcode @@ -1 +1 @@ -Subproject commit b5afd3c031c3f6ddd89e73833a1c8e551134e291 +Subproject commit db9477e1bf46b252bbd8ed8bc0f374c564d0ad00 From 5d968a5463e9a11c3459e06475b7287a9572e916 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 16 Jun 2022 14:48:23 +0100 Subject: [PATCH 74/84] ulab: Support for MicroPython v1.19 --- micropython/modules/ulab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/modules/ulab b/micropython/modules/ulab index 0c7c6b88..00139bdd 160000 --- a/micropython/modules/ulab +++ b/micropython/modules/ulab @@ -1 +1 @@ -Subproject commit 0c7c6b88f3ec1b1d11d2f7d8b185e28ac657c06d +Subproject commit 00139bdd9684bd9d10b0d89fa8fbb0906f2d05af From 3cd64747b2268ae392465cb5a193e3d92204e1f6 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 16 Jun 2022 14:49:06 +0100 Subject: [PATCH 75/84] MicroPython: Bump CI to v1.19. --- .github/workflows/micropython-badger2040.yml | 2 +- .github/workflows/micropython.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/micropython-badger2040.yml b/.github/workflows/micropython-badger2040.yml index ff469c40..da266933 100644 --- a/.github/workflows/micropython-badger2040.yml +++ b/.github/workflows/micropython-badger2040.yml @@ -7,7 +7,7 @@ on: types: [created] env: - MICROPYTHON_VERSION: v1.18 + MICROPYTHON_VERSION: v1.19 BOARD_TYPE: PICO # 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.uf2 diff --git a/.github/workflows/micropython.yml b/.github/workflows/micropython.yml index 23fb076a..5450247a 100644 --- a/.github/workflows/micropython.yml +++ b/.github/workflows/micropython.yml @@ -7,7 +7,7 @@ on: types: [created] env: - MICROPYTHON_VERSION: v1.18 + MICROPYTHON_VERSION: v1.19 jobs: deps: From 76715e45f8015d232a7493d5fccffbc4a2dc55f6 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 16 Jun 2022 17:38:57 +0100 Subject: [PATCH 76/84] ST7789: Convert Parallel IO to PIO + DMA. Make display updates around 4x faster. Requires a PIO + SM to run Tufty 2040. --- drivers/st7789/st7789.cmake | 4 +- drivers/st7789/st7789.cpp | 54 +++- drivers/st7789/st7789.hpp | 51 +++- drivers/st7789/st7789_parallel.pio | 7 + libraries/pico_graphics/pico_graphics.hpp | 254 +++++++++++++++++- .../pico_graphics_pen_rgb332.cpp | 19 +- .../modules/picographics/micropython.cmake | 2 + .../modules/picographics/picographics.c | 6 + .../modules/picographics/picographics.cpp | 8 +- .../modules/picographics/picographics.h | 4 +- 10 files changed, 388 insertions(+), 21 deletions(-) create mode 100644 drivers/st7789/st7789_parallel.pio diff --git a/drivers/st7789/st7789.cmake b/drivers/st7789/st7789.cmake index a08f111c..45d5247c 100644 --- a/drivers/st7789/st7789.cmake +++ b/drivers/st7789/st7789.cmake @@ -4,9 +4,11 @@ add_library(${DRIVER_NAME} INTERFACE) target_sources(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp) +pico_generate_pio_header(${DRIVER_NAME} ${CMAKE_CURRENT_LIST_DIR}/st7789_parallel.pio) + target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) target_include_directories(st7789 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma pico_graphics) +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_pio hardware_dma pico_graphics) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 688e008f..e3243122 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -109,6 +109,20 @@ namespace pimoroni { } } + void ST7789::cleanup() { + if(spi) return; // SPI mode needs no tear down + if(dma_channel_is_claimed(parallel_dma)) { + dma_channel_abort(parallel_dma); + dma_channel_unclaim(parallel_dma); + } + + if(pio_sm_is_claimed(parallel_pio, parallel_sm)) { + pio_sm_set_enabled(parallel_pio, parallel_sm, false); + pio_sm_drain_tx_fifo(parallel_pio, parallel_sm); + pio_sm_unclaim(parallel_pio, parallel_sm); + } + } + void ST7789::configure_display(Rotation rotate) { bool rotate180 = rotate == ROTATE_180 || rotate == ROTATE_90; @@ -209,16 +223,37 @@ namespace pimoroni { command(reg::MADCTL, 1, (char *)&madctl); } + void ST7789::write_blocking_parallel_dma(const uint8_t *src, size_t len) { + while (dma_channel_is_busy(parallel_dma)) + ; + dma_channel_set_trans_count(parallel_dma, len, false); + dma_channel_set_read_addr(parallel_dma, src, true); + } + void ST7789::write_blocking_parallel(const uint8_t *src, size_t len) { - uint32_t mask = 0xff << d0; + const uint8_t *p = src; + while(len--) { + // Does not byte align correctly + //pio_sm_put_blocking(parallel_pio, parallel_sm, *p); + while (pio_sm_is_tx_fifo_full(parallel_pio, parallel_sm)) + ; + *(volatile uint8_t*)¶llel_pio->txf[parallel_sm] = *p; + p++; + } + + uint32_t sm_stall_mask = 1u << (parallel_sm + PIO_FDEBUG_TXSTALL_LSB); + parallel_pio->fdebug = sm_stall_mask; + while (!(parallel_pio->fdebug & sm_stall_mask)) + ; + /*uint32_t mask = 0xff << d0; while(len--) { gpio_put(wr_sck, false); uint8_t v = *src++; gpio_put_masked(mask, v << d0); - asm("nop;"); + //asm("nop;"); gpio_put(wr_sck, true); asm("nop;"); - } + }*/ } void ST7789::command(uint8_t command, size_t len, const char *data) { @@ -266,8 +301,17 @@ namespace pimoroni { write_blocking_parallel(&cmd, 1); gpio_put(dc, 1); // data mode - graphics->scanline_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) { - write_blocking_parallel((const uint8_t*)data, length); + int scanline = 0; + + graphics->scanline_convert(PicoGraphics::PEN_RGB565, [this, scanline](void *data, size_t length) mutable { + write_blocking_parallel_dma((const uint8_t*)data, length); + + // Stall on the last scanline since "data" goes out of scope and is lost + scanline++; + if(scanline == height) { + while (dma_channel_is_busy(parallel_dma)) + ; + } }); gpio_put(cs, 1); diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index 5be438c3..2a7fa36f 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -1,12 +1,17 @@ #pragma once #include "hardware/spi.h" +#include "hardware/dma.h" #include "hardware/gpio.h" +#include "hardware/pio.h" #include "hardware/pwm.h" #include "common/pimoroni_common.hpp" #include "common/pimoroni_bus.hpp" #include "libraries/pico_graphics/pico_graphics.hpp" + +#include "st7789_parallel.pio.h" + #include @@ -31,6 +36,11 @@ namespace pimoroni { uint d0; uint bl; uint vsync = PIN_UNUSED; // only available on some products + uint parallel_sm; + PIO parallel_pio; + uint parallel_offset; + uint parallel_dma; + // The ST7789 requires 16 ns between SPI rising edges. // 16 ns = 62,500,000 Hz @@ -43,17 +53,47 @@ namespace pimoroni { DisplayDriver(width, height, rotation), spi(nullptr), round(false), cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl) { + + parallel_pio = pio1; + parallel_sm = pio_claim_unused_sm(parallel_pio, true); + parallel_offset = pio_add_program(parallel_pio, &st7789_parallel_program); - gpio_set_function(wr_sck, GPIO_FUNC_SIO); - gpio_set_dir(wr_sck, GPIO_OUT); + //gpio_init(wr_sck); + //gpio_set_dir(wr_sck, GPIO_OUT); + //gpio_set_function(wr_sck, GPIO_FUNC_SIO); + pio_gpio_init(parallel_pio, wr_sck); gpio_set_function(rd_sck, GPIO_FUNC_SIO); gpio_set_dir(rd_sck, GPIO_OUT); for(auto i = 0u; i < 8; i++) { - gpio_set_function(d0 + i, GPIO_FUNC_SIO); - gpio_set_dir(d0 + i, GPIO_OUT); + //gpio_set_function(d0 + i, GPIO_FUNC_SIO); + //gpio_set_dir(d0 + i, GPIO_OUT); + //gpio_init(d0 + 0); gpio_set_dir(d0 + i, GPIO_OUT); + pio_gpio_init(parallel_pio, d0 + i); } + + pio_sm_set_consecutive_pindirs(parallel_pio, parallel_sm, d0, 8, true); + pio_sm_set_consecutive_pindirs(parallel_pio, parallel_sm, wr_sck, 1, true); + + pio_sm_config c = st7789_parallel_program_get_default_config(parallel_offset); + + sm_config_set_out_pins(&c, d0, 8); + sm_config_set_sideset_pins(&c, wr_sck); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + sm_config_set_out_shift(&c, false, true, 8); + sm_config_set_clkdiv(&c, 4); + + pio_sm_init(parallel_pio, parallel_sm, parallel_offset, &c); + pio_sm_set_enabled(parallel_pio, parallel_sm, true); + + + parallel_dma = dma_claim_unused_channel(true); + dma_channel_config config = dma_channel_get_default_config(parallel_dma); + channel_config_set_transfer_data_size(&config, DMA_SIZE_8); + channel_config_set_bswap(&config, false); + channel_config_set_dreq(&config, pio_get_dreq(parallel_pio, parallel_sm, true)); + dma_channel_configure(parallel_dma, &config, ¶llel_pio->txf[parallel_sm], NULL, 0, false); gpio_put(rd_sck, 1); @@ -75,13 +115,14 @@ namespace pimoroni { common_init(); } - + void cleanup() override; void update(PicoGraphics *graphics) override; void set_backlight(uint8_t brightness) override; private: void common_init(); void configure_display(Rotation rotate); + void write_blocking_parallel_dma(const uint8_t *src, size_t len); void write_blocking_parallel(const uint8_t *src, size_t len); void command(uint8_t command, size_t len = 0, const char *data = NULL); }; diff --git a/drivers/st7789/st7789_parallel.pio b/drivers/st7789/st7789_parallel.pio new file mode 100644 index 00000000..6438c028 --- /dev/null +++ b/drivers/st7789/st7789_parallel.pio @@ -0,0 +1,7 @@ +.program st7789_parallel +.side_set 1 + +.wrap_target + out pins, 8 side 0 + nop side 1 +.wrap \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 0fddba41..926db4eb 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -125,6 +125,258 @@ namespace pimoroni { void deflate(int32_t v); }; + static const RGB565 rgb332_to_rgb565_lut[256] = { + 0x0000, 0x0800, 0x1000, 0x1800, 0x0001, 0x0801, 0x1001, 0x1801, +0x0002, +0x0802, +0x1002, +0x1802, +0x0003, +0x0803, +0x1003, +0x1803, +0x0004, +0x0804, +0x1004, +0x1804, +0x0005, +0x0805, +0x1005, +0x1805, +0x0006, +0x0806, +0x1006, +0x1806, +0x0007, +0x0807, +0x1007, +0x1807, +0x0020, +0x0820, +0x1020, +0x1820, +0x0021, +0x0821, +0x1021, +0x1821, +0x0022, +0x0822, +0x1022, +0x1822, +0x0023, +0x0823, +0x1023, +0x1823, +0x0024, +0x0824, +0x1024, +0x1824, +0x0025, +0x0825, +0x1025, +0x1825, +0x0026, +0x0826, +0x1026, +0x1826, +0x0027, +0x0827, +0x1027, +0x1827, +0x0040, +0x0840, +0x1040, +0x1840, +0x0041, +0x0841, +0x1041, +0x1841, +0x0042, +0x0842, +0x1042, +0x1842, +0x0043, +0x0843, +0x1043, +0x1843, +0x0044, +0x0844, +0x1044, +0x1844, +0x0045, +0x0845, +0x1045, +0x1845, +0x0046, +0x0846, +0x1046, +0x1846, +0x0047, +0x0847, +0x1047, +0x1847, +0x0060, +0x0860, +0x1060, +0x1860, +0x0061, +0x0861, +0x1061, +0x1861, +0x0062, +0x0862, +0x1062, +0x1862, +0x0063, +0x0863, +0x1063, +0x1863, +0x0064, +0x0864, +0x1064, +0x1864, +0x0065, +0x0865, +0x1065, +0x1865, +0x0066, +0x0866, +0x1066, +0x1866, +0x0067, +0x0867, +0x1067, +0x1867, +0x0080, +0x0880, +0x1080, +0x1880, +0x0081, +0x0881, +0x1081, +0x1881, +0x0082, +0x0882, +0x1082, +0x1882, +0x0083, +0x0883, +0x1083, +0x1883, +0x0084, +0x0884, +0x1084, +0x1884, +0x0085, +0x0885, +0x1085, +0x1885, +0x0086, +0x0886, +0x1086, +0x1886, +0x0087, +0x0887, +0x1087, +0x1887, +0x00a0, +0x08a0, +0x10a0, +0x18a0, +0x00a1, +0x08a1, +0x10a1, +0x18a1, +0x00a2, +0x08a2, +0x10a2, +0x18a2, +0x00a3, +0x08a3, +0x10a3, +0x18a3, +0x00a4, +0x08a4, +0x10a4, +0x18a4, +0x00a5, +0x08a5, +0x10a5, +0x18a5, +0x00a6, +0x08a6, +0x10a6, +0x18a6, +0x00a7, +0x08a7, +0x10a7, +0x18a7, +0x00c0, +0x08c0, +0x10c0, +0x18c0, +0x00c1, +0x08c1, +0x10c1, +0x18c1, +0x00c2, +0x08c2, +0x10c2, +0x18c2, +0x00c3, +0x08c3, +0x10c3, +0x18c3, +0x00c4, +0x08c4, +0x10c4, +0x18c4, +0x00c5, +0x08c5, +0x10c5, +0x18c5, +0x00c6, +0x08c6, +0x10c6, +0x18c6, +0x00c7, +0x08c7, +0x10c7, +0x18c7, +0x00e0, +0x08e0, +0x10e0, +0x18e0, +0x00e1, +0x08e1, +0x10e1, +0x18e1, +0x00e2, +0x08e2, +0x10e2, +0x18e2, +0x00e3, +0x08e3, +0x10e3, +0x18e3, +0x00e4, +0x08e4, +0x10e4, +0x18e4, +0x00e5, +0x08e5, +0x10e5, +0x18e5, +0x00e6, +0x08e6, +0x10e6, +0x18e6, +0x00e7, +0x08e7, +0x10e7, +0x18e7, + }; + class PicoGraphics { public: enum PenType { @@ -301,7 +553,6 @@ namespace pimoroni { class PicoGraphics_PenRGB332 : public PicoGraphics { public: RGB332 color; - RGB palette[256]; PicoGraphics_PenRGB332(uint16_t width, uint16_t height, void *frame_buffer); void set_pen(uint c) override; void set_pen(uint8_t r, uint8_t g, uint8_t b) override; @@ -344,6 +595,7 @@ namespace pimoroni { virtual void update(PicoGraphics *display) {}; virtual void set_backlight(uint8_t brightness) {}; + virtual void cleanup() {}; }; } diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp index d8389229..9fb7bb1c 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp @@ -1,4 +1,5 @@ #include "pico_graphics.hpp" +#include namespace pimoroni { PicoGraphics_PenRGB332::PicoGraphics_PenRGB332(uint16_t width, uint16_t height, void *frame_buffer) @@ -7,9 +8,6 @@ namespace pimoroni { if(this->frame_buffer == nullptr) { this->frame_buffer = (void *)(new uint8_t[buffer_size(width, height)]); } - for(auto i = 0u; i < 256; i++) { - palette[i] = RGB((RGB332)i); - } } void PicoGraphics_PenRGB332::set_pen(uint c) { color = c; @@ -86,12 +84,18 @@ namespace pimoroni { } void PicoGraphics_PenRGB332::scanline_convert(PenType type, conversion_callback_func callback) { if(type == PEN_RGB565) { - // Cache the RGB888 palette as RGB565 - RGB565 cache[256]; + + static RGB565 cache[256]; for(auto i = 0u; i < 256; i++) { - cache[i] = palette[i].to_rgb565(); + cache[i] = rgb332_to_rgb565_lut[i]; // defined in pico_graphics.hpp } + // 2ms slower, I swear! + /* + static RGB565 cache[256]; + memcpy(cache, rgb332_to_rgb565_lut, 256 * sizeof(RGB565)); + */ + // Treat our void* frame_buffer as uint8_t uint8_t *src = (uint8_t *)frame_buffer; @@ -99,7 +103,8 @@ namespace pimoroni { uint16_t row_buf[bounds.w]; for(auto y = 0; y < bounds.h; y++) { for(auto x = 0; x < bounds.w; x++) { - row_buf[x] = cache[src[bounds.w * y + x]]; + row_buf[x] = cache[*src]; + src++; } // Callback to the driver with the row data callback(row_buf, bounds.w * sizeof(RGB565)); diff --git a/micropython/modules/picographics/micropython.cmake b/micropython/modules/picographics/micropython.cmake index e3713556..9a1675af 100644 --- a/micropython/modules/picographics/micropython.cmake +++ b/micropython/modules/picographics/micropython.cmake @@ -17,6 +17,8 @@ target_sources(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp ) +pico_generate_pio_header(usermod_${MOD_NAME} ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789_parallel.pio) + target_include_directories(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR} ) diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index 86ec0ee2..63bafca8 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -46,6 +46,10 @@ MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics_get_bounds_obj, ModPicoGraphics_get_bo MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_font_obj, ModPicoGraphics_set_font); MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_framebuffer_obj, ModPicoGraphics_set_framebuffer); + +MP_DEFINE_CONST_FUN_OBJ_1(ModPicoGraphics__del__obj, ModPicoGraphics__del__); + + STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&ModPicoGraphics_pixel_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&ModPicoGraphics_set_pen_obj) }, @@ -79,6 +83,8 @@ STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_get_bounds), MP_ROM_PTR(&ModPicoGraphics_get_bounds_obj) }, { MP_ROM_QSTR(MP_QSTR_set_font), MP_ROM_PTR(&ModPicoGraphics_set_font_obj) }, { MP_ROM_QSTR(MP_QSTR_set_framebuffer), MP_ROM_PTR(&ModPicoGraphics_set_framebuffer_obj) }, + + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ModPicoGraphics__del__obj) }, }; STATIC MP_DEFINE_CONST_DICT(ModPicoGraphics_locals_dict, ModPicoGraphics_locals_dict_table); diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 8626e690..abffeb59 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -108,7 +108,7 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - self = m_new_obj(ModPicoGraphics_obj_t); + self = m_new_obj_with_finaliser(ModPicoGraphics_obj_t); self->base.type = &ModPicoGraphics_type; @@ -210,6 +210,12 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size return MP_OBJ_FROM_PTR(self); } +mp_obj_t ModPicoGraphics__del__(mp_obj_t self_in) { + ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); + self->display->cleanup(); + return mp_const_none; +} + mp_obj_t ModPicoGraphics_set_spritesheet(mp_obj_t self_in, mp_obj_t spritedata) { ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(self_in, ModPicoGraphics_obj_t); if(spritedata == mp_const_none) { diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index 01a26233..e081ed83 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -73,4 +73,6 @@ extern mp_obj_t ModPicoGraphics_set_font(mp_obj_t self_in, mp_obj_t font); extern mp_obj_t ModPicoGraphics_get_bounds(mp_obj_t self_in); extern mp_obj_t ModPicoGraphics_set_framebuffer(mp_obj_t self_in, mp_obj_t framebuffer); -extern mp_int_t ModPicoGraphics_get_framebuffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); \ No newline at end of file +extern mp_int_t ModPicoGraphics_get_framebuffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); + +extern mp_obj_t ModPicoGraphics__del__(mp_obj_t self_in); \ No newline at end of file From 077159adeb8be9557160b4758c158ae9ad66e53c Mon Sep 17 00:00:00 2001 From: jon Date: Fri, 17 Jun 2022 08:08:47 +0100 Subject: [PATCH 77/84] PicoGraphics: Add set_pixel_span and call where appropriate. --- libraries/pico_graphics/pico_graphics.cpp | 10 ++------ libraries/pico_graphics/pico_graphics.hpp | 15 ++++++++--- .../pico_graphics/pico_graphics_pen_1bit.cpp | 25 +++++++++++++++++++ .../pico_graphics/pico_graphics_pen_p4.cpp | 23 +++++++++++++++-- .../pico_graphics/pico_graphics_pen_p8.cpp | 10 ++++++++ .../pico_graphics_pen_rgb332.cpp | 9 +++++++ .../pico_graphics_pen_rgb565.cpp | 9 +++++++ 7 files changed, 87 insertions(+), 14 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 8bdd2eb3..4d1e82bc 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -2,12 +2,9 @@ namespace pimoroni { - void PicoGraphics::set_pen(uint c) {}; - void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) {}; int PicoGraphics::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {return -1;}; int PicoGraphics::reset_pen(uint8_t i) {return -1;}; int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;}; - void PicoGraphics::set_pixel(const Point &p) {}; void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {}; void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {}; void PicoGraphics::scanline_convert(PenType type, conversion_callback_func callback) {}; @@ -74,10 +71,7 @@ namespace pimoroni { if(clipped.x + l >= clip.x + clip.w) {l = clip.x + clip.w - clipped.x;} Point dest(clipped.x, clipped.y); - while(l--) { - set_pixel(dest); - dest.x++; - } + set_pixel_span(dest, l); } void PicoGraphics::rectangle(const Rect &r) { @@ -89,7 +83,7 @@ namespace pimoroni { Point dest(clipped.x, clipped.y); while(clipped.h--) { // draw span of pixels for this row - pixel_span(dest, clipped.w); + set_pixel_span(dest, clipped.w); // move to next scanline dest.y++; } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 926db4eb..0fb43837 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -437,12 +437,14 @@ namespace pimoroni { set_font(&font6); }; - virtual void set_pen(uint c); - virtual void set_pen(uint8_t r, uint8_t g, uint8_t b); + virtual void set_pen(uint c) = 0; + virtual void set_pen(uint8_t r, uint8_t g, uint8_t b) = 0; + virtual void set_pixel(const Point &p) = 0; + virtual void set_pixel_span(const Point &p, uint l) = 0; + + virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); virtual int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b); virtual int reset_pen(uint8_t i); - virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); - virtual void set_pixel(const Point &p); virtual void set_pixel_dither(const Point &p, const RGB &c); virtual void set_pixel_dither(const Point &p, const RGB565 &c); virtual void scanline_convert(PenType type, conversion_callback_func callback); @@ -483,6 +485,7 @@ namespace pimoroni { void set_pen(uint8_t r, uint8_t g, uint8_t b) override; void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; static size_t buffer_size(uint w, uint h) { return w * h / 8; @@ -511,6 +514,7 @@ namespace pimoroni { int reset_pen(uint8_t i) override; void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); void set_pixel_dither(const Point &p, const RGB &c) override; @@ -541,6 +545,7 @@ namespace pimoroni { int reset_pen(uint8_t i) override; void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); void set_pixel_dither(const Point &p, const RGB &c) override; @@ -559,6 +564,7 @@ namespace pimoroni { int create_pen(uint8_t r, uint8_t g, uint8_t b) override; void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; void set_pixel_dither(const Point &p, const RGB &c) override; void set_pixel_dither(const Point &p, const RGB565 &c) override; @@ -579,6 +585,7 @@ namespace pimoroni { void set_pen(uint8_t r, uint8_t g, uint8_t b) override; int create_pen(uint8_t r, uint8_t g, uint8_t b) override; void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; static size_t buffer_size(uint w, uint h) { return w * h * sizeof(RGB565); } diff --git a/libraries/pico_graphics/pico_graphics_pen_1bit.cpp b/libraries/pico_graphics/pico_graphics_pen_1bit.cpp index af052d4b..ef0f2d0b 100644 --- a/libraries/pico_graphics/pico_graphics_pen_1bit.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_1bit.cpp @@ -32,4 +32,29 @@ namespace pimoroni { *f |= (color << bo); } + void PicoGraphics_Pen1Bit::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + uint8_t *f = &buf[(p.x / 8) + (p.y * bounds.w / 8)]; + + uint bo = 7 - (p.x & 0b111); + + // TODO: this could trivially be sped up by processing single bits only at + // the start and the end of the span and writing full bytes (8 pixels at + // a time) in the middle portion of the span. would only be more efficient + // for longer spans (probably around 20 pixels or more) + while(l--) { + // forceably clear the bit and then set to the correct value + *f &= ~(1U << bo); + *f |= (color << bo); + + if(bo == 0) { // last bit of this byte? + // move to next byte in framebuffer and reset the bit offset + f++; bo = 8; + } + + bo--; + } + } + } \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics_pen_p4.cpp b/libraries/pico_graphics/pico_graphics_pen_p4.cpp index 17bf6b6c..11fbeb99 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p4.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p4.cpp @@ -1,6 +1,7 @@ #include "pico_graphics.hpp" namespace pimoroni { + PicoGraphics_PenP4::PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer) : PicoGraphics(width, height, frame_buffer) { this->pen_type = PEN_P4; @@ -19,7 +20,7 @@ namespace pimoroni { } void PicoGraphics_PenP4::set_pen(uint c) { color = c & 0xf; - } + } void PicoGraphics_PenP4::set_pen(uint8_t r, uint8_t g, uint8_t b) { int pen = RGB(r, g, b).closest(palette, palette_size); if(pen != -1) color = pen; @@ -61,7 +62,25 @@ namespace pimoroni { *f &= m; // clear bits *f |= b; // set value } - + + void PicoGraphics_PenP4::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + uint8_t *f = &buf[(p.x / 2) + (p.y * bounds.w / 2)]; + + // doubled up color value, so the color is stored in both nibbles + uint8_t cc = color | (color << 4); + + // handle the first pixel if not byte aligned + if(p.x & 0b1) {*f &= 0b11110000; *f |= (cc & 0b00001111); f++; l--;} + + // write any double nibble pixels + while(l > 1) {*f++ = cc; l -= 2;} + + // handle the last pixel if not byte aligned + if(l) {*f &= 0b00001111; *f |= (cc & 0b11110000);} + } + void PicoGraphics_PenP4::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates) { RGB error; for(size_t i = 0; i < candidates.size(); i++) { diff --git a/libraries/pico_graphics/pico_graphics_pen_p8.cpp b/libraries/pico_graphics/pico_graphics_pen_p8.cpp index 7f1f60c7..a2f3aad1 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p8.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p8.cpp @@ -50,6 +50,16 @@ namespace pimoroni { buf[p.y * bounds.w + p.x] = color; } + void PicoGraphics_PenP8::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + buf = &buf[p.y * bounds.w + p.x]; + + while(l--) { + *buf++ = color; + } + } + void PicoGraphics_PenP8::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates) { RGB error; for(size_t i = 0; i < candidates.size(); i++) { diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp index 9fb7bb1c..d99970f0 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp @@ -22,6 +22,15 @@ namespace pimoroni { uint8_t *buf = (uint8_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } + void PicoGraphics_PenRGB332::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + buf = &buf[p.y * bounds.w + p.x]; + + while(l--) { + *buf++ = color; + } + } void PicoGraphics_PenRGB332::set_pixel_dither(const Point &p, const RGB &c) { if(!bounds.contains(p)) return; static uint8_t _odm[16] = { diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp index cdfa0b32..37520703 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp @@ -22,4 +22,13 @@ namespace pimoroni { uint16_t *buf = (uint16_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } + void PicoGraphics_PenRGB565::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint16_t *buf = (uint16_t *)frame_buffer; + buf = &buf[p.y * bounds.w + p.x]; + + while(l--) { + *buf++ = color; + } + } } \ No newline at end of file From b0a386f240991d95ea6e18c19275115748c2b4c8 Mon Sep 17 00:00:00 2001 From: jon Date: Fri, 17 Jun 2022 10:37:54 +0100 Subject: [PATCH 78/84] PicoGraphics: RGB332 use 332->565 flash LUT. --- libraries/pico_graphics/pico_graphics.hpp | 265 ++---------------- .../pico_graphics_pen_rgb332.cpp | 14 +- 2 files changed, 18 insertions(+), 261 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 0fb43837..9493acb0 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -126,255 +126,22 @@ namespace pimoroni { }; static const RGB565 rgb332_to_rgb565_lut[256] = { - 0x0000, 0x0800, 0x1000, 0x1800, 0x0001, 0x0801, 0x1001, 0x1801, -0x0002, -0x0802, -0x1002, -0x1802, -0x0003, -0x0803, -0x1003, -0x1803, -0x0004, -0x0804, -0x1004, -0x1804, -0x0005, -0x0805, -0x1005, -0x1805, -0x0006, -0x0806, -0x1006, -0x1806, -0x0007, -0x0807, -0x1007, -0x1807, -0x0020, -0x0820, -0x1020, -0x1820, -0x0021, -0x0821, -0x1021, -0x1821, -0x0022, -0x0822, -0x1022, -0x1822, -0x0023, -0x0823, -0x1023, -0x1823, -0x0024, -0x0824, -0x1024, -0x1824, -0x0025, -0x0825, -0x1025, -0x1825, -0x0026, -0x0826, -0x1026, -0x1826, -0x0027, -0x0827, -0x1027, -0x1827, -0x0040, -0x0840, -0x1040, -0x1840, -0x0041, -0x0841, -0x1041, -0x1841, -0x0042, -0x0842, -0x1042, -0x1842, -0x0043, -0x0843, -0x1043, -0x1843, -0x0044, -0x0844, -0x1044, -0x1844, -0x0045, -0x0845, -0x1045, -0x1845, -0x0046, -0x0846, -0x1046, -0x1846, -0x0047, -0x0847, -0x1047, -0x1847, -0x0060, -0x0860, -0x1060, -0x1860, -0x0061, -0x0861, -0x1061, -0x1861, -0x0062, -0x0862, -0x1062, -0x1862, -0x0063, -0x0863, -0x1063, -0x1863, -0x0064, -0x0864, -0x1064, -0x1864, -0x0065, -0x0865, -0x1065, -0x1865, -0x0066, -0x0866, -0x1066, -0x1866, -0x0067, -0x0867, -0x1067, -0x1867, -0x0080, -0x0880, -0x1080, -0x1880, -0x0081, -0x0881, -0x1081, -0x1881, -0x0082, -0x0882, -0x1082, -0x1882, -0x0083, -0x0883, -0x1083, -0x1883, -0x0084, -0x0884, -0x1084, -0x1884, -0x0085, -0x0885, -0x1085, -0x1885, -0x0086, -0x0886, -0x1086, -0x1886, -0x0087, -0x0887, -0x1087, -0x1887, -0x00a0, -0x08a0, -0x10a0, -0x18a0, -0x00a1, -0x08a1, -0x10a1, -0x18a1, -0x00a2, -0x08a2, -0x10a2, -0x18a2, -0x00a3, -0x08a3, -0x10a3, -0x18a3, -0x00a4, -0x08a4, -0x10a4, -0x18a4, -0x00a5, -0x08a5, -0x10a5, -0x18a5, -0x00a6, -0x08a6, -0x10a6, -0x18a6, -0x00a7, -0x08a7, -0x10a7, -0x18a7, -0x00c0, -0x08c0, -0x10c0, -0x18c0, -0x00c1, -0x08c1, -0x10c1, -0x18c1, -0x00c2, -0x08c2, -0x10c2, -0x18c2, -0x00c3, -0x08c3, -0x10c3, -0x18c3, -0x00c4, -0x08c4, -0x10c4, -0x18c4, -0x00c5, -0x08c5, -0x10c5, -0x18c5, -0x00c6, -0x08c6, -0x10c6, -0x18c6, -0x00c7, -0x08c7, -0x10c7, -0x18c7, -0x00e0, -0x08e0, -0x10e0, -0x18e0, -0x00e1, -0x08e1, -0x10e1, -0x18e1, -0x00e2, -0x08e2, -0x10e2, -0x18e2, -0x00e3, -0x08e3, -0x10e3, -0x18e3, -0x00e4, -0x08e4, -0x10e4, -0x18e4, -0x00e5, -0x08e5, -0x10e5, -0x18e5, -0x00e6, -0x08e6, -0x10e6, -0x18e6, -0x00e7, -0x08e7, -0x10e7, -0x18e7, + 0x0000, 0x0800, 0x1000, 0x1800, 0x0001, 0x0801, 0x1001, 0x1801, 0x0002, 0x0802, 0x1002, 0x1802, 0x0003, 0x0803, 0x1003, 0x1803, + 0x0004, 0x0804, 0x1004, 0x1804, 0x0005, 0x0805, 0x1005, 0x1805, 0x0006, 0x0806, 0x1006, 0x1806, 0x0007, 0x0807, 0x1007, 0x1807, + 0x0020, 0x0820, 0x1020, 0x1820, 0x0021, 0x0821, 0x1021, 0x1821, 0x0022, 0x0822, 0x1022, 0x1822, 0x0023, 0x0823, 0x1023, 0x1823, + 0x0024, 0x0824, 0x1024, 0x1824, 0x0025, 0x0825, 0x1025, 0x1825, 0x0026, 0x0826, 0x1026, 0x1826, 0x0027, 0x0827, 0x1027, 0x1827, + 0x0040, 0x0840, 0x1040, 0x1840, 0x0041, 0x0841, 0x1041, 0x1841, 0x0042, 0x0842, 0x1042, 0x1842, 0x0043, 0x0843, 0x1043, 0x1843, + 0x0044, 0x0844, 0x1044, 0x1844, 0x0045, 0x0845, 0x1045, 0x1845, 0x0046, 0x0846, 0x1046, 0x1846, 0x0047, 0x0847, 0x1047, 0x1847, + 0x0060, 0x0860, 0x1060, 0x1860, 0x0061, 0x0861, 0x1061, 0x1861, 0x0062, 0x0862, 0x1062, 0x1862, 0x0063, 0x0863, 0x1063, 0x1863, + 0x0064, 0x0864, 0x1064, 0x1864, 0x0065, 0x0865, 0x1065, 0x1865, 0x0066, 0x0866, 0x1066, 0x1866, 0x0067, 0x0867, 0x1067, 0x1867, + 0x0080, 0x0880, 0x1080, 0x1880, 0x0081, 0x0881, 0x1081, 0x1881, 0x0082, 0x0882, 0x1082, 0x1882, 0x0083, 0x0883, 0x1083, 0x1883, + 0x0084, 0x0884, 0x1084, 0x1884, 0x0085, 0x0885, 0x1085, 0x1885, 0x0086, 0x0886, 0x1086, 0x1886, 0x0087, 0x0887, 0x1087, 0x1887, + 0x00a0, 0x08a0, 0x10a0, 0x18a0, 0x00a1, 0x08a1, 0x10a1, 0x18a1, 0x00a2, 0x08a2, 0x10a2, 0x18a2, 0x00a3, 0x08a3, 0x10a3, 0x18a3, + 0x00a4, 0x08a4, 0x10a4, 0x18a4, 0x00a5, 0x08a5, 0x10a5, 0x18a5, 0x00a6, 0x08a6, 0x10a6, 0x18a6, 0x00a7, 0x08a7, 0x10a7, 0x18a7, + 0x00c0, 0x08c0, 0x10c0, 0x18c0, 0x00c1, 0x08c1, 0x10c1, 0x18c1, 0x00c2, 0x08c2, 0x10c2, 0x18c2, 0x00c3, 0x08c3, 0x10c3, 0x18c3, + 0x00c4, 0x08c4, 0x10c4, 0x18c4, 0x00c5, 0x08c5, 0x10c5, 0x18c5, 0x00c6, 0x08c6, 0x10c6, 0x18c6, 0x00c7, 0x08c7, 0x10c7, 0x18c7, + 0x00e0, 0x08e0, 0x10e0, 0x18e0, 0x00e1, 0x08e1, 0x10e1, 0x18e1, 0x00e2, 0x08e2, 0x10e2, 0x18e2, 0x00e3, 0x08e3, 0x10e3, 0x18e3, + 0x00e4, 0x08e4, 0x10e4, 0x18e4, 0x00e5, 0x08e5, 0x10e5, 0x18e5, 0x00e6, 0x08e6, 0x10e6, 0x18e6, 0x00e7, 0x08e7, 0x10e7, 0x18e7, }; class PicoGraphics { diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp index d99970f0..3489c1d2 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp @@ -94,17 +94,6 @@ namespace pimoroni { void PicoGraphics_PenRGB332::scanline_convert(PenType type, conversion_callback_func callback) { if(type == PEN_RGB565) { - static RGB565 cache[256]; - for(auto i = 0u; i < 256; i++) { - cache[i] = rgb332_to_rgb565_lut[i]; // defined in pico_graphics.hpp - } - - // 2ms slower, I swear! - /* - static RGB565 cache[256]; - memcpy(cache, rgb332_to_rgb565_lut, 256 * sizeof(RGB565)); - */ - // Treat our void* frame_buffer as uint8_t uint8_t *src = (uint8_t *)frame_buffer; @@ -112,7 +101,8 @@ namespace pimoroni { uint16_t row_buf[bounds.w]; for(auto y = 0; y < bounds.h; y++) { for(auto x = 0; x < bounds.w; x++) { - row_buf[x] = cache[*src]; + row_buf[x] = rgb332_to_rgb565_lut[*src]; + src++; } // Callback to the driver with the row data From 122e57aa9a8fad3e16ab491914eec4b7f28a0e16 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 17 Jun 2022 11:29:24 +0100 Subject: [PATCH 79/84] CI: Build Tufty 2040 + Board fixups. Add board fixups including Pico SDK board .h and MicroPython board dir since these are not yet upstream. --- .github/workflows/micropython.yml | 8 +++ micropython/_board/board-fixup.sh | 16 +++++ .../tufty2040/PIMORONI_TUFTY2040/board.json | 21 ++++++ .../PIMORONI_TUFTY2040/mpconfigboard.cmake | 1 + .../PIMORONI_TUFTY2040/mpconfigboard.h | 28 ++++++++ .../_board/tufty2040/pimoroni_tufty2040.h | 68 +++++++++++++++++++ .../modules/micropython-tufty2040.cmake | 7 ++ 7 files changed, 149 insertions(+) create mode 100755 micropython/_board/board-fixup.sh create mode 100644 micropython/_board/tufty2040/PIMORONI_TUFTY2040/board.json create mode 100644 micropython/_board/tufty2040/PIMORONI_TUFTY2040/mpconfigboard.cmake create mode 100644 micropython/_board/tufty2040/PIMORONI_TUFTY2040/mpconfigboard.h create mode 100644 micropython/_board/tufty2040/pimoroni_tufty2040.h create mode 100644 micropython/modules/micropython-tufty2040.cmake diff --git a/.github/workflows/micropython.yml b/.github/workflows/micropython.yml index 5450247a..8a2c8523 100644 --- a/.github/workflows/micropython.yml +++ b/.github/workflows/micropython.yml @@ -66,6 +66,8 @@ jobs: board: PIMORONI_PICOLIPO_4MB - name: picolipo_16mb board: PIMORONI_PICOLIPO_16MB + - name: tufty2040 + board: PIMORONI_TUFTY2040 env: # MicroPython version will be contained in github.event.release.tag_name for releases @@ -107,6 +109,12 @@ jobs: 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 ${{matrix.name}} ${{matrix.board}} ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board - name: Configure MicroPython shell: bash diff --git a/micropython/_board/board-fixup.sh b/micropython/_board/board-fixup.sh new file mode 100755 index 00000000..ecc4fd60 --- /dev/null +++ b/micropython/_board/board-fixup.sh @@ -0,0 +1,16 @@ +NAME=$1 +BOARD=$2 +FIXUP_DIR=$3 +MPY_DIR=`pwd` + +echo "Fixup: $NAME $BOARD $MPY_DIR" + +if [[ ! -f "$MPY_DIR/../../lib/pico-sdk/src/boards/include/boards/pimoroni_$NAME.h" ]]; then + echo "Missing Pico SDK board .h. Copying: $FIXUP_DIR/$NAME/pimoroni_$NAME.h to $MPY_DIR/../../lib/pico-sdk/src/boards/include/boards/pimoroni_$NAME.h" + cp "$FIXUP_DIR/$NAME/pimoroni_$NAME.h" "$MPY_DIR/../../lib/pico-sdk/src/boards/include/boards/pimoroni_$NAME.h" +fi + +if [[ ! -d "$MPY_DIR/boards/$BOARD" ]]; then + echo "Missing board dir. Copying: $FIXUP_DIR/$NAME/$BOARD/ to $MPY_DIR/boards/" + cp -r "$FIXUP_DIR/$NAME/$BOARD/" "$MPY_DIR/boards/" +fi \ No newline at end of file diff --git a/micropython/_board/tufty2040/PIMORONI_TUFTY2040/board.json b/micropython/_board/tufty2040/PIMORONI_TUFTY2040/board.json new file mode 100644 index 00000000..c2bfdff0 --- /dev/null +++ b/micropython/_board/tufty2040/PIMORONI_TUFTY2040/board.json @@ -0,0 +1,21 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "SPI Flash", + "STEMMA QT/QWIIC", + "USB-C", + "320*240 LCD", + "Buttons", + "LiPo/Battery Support" + ], + "images": [ + ], + "mcu": "rp2040", + "product": "Tufty2040 (8MiB)", + "thumbnail": "", + "url": "https://shop.pimoroni.com/products/pimoroni-tufty-2040", + "vendor": "Pimoroni" +} diff --git a/micropython/_board/tufty2040/PIMORONI_TUFTY2040/mpconfigboard.cmake b/micropython/_board/tufty2040/PIMORONI_TUFTY2040/mpconfigboard.cmake new file mode 100644 index 00000000..f14f21fd --- /dev/null +++ b/micropython/_board/tufty2040/PIMORONI_TUFTY2040/mpconfigboard.cmake @@ -0,0 +1 @@ +# cmake file for Pimoroni Tufty 2040 diff --git a/micropython/_board/tufty2040/PIMORONI_TUFTY2040/mpconfigboard.h b/micropython/_board/tufty2040/PIMORONI_TUFTY2040/mpconfigboard.h new file mode 100644 index 00000000..1140d377 --- /dev/null +++ b/micropython/_board/tufty2040/PIMORONI_TUFTY2040/mpconfigboard.h @@ -0,0 +1,28 @@ +// https://shop.pimoroni.com/products/pimoroni-tufty-2040 + +#define MICROPY_HW_BOARD_NAME "Pimoroni Tufty 2040" +#define MICROPY_HW_FLASH_STORAGE_BYTES (7 * 1024 * 1024) + +#define MICROPY_HW_USB_VID (0x2E8A) +#define MICROPY_HW_USB_PID (0x1002) + +#define MICROPY_HW_UART1_TX (8) +#define MICROPY_HW_UART1_RX (9) +#define MICROPY_HW_UART1_CTS (10) +#define MICROPY_HW_UART1_RTS (11) + +// Qwiic on I2C0 +#define MICROPY_HW_I2C0_SCL (4) +#define MICROPY_HW_I2C0_SDA (5) + +#define MICROPY_HW_SPI0_SCK (18) +#define MICROPY_HW_SPI0_MOSI (19) +#define MICROPY_HW_SPI0_MISO (16) + +// User LED GPIO25 + +// VBUS_SENSE GPIO24 + +// BAT_SENSE GPIO29 + +// Boot button GPIO23 diff --git a/micropython/_board/tufty2040/pimoroni_tufty2040.h b/micropython/_board/tufty2040/pimoroni_tufty2040.h new file mode 100644 index 00000000..28a6a24f --- /dev/null +++ b/micropython/_board/tufty2040/pimoroni_tufty2040.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +// ----------------------------------------------------- +// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO +// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES +// ----------------------------------------------------- + +#ifndef _BOARDS_PIMORONI_TUFTY_2040_H +#define _BOARDS_PIMORONI_TUFTY_2040_H + +// For board detection +#define PIMORONI_TUFTY_2040 + +// --- LED --- +#ifndef PICO_DEFAULT_LED_PIN +#define PICO_DEFAULT_LED_PIN 25 +#endif +// no PICO_DEFAULT_WS2812_PIN + +// --- I2C --- +#ifndef PICO_DEFAULT_I2C +#define PICO_DEFAULT_I2C 0 +#endif +#ifndef PICO_DEFAULT_I2C_SDA_PIN +#define PICO_DEFAULT_I2C_SDA_PIN 4 +#endif +#ifndef PICO_DEFAULT_I2C_SCL_PIN +#define PICO_DEFAULT_I2C_SCL_PIN 5 +#endif + +// --- SPI --- +#ifndef PICO_DEFAULT_SPI +#define PICO_DEFAULT_SPI 0 +#endif +#ifndef PICO_DEFAULT_SPI_SCK_PIN +#define PICO_DEFAULT_SPI_SCK_PIN 18 +#endif +#ifndef PICO_DEFAULT_SPI_TX_PIN +#define PICO_DEFAULT_SPI_TX_PIN 19 +#endif +#ifndef PICO_DEFAULT_SPI_RX_PIN +#define PICO_DEFAULT_SPI_RX_PIN 16 +#endif +#ifndef PICO_DEFAULT_SPI_CSN_PIN +#define PICO_DEFAULT_SPI_CSN_PIN 17 +#endif + +// --- FLASH --- +#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1 + +#ifndef PICO_FLASH_SPI_CLKDIV +#define PICO_FLASH_SPI_CLKDIV 2 +#endif + +#ifndef PICO_FLASH_SIZE_BYTES +#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024) +#endif + +// All boards have B1 RP2040 +#ifndef PICO_RP2040_B0_SUPPORTED +#define PICO_RP2040_B0_SUPPORTED 0 +#endif + +#endif diff --git a/micropython/modules/micropython-tufty2040.cmake b/micropython/modules/micropython-tufty2040.cmake new file mode 100644 index 00000000..d7f7a2ca --- /dev/null +++ b/micropython/modules/micropython-tufty2040.cmake @@ -0,0 +1,7 @@ +include_directories(${CMAKE_CURRENT_LIST_DIR}/../../) + +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}/../../") + +include(micropython-common) From 0258247b4b8ad69b8d51568b8af991ab24573486 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Fri, 17 Jun 2022 11:25:41 +0100 Subject: [PATCH 80/84] PCF85063A: Change location of some constants. --- micropython/modules/pcf85063a/pcf85063a.c | 29 +++++++++++------------ 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/micropython/modules/pcf85063a/pcf85063a.c b/micropython/modules/pcf85063a/pcf85063a.c index 971240c1..ebd5e9fa 100644 --- a/micropython/modules/pcf85063a/pcf85063a.c +++ b/micropython/modules/pcf85063a/pcf85063a.c @@ -42,6 +42,20 @@ STATIC const mp_rom_map_elem_t PCF85063A_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_unset_timer), MP_ROM_PTR(&PCF85063A_unset_timer_obj) }, { MP_ROM_QSTR(MP_QSTR_set_clock_output), MP_ROM_PTR(&PCF85063A_set_clock_output_obj) }, + + { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_32768HZ), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_16384HZ), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_8192HZ), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_4096HZ), MP_ROM_INT(3) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_2048HZ), MP_ROM_INT(4) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_1024HZ), MP_ROM_INT(5) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_1HZ), MP_ROM_INT(6) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_OFF), MP_ROM_INT(7) }, + + { MP_ROM_QSTR(MP_QSTR_TIMER_TICK_4096HZ), MP_ROM_INT(0b00) }, + { MP_ROM_QSTR(MP_QSTR_TIMER_TICK_64HZ), MP_ROM_INT(0b01) }, + { MP_ROM_QSTR(MP_QSTR_TIMER_TICK_1HZ), MP_ROM_INT(0b10) }, + { MP_ROM_QSTR(MP_QSTR_TIMER_TICK_1_OVER_60HZ), MP_ROM_INT(0b11) }, }; STATIC MP_DEFINE_CONST_DICT(PCF85063A_locals_dict, PCF85063A_locals_dict_table); @@ -61,21 +75,6 @@ const mp_obj_type_t pcf85063a_PCF85063A_type = { STATIC const mp_map_elem_t pcf85063a_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pcf85063a) }, { MP_OBJ_NEW_QSTR(MP_QSTR_PCF85063A), (mp_obj_t)&pcf85063a_PCF85063A_type }, - - { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_32768HZ), MP_ROM_INT(0) }, - { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_16384HZ), MP_ROM_INT(1) }, - { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_8192HZ), MP_ROM_INT(2) }, - { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_4096HZ), MP_ROM_INT(3) }, - { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_2048HZ), MP_ROM_INT(4) }, - { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_1024HZ), MP_ROM_INT(5) }, - { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_1HZ), MP_ROM_INT(6) }, - { MP_ROM_QSTR(MP_QSTR_CLOCK_OUT_OFF), MP_ROM_INT(7) }, - - { MP_ROM_QSTR(MP_QSTR_TIMER_TICK_4096HZ), MP_ROM_INT(0b00) }, - { MP_ROM_QSTR(MP_QSTR_TIMER_TICK_64HZ), MP_ROM_INT(0b01) }, - { MP_ROM_QSTR(MP_QSTR_TIMER_TICK_1HZ), MP_ROM_INT(0b10) }, - { MP_ROM_QSTR(MP_QSTR_TIMER_TICK_1_OVER_60HZ), MP_ROM_INT(0b11) }, - { MP_ROM_QSTR(MP_QSTR_MONDAY), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_TUESDAY), MP_ROM_INT(1) }, { MP_ROM_QSTR(MP_QSTR_WEDNESDAY), MP_ROM_INT(2) }, From ef1bdff2bd70488bee45f00311cb0828db86ab8c Mon Sep 17 00:00:00 2001 From: thirdr Date: Fri, 17 Jun 2022 14:09:02 +0100 Subject: [PATCH 81/84] Tufty2040: MicroPython examples. Co-authored-by: Phil Howard --- micropython/examples/tufty2040/clock.py | 151 ++++++++++++++ micropython/examples/tufty2040/game.py | 197 ++++++++++++++++++ micropython/examples/tufty2040/namebadge.py | 68 ++++++ micropython/examples/tufty2040/scrolltext.py | 46 ++++ .../examples/tufty2040/sketchysketch.py | 89 ++++++++ micropython/examples/tufty2040/textwave.py | 48 +++++ 6 files changed, 599 insertions(+) create mode 100644 micropython/examples/tufty2040/clock.py create mode 100644 micropython/examples/tufty2040/game.py create mode 100644 micropython/examples/tufty2040/namebadge.py create mode 100644 micropython/examples/tufty2040/scrolltext.py create mode 100644 micropython/examples/tufty2040/sketchysketch.py create mode 100644 micropython/examples/tufty2040/textwave.py diff --git a/micropython/examples/tufty2040/clock.py b/micropython/examples/tufty2040/clock.py new file mode 100644 index 00000000..047bb89d --- /dev/null +++ b/micropython/examples/tufty2040/clock.py @@ -0,0 +1,151 @@ +import time +import machine +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 + +rtc = machine.RTC() +display = PicoGraphics(display=DISPLAY_TUFTY_2040) + +# Tufty constants. +A = 7 +B = 8 +C = 15 +UP = 22 +DOWN = 6 +LED = 25 + +WIDTH, HEIGHT = display.get_bounds() +display.set_backlight(1.0) + +# Buttons +button_a = machine.Pin(A, machine.Pin.IN) +button_b = machine.Pin(B, machine.Pin.IN) +button_c = machine.Pin(C, machine.Pin.IN) +button_up = machine.Pin(UP, machine.Pin.IN) +button_down = machine.Pin(DOWN, machine.Pin.IN) + +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) + +PINK = display.create_pen(214, 28, 78) +ORANGE_1 = display.create_pen(247, 126, 33) +ORANGE_2 = display.create_pen(250, 194, 19) + +cursors = ["hour", "minute"] +set_clock = False +cursor = 0 +last = 0 + + +def days_in_month(month, year): + if month == 2 and ((year % 4 == 0 and year % 100 != 0) or year % 400 == 0): + return 29 + return (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[month - 1] + + +# Button handling function +def button(pin): + global last, set_clock, cursor, year, month, day, hour, minute + + time.sleep(0.01) + if not pin.value(): + return + + if button_a.value() and button_c.value(): + machine.reset() + + adjust = 0 + changed = False + + if pin == button_b: + set_clock = not set_clock + changed = True + if not set_clock: + rtc.datetime((year, month, day, 0, hour, minute, second, 0)) + + if set_clock: + if pin == button_c: + cursor += 1 + cursor %= len(cursors) + + if pin == button_a: + cursor -= 1 + cursor %= len(cursors) + + if pin == button_up: + adjust = 1 + + if pin == button_down: + adjust = -1 + + if cursors[cursor] == "hour": + hour += adjust + hour %= 24 + if cursors[cursor] == "minute": + minute += adjust + minute %= 60 + + if set_clock or changed: + draw_clock() + + +# Register the button handling function with the buttons +button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button) +button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) + + +def draw_clock(): + + display.set_pen(WHITE) + display.clear() + + hr = "{:02}".format(hour) + min = "{:02}".format(minute) + sec = "{:02}".format(second) + + hr_width = display.measure_text(hr, 1) + hr_offset = 15 + + minute_width = display.measure_text(min, 1) + minute_offset = 15 + + second_width = display.measure_text(sec, 1) + second_offset = 5 + + display.set_pen(PINK) + display.rectangle(10, 10, (hour * 13), 60) + display.set_pen(ORANGE_1) + display.rectangle(10, 85, (minute * 5), 60) + display.set_pen(ORANGE_2) + display.rectangle(10, 160, (second * 5), 60) + + display.set_pen(WHITE) + display.text(hr, (hour * 13) - hr_width - hr_offset, 45, 10, 3) + display.text(min, (minute * 5) - minute_width - minute_offset, 120, 10, 3) + display.text(sec, (second * 5) - second_width - second_offset, 202, 10, 2) + + display.set_pen(BLACK) + + if set_clock: + + if cursors[cursor] == "hour": + display.line(5, 10, 5, 70) + if cursors[cursor] == "minute": + display.line(5, 85, 5, 145) + + display.update() + + +year, month, day, wd, hour, minute, second, _ = rtc.datetime() + +last_second = second + +while True: + if not set_clock: + year, month, day, wd, hour, minute, second, _ = rtc.datetime() + if second != last_second: + draw_clock() + last_second = second + time.sleep(0.01) diff --git a/micropython/examples/tufty2040/game.py b/micropython/examples/tufty2040/game.py new file mode 100644 index 00000000..e375d19e --- /dev/null +++ b/micropython/examples/tufty2040/game.py @@ -0,0 +1,197 @@ +import time +import random +from pimoroni import Button +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 + +display = PicoGraphics(display=DISPLAY_TUFTY_2040) +WIDTH, HEIGHT = display.get_bounds() + +# Load the spritsheets so we can flip between them +tilemap = bytearray(128 * 128) +open("s4m_ur4i-pirate-tilemap.rgb332", "rb").readinto(tilemap) + +character = bytearray(128 * 128) +open("s4m_ur4i-pirate-characters.rgb332", "rb").readinto(character) + +display.set_spritesheet(character) + + +# Buttons +button_a = Button(7, invert=False) +button_b = Button(8, invert=False) +button_c = Button(9, invert=False) +button_up = Button(22, invert=False) +button_down = Button(6, invert=False) + +display.set_backlight(1.0) +display.set_pen(255) +display.clear() + + +class Player(): + def __init__(self): + self.reset() + + def reset(self): + self.x = 150 + self.y = 180 + self.w = 15 + self.h = 30 + self.speed = 10 + self.is_alive = True + self.lives = 3 + self.score = 0 + self.moving = 0 + + def move(self, x, y): + if self.x + x > 0 - self.w and self.x + x < WIDTH - self.w: + self.x += x + self.y += y + + def sprite(self): + display.set_spritesheet(character) + display.sprite(1, 1 if self.moving else 0, self.x, self.y, 4, 0) + + +class Treasure(): + def __init__(self): + self.w = 16 + self.h = 16 + self.randomize() + + def sprite(self): + if not self.enabled: + return + display.set_spritesheet(tilemap) + display.sprite(4, 2, self.x, self.y, 3, 0) + + def randomize(self): + self.enabled = True + self.x = random.randint(15, WIDTH - 60) + self.y = HEIGHT - 50 + + +class Block(): + def __init__(self): + self.w = 16 + self.h = 16 + self.is_alive = True + self.randomize() + + def move(self): + self.y += self.speed + + def sprite(self): + display.set_spritesheet(character) + display.sprite(10, 8, self.x, self.y, 4, 0) + + def randomize(self): + self.last_update = time.time() + self.x = random.randint(10, WIDTH - self.w - 10) + self.y = -self.h + self.speed = random.randint(4, 12) + + +class Game(): + def __init__(self): + self.player = Player() + self.block = [] + self.last_new_block = 0 + + self.treasure = Treasure() + self.last_treasure = 0 + + self.SKY = display.create_pen(72, 180, 224) + + for i in range(5): + self.block.append(Block()) + + def reset(self): + for block in self.block: + block.randomize() + + self.treasure.randomize() + self.player.reset() + + def get_input(self): + if button_c.read(): + self.player.move(self.player.speed, 0) + self.player.moving = 0 + if button_a.read(): + self.player.move(-self.player.speed, 0) + self.player.moving = 1 + + def background(self): + display.set_spritesheet(tilemap) + display.set_pen(self.SKY) + display.clear() + + for i in range(WIDTH / 32): + display.sprite(1, 2, i * 32, 210, 4, 0) + + def draw(self): + self.background() + for block in self.block: + block.sprite() + display.set_pen(255) + display.text("Score: " + str(self.player.score), 10, 10, 320, 2) + self.treasure.sprite() + display.set_pen(0) + self.player.sprite() + display.update() + time.sleep(0.01) + + def check_collision(self, a, b): + return a.x + a.w >= b.x and a.x <= b.x + b.w and a.y + a.h >= b.y and a.y <= b.y + b.h + + def update(self): + for block in self.block: + block.move() + if block.y > HEIGHT: + block.randomize() + + if block.y + block.h >= self.player.y and self.check_collision(self.player, block): + block.randomize() + self.player.is_alive = False + + if self.treasure.enabled: + if self.check_collision(self.player, self.treasure): + self.player.score += 1 + self.treasure.enabled = False + self.last_treasure = time.time() + + if time.time() - self.last_treasure > 2: + if not self.treasure.enabled: + self.treasure.randomize() + + if self.player.lives == 0: + self.player.is_alive = False + + +game = Game() + +while True: + game.background() + display.set_pen(255) + display.text("ARGH!", 40, 35, 200, 10) + display.text("Press B to Start", 80, 150, 180, 2) + display.update() + + while not button_b.read(): + pass + + while game.player.is_alive: + game.get_input() + game.update() + game.draw() + + game.background() + display.set_pen(255) + display.text("OOPS!", 40, 35, 200, 10) + display.text("Your score: " + str(game.player.score), 50, 150, 180, 2) + display.update() + + while not button_b.read(): + pass + + game.reset() diff --git a/micropython/examples/tufty2040/namebadge.py b/micropython/examples/tufty2040/namebadge.py new file mode 100644 index 00000000..cc0c655f --- /dev/null +++ b/micropython/examples/tufty2040/namebadge.py @@ -0,0 +1,68 @@ +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 + +display = PicoGraphics(display=DISPLAY_TUFTY_2040) +WIDTH, HEIGHT = display.get_bounds() +display.set_backlight(1.0) + +# Tufty constants +A = 7 +B = 8 +C = 15 +UP = 22 +DOWN = 6 +LED = 25 + +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) +RED = display.create_pen(200, 0, 0) + +# Read name from file +try: + file = open("badge.txt", "r") + name = file.readline() + file.close() +except OSError: + name = "open name.txt in thonny to edit badge :)" + + +text_size = 12 +text_x = 0 +text_y = 100 + +# Clear the screen +display.set_pen(WHITE) +display.clear() +display.update() + + +# Draws a blank badge +def draw_badge(): + display.set_pen(RED) + display.rectangle(0, 0, WIDTH, 60) + display.rectangle(0, HEIGHT - 20, WIDTH, 50) + display.set_pen(WHITE) + display.text("HELLO", 125, 5, 0, 3) + display.text("My name is:", 110, 35, 320, 2) + display.update() + + +def calculate_text_size(): + global text_size + name_width = display.measure_text(name, text_size) + # Calculate the width of the text in pixels, adjusts according to the screen width + while name_width > 290: + text_size -= 1 + name_width = display.measure_text(name, text_size) + + # Calculate the margin to be applied on X + margin_x = (WIDTH - name_width) / 2 + + return int(margin_x) + + +draw_badge() +text_x = calculate_text_size() + +display.set_pen(BLACK) +display.text(name, text_x, text_y, 300, text_size) +display.update() diff --git a/micropython/examples/tufty2040/scrolltext.py b/micropython/examples/tufty2040/scrolltext.py new file mode 100644 index 00000000..9a57ca3f --- /dev/null +++ b/micropython/examples/tufty2040/scrolltext.py @@ -0,0 +1,46 @@ +import time +import math +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 + +display = PicoGraphics(display=DISPLAY_TUFTY_2040) + +display.set_backlight(1.0) + +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) + +# Reads name from file, and then closes the file. +try: + file = open("message.txt", "r") + message = file.readline() + file.close() +except OSError: + message = "CREATE MESSAGE.TXT IN THONNY :)" + +message_length = display.measure_text(message, 10) + +while True: + t = 0 # counter + x = 320 # Starting position of message, begins just off screen. + offset = 10 + + # How many loops it will take to scroll the whole message plus a little extra margin. + scroll = (message_length / offset) + 30 + + while t < scroll: + step = t + t + y = int(80 + math.sin(step / 5) * 30) + h = 100 + math.sin(step / 5) * 100 + + x -= offset + + display.set_pen(WHITE) + display.clear() + + display.set_pen(BLACK) + display.text(message, x, y, message_length, 10) + display.update() + + time.sleep(0.02) + + t += 1 diff --git a/micropython/examples/tufty2040/sketchysketch.py b/micropython/examples/tufty2040/sketchysketch.py new file mode 100644 index 00000000..1964edd2 --- /dev/null +++ b/micropython/examples/tufty2040/sketchysketch.py @@ -0,0 +1,89 @@ +import time +from pimoroni import Button +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 + +display = PicoGraphics(display=DISPLAY_TUFTY_2040) + +# Tufty constants +A = 7 +B = 8 +C = 15 +UP = 22 +DOWN = 6 +LED = 25 + +WIDTH, HEIGHT = display.get_bounds() +display.set_backlight(1.0) + +# Buttons +button_a = Button(7, invert=False) +button_b = Button(8, invert=False) +button_c = Button(9, invert=False) +button_up = Button(22, invert=False) +button_down = Button(6, invert=False) + +# Pens +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) +RED = display.create_pen(200, 0, 0) +YELLOW = display.create_pen(255, 215, 0) + + +def draw_area(): + display.set_pen(RED) + display.clear() + + display.set_pen(YELLOW) + display.text("Sketchy-Sketch", 90, 5, 0, 2) + display.set_pen(WHITE) + display.circle(55, 215, 15) + display.circle(260, 215, 15) + display.rectangle(10, 25, 300, 170) + display.update() + + +position_x = 15 +position_y = 30 + +last_x = 15 +last_y = 30 + +draw_area() + +while True: + display.set_pen(0) + + if button_c.raw(): + if position_x < 308: + last_x = position_x + last_y = position_y + position_x += 2 + + if button_a.raw(): + if position_x > 12: + last_x = position_x + last_y = position_y + position_x -= 2 + + if button_up.raw(): + if position_y > 26: + last_x = position_x + last_y = position_y + position_y -= 2 + + if button_down.raw(): + if position_y < 193: + last_x = position_x + last_y = position_y + position_y += 2 + + if button_b.raw(): + draw_area() + position_x = 15 + position_y = 30 + last_x = 15 + last_y = 30 + + display.line(last_x, last_y, position_x, position_y) + display.update() + time.sleep(0.01) diff --git a/micropython/examples/tufty2040/textwave.py b/micropython/examples/tufty2040/textwave.py new file mode 100644 index 00000000..ffa90fc4 --- /dev/null +++ b/micropython/examples/tufty2040/textwave.py @@ -0,0 +1,48 @@ +import math +import time +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 + +display = PicoGraphics(display=DISPLAY_TUFTY_2040) + +WIDTH, HEIGHT = 320, 240 +display.set_backlight(1.0) + +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) + +display.set_pen(WHITE) +display.clear() +display.update() + +message = "HELLO WORLD!" + + +def calculate_text_size(text): + size = 20 + width = display.measure_text(text, size) + while width > 280 and size > 1: + size -= 1 + width = display.measure_text(text, size) + + return size + + +size = calculate_text_size(message) +length = len(message) + +while True: + display.set_pen(WHITE) + display.clear() + display.set_pen(BLACK) + + t = time.ticks_ms() / 10 / size + + left = int((WIDTH - ((length - 1) * size * 6)) / 2) + top = 120 - int((size * 6) / 2) + + for i in range(length): + step = t + i + y = top - math.sin(step / length * math.pi) * 10 + display.text(message[i], left + (i * size * 6), int(y), 0, size) + + display.update() From 3cd64202fd77d0fd090f2e7fe5be7a4b3d73862d Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 17 Jun 2022 14:24:23 +0100 Subject: [PATCH 82/84] MicroPython: Correct is not True usage. Co-authored-by: ZodiusInfuser --- micropython/examples/motor2040/led_rainbow.py | 2 +- micropython/examples/motor2040/motor_wave.py | 2 +- micropython/examples/motor2040/position_control.py | 2 +- micropython/examples/motor2040/position_on_velocity_control.py | 2 +- micropython/examples/motor2040/position_on_velocity_tuning.py | 2 +- micropython/examples/motor2040/position_tuning.py | 2 +- micropython/examples/motor2040/quad_position_wave.py | 2 +- micropython/examples/motor2040/quad_velocity_sequence.py | 2 +- micropython/examples/motor2040/reactive_encoder.py | 2 +- micropython/examples/motor2040/read_encoders.py | 2 +- micropython/examples/motor2040/read_sensors.py | 2 +- micropython/examples/motor2040/velocity_control.py | 2 +- micropython/examples/motor2040/velocity_tuning.py | 2 +- micropython/examples/servo2040/current_meter.py | 2 +- micropython/examples/servo2040/led_rainbow.py | 2 +- micropython/examples/servo2040/read_sensors.py | 2 +- micropython/examples/servo2040/sensor_feedback.py | 2 +- micropython/examples/servo2040/servo_wave.py | 2 +- micropython/examples/servo2040/simple_easing.py | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/micropython/examples/motor2040/led_rainbow.py b/micropython/examples/motor2040/led_rainbow.py index e20f1dd6..ce610891 100644 --- a/micropython/examples/motor2040/led_rainbow.py +++ b/micropython/examples/motor2040/led_rainbow.py @@ -30,7 +30,7 @@ led.start() hue = 0.0 # Make rainbows until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): hue += SPEED / 1000.0 diff --git a/micropython/examples/motor2040/motor_wave.py b/micropython/examples/motor2040/motor_wave.py index 7aab108b..e63e5c09 100644 --- a/micropython/examples/motor2040/motor_wave.py +++ b/micropython/examples/motor2040/motor_wave.py @@ -40,7 +40,7 @@ led.start() offset = 0.0 # Make waves until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): offset += SPEED / 1000.0 diff --git a/micropython/examples/motor2040/position_control.py b/micropython/examples/motor2040/position_control.py index 8a514738..9ffdb94b 100644 --- a/micropython/examples/motor2040/position_control.py +++ b/micropython/examples/motor2040/position_control.py @@ -66,7 +66,7 @@ start_value = 0.0 end_value = random.uniform(-POSITION_EXTENT, POSITION_EXTENT) # Continually move the motor until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Capture the state of the encoder capture = enc.capture() diff --git a/micropython/examples/motor2040/position_on_velocity_control.py b/micropython/examples/motor2040/position_on_velocity_control.py index 87e5e065..f996dd4b 100644 --- a/micropython/examples/motor2040/position_on_velocity_control.py +++ b/micropython/examples/motor2040/position_on_velocity_control.py @@ -73,7 +73,7 @@ start_value = 0.0 end_value = random.uniform(-POSITION_EXTENT, POSITION_EXTENT) # Continually move the motor until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Capture the state of the encoder capture = enc.capture() diff --git a/micropython/examples/motor2040/position_on_velocity_tuning.py b/micropython/examples/motor2040/position_on_velocity_tuning.py index 993b248a..fac44a76 100644 --- a/micropython/examples/motor2040/position_on_velocity_tuning.py +++ b/micropython/examples/motor2040/position_on_velocity_tuning.py @@ -71,7 +71,7 @@ update = 0 print_count = 0 # Continually move the motor until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Capture the state of the encoder capture = enc.capture() diff --git a/micropython/examples/motor2040/position_tuning.py b/micropython/examples/motor2040/position_tuning.py index 69e0df42..27218259 100644 --- a/micropython/examples/motor2040/position_tuning.py +++ b/micropython/examples/motor2040/position_tuning.py @@ -64,7 +64,7 @@ update = 0 print_count = 0 # Continually move the motor until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Capture the state of the encoder capture = enc.capture() diff --git a/micropython/examples/motor2040/quad_position_wave.py b/micropython/examples/motor2040/quad_position_wave.py index c9a0d6d2..deab932f 100644 --- a/micropython/examples/motor2040/quad_position_wave.py +++ b/micropython/examples/motor2040/quad_position_wave.py @@ -78,7 +78,7 @@ end_value = 270.0 captures = [None] * motor2040.NUM_MOTORS # Continually move the motor until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Capture the state of all the encoders for i in range(motor2040.NUM_MOTORS): diff --git a/micropython/examples/motor2040/quad_velocity_sequence.py b/micropython/examples/motor2040/quad_velocity_sequence.py index c153ad2d..7ef50b22 100644 --- a/micropython/examples/motor2040/quad_velocity_sequence.py +++ b/micropython/examples/motor2040/quad_velocity_sequence.py @@ -102,7 +102,7 @@ sequence = 0 captures = [None] * motor2040.NUM_MOTORS # Continually move the motor until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Capture the state of all the encoders for i in range(motor2040.NUM_MOTORS): diff --git a/micropython/examples/motor2040/reactive_encoder.py b/micropython/examples/motor2040/reactive_encoder.py index 4f1cb7fd..7dbf6ccf 100644 --- a/micropython/examples/motor2040/reactive_encoder.py +++ b/micropython/examples/motor2040/reactive_encoder.py @@ -92,7 +92,7 @@ detent_change(0) # Continually move the motor until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Capture the state of the encoder capture = enc.capture() diff --git a/micropython/examples/motor2040/read_encoders.py b/micropython/examples/motor2040/read_encoders.py index 3d07ef64..7561f6b9 100644 --- a/micropython/examples/motor2040/read_encoders.py +++ b/micropython/examples/motor2040/read_encoders.py @@ -34,7 +34,7 @@ encoders = [Encoder(0, i, ENCODER_PINS[i], counts_per_rev=COUNTS_PER_REV, count_ user_sw = Button(motor2040.USER_SW) # Read the encoders until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Print out the angle of each encoder for i in range(NUM_ENCODERS): diff --git a/micropython/examples/motor2040/read_sensors.py b/micropython/examples/motor2040/read_sensors.py index 7ca4909c..c8caa324 100644 --- a/micropython/examples/motor2040/read_sensors.py +++ b/micropython/examples/motor2040/read_sensors.py @@ -33,7 +33,7 @@ user_sw = Button(motor2040.USER_SW) # Read sensors until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Read each sensor in turn and print its voltage for i in range(len(sensor_addrs)): diff --git a/micropython/examples/motor2040/velocity_control.py b/micropython/examples/motor2040/velocity_control.py index 53d47668..45b160e0 100644 --- a/micropython/examples/motor2040/velocity_control.py +++ b/micropython/examples/motor2040/velocity_control.py @@ -66,7 +66,7 @@ start_value = 0.0 end_value = random.uniform(-VELOCITY_EXTENT, VELOCITY_EXTENT) # Continually move the motor until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Capture the state of the encoder capture = enc.capture() diff --git a/micropython/examples/motor2040/velocity_tuning.py b/micropython/examples/motor2040/velocity_tuning.py index 6f275f3b..071c1789 100644 --- a/micropython/examples/motor2040/velocity_tuning.py +++ b/micropython/examples/motor2040/velocity_tuning.py @@ -64,7 +64,7 @@ update = 0 print_count = 0 # Continually move the motor until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Capture the state of the encoder capture = enc.capture() diff --git a/micropython/examples/servo2040/current_meter.py b/micropython/examples/servo2040/current_meter.py index 5e4f4220..3082c699 100644 --- a/micropython/examples/servo2040/current_meter.py +++ b/micropython/examples/servo2040/current_meter.py @@ -52,7 +52,7 @@ led_bar.start() servos.enable_all() # Read sensors until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Select the current sense mux.select(servo2040.CURRENT_SENSE_ADDR) diff --git a/micropython/examples/servo2040/led_rainbow.py b/micropython/examples/servo2040/led_rainbow.py index 6f4c4307..8d1da7cc 100644 --- a/micropython/examples/servo2040/led_rainbow.py +++ b/micropython/examples/servo2040/led_rainbow.py @@ -30,7 +30,7 @@ led_bar.start() offset = 0.0 # Make rainbows until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): offset += SPEED / 1000.0 diff --git a/micropython/examples/servo2040/read_sensors.py b/micropython/examples/servo2040/read_sensors.py index e6c64c66..2b263578 100644 --- a/micropython/examples/servo2040/read_sensors.py +++ b/micropython/examples/servo2040/read_sensors.py @@ -30,7 +30,7 @@ user_sw = Button(servo2040.USER_SW) # Read sensors until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Read each sensor in turn and print its voltage for i in range(len(sensor_addrs)): diff --git a/micropython/examples/servo2040/sensor_feedback.py b/micropython/examples/servo2040/sensor_feedback.py index c781cc92..d4bbd2a8 100644 --- a/micropython/examples/servo2040/sensor_feedback.py +++ b/micropython/examples/servo2040/sensor_feedback.py @@ -41,7 +41,7 @@ led_bar.start() # Read sensors until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Read each sensor in turn and print its voltage for i in range(len(sensor_addrs)): diff --git a/micropython/examples/servo2040/servo_wave.py b/micropython/examples/servo2040/servo_wave.py index 1db21c02..7557042a 100644 --- a/micropython/examples/servo2040/servo_wave.py +++ b/micropython/examples/servo2040/servo_wave.py @@ -41,7 +41,7 @@ led_bar.start() offset = 0.0 # Make waves until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): offset += SPEED / 1000.0 diff --git a/micropython/examples/servo2040/simple_easing.py b/micropython/examples/servo2040/simple_easing.py index 54647ebc..ae138b57 100644 --- a/micropython/examples/servo2040/simple_easing.py +++ b/micropython/examples/servo2040/simple_easing.py @@ -31,7 +31,7 @@ user_sw = Button(servo2040.USER_SW) update = 0 # Continually move the servo until the user button is pressed -while user_sw.raw() is not True: +while not user_sw.raw(): # Calculate how far along this movement to be percent_along = update / UPDATES_PER_MOVE From f20049aa260818586da186d7ecfe5140ae4001f5 Mon Sep 17 00:00:00 2001 From: helgibbons <50950368+helgibbons@users.noreply.github.com> Date: Fri, 17 Jun 2022 15:12:35 +0100 Subject: [PATCH 83/84] Tufty2040: MicroPython examples. --- micropython/examples/tufty2040/battery.py | 81 ++++++++++ micropython/examples/tufty2040/buttons.py | 76 +++++++++ micropython/examples/tufty2040/pride_badge.py | 90 +++++++++++ micropython/examples/tufty2040/retro_badge.py | 152 ++++++++++++++++++ micropython/examples/tufty2040/squirrel.jpg | Bin 0 -> 44317 bytes 5 files changed, 399 insertions(+) create mode 100644 micropython/examples/tufty2040/battery.py create mode 100644 micropython/examples/tufty2040/buttons.py create mode 100644 micropython/examples/tufty2040/pride_badge.py create mode 100644 micropython/examples/tufty2040/retro_badge.py create mode 100644 micropython/examples/tufty2040/squirrel.jpg diff --git a/micropython/examples/tufty2040/battery.py b/micropython/examples/tufty2040/battery.py new file mode 100644 index 00000000..c881c262 --- /dev/null +++ b/micropython/examples/tufty2040/battery.py @@ -0,0 +1,81 @@ +# This example reads the voltage from a battery connected to Tufty 2040 +# and uses this reading to calculate how much charge is left in the battery. + +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 +from machine import ADC, Pin +import time + +display = PicoGraphics(display=DISPLAY_TUFTY_2040) + +display.set_backlight(0.8) + +# set up the ADCs for measuring battery voltage +vbat_adc = ADC(29) +vref_adc = ADC(28) +vref_en = Pin(27) +vref_en.init(Pin.OUT) +vref_en.value(0) +usb_power = Pin(24, Pin.IN) # reading GP24 tells us whether or not USB power is connected + +# Reference voltages for a full/empty battery, in volts +# the values could vary by battery size/manufacturer so you might need to adjust them +# Values for a Galleon 400mAh LiPo: +full_battery = 3.7 +empty_battery = 2.5 + +# set up some colours to draw with +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) +GREY = display.create_pen(190, 190, 190) +GREEN = display.create_pen(0, 255, 0) +RED = display.create_pen(255, 0, 0) + +display.set_font("bitmap8") + +while True: + # The voltage reference on Tufty means we can measure battery voltage precisely, even when batteries are low. + # Enable the onboard voltage reference + vref_en.value(1) + + # Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries + vdd = 1.24 * (65535 / vref_adc.read_u16()) + vbat = ( + (vbat_adc.read_u16() / 65535) * 3 * vdd + ) # 3 in this is a gain, not rounding of 3.3V + + # Disable the onboard voltage reference + vref_en.value(0) + + # Print out the voltage + print("Battery Voltage = ", vbat, "V", sep="") + + # convert the raw ADC read into a voltage, and then a percentage + percentage = 100 * ((vbat - empty_battery) / (full_battery - empty_battery)) + if percentage > 100: + percentage = 100 + if percentage < 0: + percentage = 0 + + # draw the battery outline + display.set_pen(BLACK) + display.clear() + display.set_pen(GREY) + display.rectangle(0, 0, 220, 135) + display.rectangle(220, 40, 20, 55) + display.set_pen(WHITE) + display.rectangle(3, 3, 214, 129) + + # draw a green box for the battery level + display.set_pen(GREEN) + display.rectangle(5, 5, int((210 / 100) * percentage), 125) + + # add text + display.set_pen(RED) + if usb_power.value() == 1: # if it's plugged into USB power... + display.text("USB power!", 15, 90, 240, 4) + + display.text('{:.2f}'.format(vbat) + "v", 15, 10, 240, 5) + display.text('{:.0f}%'.format(percentage), 15, 50, 240, 5) + + display.update() + time.sleep(0.5) diff --git a/micropython/examples/tufty2040/buttons.py b/micropython/examples/tufty2040/buttons.py new file mode 100644 index 00000000..e17ef0cc --- /dev/null +++ b/micropython/examples/tufty2040/buttons.py @@ -0,0 +1,76 @@ +# This example shows you a simple, non-interrupt way of reading Tufty 2040's buttons with a loop that checks to see if buttons are pressed. + +import time +from pimoroni import Button +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 + +display = PicoGraphics(display=DISPLAY_TUFTY_2040) + +display.set_backlight(1.0) +display.set_font("bitmap8") + +button_a = Button(7, invert=False) +button_b = Button(8, invert=False) +button_c = Button(9, invert=False) +button_up = Button(22, invert=False) +button_down = Button(6, invert=False) + +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) +TEAL = display.create_pen(0, 255, 255) +MAGENTA = display.create_pen(255, 0, 255) +YELLOW = display.create_pen(255, 255, 0) +RED = display.create_pen(255, 0, 0) +GREEN = display.create_pen(0, 255, 0) + +WIDTH, HEIGHT = display.get_bounds() + +while True: + if button_a.is_pressed: # if a button press is detected then... + display.set_pen(BLACK) # set pen to black + display.clear() # clear display to the pen colour + display.set_pen(WHITE) # change the pen colour + display.text("Button A pressed", 10, 10, WIDTH - 10, 3) # display some text on the screen + display.update() # update the display + time.sleep(1) # pause for a sec + + elif button_b.is_pressed: + display.set_pen(BLACK) + display.clear() + display.set_pen(TEAL) + display.text("Button B pressed", 10, 10, WIDTH - 10, 3) + display.update() + time.sleep(1) + + elif button_c.is_pressed: + display.set_pen(BLACK) + display.clear() + display.set_pen(MAGENTA) + display.text("Button C pressed", 10, 10, WIDTH - 10, 3) + display.update() + time.sleep(1) + + elif button_up.is_pressed: + display.set_pen(BLACK) + display.clear() + display.set_pen(YELLOW) + display.text("Button up pressed", 10, 10, WIDTH - 10, 3) + display.update() + time.sleep(1) + + elif button_down.is_pressed: + display.set_pen(BLACK) + display.clear() + display.set_pen(GREEN) + display.text("Button down pressed", 10, 10, WIDTH - 10, 3) + display.update() + time.sleep(1) + + else: + display.set_pen(BLACK) + display.clear() + display.set_pen(RED) + display.text("Press any button!", 10, 10, WIDTH, 3) + display.update() + + time.sleep(0.1) # this number is how frequently Tufty checks for button presses diff --git a/micropython/examples/tufty2040/pride_badge.py b/micropython/examples/tufty2040/pride_badge.py new file mode 100644 index 00000000..b50237fa --- /dev/null +++ b/micropython/examples/tufty2040/pride_badge.py @@ -0,0 +1,90 @@ +# A name badge with customisable Pride flag background. + +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 + +display = PicoGraphics(display=DISPLAY_TUFTY_2040) + +WIDTH, HEIGHT = display.get_bounds() + +# List of available pen colours, add more if necessary +RED = display.create_pen(209, 34, 41) +ORANGE = display.create_pen(246, 138, 30) +YELLOW = display.create_pen(255, 216, 0) +GREEN = display.create_pen(0, 121, 64) +INDIGO = display.create_pen(36, 64, 142) +VIOLET = display.create_pen(115, 41, 130) +WHITE = display.create_pen(255, 255, 255) +PINK = display.create_pen(255, 175, 200) +BLUE = display.create_pen(116, 215, 238) +BROWN = display.create_pen(97, 57, 21) +BLACK = display.create_pen(0, 0, 0) +MAGENTA = display.create_pen(255, 33, 140) +CYAN = display.create_pen(33, 177, 255) + +# Uncomment one of these to change flag +# If adding your own, colour order is left to right (or top to bottom) +COLOUR_ORDER = [RED, ORANGE, YELLOW, GREEN, INDIGO, VIOLET] # traditional pride flag +# COLOUR_ORDER = [BLACK, BROWN, RED, ORANGE, YELLOW, GREEN, INDIGO, VIOLET] # Philadelphia pride flag +# COLOUR_ORDER = [BLUE, PINK, WHITE, PINK, BLUE] # trans flag +# COLOUR_ORDER = [MAGENTA, YELLOW, CYAN] # pan flag +# COLOUR_ORDER = [MAGENTA, VIOLET, INDIGO] # bi flag + +# Change this for vertical stripes +STRIPES_DIRECTION = "horizontal" + +# Change details here! Works best with a short, one word name +NAME = "Hel" +PRONOUNS = "She/they" + +# Change the colour of the text (swapping these works better on a light background) +TEXT_COLOUR = WHITE +DROP_SHADOW_COLOUR = BLACK + +# Draw the flag +if STRIPES_DIRECTION == "horizontal": + stripe_width = round(HEIGHT / len(COLOUR_ORDER)) + for x in range(len(COLOUR_ORDER)): + display.set_pen(COLOUR_ORDER[x]) + display.rectangle(0, stripe_width * x, WIDTH, stripe_width) + +if STRIPES_DIRECTION == "vertical": + stripe_width = round(WIDTH / len(COLOUR_ORDER)) + for x in range(len(COLOUR_ORDER)): + display.set_pen(COLOUR_ORDER[x]) + display.rectangle(stripe_width * x, 0, stripe_width, HEIGHT) + +# Set a starting scale for text size. +# This is intentionally bigger than will fit on the screen, we'll shrink it to fit. +name_size = 20 +pronouns_size = 20 + +# These loops adjust the scale of the text until it fits on the screen +while True: + display.set_font("bitmap8") + name_length = display.measure_text(NAME, name_size) + if name_length >= WIDTH - 20: + name_size -= 1 + else: + # comment out this section if you hate drop shadow + DROP_SHADOW_OFFSET = 5 + display.set_pen(DROP_SHADOW_COLOUR) + display.text(NAME, int((WIDTH - name_length) / 2 + 10) - DROP_SHADOW_OFFSET, 10 + DROP_SHADOW_OFFSET, WIDTH, name_size) + + # draw name and stop looping + display.set_pen(TEXT_COLOUR) + display.text(NAME, int((WIDTH - name_length) / 2 + 10), 10, WIDTH, name_size) + break + +while True: + display.set_font("bitmap8") + pronouns_length = display.measure_text(PRONOUNS, pronouns_size) + if pronouns_length >= WIDTH - 60: + pronouns_size -= 1 + else: + # draw pronouns and stop looping + display.set_pen(TEXT_COLOUR) + display.text(PRONOUNS, int((WIDTH - pronouns_length) / 2), 175, WIDTH, pronouns_size) + break + +# Once all the adjusting and drawing is done, update the display. +display.update() diff --git a/micropython/examples/tufty2040/retro_badge.py b/micropython/examples/tufty2040/retro_badge.py new file mode 100644 index 00000000..5f3ff12f --- /dev/null +++ b/micropython/examples/tufty2040/retro_badge.py @@ -0,0 +1,152 @@ +# A retro badge with photo and QR code. +# Copy your image to your Tufty alongside this example - it should be a 120 x 120 jpg. + +from picographics import PicoGraphics, DISPLAY_TUFTY_2040 +from pimoroni import Button +import time +import jpegdec +import qrcode + +display = PicoGraphics(display=DISPLAY_TUFTY_2040) +button_c = Button(9, invert=False) + +WIDTH, HEIGHT = display.get_bounds() + +# Uncomment one of these four colour palettes - find more at lospec.com ! +# Nostalgia colour palette by WildLeoKnight - https://lospec.com/palette-list/nostalgia +LIGHTEST = display.create_pen(208, 208, 88) +LIGHT = display.create_pen(160, 168, 64) +DARK = display.create_pen(112, 128, 40) +DARKEST = display.create_pen(64, 80, 16) + +# 2bit Demichrome colour palette by Space Sandwich - https://lospec.com/palette-list/2bit-demichrome +# LIGHTEST = display.create_pen(233, 239, 236) +# LIGHT = display.create_pen(160, 160, 139) +# DARK = display.create_pen(85, 85, 104) +# DARKEST = display.create_pen(33, 30, 32) + +# CGA PALETTE 1 (HIGH) - https://lospec.com/palette-list/cga-palette-1-high +# LIGHTEST = display.create_pen(255, 255, 255) +# LIGHT = display.create_pen(85, 254, 255) +# DARK = display.create_pen(255, 85, 255) +# DARKEST = display.create_pen(0, 0, 0) + +# Change your badge and QR details here! +COMPANY_NAME = "sciurus cybernetics" +NAME = "M. 'TuFTy'" +BLURB1 = "RP2040 plus 320x240 TFT LCD" +BLURB2 = "Nuts From Trees collector" +BLURB3 = "Will work for peanuts" + +QR_TEXT = "pimoroni.com/tufty2040" + +IMAGE_NAME = "squirrel.jpg" + +# Some constants we'll use for drawing +BORDER_SIZE = 4 +PADDING = 10 +COMPANY_HEIGHT = 40 + + +def draw_badge(): + # draw border + display.set_pen(LIGHTEST) + display.clear() + + # draw background + display.set_pen(DARK) + display.rectangle(BORDER_SIZE, BORDER_SIZE, WIDTH - (BORDER_SIZE * 2), HEIGHT - (BORDER_SIZE * 2)) + + # draw company box + display.set_pen(DARKEST) + display.rectangle(BORDER_SIZE, BORDER_SIZE, WIDTH - (BORDER_SIZE * 2), COMPANY_HEIGHT) + + # draw company text + display.set_pen(LIGHT) + display.set_font("bitmap6") + display.text(COMPANY_NAME, BORDER_SIZE + PADDING, BORDER_SIZE + PADDING, WIDTH, 3) + + # draw name text + display.set_pen(LIGHTEST) + display.set_font("bitmap8") + display.text(NAME, BORDER_SIZE + PADDING, BORDER_SIZE + PADDING + COMPANY_HEIGHT, WIDTH, 5) + + # draws the bullet points + display.set_pen(DARKEST) + display.text("*", BORDER_SIZE + PADDING + 120 + PADDING, 105, 160, 2) + display.text("*", BORDER_SIZE + PADDING + 120 + PADDING, 140, 160, 2) + display.text("*", BORDER_SIZE + PADDING + 120 + PADDING, 175, 160, 2) + + # draws the blurb text (4 - 5 words on each line works best) + display.set_pen(LIGHTEST) + display.text(BLURB1, BORDER_SIZE + PADDING + 135 + PADDING, 105, 160, 2) + display.text(BLURB2, BORDER_SIZE + PADDING + 135 + PADDING, 140, 160, 2) + display.text(BLURB3, BORDER_SIZE + PADDING + 135 + PADDING, 175, 160, 2) + + +def show_photo(): + j = jpegdec.JPEG(display) + + # Open the JPEG file + j.open_file(IMAGE_NAME) + + # Draws a box around the image + display.set_pen(DARKEST) + display.rectangle(PADDING, HEIGHT - ((BORDER_SIZE * 2) + PADDING) - 120, 120 + (BORDER_SIZE * 2), 120 + (BORDER_SIZE * 2)) + + # Decode the JPEG + j.decode(BORDER_SIZE + PADDING, HEIGHT - (BORDER_SIZE + PADDING) - 120) + + # Draw QR button label + display.set_pen(LIGHTEST) + display.text("QR", 240, 215, 160, 2) + + +def measure_qr_code(size, code): + w, h = code.get_size() + module_size = int(size / w) + return module_size * w, module_size + + +def draw_qr_code(ox, oy, size, code): + size, module_size = measure_qr_code(size, code) + display.set_pen(LIGHTEST) + display.rectangle(ox, oy, size, size) + display.set_pen(DARKEST) + for x in range(size): + for y in range(size): + if code.get_module(x, y): + display.rectangle(ox + x * module_size, oy + y * module_size, module_size, module_size) + + +def show_qr(): + display.set_pen(DARK) + display.clear() + + code = qrcode.QRCode() + code.set_text(QR_TEXT) + + size, module_size = measure_qr_code(HEIGHT, code) + left = int((WIDTH // 2) - (size // 2)) + top = int((HEIGHT // 2) - (size // 2)) + draw_qr_code(left, top, HEIGHT, code) + + +# draw the badge for the first time +badge_mode = "photo" +draw_badge() +show_photo() +display.update() + +while True: + if button_c.is_pressed: + if badge_mode == "photo": + badge_mode = "qr" + show_qr() + display.update() + else: + badge_mode = "photo" + draw_badge() + show_photo() + display.update() + time.sleep(1) diff --git a/micropython/examples/tufty2040/squirrel.jpg b/micropython/examples/tufty2040/squirrel.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8d1b2c9e597399937e94b0905f6334b11ea7659e GIT binary patch literal 44317 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 Date: Fri, 17 Jun 2022 15:42:20 +0100 Subject: [PATCH 84/84] Tufty2040: Tidy up examples. Wavy Message. Co-authored-by: Phil Howard --- .../tufty2040/{game.py => awesome_game.py} | 0 .../tufty2040/{buttons.py => button_test.py} | 0 micropython/examples/tufty2040/main.py | 151 ++++++++++++++++++ .../tufty2040/{namebadge.py => name_badge.py} | 0 .../s4m_ur4i-pirate-characters.rgb332 | Bin 0 -> 16384 bytes .../tufty2040/s4m_ur4i-pirate-tilemap.rgb332 | Bin 0 -> 16384 bytes micropython/examples/tufty2040/scrolltext.py | 46 ------ .../examples/tufty2040/sketchy_sketch.py | 83 ++++++++++ .../examples/tufty2040/sketchysketch.py | 89 ----------- micropython/examples/tufty2040/textwave.py | 48 ------ .../examples/tufty2040/wavy_message.py | 64 ++++++++ 11 files changed, 298 insertions(+), 183 deletions(-) rename micropython/examples/tufty2040/{game.py => awesome_game.py} (100%) rename micropython/examples/tufty2040/{buttons.py => button_test.py} (100%) create mode 100644 micropython/examples/tufty2040/main.py rename micropython/examples/tufty2040/{namebadge.py => name_badge.py} (100%) create mode 100644 micropython/examples/tufty2040/s4m_ur4i-pirate-characters.rgb332 create mode 100644 micropython/examples/tufty2040/s4m_ur4i-pirate-tilemap.rgb332 delete mode 100644 micropython/examples/tufty2040/scrolltext.py create mode 100644 micropython/examples/tufty2040/sketchy_sketch.py delete mode 100644 micropython/examples/tufty2040/sketchysketch.py delete mode 100644 micropython/examples/tufty2040/textwave.py create mode 100644 micropython/examples/tufty2040/wavy_message.py diff --git a/micropython/examples/tufty2040/game.py b/micropython/examples/tufty2040/awesome_game.py similarity index 100% rename from micropython/examples/tufty2040/game.py rename to micropython/examples/tufty2040/awesome_game.py diff --git a/micropython/examples/tufty2040/buttons.py b/micropython/examples/tufty2040/button_test.py similarity index 100% rename from micropython/examples/tufty2040/buttons.py rename to micropython/examples/tufty2040/button_test.py diff --git a/micropython/examples/tufty2040/main.py b/micropython/examples/tufty2040/main.py new file mode 100644 index 00000000..f8c56e19 --- /dev/null +++ b/micropython/examples/tufty2040/main.py @@ -0,0 +1,151 @@ +from picographics import PicoGraphics, DISPLAY_TUFTY_2040, PEN_RGB332 +from os import listdir +import time +import gc +from pimoroni import Button + +display = PicoGraphics(display=DISPLAY_TUFTY_2040, pen_type=PEN_RGB332, rotate=180) + + +def hsv_to_rgb(h, s, v): + if s == 0.0: + return v, v, v + i = int(h * 6.0) + f = (h * 6.0) - i + p = v * (1.0 - s) + q = v * (1.0 - s * f) + t = v * (1.0 - s * (1.0 - f)) + v = int(v * 255) + t = int(t * 255) + p = int(p * 255) + q = int(q * 255) + i = i % 6 + if i == 0: + return v, t, p + if i == 1: + return q, v, p + if i == 2: + return p, v, t + if i == 3: + return p, q, v + if i == 4: + return t, p, v + if i == 5: + return v, p, q + + +def get_applications(): + # fetch a list of the applications that are stored in the filesystem + applications = [] + for file in listdir(): + if file.endswith(".py") and file != "main.py": + # convert the filename from "something_or_other.py" to "Something Or Other" + # via weird incantations and a sprinkling of voodoo + title = " ".join([v[:1].upper() + v[1:] for v in file[:-3].split("_")]) + + applications.append( + { + "file": file, + "title": title + } + ) + + # sort the application list alphabetically by title and return the list + return sorted(applications, key=lambda x: x["title"]) + + +def launch_application(application): + for k in locals().keys(): + if k not in ("gc", "file", "badger_os"): + del locals()[k] + + gc.collect() + + __import__(application["file"]) + + +applications = get_applications() + +button_up = Button(22, invert=False) +button_down = Button(6, invert=False) +button_a = Button(7, invert=False) + +display.set_backlight(1.0) + +WHITE = display.create_pen(255, 255, 255) +BLACK = display.create_pen(0, 0, 0) +RED = display.create_pen(200, 0, 0) + + +def text(text, x, y, pen, s): + display.set_pen(pen) + display.text(text, x, y, -1, s) + + +selected_item = 2 +scroll_position = 2 +target_scroll_position = 2 + +selected_pen = display.create_pen(255, 255, 255) +unselected_pen = display.create_pen(80, 80, 100) +background_pen = display.create_pen(50, 50, 70) +shadow_pen = display.create_pen(0, 0, 0) + +while True: + t = time.ticks_ms() / 1000.0 + + if button_up.read(): + target_scroll_position -= 1 + target_scroll_position = target_scroll_position if target_scroll_position >= 0 else len(applications) - 1 + + if button_down.read(): + target_scroll_position += 1 + target_scroll_position = target_scroll_position if target_scroll_position < len(applications) else 0 + + if button_a.read(): + launch_application(applications[selected_item]) + + display.set_pen(background_pen) + display.clear() + + scroll_position += (target_scroll_position - scroll_position) / 5 + + grid_size = 40 + for y in range(0, 240 / grid_size): + for x in range(0, 320 / grid_size): + h = x + y + int(t * 5) + h = h / 50.0 + r, g, b = hsv_to_rgb(h, .5, 1) + + display.set_pen(display.create_pen(r, g, b)) + display.rectangle(x * grid_size, y * grid_size, grid_size, grid_size) + + # work out which item is selected (closest to the current scroll position) + selected_item = round(target_scroll_position) + + start = time.ticks_ms() + + for list_index, application in enumerate(applications): + distance = list_index - scroll_position + + text_size = 4 if selected_item == list_index else 3 + + # center text horixontally + title_width = display.measure_text(application["title"], text_size) + text_x = int(160 - title_width / 2) + + row_height = text_size * 5 + 20 + + # center list items vertically + text_y = int(120 + distance * row_height - (row_height / 2)) + + # draw the text, selected item brightest and with shadow + if selected_item == list_index: + text(application["title"], text_x + 1, text_y + 1, shadow_pen, text_size) + + text_pen = selected_pen if selected_item == list_index else unselected_pen + text(application["title"], text_x, text_y, text_pen, text_size) + + start = time.ticks_ms() + + display.update() diff --git a/micropython/examples/tufty2040/namebadge.py b/micropython/examples/tufty2040/name_badge.py similarity index 100% rename from micropython/examples/tufty2040/namebadge.py rename to micropython/examples/tufty2040/name_badge.py diff --git a/micropython/examples/tufty2040/s4m_ur4i-pirate-characters.rgb332 b/micropython/examples/tufty2040/s4m_ur4i-pirate-characters.rgb332 new file mode 100644 index 0000000000000000000000000000000000000000..5c93e9baf9e96829c2bb4e103273a1fcc81ffa42 GIT binary patch literal 16384 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 Mm`bU7BWe8q08foQ761SM literal 0 HcmV?d00001 diff --git a/micropython/examples/tufty2040/s4m_ur4i-pirate-tilemap.rgb332 b/micropython/examples/tufty2040/s4m_ur4i-pirate-tilemap.rgb332 new file mode 100644 index 0000000000000000000000000000000000000000..1fabfa955c843bead7cb4991a0b46fda1538a947 GIT binary patch literal 16384 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 30: + position_x -= 1 + + if button_up.raw() and position_y > 30: + position_y -= 1 + + if button_down.raw() and position_y < 200: + position_y += 1 + + if button_b.raw(): + draw_area() + + # draw the line + display.set_pen(display.create_pen(50, 50, 50)) + display.circle(position_x, position_y, 2) + + # update the screen contents + display.update() + + time.sleep(0.005) diff --git a/micropython/examples/tufty2040/sketchysketch.py b/micropython/examples/tufty2040/sketchysketch.py deleted file mode 100644 index 1964edd2..00000000 --- a/micropython/examples/tufty2040/sketchysketch.py +++ /dev/null @@ -1,89 +0,0 @@ -import time -from pimoroni import Button -from picographics import PicoGraphics, DISPLAY_TUFTY_2040 - -display = PicoGraphics(display=DISPLAY_TUFTY_2040) - -# Tufty constants -A = 7 -B = 8 -C = 15 -UP = 22 -DOWN = 6 -LED = 25 - -WIDTH, HEIGHT = display.get_bounds() -display.set_backlight(1.0) - -# Buttons -button_a = Button(7, invert=False) -button_b = Button(8, invert=False) -button_c = Button(9, invert=False) -button_up = Button(22, invert=False) -button_down = Button(6, invert=False) - -# Pens -WHITE = display.create_pen(255, 255, 255) -BLACK = display.create_pen(0, 0, 0) -RED = display.create_pen(200, 0, 0) -YELLOW = display.create_pen(255, 215, 0) - - -def draw_area(): - display.set_pen(RED) - display.clear() - - display.set_pen(YELLOW) - display.text("Sketchy-Sketch", 90, 5, 0, 2) - display.set_pen(WHITE) - display.circle(55, 215, 15) - display.circle(260, 215, 15) - display.rectangle(10, 25, 300, 170) - display.update() - - -position_x = 15 -position_y = 30 - -last_x = 15 -last_y = 30 - -draw_area() - -while True: - display.set_pen(0) - - if button_c.raw(): - if position_x < 308: - last_x = position_x - last_y = position_y - position_x += 2 - - if button_a.raw(): - if position_x > 12: - last_x = position_x - last_y = position_y - position_x -= 2 - - if button_up.raw(): - if position_y > 26: - last_x = position_x - last_y = position_y - position_y -= 2 - - if button_down.raw(): - if position_y < 193: - last_x = position_x - last_y = position_y - position_y += 2 - - if button_b.raw(): - draw_area() - position_x = 15 - position_y = 30 - last_x = 15 - last_y = 30 - - display.line(last_x, last_y, position_x, position_y) - display.update() - time.sleep(0.01) diff --git a/micropython/examples/tufty2040/textwave.py b/micropython/examples/tufty2040/textwave.py deleted file mode 100644 index ffa90fc4..00000000 --- a/micropython/examples/tufty2040/textwave.py +++ /dev/null @@ -1,48 +0,0 @@ -import math -import time -from picographics import PicoGraphics, DISPLAY_TUFTY_2040 - -display = PicoGraphics(display=DISPLAY_TUFTY_2040) - -WIDTH, HEIGHT = 320, 240 -display.set_backlight(1.0) - -WHITE = display.create_pen(255, 255, 255) -BLACK = display.create_pen(0, 0, 0) - -display.set_pen(WHITE) -display.clear() -display.update() - -message = "HELLO WORLD!" - - -def calculate_text_size(text): - size = 20 - width = display.measure_text(text, size) - while width > 280 and size > 1: - size -= 1 - width = display.measure_text(text, size) - - return size - - -size = calculate_text_size(message) -length = len(message) - -while True: - display.set_pen(WHITE) - display.clear() - display.set_pen(BLACK) - - t = time.ticks_ms() / 10 / size - - left = int((WIDTH - ((length - 1) * size * 6)) / 2) - top = 120 - int((size * 6) / 2) - - for i in range(length): - step = t + i - y = top - math.sin(step / length * math.pi) * 10 - display.text(message[i], left + (i * size * 6), int(y), 0, size) - - display.update() diff --git a/micropython/examples/tufty2040/wavy_message.py b/micropython/examples/tufty2040/wavy_message.py new file mode 100644 index 00000000..c9777423 --- /dev/null +++ b/micropython/examples/tufty2040/wavy_message.py @@ -0,0 +1,64 @@ +from picographics import PicoGraphics, DISPLAY_TUFTY_2040, PEN_RGB332 +import math +import time + +display = PicoGraphics(display=DISPLAY_TUFTY_2040, pen_type=PEN_RGB332, rotate=180) + + +# convert a hue, saturation, and value into rgb values +def hsv_to_rgb(h, s, v): + if s == 0.0: + return v, v, v + i = int(h * 6.0) + f = (h * 6.0) - i + p, q, t = v * (1.0 - s), v * (1.0 - s * f), v * (1.0 - s * (1.0 - f)) + v, t, p, q = int(v * 255), int(t * 255), int(p * 255), int(q * 255) + i = i % 6 + if i == 0: + return v, t, p + if i == 1: + return q, v, p + if i == 2: + return p, v, t + if i == 3: + return p, q, v + if i == 4: + return t, p, v + if i == 5: + return v, p, q + + +display.set_backlight(1.0) + +message = "Tufty 2040 is a hackable, programmable badge with a TFT LCD colour display, powered by the Raspberry Pi RP2040!" +text_size = 10 +message_width = display.measure_text(message, text_size) + +x_scroll = 0 + +while 1: + t = time.ticks_ms() / 1000.0 + display.set_pen(display.create_pen(50, 50, 50)) + display.clear() + + x_scroll -= 10 + if x_scroll < -(message_width + 320 + 100): + x_scroll = 0 + + # for each character we'll calculate a position and colour, then draw it + for i in range(0, len(message)): + cx = int(x_scroll + (i * text_size * 5.5)) + cy = int(80 + math.sin(t * 10 + i) * 20) + + # to speed things up we only bother doing the hardware if the character will be visible on screen + if cx > -50 and cx < 320: + # draw a shadow for the character + display.set_pen(display.create_pen(0, 0, 0)) + display.text(message[i], cx + 15, cy + 15, -1, text_size) + + # generate a rainbow colour that cycles with time + r, g, b = hsv_to_rgb(i / 10 + t / 5, 1, 1) + display.set_pen(display.create_pen(r, g, b)) + display.text(message[i], cx, cy, -1, text_size) + + display.update()