Prefer RGB332, add palette management functions

This commit is contained in:
Phil Howard 2022-05-26 11:51:15 +01:00
parent 7abe4aae7f
commit 51ad7edb09
16 changed files with 117 additions and 69 deletions

View File

@ -219,8 +219,13 @@ namespace pimoroni {
gpio_put(cs, 1);
}
// Native 16-bit framebuffer update
void ST7789::update() {
command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer);
}
// 8-bit framebuffer with palette conversion update
void ST7789::update(uint16_t *palette) {
//command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer);
command(reg::RAMWR);
uint16_t row[width];
gpio_put(dc, 1); // data mode
@ -228,8 +233,9 @@ namespace pimoroni {
for(auto y = 0u; y < height; y++) {
for(auto x = 0u; x < width; x++) {
auto i = y * width + x;
row[x] = palette[frame_buffer[i]];
row[x] = palette[((uint8_t *)frame_buffer)[i]];
}
// TODO: Add DMA->SPI / PIO while we prep the next row
if(spi) {
spi_write_blocking(spi, (const uint8_t*)row, width * sizeof(uint16_t));
} else {

View File

@ -36,10 +36,10 @@ namespace pimoroni {
public:
// frame buffer where pixel data is stored
uint8_t *frame_buffer;
void *frame_buffer;
// Parallel init
ST7789(uint16_t width, uint16_t height, uint8_t *frame_buffer,
ST7789(uint16_t width, uint16_t height, void *frame_buffer,
uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) :
spi(nullptr),
width(width), height(height), round(false),
@ -68,7 +68,7 @@ namespace pimoroni {
}
// Serial init
ST7789(uint16_t width, uint16_t height, bool round, uint8_t *frame_buffer,
ST7789(uint16_t width, uint16_t height, bool round, void *frame_buffer,
spi_inst_t *spi,
uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) :
spi(spi),
@ -101,6 +101,7 @@ namespace pimoroni {
uint get_bl() const;
void command(uint8_t command, size_t len = 0, const char *data = NULL);
void update();
void update(uint16_t *palette);
void set_backlight(uint8_t brightness);
void flip();

View File

@ -10,21 +10,21 @@ namespace pimoroni {
ST7789 st7789;
public:
ST7789Generic(uint16_t width, uint16_t height, bool round=false, uint8_t *frame_buffer=nullptr) :
ST7789Generic(uint16_t width, uint16_t height, bool round=false, void *frame_buffer=nullptr) :
PicoGraphics(width, height, frame_buffer),
st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
this->frame_buffer = (Pen *)st7789.frame_buffer;
this->st7789.init();
};
ST7789Generic(uint16_t width, uint16_t height, bool round, uint8_t *frame_buffer, BG_SPI_SLOT slot) :
ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer, BG_SPI_SLOT slot) :
PicoGraphics(width, height, frame_buffer),
st7789(width, height, round, frame_buffer, PIMORONI_SPI_DEFAULT_INSTANCE, st7789.get_slot_cs(slot), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, st7789.get_slot_bl(slot)) {
this->frame_buffer = (Pen *)st7789.frame_buffer;
this->st7789.init();
};
ST7789Generic(uint16_t width, uint16_t height, bool round, uint8_t *frame_buffer,
ST7789Generic(uint16_t width, uint16_t height, bool round, void *frame_buffer,
spi_inst_t *spi,
uint cs, uint dc, uint sck, uint mosi, uint bl = PIN_UNUSED) :
PicoGraphics(width, height, frame_buffer),
@ -33,7 +33,7 @@ namespace pimoroni {
this->st7789.init();
};
ST7789Generic(uint16_t width, uint16_t height, uint8_t *frame_buffer,
ST7789Generic(uint16_t width, uint16_t height, void *frame_buffer,
uint cs, uint dc, uint wr_sck, uint rd_sck, uint d0, uint bl = PIN_UNUSED) :
PicoGraphics(width, height, frame_buffer),
st7789(width, height, frame_buffer, cs, dc, wr_sck, rd_sck, d0, bl) {

View File

@ -8,13 +8,13 @@
namespace pimoroni {
PicoDisplay::PicoDisplay(uint16_t *buf)
PicoDisplay::PicoDisplay(void *buf)
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf,
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
__fb = buf;
}
PicoDisplay::PicoDisplay(uint16_t *buf, int width, int height)
PicoDisplay::PicoDisplay(void *buf, int width, int height)
: PicoGraphics(width, height, buf), screen(width, height, false, buf,
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
__fb = buf;

View File

@ -19,13 +19,13 @@ namespace pimoroni {
static const uint8_t LED_G = 7;
static const uint8_t LED_B = 8;
uint16_t *__fb;
void *__fb;
private:
ST7789 screen;
public:
PicoDisplay(uint16_t *buf);
PicoDisplay(uint16_t *buf, int width, int height);
PicoDisplay(void *buf);
PicoDisplay(void *buf, int width, int height);
void init();
void update();

View File

@ -8,13 +8,13 @@
namespace pimoroni {
PicoDisplay2::PicoDisplay2(uint16_t *buf)
PicoDisplay2::PicoDisplay2(void *buf)
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, false, buf,
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
__fb = buf;
}
PicoDisplay2::PicoDisplay2(uint16_t *buf, int width, int height)
PicoDisplay2::PicoDisplay2(void *buf, int width, int height)
: PicoGraphics(width, height, buf), screen(width, height, false, buf,
PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, SPI_BG_FRONT_PWM) {
__fb = buf;

View File

@ -19,13 +19,13 @@ namespace pimoroni {
static const uint8_t LED_G = 7;
static const uint8_t LED_B = 8;
uint16_t *__fb;
void *__fb;
private:
ST7789 screen;
public:
PicoDisplay2(uint16_t *buf);
PicoDisplay2(uint16_t *buf, int width, int height);
PicoDisplay2(void *buf);
PicoDisplay2(void *buf, int width, int height);
void init();
void update();

View File

@ -14,7 +14,7 @@ const uint8_t MOTOR2P = 11;
namespace pimoroni {
PicoExplorer::PicoExplorer(uint8_t *buf)
PicoExplorer::PicoExplorer(void *buf)
: PicoGraphics(WIDTH, HEIGHT, buf),
screen(WIDTH, HEIGHT, false, buf, PIMORONI_SPI_DEFAULT_INSTANCE, screen.get_slot_cs(PICO_EXPLORER_ONBOARD), SPI_DEFAULT_MISO, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, screen.get_slot_bl(PICO_EXPLORER_ONBOARD)) {
__fb = buf;

View File

@ -34,13 +34,13 @@ namespace pimoroni {
static const uint GP6 = 6;
static const uint GP7 = 7;
uint8_t *__fb;
void *__fb;
private:
ST7789 screen;
int8_t audio_pin = -1;
public:
PicoExplorer(uint8_t *buf);
PicoExplorer(void *buf);
void init();
void update();

View File

@ -4,6 +4,7 @@ namespace pimoroni {
PicoGraphics::PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer)
: frame_buffer((Pen *)frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) {
set_font(&font6);
default_palette();
};
void PicoGraphics::set_font(const bitmap::font_t *font){
@ -11,28 +12,36 @@ namespace pimoroni {
}
void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) {
pen = create_pen(r, g, b);
pen = put_palette(create_pen_rgb332(r, g, b));
}
void PicoGraphics::set_pen(Pen p) {
pen = p;
}
void PicoGraphics::set_pen_raw(uint16_t p) {
for(auto i=0u; i < palette_ptr; i++) {
if(palette[i] == p) {
pen = i;
return;
};
}
uint16_t PicoGraphics::get_palette(uint8_t i) {
return palette[i];
}
if(palette_ptr < 256) {
palette[palette_ptr] = p;
pen = palette_ptr;
palette_ptr += 1;
void PicoGraphics::put_palette(uint16_t p, uint8_t i) {
palette[i] = p;
if (i > palette_entries) {
palette_entries = i;
}
}
uint8_t PicoGraphics::put_palette(uint16_t p) {
for(auto i=0u; i < palette_entries; i++) {
if(palette[i] == p) return i;
}
if(palette_entries < 256) {
palette[palette_entries] = p;
palette_entries += 1;
}
return palette_entries - 1;
};
void PicoGraphics::set_clip(const Rect &r) {
clip = bounds.intersection(r);
}
@ -136,6 +145,10 @@ namespace pimoroni {
}, t, p.x, p.y, wrap, scale);
}
void PicoGraphics::measure_text(const std::string &t, uint8_t scale) {
bitmap::measure_text(font, t, scale);
}
int32_t orient2d(Point p1, Point p2, Point p3) {
return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
}

View File

@ -55,32 +55,48 @@ namespace pimoroni {
const bitmap::font_t *font;
uint16_t palette[256];
uint16_t palette_ptr = 0;
uint16_t palette_entries = 0;
public:
PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer);
void set_font(const bitmap::font_t *font);
void set_pen(uint8_t r, uint8_t g, uint8_t b);
void set_pen(Pen p);
void set_pen_raw(uint16_t p);
constexpr Pen create_pen(uint8_t r, uint8_t g, uint8_t b) {
constexpr uint16_t create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) {
uint16_t p = ((r & 0b11111000) << 8) |
((g & 0b11111100) << 3) |
((b & 0b11111000) >> 3);
((g & 0b11111100) << 3) |
((b & 0b11111000) >> 3);
p = __builtin_bswap16(p);
return __builtin_bswap16(p);
}
constexpr uint16_t create_pen_rgb332(uint8_t r, uint8_t g, uint8_t b) {
uint16_t p = ((r & 0b11100000) << 8) |
((g & 0b11100000) << 3) |
((b & 0b11000000) >> 3);
for(auto i=0u; i < palette_ptr; i++) {
if(palette[i] == p) return i;
return __builtin_bswap16(p);
}
Pen create_pen(uint8_t r, uint8_t g, uint8_t b) {
return put_palette(create_pen_rgb332(r, g, b));
}
void flush_palette() {
palette_entries = 0;
}
void default_palette() {
for (auto i = 0u; i < 255; i++) {
palette[i] = i;
}
palette_entries = 255;
}
if(palette_ptr < 256) {
palette[palette_ptr] = p;
palette_ptr += 1;
}
return palette_ptr - 1;
};
uint8_t put_palette(uint16_t p);
uint16_t get_palette(uint8_t i);
void put_palette(uint16_t p, uint8_t i);
void set_clip(const Rect &r);
void remove_clip();
@ -96,6 +112,7 @@ namespace pimoroni {
void circle(const Point &p, int32_t r);
void character(const char c, const Point &p, uint8_t scale = 2);
void text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale = 2);
void measure_text(const std::string &t, uint8_t scale = 2);
void polygon(const std::vector<Point> &points);
void triangle(Point p1, Point p2, Point p3);
void line(Point p1, Point p2);

View File

@ -27,7 +27,7 @@ mp_obj_t picodisplay_init(mp_obj_t buf_obj) {
}
// Create a new display pointing to the newly provided buffer
display = new PicoDisplay((uint16_t *)bufinfo.buf);
display = new PicoDisplay(bufinfo.buf);
display->init();
return mp_const_none;

View File

@ -27,7 +27,7 @@ mp_obj_t picodisplay2_init(mp_obj_t buf_obj) {
}
// Create a new display pointing to the newly provided buffer
display2 = new PicoDisplay2((uint16_t *)bufinfo.buf);
display2 = new PicoDisplay2(bufinfo.buf);
display2->init();
return mp_const_none;

View File

@ -1,6 +1,8 @@
#include "st7789.h"
MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_update_obj, GenericST7789_update);
MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_flush_palette_obj, GenericST7789_flush_palette);
MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_default_palette_obj, GenericST7789_default_palette);
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_backlight_obj, 1, GenericST7789_set_backlight);
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_set_pen_obj, 1, GenericST7789_set_pen);
MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_create_pen_obj, 1, GenericST7789_create_pen);
@ -19,13 +21,15 @@ MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_line_obj, 1, GenericST7789_line);
STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) },
{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&GenericST7789_pixel_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) },
{ MP_ROM_QSTR(MP_QSTR_flush_palette), MP_ROM_PTR(&GenericST7789_flush_palette_obj) },
{ MP_ROM_QSTR(MP_QSTR_default_palette), MP_ROM_PTR(&GenericST7789_default_palette_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) },
{ MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&GenericST7789_set_clip_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&GenericST7789_remove_clip_obj) },
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&GenericST7789_clear_obj) },
{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&GenericST7789_pixel_obj) },
{ MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&GenericST7789_pixel_span_obj) },
{ MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&GenericST7789_rectangle_obj) },
{ MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&GenericST7789_circle_obj) },

