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
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
116152picodvi_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