From ef6179e77d6f914917e4d8cffbf52678d123c070 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 27 May 2022 16:52:43 +0100 Subject: [PATCH] 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);