Skip to content

Commit 3a7135f

Browse files
committed
untested: support 800x480@60Hz (& 400x240) on rp2350
1 parent 71638ad commit 3a7135f

File tree

1 file changed

+76
-30
lines changed

1 file changed

+76
-30
lines changed

ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,17 @@
5353
#define SYNC_V1_H0 (TMDS_CTRL_10 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20))
5454
#define SYNC_V1_H1 (TMDS_CTRL_11 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20))
5555

56-
#define MODE_H_SYNC_POLARITY 0
57-
#define MODE_H_FRONT_PORCH 16
58-
#define MODE_H_SYNC_WIDTH 96
59-
#define MODE_H_BACK_PORCH 48
60-
#define MODE_H_ACTIVE_PIXELS 640
56+
#define MODE_800_H_SYNC_POLARITY 0
57+
#define MODE_800_H_FRONT_PORCH 16
58+
#define MODE_800_H_SYNC_WIDTH 96
59+
#define MODE_800_H_BACK_PORCH 48
60+
#define MODE_800_H_ACTIVE_PIXELS 800
61+
62+
#define MODE_640_H_SYNC_POLARITY 0
63+
#define MODE_640_H_FRONT_PORCH 16
64+
#define MODE_640_H_SYNC_WIDTH 96
65+
#define MODE_640_H_BACK_PORCH 48
66+
#define MODE_640_H_ACTIVE_PIXELS 640
6167

6268
#define MODE_V_SYNC_POLARITY 0
6369
#define MODE_V_FRONT_PORCH 10
@@ -83,34 +89,64 @@
8389
// ----------------------------------------------------------------------------
8490
// HSTX command lists
8591

86-
static uint32_t vblank_line_vsync_off[] = {
87-
HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH,
92+
static uint32_t vblank_line640_vsync_off[] = {
93+
HSTX_CMD_RAW_REPEAT | MODE_640_H_FRONT_PORCH,
8894
SYNC_V1_H1,
89-
HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH,
95+
HSTX_CMD_RAW_REPEAT | MODE_640_H_SYNC_WIDTH,
9096
SYNC_V1_H0,
91-
HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS),
97+
HSTX_CMD_RAW_REPEAT | (MODE_640_H_BACK_PORCH + MODE_640_H_ACTIVE_PIXELS),
9298
SYNC_V1_H1
9399
};
94100

95-
static uint32_t vblank_line_vsync_on[] = {
96-
HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH,
101+
static uint32_t vblank_line640_vsync_on[] = {
102+
HSTX_CMD_RAW_REPEAT | MODE_640_H_FRONT_PORCH,
97103
SYNC_V0_H1,
98-
HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH,
104+
HSTX_CMD_RAW_REPEAT | MODE_640_H_SYNC_WIDTH,
99105
SYNC_V0_H0,
100-
HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS),
106+
HSTX_CMD_RAW_REPEAT | (MODE_640_H_BACK_PORCH + MODE_640_H_ACTIVE_PIXELS),
101107
SYNC_V0_H1
102108
};
103109

