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