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,6 +165,16 @@ static void __not_in_flash_func(dma_irq_handler)(void) {
129165 ch -> al3_read_addr_trig = (uintptr_t )active_picodvi -> dma_commands ;
130166}
131167
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 )) {
170+ return true;
171+ }
172+ if ((width == 320 || width == 400 ) && height == 240 ) {
173+ return true;
174+ }
175+ return false;
176+ }
177+
132178void common_hal_picodvi_framebuffer_construct (picodvi_framebuffer_obj_t * self ,
133179 mp_uint_t width , mp_uint_t height ,
134180 const mcu_pin_obj_t * clk_dp , const mcu_pin_obj_t * clk_dn ,
@@ -140,11 +186,11 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
140186 mp_raise_msg_varg (& mp_type_RuntimeError , MP_ERROR_TEXT ("%q in use" ), MP_QSTR_picodvi );
141187 }
142188
143- if (!(width == 640 && height == 480 ) && !( width == 320 && height == 240 && ( color_depth == 16 || color_depth == 8 ) )) {
144- mp_raise_ValueError_varg (MP_ERROR_TEXT ("Invalid %q and %q" ), MP_QSTR_width , MP_QSTR_height );
189+ if (!mode_ok (width , height , color_depth )) {
190+ mp_raise_ValueError_varg (MP_ERROR_TEXT ("Invalid %q and %q for color depth %d " ), MP_QSTR_width , MP_QSTR_height , color_depth );
145191 }
146192
147- bool pixel_doubled = width == 320 && height == 240 ;
193+ bool pixel_doubled = height == 240 ;
148194
149195 size_t all_allocated = 0 ;
150196 int8_t pins [8 ] = {
@@ -267,22 +313,27 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
267313 dma_channel_hw_addr (self -> dma_pixel_channel )-> al1_ctrl = dma_ctrl ;
268314 dma_channel_hw_addr (self -> dma_pixel_channel )-> al1_write_addr = dma_write_addr ;
269315 }
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+
270321 for (size_t v_scanline = 0 ; v_scanline < MODE_V_TOTAL_LINES ; v_scanline ++ ) {
271322 if (pixel_doubled ) {
272323 self -> dma_commands [command_word ++ ] = dma_ctrl ;
273324 self -> dma_commands [command_word ++ ] = dma_write_addr ;
274325 }
275326 if (vsync_start <= v_scanline && v_scanline < vsync_end ) {
276- self -> dma_commands [command_word ++ ] = count_of (vblank_line_vsync_on );
327+ self -> dma_commands [command_word ++ ] = count_of (vblank_line640_vsync_on );
277328 self -> dma_commands [command_word ++ ] = (uintptr_t )vblank_line_vsync_on ;
278329 } else if (backporch_start <= v_scanline && v_scanline < backporch_end ) {
279- self -> dma_commands [command_word ++ ] = count_of (vblank_line_vsync_off );
330+ self -> dma_commands [command_word ++ ] = count_of (vblank_line640_vsync_off );
280331 self -> dma_commands [command_word ++ ] = (uintptr_t )vblank_line_vsync_off ;
281332 } else if (frontporch_start <= v_scanline && v_scanline < frontporch_end ) {
282- self -> dma_commands [command_word ++ ] = count_of (vblank_line_vsync_off );
333+ self -> dma_commands [command_word ++ ] = count_of (vblank_line640_vsync_off );
283334 self -> dma_commands [command_word ++ ] = (uintptr_t )vblank_line_vsync_off ;
284335 } else {
285- self -> dma_commands [command_word ++ ] = count_of (vactive_line );
336+ self -> dma_commands [command_word ++ ] = count_of (vactive_line640 );
286337 self -> dma_commands [command_word ++ ] = (uintptr_t )vactive_line ;
287338 size_t row = v_scanline - active_start ;
288339 size_t transfer_count = words_per_line ;
@@ -361,13 +412,15 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
361412 1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB |
362413 0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB ;
363414
364- // Serial output config: clock period of 5 cycles, pop from command
365- // 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.
366419 hstx_ctrl_hw -> csr = 0 ;
367420 hstx_ctrl_hw -> csr =
368421 HSTX_CTRL_CSR_EXPAND_EN_BITS |
369- 5u << HSTX_CTRL_CSR_CLKDIV_LSB |
370- 5u << HSTX_CTRL_CSR_N_SHIFTS_LSB |
422+ clk_factor << HSTX_CTRL_CSR_CLKDIV_LSB |
423+ clk_factor << HSTX_CTRL_CSR_N_SHIFTS_LSB |
371424 2u << HSTX_CTRL_CSR_SHIFT_LSB |
372425 HSTX_CTRL_CSR_EN_BITS ;
373426
@@ -376,6 +429,9 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
376429 // 250 Mbps, which is very close to the bit clock for 480p 60Hz (252 MHz).
377430 // If we want the exact rate then we'll have to reconfigure PLLs.
378431
432+ // Similarly for 800 it's at least close to the nominal rate, we hope..
433+ // (since 800/640 is 5/4)
434+
379435 // Setup the data to pin mapping. `pins` is a pair of pins in a standard
380436 // order: clock, red, green and blue. We don't actually care they are next
381437 // to one another but they'll work better that way.
0 commit comments