104-
static uint32_t vactive_line[] = {
105-
HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH,
110+
static uint32_t vactive_line640[] = {
111+
HSTX_CMD_RAW_REPEAT | MODE_640_H_FRONT_PORCH,
106112
SYNC_V1_H1,
107113
HSTX_CMD_NOP,
108-
HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH,
114+
HSTX_CMD_RAW_REPEAT | MODE_640_H_SYNC_WIDTH,
109115
SYNC_V1_H0,
110116
HSTX_CMD_NOP,
111-
HSTX_CMD_RAW_REPEAT | MODE_H_BACK_PORCH,
117+
HSTX_CMD_RAW_REPEAT | MODE_640_H_BACK_PORCH,
112118
SYNC_V1_H1,
113-
HSTX_CMD_TMDS | MODE_H_ACTIVE_PIXELS
119+
HSTX_CMD_TMDS | MODE_640_H_ACTIVE_PIXELS
120+
};
121+
122+
static uint32_t vblank_line800_vsync_off[] = {
123+
HSTX_CMD_RAW_REPEAT | MODE_800_H_FRONT_PORCH,
124+
SYNC_V1_H1,
125+
HSTX_CMD_RAW_REPEAT | MODE_800_H_SYNC_WIDTH,
126+
SYNC_V1_H0,
127+
HSTX_CMD_RAW_REPEAT | (MODE_800_H_BACK_PORCH + MODE_800_H_ACTIVE_PIXELS),
128+
SYNC_V1_H1
129+
};
130+
131+
static uint32_t vblank_line800_vsync_on[] = {
132+
HSTX_CMD_RAW_REPEAT | MODE_800_H_FRONT_PORCH,
133+
SYNC_V0_H1,
134+
HSTX_CMD_RAW_REPEAT | MODE_800_H_SYNC_WIDTH,
135+
SYNC_V0_H0,
136+
HSTX_CMD_RAW_REPEAT | (MODE_800_H_BACK_PORCH + MODE_800_H_ACTIVE_PIXELS),
137+
SYNC_V0_H1
138+
};
139+
140+
static uint32_t vactive_line800[] = {
141+
HSTX_CMD_RAW_REPEAT | MODE_800_H_FRONT_PORCH,
142+
SYNC_V1_H1,
143+
HSTX_CMD_NOP,
144+
HSTX_CMD_RAW_REPEAT | MODE_800_H_SYNC_WIDTH,
145+
SYNC_V1_H0,
146+
HSTX_CMD_NOP,
147+
HSTX_CMD_RAW_REPEAT | MODE_800_H_BACK_PORCH,
148+
SYNC_V1_H1,
149+
HSTX_CMD_TMDS | MODE_800_H_ACTIVE_PIXELS
114150
};
115151

116152
picodvi_framebuffer_obj_t *active_picodvi = NULL;
@@ -129,11 +165,11 @@ static void __not_in_flash_func(dma_irq_handler)(void) {
129165
ch->al3_read_addr_trig = (uintptr_t)active_picodvi->dma_commands;
130166
}
131167

132-
static void mode_ok(mp_uint_t width, mp_uint_t height, mp_uint_t color_depth) {
133-
if (width == 640 && height == 480 && (color_depth < 8)) {
168+
static bool mode_ok(mp_uint_t width, mp_uint_t height, mp_uint_t color_depth) {
169+
if ((width == 640 || width == 800) && height == 480 && (color_depth < 8)) {
134170
return true;
135171
}
136-
if (width == 320 && height == 240 )
172+
if ((width == 320 || width == 400) && height == 240) {
137173
return true;
138174
}
139175
return false;
@@ -154,7 +190,7 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
154190
mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q and %q for color depth %d"), MP_QSTR_width, MP_QSTR_height, color_depth);
155191
}
156192

157-
bool pixel_doubled = width == 320 && height == 240;
193+
bool pixel_doubled = height == 240;
158194

159195
size_t all_allocated = 0;
160196
int8_t pins[8] = {
@@ -277,22 +313,27 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
277313
dma_channel_hw_addr(self->dma_pixel_channel)->al1_ctrl = dma_ctrl;
278314
dma_channel_hw_addr(self->dma_pixel_channel)->al1_write_addr = dma_write_addr;
279315
}
316+
bool is_640_based = (width == 320 || width == 640);
317+
uint32_t *vblank_line_vsync_on = is_640_based ? vblank_line640_vsync_on : vblank_line800_vsync_on;
318+
uint32_t *vblank_line_vsync_off = is_640_based ? vblank_line640_vsync_off : vblank_line800_vsync_off;
319+
uint32_t *vactive_line = is_640_based ? vactive_line640 : vactive_line800;
320+
280321
for (size_t v_scanline = 0; v_scanline < MODE_V_TOTAL_LINES; v_scanline++) {
281322
if (pixel_doubled) {
282323
self->dma_commands[command_word++] = dma_ctrl;
283324
self->dma_commands[command_word++] = dma_write_addr;
284325
}
285326
if (vsync_start <= v_scanline && v_scanline < vsync_end) {
286-
self->dma_commands[command_word++] = count_of(vblank_line_vsync_on);
327+
self->dma_commands[command_word++] = count_of(vblank_line640_vsync_on);
287328
self->dma_commands[command_word++] = (uintptr_t)vblank_line_vsync_on;
288329
} else if (backporch_start <= v_scanline && v_scanline < backporch_end) {
289-
self->dma_commands[command_word++] = count_of(vblank_line_vsync_off);
330+
self->dma_commands[command_word++] = count_of(vblank_line640_vsync_off);
290331
self->dma_commands[command_word++] = (uintptr_t)vblank_line_vsync_off;
291332
} else if (frontporch_start <= v_scanline && v_scanline < frontporch_end) {
292-
self->dma_commands[command_word++] = count_of(vblank_line_vsync_off);
333+
self->dma_commands[command_word++] = count_of(vblank_line640_vsync_off);
293334
self->dma_commands[command_word++] = (uintptr_t)vblank_line_vsync_off;
294335
} else {
295-
self->dma_commands[command_word++] = count_of(vactive_line);
336+
self->dma_commands[command_word++] = count_of(vactive_line640);
296337
self->dma_commands[command_word++] = (uintptr_t)vactive_line;
297338
size_t row = v_scanline - active_start;
298339
size_t transfer_count = words_per_line;
@@ -371,13 +412,15 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
371412
1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB |
372413
0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB;
373414

374-
// Serial output config: clock period of 5 cycles, pop from command
375-
// expander every 5 cycles, shift the output shiftreg by 2 every cycle.
415+
uint32_t clk_factor = is_640_based ? 5u : 4u;
416+
417+
// Serial output config: clock period of 4 or 5 cycles, pop from command
418+
// expander every 4 or 5 cycles, shift the output shiftreg by 2 every cycle.
376419
hstx_ctrl_hw->csr = 0;
377420
hstx_ctrl_hw->csr =
378421
HSTX_CTRL_CSR_EXPAND_EN_BITS |
379-
5u << HSTX_CTRL_CSR_CLKDIV_LSB |
380-
5u << HSTX_CTRL_CSR_N_SHIFTS_LSB |
422+
clk_factor << HSTX_CTRL_CSR_CLKDIV_LSB |
423+
clk_factor << HSTX_CTRL_CSR_N_SHIFTS_LSB |
381424
2u << HSTX_CTRL_CSR_SHIFT_LSB |
382425
HSTX_CTRL_CSR_EN_BITS;
383426

@@ -386,6 +429,9 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
386429
// 250 Mbps, which is very close to the bit clock for 480p 60Hz (252 MHz).
387430
// If we want the exact rate then we'll have to reconfigure PLLs.
388431

432+
// Similarly for 800 it's at least close to the nominal rate, we hope..
433+
// (since 800/640 is 5/4)
434+
389435
// Setup the data to pin mapping. `pins` is a pair of pins in a standard
390436
// order: clock, red, green and blue. We don't actually care they are next
391437
// to one another but they'll work better that way.

0 commit comments

Comments
 (0)