Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

PicoVector Enhancements & PicoGraphics Layers #1019

Open
wants to merge 58 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
e954a7c
PicoGraphics: Layers.
Gadgetoid Oct 7, 2024
5b6c47e
PicoGraphics: Support multiple layers in more types.
Gadgetoid Oct 7, 2024
4368933
PicoVector: Rewrite around new C pretty-poly.h.
Gadgetoid Sep 26, 2023
2768757
PicoVector: Rewrite MicroPython bindings.
Gadgetoid Sep 29, 2023
a90aac3
PicoVector: Suppress errors.
Gadgetoid Apr 17, 2024
4322404
PicoVector: Vendor pretty-poly and tweak rotation.
Gadgetoid Apr 18, 2024
24eaf6c
PicoVector: Swap rotate translation order.
Gadgetoid Apr 18, 2024
c2c3584
PicoVector: alright-fonts bringup.
Gadgetoid Apr 18, 2024
7340b1a
PicoVector: Break things until they work.
Gadgetoid Apr 19, 2024
7c19e72
PicoVector: fix pointer arithmatic in af_load_font_file.
Gadgetoid Jun 5, 2024
aa10390
PicoVector: Fix out of bounds drawing.
Gadgetoid Jun 5, 2024
1cd836f
PicoVector: render text that doesn't end with a linebreak.
Gadgetoid Jun 5, 2024
2ae0590
PicoVector: C++ basic bringup.
Gadgetoid Jun 11, 2024
91c3a79
PicoVector: Remove alright_fonts.cpp from cmake.
Gadgetoid Jul 9, 2024
cd6cfdb
PicoGraphics: Add RGB565 alpha blending support.
Gadgetoid Jul 11, 2024
a4ff868
PicoVector: Fix x16 anti-aliasing.
Gadgetoid Jul 11, 2024
c5d63a0
PicoGraphics: Add get_clip.
Gadgetoid Jul 11, 2024
b81beb6
PicoVector: Remove malloc from MicroPython bindings.
Gadgetoid Jul 11, 2024
768a401
PicoVector: Support float types in MicroPython bindings.
Gadgetoid Jul 11, 2024
cfc421c
PicoVector: Use tile renderer for all pens.
Gadgetoid Jul 22, 2024
ea0d52b
PicoVector: Rewrite around new linked-lists poly.
Gadgetoid Jul 22, 2024
ef1551d
PicoVector: Update C++ examples.
Gadgetoid Jul 23, 2024
8ca660b
PicoVector: Big refactor, ppp primitives.
Gadgetoid Jul 25, 2024
3e8d6c9
PicoGraphics: Add layer support to PicoVector tile renderer.
Gadgetoid Oct 8, 2024
27bdd41
PicoVector: Improve text rendering and control.
Gadgetoid Oct 8, 2024
4ab15a1
PicoGraphics: RGB565 skip layers if not enabled.
Gadgetoid Oct 9, 2024
c767068
PicoVector: Refactor text multiline support.
Gadgetoid Oct 9, 2024
d1b5b93
PicoVector: Remove (ifdef guard) debug functions.
Gadgetoid Oct 10, 2024
e9cebad
PicoGraphics: Add Presto.
Gadgetoid Aug 14, 2024
71b5add
Plasma: Add support for GPIOs >=32.
Gadgetoid Oct 24, 2024
a4ad047
PicoGraphics: Non-blocking Inky update for #936.
Gadgetoid Oct 31, 2024
aca1bc5
PicoVector: Prefix some pretty-poly variables.
Gadgetoid Nov 14, 2024
7a1d4aa
PicoVector: Runtime buffer allocation.
Gadgetoid Nov 14, 2024
379b762
PicoVector: Revert the tile buffer to be fixed.
Gadgetoid Nov 18, 2024
3365c96
PicoVector: Add optional text max width and max height.
MichaelBell Nov 17, 2024
eb3ea0d
PicoVector: Apply overall transform to text rendering.
MichaelBell Nov 17, 2024
88d796a
PicoGraphics: Presto full res option.
MichaelBell Nov 17, 2024
29afd1b
PicoGraphics: Don't force Presto to RGB565.
Gadgetoid Nov 20, 2024
31b58f9
PicoVector: Update example with text bounds.
Gadgetoid Nov 20, 2024
1208ea2
PicoGraphics/Hub75: Add support for 128x128.
Gadgetoid Nov 20, 2024
14f0469
PicoVector: Remove * 4 from pp_nodes lookup.
Gadgetoid Nov 21, 2024
4d045e1
PicoVector: Avoid MicroPython GC.
Gadgetoid Nov 21, 2024
ffbe84a
Hub75: Performance improvements and stacked mode.
Gadgetoid Nov 21, 2024
b50b0a2
Hub75: Reformat loop for performance.
MichaelBell Nov 21, 2024
a53032d
PicoGraphics: Implement RGB888 alpha blending.
Gadgetoid Nov 21, 2024
1f80f8e
PicoVector: Add star and line primitives.
lowfatcode Nov 26, 2024
a9f073e
PicoVector: Avoid clipping bottom right AA edges.
MichaelBell Nov 26, 2024
a6e8ba2
PicoVector: Tweak for C++ compatibility.
Gadgetoid Nov 26, 2024
78a7829
PicoVector: MPY bindings for line and arc.
Gadgetoid Nov 26, 2024
762c5cb
PicoGraphics: Check for out of range layers.
Gadgetoid Dec 2, 2024
d0903ca
PicoVector: Fix bug in Polygon.regular.
Gadgetoid Dec 5, 2024
a75aea8
PicoVector: Fix bug in Polygon.rectangle.
Gadgetoid Dec 6, 2024
12ed706
PicoVector: Add arbitrary matrix transform.
Gadgetoid Dec 11, 2024
301fb87
PicoVector: Initialise pp_transform().
Gadgetoid Dec 11, 2024
7367bca
PicoVector: Fully initialise text metrics.
MichaelBell Dec 13, 2024
1f4c347
Hub75: Fix LED ghosting.
MichaelBell Dec 15, 2024
54cc42f
Merge pull request #1036 from MichaelBell/fix-pv-font-init
Gadgetoid Dec 16, 2024
4cf9f44
Merge pull request #1038 from MichaelBell/fix-i75-glow
Gadgetoid Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 133 additions & 41 deletions drivers/hub75/hub75.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include <algorithm>
#include <cmath>