View File

@ -14,7 +14,7 @@ typedef struct _GenericST7789_obj_t {
mp_obj_base_t base;
ST7789Generic *st7789;
bool parallel;
uint8_t *buffer;
void *buffer;
} GenericST7789_obj_t;
/***** Print *****/
@ -85,12 +85,12 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t
if (args[ARG_buffer].u_obj != mp_const_none) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW);
self->buffer = (uint8_t *)bufinfo.buf;
if(bufinfo.len < (size_t)(width * height)) {
self->buffer = bufinfo.buf;
if(bufinfo.len < (size_t)(width * height * sizeof(Pen))) {
mp_raise_ValueError("Supplied buffer is too small!");
}
} else {
self->buffer = m_new(uint8_t, width * height);
self->buffer = m_new(uint8_t, width * height * sizeof(Pen));
}
if(args[ARG_slot].u_int != -1) {
@ -200,6 +200,20 @@ mp_obj_t GenericST7789_update(mp_obj_t self_in) {
return mp_const_none;
}
mp_obj_t GenericST7789_flush_palette(mp_obj_t self_in) {
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
self->st7789->flush_palette();
return mp_const_none;
}
mp_obj_t GenericST7789_default_palette(mp_obj_t self_in) {
GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
self->st7789->default_palette();
return mp_const_none;
}
mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_brightness };
static const mp_arg_t allowed_args[] = {
@ -225,11 +239,10 @@ mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp
mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
if(n_args <= 2) {
enum { ARG_self, ARG_pen, ARG_raw };
enum { ARG_self, ARG_pen };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_raw, MP_ARG_OBJ, { .u_obj = mp_const_false } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@ -239,18 +252,10 @@ mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t
int pen = args[ARG_pen].u_int;
if (args[ARG_raw].u_obj == mp_const_false) {
if(pen < 0 || pen > 0xff) {
mp_raise_ValueError("p is not a valid pen.");
} else {
self->st7789->set_pen(pen);
}
if(pen < 0 || pen > 0xff) {
mp_raise_ValueError("p is not a valid pen.");
} else {
if(pen < 0 || pen > 0xffff) {
mp_raise_ValueError("p is not a valid pen.");
} else {
self->st7789->set_pen_raw(pen);
}
self->st7789->set_pen(pen);
}
}
else {

View File

@ -11,6 +11,8 @@ extern mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args,
extern mp_obj_t GenericST7789Parallel_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t GenericST7789_update(mp_obj_t self_in);
extern mp_obj_t GenericST7789_flush_palette(mp_obj_t self_in);
extern mp_obj_t GenericST7789_default_palette(mp_obj_t self_in);
extern mp_obj_t GenericST7789_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t GenericST7789_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);