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

Wyświetl plik

@ -15,7 +15,16 @@
namespace pimoroni { namespace pimoroni {
// This is ARGB1555 only for now // 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 // Variables
//-------------------------------------------------- //--------------------------------------------------
@ -53,19 +62,19 @@ namespace pimoroni {
uint8_t bank = 0; uint8_t bank = 0;
uint8_t h_repeat = 1; uint8_t h_repeat = 1;
uint8_t v_repeat = 1; uint8_t v_repeat = 1;
Mode mode = MODE_RGB555;
public: public:
static constexpr int PALETTE_SIZE = 32;
// Valid resolutions are: // Valid resolutions are:
// 640x480 (60Hz), 720x480 (60Hz), 720x400 (70Hz), 720x576 (50Hz) // 640x480 (60Hz), 720x480 (60Hz), 720x400 (70Hz), 720x576 (50Hz)
// 800x600 (60Hz), 800x480 (60Hz), 800x450 (60Hz), 960x540 (50Hz), 1280x720 (30Hz) // 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. // 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. // 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) : ram(CS, D0)
, i2c(I2C_SDA, I2C_SCL) , i2c(I2C_SDA, I2C_SCL)
, width(width), height(height) , width(width), height(height)
, mode(mode)
, pixel_buffer_location(-1, -1) , 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(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 colour) override;
void write_pixel_span(const Point &p, uint l, uint16_t *data); 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; 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 init();
void flip(); void flip();
// 32 colour palette mode. Note that palette entries range from 0-31, // 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 // but when writing colour values the palette entry is in bits 6-2, so the
// entry value is effectively multiplied by 4. // 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(RGB888 palette[PALETTE_SIZE]);
void set_palette_colour(uint8_t entry, RGB888 colour); void set_palette_colour(uint8_t entry, RGB888 colour);
@ -146,7 +160,6 @@ namespace pimoroni {
private: private:
uint8_t palette[PALETTE_SIZE * 3] alignas(4); uint8_t palette[PALETTE_SIZE * 3] alignas(4);
bool use_palette_mode = false;
bool rewrite_header = false; bool rewrite_header = false;
static constexpr int PIXEL_BUFFER_LEN_IN_WORDS = 16; 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 read(uint32_t address, size_t len, uint16_t *data);
void write(uint32_t address, size_t len, const uint8_t colour); void write(uint32_t address, size_t len, const uint8_t colour);
void read(uint32_t address, size_t len, uint8_t *data); 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_palette();
void write_header(); void write_header();
@ -165,11 +179,15 @@ namespace pimoroni {
void i2c_modify_bit(uint8_t reg, uint bit, bool enable); void i2c_modify_bit(uint8_t reg, uint bit, bool enable);
uint32_t point_to_address(const Point &p) { 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) { 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; using namespace pimoroni;
#define FRAME_WIDTH 720 #define FRAME_WIDTH 360
#define FRAME_HEIGHT 480 #define FRAME_HEIGHT 240
#define READ_EDID 1 #define READ_EDID 0
#if READ_EDID #if READ_EDID
extern "C" { int decode_edid(unsigned char* edid); } extern "C" { int decode_edid(unsigned char* edid); }
#endif #endif
#define USE_PALETTE 0
void on_uart_rx() { void on_uart_rx() {
while (uart_is_readable(uart1)) { while (uart_is_readable(uart1)) {
uint8_t ch = uart_getc(uart1); uint8_t ch = uart_getc(uart1);
@ -44,9 +46,9 @@ int main() {
gpio_set_dir(BUTTON_A, GPIO_IN); gpio_set_dir(BUTTON_A, GPIO_IN);
gpio_pull_up(BUTTON_A); 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.init();
//display.test(); //display.test();
@ -61,19 +63,29 @@ int main() {
} }
#endif #endif
display.enable_palette(true); #if USE_PALETTE
display.set_mode(DVDisplay::MODE_PALETTE)
PicoGraphics_PenDV_P5 graphics(FRAME_WIDTH, FRAME_HEIGHT, display); 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(0, 0, 0);
graphics.create_pen(0xFF, 0xFF, 0xFF); graphics.create_pen(0xFF, 0xFF, 0xFF);
#if USE_PALETTE
for (int i = 0; i < 25; ++i) { for (int i = 0; i < 25; ++i) {
graphics.create_pen_hsv(i * 0.04f, 1.0f, 1.0f); graphics.create_pen_hsv(i * 0.04f, 1.0f, 1.0f);
} }
#endif
graphics.set_pen(0xFF, 0, 0); graphics.set_pen(0xFF, 0, 0);
printf(".\n");
graphics.clear(); graphics.clear();
printf("..\n");
display.flip(); display.flip();
printf("...\n");
sleep_ms(2000); sleep_ms(2000);
graphics.set_pen(0, 0, 0xFF); graphics.set_pen(0, 0, 0xFF);
graphics.clear(); graphics.clear();
@ -84,7 +96,8 @@ int main() {
constexpr int NUM_CIRCLES = 50; constexpr int NUM_CIRCLES = 50;
struct Circle { struct Circle {
uint16_t x, y, size, grow, pen; uint16_t x, y, size, grow;
uint32_t pen;
} circles[NUM_CIRCLES]; } circles[NUM_CIRCLES];
for(int i =0 ; i < 50 ; i++) for(int i =0 ; i < 50 ; i++)
@ -93,7 +106,11 @@ int main() {
circles[i].grow = std::max(0, (rand() % 50) - 25); circles[i].grow = std::max(0, (rand() % 50) - 25);
circles[i].x = rand() % graphics.bounds.w; circles[i].x = rand() % graphics.bounds.w;
circles[i].y = rand() % graphics.bounds.h; circles[i].y = rand() % graphics.bounds.h;
#if USE_PALETTE
circles[i].pen = 2 + (i >> 1); 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; 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_rgb888.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_inky7.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_rgb555.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_dv_rgb888.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_dv_p5.cpp ${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_dv_p5.cpp
) )

Wyświetl plik

@ -203,7 +203,8 @@ namespace pimoroni {
PEN_RGB888, PEN_RGB888,
PEN_INKY7, PEN_INKY7,
PEN_DV_RGB555, PEN_DV_RGB555,
PEN_DV_P5 PEN_DV_P5,
PEN_DV_RGB888,
}; };
void *frame_buffer; 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 { class PicoGraphics_PenDV_P5 : public PicoGraphics {
public: public:
static const uint16_t palette_size = 32; 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);
}
}