kopia lustrzana https://github.com/pimoroni/pimoroni-pico
DV Display: Ability to specify a larger frame than the display, and scroll it
rodzic
8f78e3d6bc
commit
1a54f7b77d
|
@ -15,24 +15,30 @@ extern "C" {
|
|||
|
||||
namespace pimoroni {
|
||||
|
||||
void DVDisplay::init(uint16_t width, uint16_t height, Mode mode) {
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->mode = mode;
|
||||
void DVDisplay::init(uint16_t display_width_, uint16_t display_height_, Mode mode_, uint16_t frame_width_, uint16_t frame_height_) {
|
||||
display_width = display_width_;
|
||||
display_height = display_height_;
|
||||
mode = mode_;
|
||||
|
||||
if (frame_width == 0) frame_width = display_width_;
|
||||
else frame_width = frame_width_;
|
||||
|
||||
if (frame_height == 0) frame_height = display_height_;
|
||||
else frame_height = frame_height_;
|
||||
|
||||
bank = 0;
|
||||
h_repeat = 1;
|
||||
v_repeat = 1;
|
||||
|
||||
uint8_t res_mode = 0xFF;
|
||||
uint16_t full_width = width;
|
||||
uint16_t full_height = height;
|
||||
uint16_t full_width = display_width;
|
||||
uint16_t full_height = display_height;
|
||||
|
||||
if (width < 640 || (width == 640 && (height == 360 || height == 720))) {
|
||||
if (display_width < 640 || (display_width == 640 && (display_height == 360 || display_height == 720))) {
|
||||
h_repeat = 2;
|
||||
full_width *= 2;
|
||||
}
|
||||
if (height < 400) {
|
||||
if (display_height < 400) {
|
||||
v_repeat = 2;
|
||||
full_height *= 2;
|
||||
}
|
||||
|
@ -58,7 +64,7 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
if (res_mode == 0xFF) {
|
||||
mp_printf(&mp_plat_print, "Resolution %dx%d is not supported. Will use 720x480.\n", width, height);
|
||||
mp_printf(&mp_plat_print, "Resolution %dx%d is not supported. Will use 720x480.\n", display_width, display_height);
|
||||
}
|
||||
|
||||
gpio_init(RAM_SEL);
|
||||
|
@ -105,7 +111,7 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
else if (pixel_buffer_location.y != -1) {
|
||||
ram.write(point_to_address(pixel_buffer_location), pixel_buffer, pixel_buffer_x << 1);
|
||||
ram.write(point_to_address16(pixel_buffer_location), pixel_buffer, pixel_buffer_x << 1);
|
||||
pixel_buffer_location.y = -1;
|
||||
}
|
||||
bank ^= 1;
|
||||
|
@ -122,6 +128,14 @@ namespace pimoroni {
|
|||
swd_reset();
|
||||
}
|
||||
|
||||
void DVDisplay::set_display_offset(const Point& p) {
|
||||
int32_t offset = (int32_t)point_to_address(p) - (int32_t)point_to_address({0,0});
|
||||
while (offset & 3) {
|
||||
offset -= pixel_size();
|
||||
}
|
||||
i2c->write_bytes(I2C_ADDR, I2C_REG_SCROLL, (uint8_t*)&offset, 4);
|
||||
}
|
||||
|
||||
uint8_t DVDisplay::get_gpio() {
|
||||
return i2c->reg_read_uint8(I2C_ADDR, I2C_REG_GPIO);
|
||||
}
|
||||
|
@ -232,13 +246,13 @@ namespace pimoroni {
|
|||
if (pixel_buffer_x & 1) pixel_buffer[pixel_buffer_x >> 1] |= (uint32_t)colour << 16;
|
||||
else pixel_buffer[pixel_buffer_x >> 1] = colour;
|
||||
if (++pixel_buffer_x == PIXEL_BUFFER_LEN_IN_WORDS * 2) {
|
||||
ram.write(point_to_address(pixel_buffer_location), pixel_buffer, PIXEL_BUFFER_LEN_IN_WORDS * 4);
|
||||
ram.write(point_to_address16(pixel_buffer_location), pixel_buffer, PIXEL_BUFFER_LEN_IN_WORDS * 4);
|
||||
pixel_buffer_location.y = -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (pixel_buffer_location.y != -1) {
|
||||
ram.write(point_to_address(pixel_buffer_location), pixel_buffer, pixel_buffer_x << 1);
|
||||
ram.write(point_to_address16(pixel_buffer_location), pixel_buffer, pixel_buffer_x << 1);
|
||||
}
|
||||
pixel_buffer_location = p;
|
||||
pixel_buffer_x = 1;
|
||||
|
@ -247,7 +261,7 @@ namespace pimoroni {
|
|||
|
||||
void DVDisplay::write_pixel_span(const Point &p, uint l, uint16_t colour)
|
||||
{
|
||||
write(point_to_address(p), l, colour);
|
||||
write(point_to_address16(p), l, colour);
|
||||
}
|
||||
|
||||
void DVDisplay::write_pixel(const Point &p, RGB888 colour)
|
||||
|
@ -265,18 +279,18 @@ namespace pimoroni {
|
|||
uint32_t offset = 0;
|
||||
if (((uintptr_t)data & 0x2) != 0) {
|
||||
uint32_t val = *data++;
|
||||
ram.write(point_to_address(p), &val, 2);
|
||||
ram.write(point_to_address16(p), &val, 2);
|
||||
--l;
|
||||
offset = 2;
|
||||
}
|
||||
if (l > 0) {
|
||||
ram.write(point_to_address(p) + offset, (uint32_t*)data, l << 1);
|
||||
ram.write(point_to_address16(p) + offset, (uint32_t*)data, l << 1);
|
||||
}
|
||||
}
|
||||
|
||||
void DVDisplay::read_pixel_span(const Point &p, uint l, uint16_t *data)
|
||||
{
|
||||
read(point_to_address(p), l, data);
|
||||
read(point_to_address16(p), l, data);
|
||||
}
|
||||
|
||||
void DVDisplay::set_mode(Mode new_mode)
|
||||
|
@ -305,7 +319,7 @@ namespace pimoroni {
|
|||
|
||||
void DVDisplay::write_palette()
|
||||
{
|
||||
uint addr = (height + 7) * 4;
|
||||
uint addr = (display_height + 7) * 4;
|
||||
ram.write(addr, (uint32_t*)palette, PALETTE_SIZE * 3);
|
||||
}
|
||||
|
||||
|
@ -355,13 +369,13 @@ namespace pimoroni {
|
|||
void DVDisplay::write_header_preamble()
|
||||
{
|
||||
uint32_t buf[8];
|
||||
uint32_t full_width = width * h_repeat;
|
||||
uint32_t full_width = display_width * h_repeat;
|
||||
buf[0] = 0x4F434950;
|
||||
buf[1] = 0x01000101 + ((uint32_t)v_repeat << 16);
|
||||
buf[2] = full_width << 16;
|
||||
buf[3] = (uint32_t)height << 16;
|
||||
buf[3] = (uint32_t)display_height << 16;
|
||||
buf[4] = 0x00000001;
|
||||
buf[5] = 0x00010000 + height + (bank << 24);
|
||||
buf[5] = 0x00010000 + display_height + (bank << 24);
|
||||
buf[6] = 0x00000001;
|
||||
ram.write(0, buf, 7 * 4);
|
||||
ram.wait_for_finish_blocking();
|
||||
|
@ -375,13 +389,31 @@ namespace pimoroni {
|
|||
uint addr = 4 * 7;
|
||||
uint line_type = 0x80000000u + ((uint)mode << 28);
|
||||
mp_printf(&mp_plat_print, "Write header, line type %08x\n", line_type);
|
||||
for (int i = 0; i < height; i += 8) {
|
||||
for (int i = 0; i < display_height; i += 8) {
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
buf[j] = line_type + ((uint32_t)h_repeat << 24) + ((i + j) * width * 6) + base_address;
|
||||
buf[j] = line_type + ((uint32_t)h_repeat << 24) + ((i + j) * frame_width * 6) + base_address;
|
||||
}
|
||||
ram.write(addr, buf, 8 * 4);
|
||||
ram.wait_for_finish_blocking();
|
||||
addr += 4 * 8;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DVDisplay::point_to_address(const Point& p) const {
|
||||
switch(mode) {
|
||||
default:
|
||||
case MODE_RGB555: return point_to_address16(p);
|
||||
case MODE_PALETTE: return point_to_address_palette(p);
|
||||
case MODE_RGB888: return point_to_address24(p);
|
||||
}
|
||||
}
|
||||
|
||||
int DVDisplay::pixel_size() const {
|
||||
switch(mode) {
|
||||
default:
|
||||
case MODE_RGB555: return 2;
|
||||
case MODE_PALETTE: return 1;
|
||||
case MODE_RGB888: return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ namespace pimoroni {
|
|||
static constexpr int PALETTE_SIZE = 32;
|
||||
|
||||
enum Mode {
|
||||
MODE_RGB555 = 1,
|
||||
MODE_PALETTE = 2,
|
||||
MODE_RGB555 = 1,
|
||||
MODE_RGB888 = 3,
|
||||
};
|
||||
|
||||
|
@ -41,6 +41,7 @@ namespace pimoroni {
|
|||
static constexpr uint I2C_REG_GPIO_HI_PULL_UP = 0xCB;
|
||||
static constexpr uint I2C_REG_GPIO_HI_PULL_DOWN = 0xCC;
|
||||
static constexpr uint I2C_REG_EDID = 0xED;
|
||||
static constexpr uint I2C_REG_SCROLL = 0xF0;
|
||||
|
||||
//--------------------------------------------------
|
||||
// Variables
|
||||
|
@ -59,8 +60,10 @@ namespace pimoroni {
|
|||
static constexpr uint RAM_SEL = 8;
|
||||
|
||||
static constexpr uint32_t base_address = 0x10000;
|
||||
uint16_t width = 0;
|
||||
uint16_t height = 0;
|
||||
uint16_t display_width = 0;
|
||||
uint16_t display_height = 0;
|
||||
uint16_t frame_width = 0;
|
||||
uint16_t frame_height = 0;
|
||||
uint8_t bank = 0;
|
||||
uint8_t h_repeat = 1;
|
||||
uint8_t v_repeat = 1;
|
||||
|
@ -127,7 +130,7 @@ namespace pimoroni {
|
|||
void write_pixel(const Point &p, RGB888 colour) override;
|
||||
void write_pixel_span(const Point &p, uint l, RGB888 colour) override;
|
||||
|
||||
void init(uint16_t width, uint16_t height, Mode mode = MODE_RGB555);
|
||||
void init(uint16_t width, uint16_t height, Mode mode = MODE_RGB555, uint16_t frame_width = 0, uint16_t frame_height = 0);
|
||||
void flip();
|
||||
void reset();
|
||||
|
||||
|
@ -137,12 +140,18 @@ namespace pimoroni {
|
|||
void set_mode(Mode new_mode);
|
||||
void set_palette(RGB888 palette[PALETTE_SIZE]);
|
||||
void set_palette_colour(uint8_t entry, RGB888 colour);
|
||||
|
||||
|
||||
void write_palette_pixel(const Point &p, uint8_t colour);
|
||||
void write_palette_pixel_span(const Point &p, uint l, uint8_t colour);
|
||||
void write_palette_pixel_span(const Point &p, uint l, uint8_t* data);
|
||||
void read_palette_pixel_span(const Point &p, uint l, uint8_t *data);
|
||||
|
||||
// Set the top left corner of the display within the frame, if a larger
|
||||
// frame is specified than the display.
|
||||
// Note that the supplied x coordinate is rounded down to the previous multiple of 2 in RGB555 mode
|
||||
// or multiple of 4 in palette or RGB888 modes
|
||||
void set_display_offset(const Point& p);
|
||||
|
||||
uint8_t get_gpio();
|
||||
uint8_t get_gpio_hi();
|
||||
void set_gpio_hi_dir(uint pin, bool output);
|
||||
|
@ -187,16 +196,19 @@ namespace pimoroni {
|
|||
void read(uint32_t address, size_t len, uint8_t *data);
|
||||
void write(uint32_t address, size_t len, const RGB888 colour);
|
||||
|
||||
uint32_t point_to_address(const Point &p) {
|
||||
return base_address + ((p.y * (uint32_t)width * 3) + p.x) * 2;
|
||||
uint32_t point_to_address(const Point& p) const;
|
||||
int pixel_size() const;
|
||||
|
||||
uint32_t point_to_address16(const Point &p) const {
|
||||
return base_address + ((p.y * (uint32_t)frame_width * 3) + p.x) * 2;
|
||||
}
|
||||
|
||||
uint32_t point_to_address_palette(const Point &p) {
|
||||
return base_address + (p.y * (uint32_t)width * 6) + p.x;
|
||||
uint32_t point_to_address_palette(const Point &p) const {
|
||||
return base_address + (p.y * (uint32_t)frame_width * 6) + p.x;
|
||||
}
|
||||
|
||||
uint32_t point_to_address24(const Point &p) {
|
||||
return base_address + ((p.y * (uint32_t)width * 2) + p.x) * 3;
|
||||
uint32_t point_to_address24(const Point &p) const {
|
||||
return base_address + ((p.y * (uint32_t)frame_width * 2) + p.x) * 3;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
|
||||
using namespace pimoroni;
|
||||
|
||||
#define FRAME_WIDTH 360
|
||||
#define FRAME_HEIGHT 480
|
||||
#define DISPLAY_WIDTH 720
|
||||
#define DISPLAY_HEIGHT 480
|
||||
|
||||
#define FRAME_WIDTH 720
|
||||
#define FRAME_HEIGHT 720
|
||||
|
||||
#define READ_EDID 0
|
||||
#if READ_EDID
|
||||
|
@ -49,7 +52,7 @@ int main() {
|
|||
//sleep_ms(5000);
|
||||
|
||||
DVDisplay display;
|
||||
display.init(FRAME_WIDTH, FRAME_HEIGHT, DVDisplay::MODE_RGB888);
|
||||
display.init(DISPLAY_WIDTH, DISPLAY_HEIGHT, DVDisplay::MODE_RGB888, FRAME_WIDTH, FRAME_HEIGHT);
|
||||
//display.test();
|
||||
|
||||
#if READ_EDID
|
||||
|
@ -97,6 +100,9 @@ int main() {
|
|||
printf("Starting\n");
|
||||
graphics.set_font("bitmap8");
|
||||
|
||||
Point scroll = {0, 0};
|
||||
int scroll_dir = 1;
|
||||
|
||||
constexpr int NUM_CIRCLES = 50;
|
||||
struct Circle {
|
||||
uint16_t x, y, size, grow;
|
||||
|
@ -198,6 +204,13 @@ int main() {
|
|||
|
||||
//printf("%02x %02x\n", display.get_gpio(), display.get_gpio_hi());
|
||||
|
||||
display.set_display_offset(scroll);
|
||||
scroll.y += scroll_dir;
|
||||
if (scroll.y + DISPLAY_HEIGHT > FRAME_HEIGHT || scroll.y < 0) {
|
||||
scroll_dir = -scroll_dir;
|
||||
scroll.y += scroll_dir;
|
||||
}
|
||||
|
||||
++frames;
|
||||
display.set_gpio_hi_pull_up_all(frames & 0x3F);
|
||||
display.set_gpio_hi_pull_down_all(~(frames & 0x3F));
|
||||
|
|
Ładowanie…
Reference in New Issue