#include "hardware/clocks.h"

#include "hub75.hpp"

namespace pimoroni {
Expand Down Expand Up @@ -37,10 +39,48 @@ Hub75::Hub75(uint width, uint height, Pixel *buffer, PanelType panel_type, bool
}

if (brightness == 0) {
#if PICO_RP2350
brightness = 6;
#else
if (width >= 64) brightness = 6;
if (width >= 96) brightness = 3;
if (width >= 128) brightness = 2;
if (width >= 160) brightness = 1;
#endif
}

switch (color_order) {
case COLOR_ORDER::RGB:
r_shift = 0;
g_shift = 10;
b_shift = 20;
break;
case COLOR_ORDER::RBG:
r_shift = 0;
g_shift = 20;
b_shift = 10;
break;
case COLOR_ORDER::GRB:
r_shift = 20;
g_shift = 0;
b_shift = 10;
break;
case COLOR_ORDER::GBR:
r_shift = 10;
g_shift = 20;
b_shift = 0;
break;
case COLOR_ORDER::BRG:
r_shift = 10;
g_shift = 00;
b_shift = 20;
break;
case COLOR_ORDER::BGR:
r_shift = 20;
g_shift = 10;
b_shift = 0;
break;

}
}

Expand All @@ -58,26 +98,16 @@ void Hub75::set_color(uint x, uint y, Pixel c) {
}

