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 63 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
3a9cdc8
PicoGraphics: Layers.
Gadgetoid Oct 7, 2024
a340b47
PicoGraphics: Support multiple layers in more types.
Gadgetoid Oct 7, 2024
f7a33ad
PicoVector: Rewrite around new C pretty-poly.h.
Gadgetoid Sep 26, 2023
d479923
PicoVector: Rewrite MicroPython bindings.
Gadgetoid Sep 29, 2023
6a8a7c4
PicoVector: Suppress errors.
Gadgetoid Apr 17, 2024
1603b64
PicoVector: Vendor pretty-poly and tweak rotation.
Gadgetoid Apr 18, 2024
c5af175
PicoVector: Swap rotate translation order.
Gadgetoid Apr 18, 2024
dc251a4
PicoVector: alright-fonts bringup.
Gadgetoid Apr 18, 2024
29ee929
PicoVector: Break things until they work.
Gadgetoid Apr 19, 2024
26c310f
PicoVector: fix pointer arithmatic in af_load_font_file.
Gadgetoid Jun 5, 2024
89fc625
PicoVector: Fix out of bounds drawing.
Gadgetoid Jun 5, 2024
e35678e
PicoVector: render text that doesn't end with a linebreak.
Gadgetoid Jun 5, 2024
2285035
PicoVector: C++ basic bringup.
Gadgetoid Jun 11, 2024
5ce870f
PicoVector: Remove alright_fonts.cpp from cmake.
Gadgetoid Jul 9, 2024
03ada25
PicoGraphics: Add RGB565 alpha blending support.
Gadgetoid Jul 11, 2024
7fd72fe
PicoVector: Fix x16 anti-aliasing.
Gadgetoid Jul 11, 2024
d6862fd
PicoGraphics: Add get_clip.
Gadgetoid Jul 11, 2024
8212fb7
PicoVector: Remove malloc from MicroPython bindings.
Gadgetoid Jul 11, 2024
80c5218
PicoVector: Support float types in MicroPython bindings.
Gadgetoid Jul 11, 2024
5c03d8e
PicoVector: Use tile renderer for all pens.
Gadgetoid Jul 22, 2024
34cd133
PicoVector: Rewrite around new linked-lists poly.
Gadgetoid Jul 22, 2024
3f46772
PicoVector: Update C++ examples.
Gadgetoid Jul 23, 2024
d4e0d66
PicoVector: Big refactor, ppp primitives.
Gadgetoid Jul 25, 2024
23d1668
PicoGraphics: Add layer support to PicoVector tile renderer.
Gadgetoid Oct 8, 2024
9989135
PicoVector: Improve text rendering and control.
Gadgetoid Oct 8, 2024
97f00a0
PicoGraphics: RGB565 skip layers if not enabled.
Gadgetoid Oct 9, 2024
230d9fa
PicoVector: Refactor text multiline support.
Gadgetoid Oct 9, 2024
e04e6ef
PicoVector: Remove (ifdef guard) debug functions.
Gadgetoid Oct 10, 2024
b69ad9b
PicoGraphics: Add Presto.
Gadgetoid Aug 14, 2024
9985daf
Plasma: Add support for GPIOs >=32.
Gadgetoid Oct 24, 2024
25f30fb
PicoGraphics: Non-blocking Inky update for #936.
Gadgetoid Oct 31, 2024
0cd4669
PicoVector: Prefix some pretty-poly variables.
Gadgetoid Nov 14, 2024
234ea41
PicoVector: Runtime buffer allocation.
Gadgetoid Nov 14, 2024
cc38cf0
PicoVector: Revert the tile buffer to be fixed.
Gadgetoid Nov 18, 2024
6942bc7
PicoVector: Add optional text max width and max height.
MichaelBell Nov 17, 2024
4274cd1
PicoVector: Apply overall transform to text rendering.
MichaelBell Nov 17, 2024
b9f11a3
PicoGraphics: Presto full res option.
MichaelBell Nov 17, 2024
c9c7f1d
PicoGraphics: Don't force Presto to RGB565.
Gadgetoid Nov 20, 2024
27b363d
PicoVector: Update example with text bounds.
Gadgetoid Nov 20, 2024
b71324b
PicoGraphics/Hub75: Add support for 128x128.
Gadgetoid Nov 20, 2024
93323f4
PicoVector: Remove * 4 from pp_nodes lookup.
Gadgetoid Nov 21, 2024
515521c
PicoVector: Avoid MicroPython GC.
Gadgetoid Nov 21, 2024
44ffeee
Hub75: Performance improvements and stacked mode.
Gadgetoid Nov 21, 2024
4fc8323
Hub75: Reformat loop for performance.
MichaelBell Nov 21, 2024
f441968
PicoGraphics: Implement RGB888 alpha blending.
Gadgetoid Nov 21, 2024
749feb0
PicoVector: Add star and line primitives.
lowfatcode Nov 26, 2024
e99a791
PicoVector: Avoid clipping bottom right AA edges.
MichaelBell Nov 26, 2024
bed45f6
PicoVector: Tweak for C++ compatibility.
Gadgetoid Nov 26, 2024
ff1917c
PicoVector: MPY bindings for line and arc.
Gadgetoid Nov 26, 2024
796e7cf
PicoGraphics: Check for out of range layers.
Gadgetoid Dec 2, 2024
09a06bd
PicoVector: Fix bug in Polygon.regular.
Gadgetoid Dec 5, 2024
3f2bce2
PicoVector: Fix bug in Polygon.rectangle.
Gadgetoid Dec 6, 2024
3a0b049
PicoVector: Add arbitrary matrix transform.
Gadgetoid Dec 11, 2024
219b93c
PicoVector: Initialise pp_transform().
Gadgetoid Dec 11, 2024
dff55e1
PicoVector: Fully initialise text metrics.
MichaelBell Dec 13, 2024
d10fa81
Hub75: Fix LED ghosting.
MichaelBell Dec 15, 2024
974b3cc
PicoVector: Fix ppp arc memory corruption.
MichaelBell Jan 8, 2025
5d883cc
ST7789: Add RAMCTRL mentioned in #1040.
Gadgetoid Jan 15, 2025
1ae1814
Tufty 2040: Update polygons example.
Gadgetoid Jan 16, 2025
0df3095
PicoVector: Fix bug in polygon iterator.
Gadgetoid Jan 16, 2025
fc42c6a
Tufty 2040: Update spectrometer vector example.
Gadgetoid Jan 16, 2025
5e2ba8d
PicoVector: Fix fonts not rendering with no transform set.
Gadgetoid Jan 16, 2025
a2e6a88
PicoVector: AF: Support for 16bit point count.
Gadgetoid Jan 16, 2025
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
9 changes: 8 additions & 1 deletion drivers/st7789/st7789.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace pimoroni {
TEON = 0x35,
MADCTL = 0x36,
COLMOD = 0x3A,
RAMCTRL = 0xB0,
GCTRL = 0xB7,
VCOMS = 0xBB,
LCMCTRL = 0xC0,
Expand Down Expand Up @@ -79,6 +80,12 @@ namespace pimoroni {
command(reg::PWCTRL1, 2, "\xa4\xa1");
command(reg::FRCTRL2, 1, "\x0f");

// As noted in https://github.com/pimoroni/pimoroni-pico/issues/1040
// this is required to avoid a weird light grey banding issue with low brightness green.
// The banding is not visible without tweaking gamma settings (GMCTRP1 & GMCTRN1) but
// it makes sense to fix it anyway.
command(reg::RAMCTRL, 2, "\x00\xc0");

if(width == 240 && height == 240) {
command(reg::GCTRL, 1, "\x14");
command(reg::VCOMS, 1, "\x37");
Expand Down Expand Up @@ -282,7 +289,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 @@ -64,3 +64,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