Skip to content

Commit 361c988

Browse files
Simplify resolution spec and switch some constructor args around
1 parent 8d0223b commit 361c988

File tree

8 files changed

+119
-89
lines changed

8 files changed

+119
-89
lines changed

examples/1bit_double_buffer/1bit_double_buffer.ino

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
#include <PicoDVI.h>
55

66
// Double-buffered 1-bit and 8-bit are declared a little differently...
7-
// 1-bit accepts a boolean after the the canvas dimensions to enable/disable
7+
// 1-bit accepts a boolean after the the resolution to enable/disable
88
// double-buffering, whereas 8-bit double-buffered uses a distinct class.
9-
//DVIGFX1 display(640, 480, true, dvi_timing_640x480p_60hz, VREG_VOLTAGE_1_30, pimoroni_demo_hdmi_cfg);
10-
DVIGFX1 display(800, 480, true, dvi_timing_800x480p_60hz, VREG_VOLTAGE_1_30, pimoroni_demo_hdmi_cfg);
9+
// 1-bit currently supports 640x480 and 800x480 resolutions only.
10+
DVIGFX1 display(DVI_RES_800x480p60, true, pimoroni_demo_hdmi_cfg);
1111

1212
#define N_BALLS 100
1313
struct {

examples/1bit_single_buffer/1bit_single_buffer.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
#include <PicoDVI.h>
44

5-
//DVIGFX1 display(640, 480, false, dvi_timing_640x480p_60hz, VREG_VOLTAGE_1_30, pimoroni_demo_hdmi_cfg);
6-
DVIGFX1 display(800, 480, false, dvi_timing_800x480p_60hz, VREG_VOLTAGE_1_30, pimoroni_demo_hdmi_cfg);
5+
// 1-bit currently supports 640x480 and 800x480 resolutions only.
6+
DVIGFX1 display(DVI_RES_800x480p60, false, pimoroni_demo_hdmi_cfg);
77

88
void setup() {
99
Serial.begin(115200);

examples/8bit_double_buffer/8bit_double_buffer.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
// 8-bit requires a distinct class for double-buffering, as its memory
88
// requirements are unique, while 1-bit has an extra constructor
99
// argument to enable or disable this.
10-
//DVIGFX8x2 display(320, 240, dvi_timing_640x480p_60hz, VREG_VOLTAGE_1_20, pimoroni_demo_hdmi_cfg);
11-
DVIGFX8x2 display(400, 240, dvi_timing_800x480p_60hz, VREG_VOLTAGE_1_30, pimoroni_demo_hdmi_cfg);
10+
// 8-bit currently supports 320x240 and 400x240 resolutions only.
11+
DVIGFX8x2 display(DVI_RES_400x240p60, pimoroni_demo_hdmi_cfg);
1212

1313
#define N_BALLS 100 // 1-254 (not 255)
1414
struct {

examples/8bit_single_buffer/8bit_single_buffer.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
#include <PicoDVI.h>
44

5-
DVIGFX8 display(320, 240, dvi_timing_640x480p_60hz, VREG_VOLTAGE_1_20, pimoroni_demo_hdmi_cfg);
6-
//DVIGFX8 display(400, 240, dvi_timing_800x480p_60hz, VREG_VOLTAGE_1_30, pimoroni_demo_hdmi_cfg);
5+
// 8-bit currently supports 320x240 and 400x240 resolutions only.
6+
DVIGFX8 display(DVI_RES_400x240p60, pimoroni_demo_hdmi_cfg);
77

88
void setup() {
99
Serial.begin(115200);

examples/hello/hello.ino

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
#include <Fonts/FreeSansBold18pt7b.h> // A custom font
66

77
// Your basic 320x240 16-bit color display:
8-
DVIGFX16 display(320, 240, dvi_timing_640x480p_60hz, VREG_VOLTAGE_1_20, pimoroni_demo_hdmi_cfg);
9-
// Not all RP2040s can deal with the 295 MHz overclock this requires, but if you'd like to try:
10-
//DVIGFX16 display(400, 240, dvi_timing_800x480p_60hz, VREG_VOLTAGE_1_30, pimoroni_demo_hdmi_cfg);
8+
DVIGFX16 display(DVI_RES_320x240p60, pimoroni_demo_hdmi_cfg);
9+
// 16-bit currently supports 320x240 and 400x240 resolutions only.
1110

1211
void setup() {
1312
Serial.begin(115200);

examples/virtual_spitft/virtual_spitft.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
#define PIN_DATA 18 // 3 contiguous pins start here: data, DC, clk
1212
#define PIN_CS 21 // Chip-select need not be contiguous
1313

14-
// 320x240 16-bit color display:
15-
DVIGFX16 display(320, 240, dvi_timing_640x480p_60hz, VREG_VOLTAGE_1_20, pimoroni_demo_hdmi_cfg);
14+
// 320x240 16-bit color display (to match common TFT display resolution):
15+
DVIGFX16 display(DVI_RES_320x240p60, pimoroni_demo_hdmi_cfg);
1616

1717
// Output of pioasm ----
1818

src/PicoDVI.cpp

Lines changed: 68 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,29 @@
44
// PicoDVI class encapsulates some of the libdvi functionality -------------
55
// Subclasses then implement specific display types.
66

7+
static struct {
8+
const dvi_timing &timing;
9+
vreg_voltage v;
10+
uint16_t width;
11+
uint16_t height;
12+
uint8_t v_rep;
13+
} dvispec[] = {
14+
{dvi_timing_640x480p_60hz, VREG_VOLTAGE_1_20, 320, 240, 2},
15+
{dvi_timing_800x480p_60hz, VREG_VOLTAGE_1_20, 400, 240, 2},
16+
{dvi_timing_640x480p_60hz, VREG_VOLTAGE_1_20, 640, 480, 1},
17+
{dvi_timing_800x480p_60hz, VREG_VOLTAGE_1_20, 800, 480, 1},
18+
// Additional resolutions might get added here if the overclock issue can
19+
// be sorted out. Regardless, always keep this list 1:1 in sync with the
20+
// DVIresolution enum in PicoDVI.h.
21+
{dvi_timing_1280x720p_30hz, VREG_VOLTAGE_1_30, 1280, 720, 1},
22+
};
23+
724
static PicoDVI *dviptr = NULL; // For C access to active C++ object
825
// Semaphore might be preferable, but this seems to work for now...
926
static volatile bool wait_begin = true;
1027

1128
// Runs on core 1 on startup
12-
void __not_in_flash("main") setup1(void) {
29+
void setup1(void) {
1330
while (wait_begin)
1431
; // Wait for DVIGFX*::begin() to do its thing on core 0
1532
dviptr->_setup();
@@ -22,8 +39,8 @@ void PicoDVI::_setup(void) {
2239
(*mainloop)(&dvi0);
2340
}
2441

25-
PicoDVI::PicoDVI(const struct dvi_timing &t, vreg_voltage v,
26-
const struct dvi_serialiser_cfg &c)
42+
PicoDVI::PicoDVI(const struct dvi_timing &t, const struct dvi_serialiser_cfg &c,
43+
vreg_voltage v)
2744
: voltage(v) {
2845
dvi0.timing = &t;
2946
memcpy(&dvi0.ser_cfg, &c, sizeof dvi0.ser_cfg);
@@ -46,11 +63,11 @@ void PicoDVI::begin(void) {
4663

4764
static void *gfxptr = NULL; // For C access to active C++ object
4865

49-
DVIGFX16::DVIGFX16(const uint16_t w, const uint16_t h,
50-
const struct dvi_timing &t, vreg_voltage v,
51-
const struct dvi_serialiser_cfg &c)
52-
: PicoDVI(t, v, c), GFXcanvas16(w, h) {
53-
dvi_vertical_repeat = 2;
66+
DVIGFX16::DVIGFX16(const DVIresolution r, const struct dvi_serialiser_cfg &c,
67+
vreg_voltage v)
68+
: PicoDVI(dvispec[r].timing, c, v),
69+
GFXcanvas16(dvispec[r].width, dvispec[r].height) {
70+
dvi_vertical_repeat = dvispec[r].v_rep;
5471
dvi_monochrome_tmds = false;
5572
}
5673

@@ -103,11 +120,12 @@ bool DVIGFX16::begin(void) {
103120
// HEIGHT value is de-tweaked to the original value so clipping won't allow
104121
// any drawing operations to spill into the 16-bit scanlines.
105122

106-
DVIGFX8::DVIGFX8(const uint16_t w, const uint16_t h, const struct dvi_timing &t,
107-
vreg_voltage v, const struct dvi_serialiser_cfg &c)
108-
: PicoDVI(t, v, c), GFXcanvas8(w, ((h + 1) & ~1) + 4) {
109-
HEIGHT = _height = h;
110-
dvi_vertical_repeat = 2;
123+
DVIGFX8::DVIGFX8(const DVIresolution r, const struct dvi_serialiser_cfg &c,
124+
vreg_voltage v)
125+
: PicoDVI(dvispec[r].timing, c, v),
126+
GFXcanvas8(dvispec[r].width, ((dvispec[r].height + 1) & ~1) + 4) {
127+
HEIGHT = _height = dvispec[r].height;
128+
dvi_vertical_repeat = dvispec[r].v_rep;
111129
dvi_monochrome_tmds = false;
112130
}
113131

@@ -163,13 +181,13 @@ bool DVIGFX8::begin(void) {
163181
// "back" state. Call swap() to switch the front/back buffers at the next
164182
// vertical sync, for flicker-free and tear-free animation.
165183

166-
DVIGFX8x2::DVIGFX8x2(const uint16_t w, const uint16_t h,
167-
const struct dvi_timing &t, vreg_voltage v,
168-
const struct dvi_serialiser_cfg &c)
169-
: PicoDVI(t, v, c), GFXcanvas8(w, h * 2 + 4) {
170-
HEIGHT = _height = h;
184+
DVIGFX8x2::DVIGFX8x2(const DVIresolution r, const struct dvi_serialiser_cfg &c,
185+
vreg_voltage v)
186+
: PicoDVI(dvispec[r].timing, c, v),
187+
GFXcanvas8(dvispec[r].width, dvispec[r].height * 2 + 4) {
188+
HEIGHT = _height = dvispec[r].height;
171189
buffer_save = buffer;
172-
dvi_vertical_repeat = 2;
190+
dvi_vertical_repeat = dvispec[r].v_rep;
173191
dvi_monochrome_tmds = false;
174192
}
175193

@@ -249,13 +267,15 @@ void DVIGFX8x2::swap(bool copy_framebuffer, bool copy_palette) {
249267

250268
// 1-bit WIP --------
251269

252-
DVIGFX1::DVIGFX1(const uint16_t w, const uint16_t h, const bool d,
253-
const struct dvi_timing &t, vreg_voltage v,
254-
const struct dvi_serialiser_cfg &c)
255-
: PicoDVI(t, v, c), GFXcanvas1(w, d ? (h * 2) : h), dbuf(d) {
256-
dvi_vertical_repeat = 1;
270+
DVIGFX1::DVIGFX1(const DVIresolution r, const bool d,
271+
const struct dvi_serialiser_cfg &c, vreg_voltage v)
272+
: PicoDVI(dvispec[r].timing, c, v),
273+
GFXcanvas1(dvispec[r].width,
274+
d ? (dvispec[r].height * 2) : dvispec[r].height),
275+
dbuf(d) {
276+
dvi_vertical_repeat = dvispec[r].v_rep;
257277
dvi_monochrome_tmds = true;
258-
HEIGHT = _height = h;
278+
HEIGHT = _height = dvispec[r].height;
259279
buffer_save = buffer;
260280
}
261281

@@ -320,21 +340,20 @@ void DVIGFX1::swap(bool copy_framebuffer) {
320340
#define FONT_FIRST_ASCII 32
321341
#include "font_8x8.h"
322342

323-
DVIterm1::DVIterm1(const uint16_t w, const uint16_t h,
324-
const struct dvi_timing &t, vreg_voltage v,
325-
const struct dvi_serialiser_cfg &c)
326-
: PicoDVI(t, v, c), GFXcanvas16(w / 8, h / 8) {
327-
dvi_vertical_repeat = 1;
343+
DVIterm1::DVIterm1(const DVIresolution r, const struct dvi_serialiser_cfg &c,
344+
vreg_voltage v)
345+
: PicoDVI(dvispec[r].timing, c, v),
346+
GFXcanvas16(dvispec[r].width / 8, dvispec[r].height / 8) {
347+
dvi_vertical_repeat = dvispec[r].v_rep;
328348
dvi_monochrome_tmds = true;
329349
}
330350

331-
DVIterm1::~DVIterm1(void) {
332-
gfxptr = NULL;
333-
}
351+
DVIterm1::~DVIterm1(void) { gfxptr = NULL; }
334352

335-
//static uint8_t scanbuf[1280 / 8] __attribute__ ((aligned (4)));
336353
// TO DO: alloc this dynamically as part of object (maybe part of canvas)
337-
static uint8_t scanbuf[1280 / 8];
354+
static uint8_t scanbuf[1280 / 8] __attribute__((aligned(4)));
355+
356+
#ifdef TERM_USE_INTERRUPT
338357

339358
void inline __not_in_flash_func(DVIterm1::_prepare_scanline)(uint16_t y) {
340359
uint16_t *row = getBuffer() + (y / FONT_CHAR_HEIGHT) * WIDTH;
@@ -348,7 +367,7 @@ void inline __not_in_flash_func(DVIterm1::_prepare_scanline)(uint16_t y) {
348367
}
349368
uint32_t *tmdsbuf;
350369
queue_remove_blocking_u32(&dvi0.q_tmds_free, &tmdsbuf);
351-
tmds_encode_1bpp((const uint32_t*)scanbuf, tmdsbuf, WIDTH * 8);
370+
tmds_encode_1bpp((const uint32_t *)scanbuf, tmdsbuf, WIDTH * 8);
352371
queue_add_blocking_u32(&dvi0.q_tmds_valid, &tmdsbuf);
353372
}
354373

@@ -360,10 +379,12 @@ void __not_in_flash_func(term1_scanline_callback)(void) {
360379

361380
static void mainloopterm1(struct dvi_inst *inst) {
362381
// Idle func, everything happens in interrupt
363-
for (;;) delay(1000);
382+
for (;;)
383+
delay(1000);
364384
}
365385

366-
#if 0
386+
#else
387+
367388
// Old way, without interrupt
368389
// This is a little simpler and might stick with it
369390
// since nothing important to do in idle func above.
@@ -373,11 +394,10 @@ static void mainloopterm1(struct dvi_inst *inst) {
373394
}
374395

375396
void __not_in_flash_func(DVIterm1::_mainloop)(void) {
376-
static uint8_t scanbuf[1280 / 8] __attribute__ ((aligned (4)));
377397
for (;;) {
378398
for (uint16_t y = 0; y < HEIGHT; y++) {
379399
uint16_t *row = getBuffer() + y * WIDTH;
380-
for (uint8_t y1=0; y1<8; y1++) {
400+
for (uint8_t y1 = 0; y1 < 8; y1++) {
381401
uint32_t offset = y1 * FONT_N_CHARS;
382402
for (uint16_t x = 0; x < WIDTH; x++) {
383403
uint8_t mask = row[x] >> 8;
@@ -392,17 +412,23 @@ void __not_in_flash_func(DVIterm1::_mainloop)(void) {
392412
}
393413
}
394414
}
395-
#endif
396415

397-
bool __not_in_flash_func(DVIterm1::begin)(void) {
416+
#endif // end TERM_USE_INTERRUPT
417+
418+
bool DVIterm1::begin(void) {
398419
if ((getBuffer())) {
399420
gfxptr = this;
421+
#ifdef TERM_USE_INTERRUPT
400422
dvi0.scanline_callback = term1_scanline_callback;
423+
#endif
401424
mainloop = mainloopterm1;
402425
PicoDVI::begin();
426+
403427
// Must do this AFTER begin because tmdsbuf (accessed in func)
404428
// doesn't exist yet until dvi_init (in begin) is called.
429+
#ifdef TERM_USE_INTERRUPT
405430
_prepare_scanline(0);
431+
#endif
406432

407433
wait_begin = false; // Set core 1 in motion
408434
return true;

src/PicoDVI.h

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,24 @@
66
#include "pico/stdlib.h" // In Pico SDK
77
#include <Adafruit_GFX.h>
88

9+
// A set list of resolutions keeps things manageable for users,
10+
// avoids some possibly-incompatible argument combos to constructors.
11+
enum DVIresolution {
12+
DVI_RES_320x240p60 = 0,
13+
DVI_RES_400x240p60,
14+
DVI_RES_640x480p60,
15+
DVI_RES_800x480p60,
16+
DVI_RES_1280x720p30 // Experimenting, plz don't use
17+
};
18+
919
extern uint8_t dvi_vertical_repeat; // In libdvi/dvi.c
1020
extern bool dvi_monochrome_tmds; // In libdvi/dvi.c
1121

1222
class PicoDVI {
1323
public:
14-
PicoDVI(const struct dvi_timing &t = dvi_timing_640x480p_60hz,
15-
vreg_voltage v = VREG_VOLTAGE_1_10,
16-
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg);
24+
PicoDVI(const struct dvi_timing &t = dvi_timing_800x480p_60hz,
25+
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
26+
vreg_voltage v = VREG_VOLTAGE_1_20);
1727
~PicoDVI(void);
1828
void _setup(void);
1929

@@ -24,25 +34,11 @@ class PicoDVI {
2434
void (*mainloop)(dvi_inst *) = NULL;
2535
};
2636

27-
class DVIterm1 : public PicoDVI, public GFXcanvas16 {
28-
public:
29-
DVIterm1(const uint16_t w = 320, const uint16_t h = 240,
30-
const struct dvi_timing &t = dvi_timing_640x480p_60hz,
31-
vreg_voltage v = VREG_VOLTAGE_1_10,
32-
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg);
33-
~DVIterm1(void);
34-
bool begin(void);
35-
void _prepare_scanline(uint16_t y);
36-
void _mainloop(void);
37-
protected:
38-
};
39-
4037
class DVIGFX16 : public PicoDVI, public GFXcanvas16 {
4138
public:
42-
DVIGFX16(const uint16_t w = 320, const uint16_t h = 240,
43-
const struct dvi_timing &t = dvi_timing_640x480p_60hz,
44-
vreg_voltage v = VREG_VOLTAGE_1_10,
45-
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg);
39+
DVIGFX16(const DVIresolution res = DVI_RES_400x240p60,
40+
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
41+
vreg_voltage v = VREG_VOLTAGE_1_20);
4642
~DVIGFX16(void);
4743
bool begin(void);
4844
uint16_t color565(uint8_t red, uint8_t green, uint8_t blue) {
@@ -56,10 +52,9 @@ class DVIGFX16 : public PicoDVI, public GFXcanvas16 {
5652

5753
class DVIGFX8 : public PicoDVI, public GFXcanvas8 {
5854
public:
59-
DVIGFX8(const uint16_t w = 320, const uint16_t h = 240,
60-
const struct dvi_timing &t = dvi_timing_640x480p_60hz,
61-
vreg_voltage v = VREG_VOLTAGE_1_10,
62-
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg);
55+
DVIGFX8(const DVIresolution res = DVI_RES_400x240p60,
56+
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
57+
vreg_voltage v = VREG_VOLTAGE_1_20);
6358
~DVIGFX8(void);
6459
bool begin(void);
6560
uint16_t *getPalette(void) { return palette; }
@@ -80,10 +75,9 @@ class DVIGFX8 : public PicoDVI, public GFXcanvas8 {
8075

8176
class DVIGFX8x2 : public PicoDVI, public GFXcanvas8 {
8277
public:
83-
DVIGFX8x2(const uint16_t w = 320, const uint16_t h = 240,
84-
const struct dvi_timing &t = dvi_timing_640x480p_60hz,
85-
vreg_voltage v = VREG_VOLTAGE_1_10,
86-
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg);
78+
DVIGFX8x2(const DVIresolution res = DVI_RES_400x240p60,
79+
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
80+
vreg_voltage v = VREG_VOLTAGE_1_20);
8781
~DVIGFX8x2(void);
8882
bool begin(void);
8983
uint16_t *getPalette(void) { return palette[back_index]; }
@@ -111,11 +105,9 @@ class DVIGFX8x2 : public PicoDVI, public GFXcanvas8 {
111105

112106
class DVIGFX1 : public PicoDVI, public GFXcanvas1 {
113107
public:
114-
DVIGFX1(const uint16_t w = 800, const uint16_t h = 480,
115-
const bool dbuf = false,
116-
const struct dvi_timing &t = dvi_timing_800x480p_60hz,
117-
vreg_voltage v = VREG_VOLTAGE_1_25,
118-
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg);
108+
DVIGFX1(const DVIresolution res = DVI_RES_800x480p60, const bool dbuf = false,
109+
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
110+
vreg_voltage v = VREG_VOLTAGE_1_20);
119111
~DVIGFX1(void);
120112
bool begin(void);
121113
void swap(bool copy_framebuffer = false);
@@ -128,3 +120,16 @@ class DVIGFX1 : public PicoDVI, public GFXcanvas1 {
128120
uint8_t back_index = 0; // Which of 2 buffers receives draw ops
129121
volatile bool swap_wait = 0; // For syncronizing front/back buffer swap
130122
};
123+
124+
class DVIterm1 : public PicoDVI, public GFXcanvas16 {
125+
public:
126+
DVIterm1(const DVIresolution res = DVI_RES_400x240p60,
127+
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
128+
vreg_voltage v = VREG_VOLTAGE_1_20);
129+
~DVIterm1(void);
130+
bool begin(void);
131+
void _prepare_scanline(uint16_t y);
132+
void _mainloop(void);
133+
134+
protected:
135+
};

0 commit comments

Comments
 (0)