void Hub75::set_pixel(uint x, uint y, uint8_t r, uint8_t g, uint8_t b) {
switch(color_order) {
case COLOR_ORDER::RGB:
set_color(x, y, Pixel(r, g, b));
break;
case COLOR_ORDER::RBG:
set_color(x, y, Pixel(r, b, g));
break;
case COLOR_ORDER::GRB:
set_color(x, y, Pixel(g, r, b));
break;
case COLOR_ORDER::GBR:
set_color(x, y, Pixel(g, b, r));
break;
case COLOR_ORDER::BRG:
set_color(x, y, Pixel(b, r, g));
break;
case COLOR_ORDER::BGR:
set_color(x, y, Pixel(b, g, r));
break;
int offset = 0;
if(x >= width || y >= height) return;
if(y >= height / 2) {
y -= height / 2;
offset = (y * width + x) * 2;
offset += 1;
} else {
offset = (y * width + x) * 2;
}
back_buffer[offset] = (GAMMA_10BIT[b] << b_shift) | (GAMMA_10BIT[g] << g_shift) | (GAMMA_10BIT[r] << r_shift);
}

void Hub75::FM6126A_write_register(uint16_t value, uint8_t position) {
Expand Down Expand Up @@ -117,6 +147,8 @@ void Hub75::start(irq_handler_t handler) {
FM6126A_setup();
}

uint latch_cycles = clock_get_hz(clk_sys) / 4000000;

// Claim the PIO so we can clean it upon soft restart
pio_sm_claim(pio, sm_data);
pio_sm_claim(pio, sm_row);
Expand All @@ -128,7 +160,7 @@ void Hub75::start(irq_handler_t handler) {
row_prog_offs = pio_add_program(pio, &hub75_row_program);
}
hub75_data_rgb888_program_init(pio, sm_data, data_prog_offs, DATA_BASE_PIN, pin_clk);
hub75_row_program_init(pio, sm_row, row_prog_offs, ROWSEL_BASE_PIN, ROWSEL_N_PINS, pin_stb);
hub75_row_program_init(pio, sm_row, row_prog_offs, ROWSEL_BASE_PIN, ROWSEL_N_PINS, pin_stb, latch_cycles);

// Prevent flicker in Python caused by the smaller dataset just blasting through the PIO too quickly
pio_sm_set_clkdiv(pio, sm_data, width <= 32 ? 2.0f : 1.0f);
Expand Down Expand Up @@ -247,28 +279,88 @@ void Hub75::dma_complete() {

void Hub75::update(PicoGraphics *graphics) {
if(graphics->pen_type == PicoGraphics::PEN_RGB888) {
uint32_t *p = (uint32_t *)graphics->frame_buffer;
for(uint y = 0; y < height; y++) {
for(uint x = 0; x < width; x++) {
uint32_t col = *p;
uint8_t r = (col & 0xff0000) >> 16;
uint8_t g = (col & 0x00ff00) >> 8;
uint8_t b = (col & 0x0000ff) >> 0;
set_pixel(x, y, r, g, b);
p++;
uint8_t *p = (uint8_t *)graphics->frame_buffer;
if(graphics->bounds.w == int32_t(width / 2) && graphics->bounds.h == int32_t(height * 2)) {
for(int y = 0; y < graphics->bounds.h; y++) {
int offsety = 0;
int sy = y;
int basex = 0;

// Assuming our canvas is 128x128 and our display is 256x64,
// consisting of 2x128x64 panels, remap the bottom half
// of the canvas to the right-half of the display,
// This gives us an optional square arrangement.
if (sy >= int(height)) {
sy -= height;
basex = width / 2;
} else {
// Awkward hack to *TEMPORARILY* rotate the top panel
sy = height - 1 - sy;
basex = (width / 2) - 1;
}

// Interlace the top and bottom halves of the panel.
// Since these are scanned out simultaneously to two chains
// of shift registers we need each pair of rows
// (N and N + height / 2) to be adjacent in the buffer.
offsety = width * 2;
if(sy >= int(height / 2)) {
sy -= height / 2;
offsety *= sy;
offsety += 1;
} else {
offsety *= sy;
}

for(int x = 0; x < graphics->bounds.w; x++) {
int sx = x;
uint8_t b = *p++;
uint8_t g = *p++;
uint8_t r = *p++;

// Assumes width / 2 is even.
if (basex & 1) {
sx = basex - sx;
} else {
sx += basex;
}
int offset = offsety + sx * 2;

back_buffer[offset] = (GAMMA_10BIT[b] << b_shift) | (GAMMA_10BIT[g] << g_shift) | (GAMMA_10BIT[r] << r_shift);

// Skip the empty byte in out 32-bit aligned 24-bit colour.
p++;
}
}
}
}
else if(graphics->pen_type == PicoGraphics::PEN_RGB565) {
uint16_t *p = (uint16_t *)graphics->frame_buffer;
for(uint y = 0; y < height; y++) {
for(uint x = 0; x < width; x++) {
uint16_t col = __builtin_bswap16(*p);
uint8_t r = (col & 0b1111100000000000) >> 8;
uint8_t g = (col & 0b0000011111100000) >> 3;
uint8_t b = (col & 0b0000000000011111) << 3;
set_pixel(x, y, r, g, b);
p++;
} else {
for(uint y = 0; y < height; y++) {
for(uint x = 0; x < width; x++) {
int offset = 0;
int sy = y;
int sx = x;
uint8_t b = *p++;
uint8_t g = *p++;
uint8_t r = *p++;

// Interlace the top and bottom halves of the panel.
// Since these are scanned out simultaneously to two chains
// of shift registers we need each pair of rows
// (N and N + height / 2) to be adjacent in the buffer.
offset = width * 2;
if(sy >= int(height / 2)) {
sy -= height / 2;
offset *= sy;
offset += 1;
} else {
offset *= sy;
}
offset += sx * 2;

back_buffer[offset] = (GAMMA_10BIT[b] << b_shift) | (GAMMA_10BIT[g] << g_shift) | (GAMMA_10BIT[r] << r_shift);

// Skip the empty byte in out 32-bit aligned 24-bit colour.
p++;
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/hub75/hub75.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ class Hub75 {
};
uint width;
uint height;
uint r_shift = 0;
uint g_shift = 10;
uint b_shift = 20;
Pixel *back_buffer;
bool managed_buffer = false;
PanelType panel_type;
Expand Down
14 changes: 11 additions & 3 deletions drivers/hub75/hub75.pio
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@

.wrap_target
out pins, 5 [1] side 0x2 ; Deassert OEn, output row select
out x, 27 [7] side 0x3 ; Pulse LATCH, get OEn pulse width
mov x, y [3] side 0x3 ; Pulse LATCH
wait_loop:
jmp x-- wait_loop side 0x2 ; Wait for row to latch
out x, 27 side 0x2 ; Get OEn pulse width
pulse_loop:
jmp x-- pulse_loop side 0x0 ; Assert OEn for x+1 cycles
.wrap
Expand All @@ -43,13 +46,16 @@ pulse_loop:

.wrap_target
out pins, 5 [1] side 0x3 ; Deassert OEn, output row select
out x, 27 [7] side 0x2 ; Pulse LATCH, get OEn pulse width
mov x, y [3] side 0x2 ; Pulse LATCH
wait_loop:
jmp x-- wait_loop side 0x3 ; Wait for row to latch
out x, 27 side 0x3 ; Get OEn pulse width
pulse_loop:
jmp x-- pulse_loop side 0x1 ; Assert OEn for x+1 cycles
.wrap

% c-sdk {
static inline void hub75_row_program_init(PIO pio, uint sm, uint offset, uint row_base_pin, uint n_row_pins, uint latch_base_pin) {
static inline void hub75_row_program_init(PIO pio, uint sm, uint offset, uint row_base_pin, uint n_row_pins, uint latch_base_pin, uint latch_cycles) {
pio_sm_set_consecutive_pindirs(pio, sm, row_base_pin, n_row_pins, true);
pio_sm_set_consecutive_pindirs(pio, sm, latch_base_pin, 2, true);
for (uint i = row_base_pin; i < row_base_pin + n_row_pins; ++i)
Expand All @@ -62,6 +68,8 @@ static inline void hub75_row_program_init(PIO pio, uint sm, uint offset, uint ro
sm_config_set_sideset_pins(&c, latch_base_pin);
sm_config_set_out_shift(&c, true, true, 32);
pio_sm_init(pio, sm, offset, &c);
pio_sm_exec(pio, sm, pio_encode_out(pio_y, 32));
pio_sm_put(pio, sm, latch_cycles);
pio_sm_set_enabled(pio, sm, true);
}

Expand Down
20 changes: 18 additions & 2 deletions drivers/plasma/apa102.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,26 @@
namespace plasma {

APA102::APA102(uint num_leds, PIO pio, uint sm, uint pin_dat, uint pin_clk, uint freq, RGB* buffer) : buffer(buffer), num_leds(num_leds), pio(pio), sm(sm) {
// NOTE: This sets the gpio_base for *the entire PIO* not just this state machine
uint range_max = std::max(pin_dat, pin_clk);
uint range_min = std::min(pin_dat, pin_clk);

// Both pins in 16-48 range
if(range_max >= 32 && range_min >= 16) {
pio_set_gpio_base(pio, 16);
// Both pins in 0-31 range
} else if(range_max <= 31) {
pio_set_gpio_base(pio, 0);
// Pins in different ranges: invalid combo!
} else {
// TODO: Need some means to notify the caller
pio_set_gpio_base(pio, 0);
}

pio_program_offset = pio_add_program(pio, &apa102_program);

pio_sm_set_pins_with_mask(pio, sm, 0, (1u << pin_clk) | (1u << pin_dat));
pio_sm_set_pindirs_with_mask(pio, sm, ~0u, (1u << pin_clk) | (1u << pin_dat));
pio_sm_set_pins_with_mask(pio, sm, 0, (1u << (pin_clk - pio_get_gpio_base(pio))) | (1u << (pin_dat - pio_get_gpio_base(pio))));
pio_sm_set_pindirs_with_mask(pio, sm, ~0u, (1u << (pin_clk - pio_get_gpio_base(pio))) | (1u << (pin_dat - pio_get_gpio_base(pio))));
pio_gpio_init(pio, pin_clk);
pio_gpio_init(pio, pin_dat);

Expand Down
3 changes: 3 additions & 0 deletions drivers/plasma/ws2812.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
namespace plasma {

WS2812::WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq, bool rgbw, COLOR_ORDER color_order, RGB* buffer) : buffer(buffer), num_leds(num_leds), color_order(color_order), pio(pio), sm(sm) {
// NOTE: This sets the gpio_base for *the entire PIO* not just this state machine
pio_set_gpio_base(pio, pin >= 32 ? 16 : 0);

pio_program_offset = pio_add_program(pio, &ws2812_program);

pio_gpio_init(pio, pin);
Expand Down
2 changes: 1 addition & 1 deletion drivers/st7735/st7735.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ namespace pimoroni {

// Native 16-bit framebuffer update
void ST7735::update(PicoGraphics *graphics) {
if(graphics->pen_type == PicoGraphics::PEN_RGB565) {
if(graphics->pen_type == PicoGraphics::PEN_RGB565 && graphics->layers == 1) {
command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer);
} else {
command(reg::RAMWR);
Expand Down
2 changes: 1 addition & 1 deletion drivers/st7789/st7789.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ namespace pimoroni {
void ST7789::update(PicoGraphics *graphics) {
uint8_t cmd = reg::RAMWR;

if(graphics->pen_type == PicoGraphics::PEN_RGB565) { // Display buffer is screen native
if(graphics->pen_type == PicoGraphics::PEN_RGB565 && graphics->layers == 1) { // Display buffer is screen native
command(cmd, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer);
} else {
gpio_put(dc, 0); // command mode
Expand Down
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@ add_subdirectory(galactic_unicorn)
add_subdirectory(gfx_pack)
add_subdirectory(cosmic_unicorn)
add_subdirectory(stellar_unicorn)
add_subdirectory(pico_w_explorer)
15 changes: 2 additions & 13 deletions examples/pico_display_2/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
add_subdirectory(mandelbrot)

set(OUTPUT_NAME pico_display2_demo)

add_executable(
${OUTPUT_NAME}
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 st7789 pico_graphics)

# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})
include(pico_display_2_demo.cmake)
include(pico_display_2_vector.cmake)
10 changes: 10 additions & 0 deletions examples/pico_display_2/pico_display_2_demo.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_executable(
pico_display_2_demo
pico_display_2_demo.cpp
)

# Pull in pico libraries that we need
target_link_libraries(pico_display_2_demo 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(pico_display_2_demo)
Loading
Loading