@@ -165,12 +165,11 @@ static void __not_in_flash_func(dma_irq_handler)(void) {
165165 return ;
166166 }
167167 uint ch_num = active_picodvi -> dma_pixel_channel ;
168- dma_channel_hw_t * ch = & dma_hw -> ch [ch_num ];
169168 dma_hw -> intr = 1u << ch_num ;
170169
171170 // Set the read_addr back to the start and trigger the first transfer (which
172171 // will trigger the pixel channel).
173- ch = & dma_hw -> ch [active_picodvi -> dma_command_channel ];
172+ dma_channel_hw_t * ch = & dma_hw -> ch [active_picodvi -> dma_command_channel ];
174173 ch -> al3_read_addr_trig = (uintptr_t )active_picodvi -> dma_commands ;
175174}
176175
@@ -224,6 +223,9 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
224223 mp_raise_ValueError_varg (MP_ERROR_TEXT ("Invalid %q and %q" ), MP_QSTR_width , MP_QSTR_height );
225224 }
226225
226+ self -> dma_command_channel = -1 ;
227+ self -> dma_pixel_channel = -1 ;
228+
227229 if (width % 160 == 0 ) {
228230 self -> output_width = 640 ;
229231 } else {
@@ -258,24 +260,18 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
258260
259261 self -> width = width ;
260262 self -> height = height ;
261- self -> pitch = (self -> width * color_depth ) / 8 ;
262263 self -> color_depth = color_depth ;
263- // Align each row to words.
264- if (self -> pitch % sizeof (uint32_t ) != 0 ) {
265- self -> pitch += sizeof (uint32_t ) - (self -> pitch % sizeof (uint32_t ));
266- }
267- self -> pitch /= sizeof (uint32_t );
264+ // Pitch is number of 32-bit words per line. We round up pitch_bytes to the nearest word
265+ // so that each scanline begins on a natural 32-bit word boundary.
266+ size_t pitch_bytes = (self -> width * color_depth ) / 8 ;
267+ self -> pitch = (pitch_bytes + sizeof (uint32_t ) - 1 ) / sizeof (uint32_t );
268268 size_t framebuffer_size = self -> pitch * self -> height ;
269269
270270 // We check that allocations aren't in PSRAM because we haven't added XIP
271271 // streaming support.
272272 self -> framebuffer = (uint32_t * )port_malloc (framebuffer_size * sizeof (uint32_t ), true);
273273 if (self -> framebuffer == NULL || ((size_t )self -> framebuffer & 0xf0000000 ) == 0x10000000 ) {
274- if (self -> framebuffer != NULL ) {
275- // Return the memory in PSRAM.
276- port_free (self -> framebuffer );
277- self -> framebuffer = NULL ;
278- }
274+ common_hal_picodvi_framebuffer_deinit (self );
279275 m_malloc_fail (framebuffer_size * sizeof (uint32_t ));
280276 return ;
281277 }
@@ -296,26 +292,26 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
296292 self -> dma_commands_len = (MODE_720_V_FRONT_PORCH + MODE_720_V_SYNC_WIDTH + MODE_720_V_BACK_PORCH + 2 * MODE_720_V_ACTIVE_LINES + 1 ) * dma_command_size ;
297293 }
298294 self -> dma_commands = (uint32_t * )port_malloc (self -> dma_commands_len * sizeof (uint32_t ), true);
299- if (self -> dma_commands == NULL || ((size_t )self -> framebuffer & 0xf0000000 ) == 0x10000000 ) {
300- port_free (self -> framebuffer );
295+ if (self -> dma_commands == NULL || ((size_t )self -> dma_commands & 0xf0000000 ) == 0x10000000 ) {
296+ common_hal_picodvi_framebuffer_deinit (self );
301297 m_malloc_fail (self -> dma_commands_len * sizeof (uint32_t ));
302298 return ;
303299 }
304300
305- int dma_pixel_channel_maybe = dma_claim_unused_channel (false);
306- if (dma_pixel_channel_maybe < 0 ) {
307- mp_raise_RuntimeError (MP_ERROR_TEXT ("Internal resource(s) in use" ));
308- return ;
309- }
301+ // The command channel and the pixel channel form a pipeline that feeds combined HSTX
302+ // commands and pixel data to the HSTX FIFO. The command channel reads a pre-computed
303+ // list of control/status words from the dma_commands buffer and writes them to the
304+ // pixel channel's control/status registers. Under control of the command channel, the
305+ // pixel channel smears/swizzles pixel data from the framebuffer and combines
306+ // it with HSTX commands, forwarding the combined stream to the HSTX FIFO.
310307
311- int dma_command_channel_maybe = dma_claim_unused_channel (false);
312- if (dma_command_channel_maybe < 0 ) {
313- dma_channel_unclaim ((uint )dma_pixel_channel_maybe );
308+ self -> dma_pixel_channel = dma_claim_unused_channel (false);
309+ self -> dma_command_channel = dma_claim_unused_channel (false);
310+ if (self -> dma_pixel_channel < 0 || self -> dma_command_channel < 0 ) {
311+ common_hal_picodvi_framebuffer_deinit (self );
314312 mp_raise_RuntimeError (MP_ERROR_TEXT ("Internal resource(s) in use" ));
315313 return ;
316314 }
317- self -> dma_pixel_channel = dma_pixel_channel_maybe ;
318- self -> dma_command_channel = dma_command_channel_maybe ;
319315
320316 size_t command_word = 0 ;
321317 size_t frontporch_start ;
@@ -582,7 +578,10 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
582578 dma_irq_handler ();
583579}
584580
585- static void _turn_off_dma (uint8_t channel ) {
581+ static void _turn_off_dma (int channel ) {
582+ if (channel < 0 ) {
583+ return ;
584+ }
586585 dma_channel_config c = dma_channel_get_default_config (channel );
587586 channel_config_set_enable (& c , false);
588587 dma_channel_set_config (channel , & c , false /* trigger */ );
@@ -605,6 +604,8 @@ void common_hal_picodvi_framebuffer_deinit(picodvi_framebuffer_obj_t *self) {
605604
606605 _turn_off_dma (self -> dma_pixel_channel );
607606 _turn_off_dma (self -> dma_command_channel );
607+ self -> dma_pixel_channel = -1 ;
608+ self -> dma_command_channel = -1 ;
608609
609610 active_picodvi = NULL ;
610611
0 commit comments