Limited support for palette and RGB888 modes

dv_stick
Mike Bell 2023-06-03 12:25:43 +01:00 zatwierdzone przez Phil Howard
rodzic a7435c6a5e
commit daf7232024
8 zmienionych plików z 1823 dodań i 1417 usunięć

Wyświetl plik

@ -9,7 +9,7 @@
namespace pimoroni {
void DVDisplay::init() {
uint8_t mode = 0xFF;
uint8_t res_mode = 0xFF;
uint16_t full_width = width;
uint16_t full_height = height;
@ -23,26 +23,26 @@ namespace pimoroni {
}
if (full_width == 640) {
mode = 0;
res_mode = 0;
}
else if (full_width == 720) {
if (full_height == 480) mode = 1;
else if (full_height == 400) mode = 2;
else if (full_height == 576) mode = 3;
if (full_height == 480) res_mode = 1;
else if (full_height == 400) res_mode = 2;
else if (full_height == 576) res_mode = 3;
}
else if (full_width == 800) {
if (full_height == 600) mode = 0x10;
else if (full_height == 480) mode = 0x11;
else if (full_height == 450) mode = 0x12;
if (full_height == 600) res_mode = 0x10;
else if (full_height == 480) res_mode = 0x11;
else if (full_height == 450) res_mode = 0x12;
}
else if (full_width == 960) {
if (full_height == 540) mode = 0x14;
if (full_height == 540) res_mode = 0x14;
}
else if (full_width == 1280) {
if (full_height == 720) mode = 0x15;
if (full_height == 720) res_mode = 0x15;
}
if (mode == 0xFF) {
if (res_mode == 0xFF) {
printf("Resolution %dx%d is not supported. Will use 720x480.\n", width, height);
}
@ -73,8 +73,8 @@ namespace pimoroni {
printf("Start I2C\n");
if (mode != 0xFF) {
i2c.reg_write_uint8(I2C_ADDR, I2C_REG_SET_RES, mode);
if (res_mode != 0xFF) {
i2c.reg_write_uint8(I2C_ADDR, I2C_REG_SET_RES, res_mode);
}
i2c.reg_write_uint8(I2C_ADDR, I2C_REG_START, 1);
@ -82,7 +82,7 @@ namespace pimoroni {
}
void DVDisplay::flip() {
if (use_palette_mode) {
if (mode == MODE_PALETTE) {
write_palette();
if (pixel_buffer_location.y != -1) {
ram.write(point_to_address_palette(pixel_buffer_location), pixel_buffer, pixel_buffer_x);
@ -169,6 +169,26 @@ namespace pimoroni {
ram.write_repeat(address, val, len << 1);
}
void DVDisplay::write(uint32_t address, size_t len, const RGB888 colour)
{
const int VAL_BUFFER_LEN = 60;
const int VAL_BUFFER_LEN_IN_PIXELS = (VAL_BUFFER_LEN / 3) * 4;
uint32_t vals[VAL_BUFFER_LEN];
for (int i = 0, j = 0; i < VAL_BUFFER_LEN_IN_PIXELS && i < (int)len; i += 4) {
vals[j++] = colour | (colour << 24);
vals[j++] = (colour >> 8) | (colour << 16);
vals[j++] = (colour >> 16) | (colour << 8);
}
for (int len_bytes = len * 3; len_bytes > 0; len_bytes -= VAL_BUFFER_LEN_IN_PIXELS * 3) {
uint len_to_write = std::min(len_bytes, VAL_BUFFER_LEN_IN_PIXELS * 3);
ram.write(address, vals, len_to_write);
address += len_to_write;
}
ram.wait_for_finish_blocking();
}
void DVDisplay::read(uint32_t address, size_t len, uint16_t *data)
{
ram.read_blocking(address, (uint32_t*)data, (len + 1) >> 1);
@ -211,6 +231,16 @@ namespace pimoroni {
write(point_to_address(p), l, colour);
}
void DVDisplay::write_pixel(const Point &p, RGB888 colour)
{
ram.write(point_to_address24(p), &colour, 3);
}
void DVDisplay::write_pixel_span(const Point &p, uint l, RGB888 colour)
{
write(point_to_address24(p), l, colour);
}
void DVDisplay::write_pixel_span(const Point &p, uint l, uint16_t *data)
{
uint32_t offset = 0;
@ -230,12 +260,14 @@ namespace pimoroni {
read(point_to_address(p), l, data);
}
void DVDisplay::enable_palette(bool enable)
void DVDisplay::set_mode(Mode new_mode)
{
use_palette_mode = enable;
mode = new_mode;
rewrite_header = true;
write_header();
write_palette();
if (mode == MODE_PALETTE) {
write_palette();
}
}
void DVDisplay::set_palette(RGB888 new_palette[PALETTE_SIZE])
@ -316,11 +348,11 @@ namespace pimoroni {
ram.wait_for_finish_blocking();
uint addr = 4 * 7;
uint line_type = 0x90000000u;
if (use_palette_mode) line_type = 0xa0000000u;
uint line_type = 0x80000000u + ((uint)mode << 28);
printf("Write header, line type %08x\n", line_type);
for (int i = 0; i < height; i += 8) {
for (int j = 0; j < 8; ++j) {
buf[j] = line_type + ((uint32_t)h_repeat << 24) + ((i + j) * width * 2) + base_address;
buf[j] = line_type + ((uint32_t)h_repeat << 24) + ((i + j) * width * 6) + base_address;
}
ram.write(addr, buf, 8 * 4);
ram.wait_for_finish_blocking();

Wyświetl plik

@ -15,7 +15,16 @@
namespace pimoroni {
// This is ARGB1555 only for now
class DVDisplay : public IDirectDisplayDriver<uint16_t>, public IPaletteDisplayDriver {
class DVDisplay : public IDirectDisplayDriver<uint16_t>, public IDirectDisplayDriver<RGB888>, public IPaletteDisplayDriver {
public:
static constexpr int PALETTE_SIZE = 32;
enum Mode {
MODE_RGB555 = 1,
MODE_PALETTE = 2,
MODE_RGB888 = 3,
};
//--------------------------------------------------
// Variables
//--------------------------------------------------
@ -53,19 +62,19 @@ namespace pimoroni {
uint8_t bank = 0;
uint8_t h_repeat = 1;
uint8_t v_repeat = 1;
Mode mode = MODE_RGB555;
public:
static constexpr int PALETTE_SIZE = 32;
// Valid resolutions are:
// 640x480 (60Hz), 720x480 (60Hz), 720x400 (70Hz), 720x576 (50Hz)
// 800x600 (60Hz), 800x480 (60Hz), 800x450 (60Hz), 960x540 (50Hz), 1280x720 (30Hz)
// Note resolutions on the second line require quite extreme overclocking and may not work on all hardware.
// Either or both of the horizontal or vertical component of any resolution may be halved.
DVDisplay(uint16_t width, uint16_t height)
DVDisplay(uint16_t width, uint16_t height, Mode mode = MODE_RGB555)
: ram(CS, D0)
, i2c(I2C_SDA, I2C_SCL)
, width(width), height(height)
, mode(mode)
, pixel_buffer_location(-1, -1)
{}
@ -102,18 +111,23 @@ namespace pimoroni {
}
}
// 16bpp interface
void write_pixel(const Point &p, uint16_t colour) override;
void write_pixel_span(const Point &p, uint l, uint16_t colour) override;
void write_pixel_span(const Point &p, uint l, uint16_t *data);
void read_pixel_span(const Point &p, uint l, uint16_t *data) override;
// 24bpp interface
void write_pixel(const Point &p, RGB888 colour) override;
void write_pixel_span(const Point &p, uint l, RGB888 colour) override;
void init();
void flip();
// 32 colour palette mode. Note that palette entries range from 0-31,
// but when writing colour values the palette entry is in bits 6-2, so the
// entry value is effectively multiplied by 4.
void enable_palette(bool enable);
void set_mode(Mode new_mode);
void set_palette(RGB888 palette[PALETTE_SIZE]);
void set_palette_colour(uint8_t entry, RGB888 colour);
@ -146,7 +160,6 @@ namespace pimoroni {
private:
uint8_t palette[PALETTE_SIZE * 3] alignas(4);
bool use_palette_mode = false;
bool rewrite_header = false;
static constexpr int PIXEL_BUFFER_LEN_IN_WORDS = 16;
@ -158,6 +171,7 @@ namespace pimoroni {
void read(uint32_t address, size_t len, uint16_t *data);
void write(uint32_t address, size_t len, const uint8_t colour);
void read(uint32_t address, size_t len, uint8_t *data);
void write(uint32_t address, size_t len, const RGB888 colour);
void write_palette();
void write_header();
@ -165,11 +179,15 @@ namespace pimoroni {
void i2c_modify_bit(uint8_t reg, uint bit, bool enable);
uint32_t point_to_address(const Point &p) {
return base_address + ((p.y * (uint32_t)width) + p.x) * 2;
return base_address + ((p.y * (uint32_t)width * 3) + p.x) * 2;
}
uint32_t point_to_address_palette(const Point &p) {
return base_address + (p.y * (uint32_t)width * 2) + p.x;
return base_address + (p.y * (uint32_t)width * 6) + p.x;
}
uint32_t point_to_address24(const Point &p) {
return base_address + ((p.y * (uint32_t)width * 2) + p.x) * 3;
}
};
}

Wyświetl plik

@ -9,14 +9,16 @@
using namespace pimoroni;
#define FRAME_WIDTH 720
#define FRAME_HEIGHT 480
#define FRAME_WIDTH 360
#define FRAME_HEIGHT 240
#define READ_EDID 1
#define READ_EDID 0
#if READ_EDID
extern "C" { int decode_edid(unsigned char* edid); }
#endif
#define USE_PALETTE 0
void on_uart_rx() {
while (uart_is_readable(uart1)) {
uint8_t ch = uart_getc(uart1);
@ -44,9 +46,9 @@ int main() {
gpio_set_dir(BUTTON_A, GPIO_IN);
gpio_pull_up(BUTTON_A);
//sleep_ms(5000);
sleep_ms(5000);
DVDisplay display(FRAME_WIDTH, FRAME_HEIGHT);
DVDisplay display(FRAME_WIDTH, FRAME_HEIGHT, DVDisplay::MODE_RGB888);
display.init();
//display.test();
@ -61,19 +63,29 @@ int main() {
}
#endif
display.enable_palette(true);
#if USE_PALETTE
display.set_mode(DVDisplay::MODE_PALETTE)
PicoGraphics_PenDV_P5 graphics(FRAME_WIDTH, FRAME_HEIGHT, display);
#else
//display.set_mode(DVDisplay::MODE_RGB888);
PicoGraphics_PenDV_RGB888 graphics(FRAME_WIDTH, FRAME_HEIGHT, display);
#endif
graphics.create_pen(0, 0, 0);
graphics.create_pen(0xFF, 0xFF, 0xFF);
#if USE_PALETTE
for (int i = 0; i < 25; ++i) {
graphics.create_pen_hsv(i * 0.04f, 1.0f, 1.0f);
}
#endif
graphics.set_pen(0xFF, 0, 0);
printf(".\n");
graphics.clear();
printf("..\n");
display.flip();
printf("...\n");
sleep_ms(2000);
graphics.set_pen(0, 0, 0xFF);
graphics.clear();
@ -84,7 +96,8 @@ int main() {
constexpr int NUM_CIRCLES = 50;
struct Circle {
uint16_t x, y, size, grow, pen;
uint16_t x, y, size, grow;
uint32_t pen;
} circles[NUM_CIRCLES];
for(int i =0 ; i < 50 ; i++)
@ -93,7 +106,11 @@ int main() {
circles[i].grow = std::max(0, (rand() % 50) - 25);
circles[i].x = rand() % graphics.bounds.w;
circles[i].y = rand() % graphics.bounds.h;
#if USE_PALETTE
circles[i].pen = 2 + (i >> 1);
#else
circles[i].pen = graphics.create_pen_hsv(i * 0.02f, 1.0f, 1.0f);
#endif
}
int frames = 0;

Wyświetl plik

@ -19,6 +19,7 @@ add_library(pico_graphics
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb888.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_inky7.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_dv_rgb555.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_dv_rgb888.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_dv_p5.cpp
)

Wyświetl plik

@ -203,7 +203,8 @@ namespace pimoroni {
PEN_RGB888,
PEN_INKY7,
PEN_DV_RGB555,
PEN_DV_P5
PEN_DV_P5,
PEN_DV_RGB888,
};
void *frame_buffer;
@ -615,6 +616,24 @@ namespace pimoroni {
}
};
class PicoGraphics_PenDV_RGB888 : public PicoGraphics {
public:
RGB888 color;
IDirectDisplayDriver<RGB888> &driver;
PicoGraphics_PenDV_RGB888(uint16_t width, uint16_t height, IDirectDisplayDriver<RGB888> &direct_display_driver);
void set_pen(uint c) override;
void set_pen(uint8_t r, uint8_t g, uint8_t b) override;
int create_pen(uint8_t r, uint8_t g, uint8_t b) override;
int create_pen_hsv(float h, float s, float v) override;
void set_pixel(const Point &p) override;
void set_pixel_span(const Point &p, uint l) override;
static size_t buffer_size(uint w, uint h) {
return w * h * sizeof(RGB888);
}
};
class PicoGraphics_PenDV_P5 : public PicoGraphics {
public:
static const uint16_t palette_size = 32;

Wyświetl plik

@ -0,0 +1,29 @@
#include "pico_graphics.hpp"
namespace pimoroni {
PicoGraphics_PenDV_RGB888::PicoGraphics_PenDV_RGB888(uint16_t width, uint16_t height, IDirectDisplayDriver<RGB888> &direct_display_driver)
: PicoGraphics(width, height, nullptr),
driver(direct_display_driver)
{
this->pen_type = PEN_DV_RGB888;
}
void PicoGraphics_PenDV_RGB888::set_pen(uint c) {
color = c;
}
void PicoGraphics_PenDV_RGB888::set_pen(uint8_t r, uint8_t g, uint8_t b) {
RGB src_color{r, g, b};
color = src_color.to_rgb888();
}
int PicoGraphics_PenDV_RGB888::create_pen(uint8_t r, uint8_t g, uint8_t b) {
return RGB(r, g, b).to_rgb888();
}
int PicoGraphics_PenDV_RGB888::create_pen_hsv(float h, float s, float v) {
return RGB::from_hsv(h, s, v).to_rgb888();
}
void PicoGraphics_PenDV_RGB888::set_pixel(const Point &p) {
driver.write_pixel(p, color);
}
void PicoGraphics_PenDV_RGB888::set_pixel_span(const Point &p, uint l) {
driver.write_pixel_span(p, l, color);
}
}