@@ -165,12 +165,11 @@ static void __not_in_flash_func(dma_irq_handler)(void) {
165
165
return ;
166
166
}
167
167
uint ch_num = active_picodvi -> dma_pixel_channel ;
168
- dma_channel_hw_t * ch = & dma_hw -> ch [ch_num ];
169
168
dma_hw -> intr = 1u << ch_num ;
170
169
171
170
// Set the read_addr back to the start and trigger the first transfer (which
172
171
// 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 ];
174
173
ch -> al3_read_addr_trig = (uintptr_t )active_picodvi -> dma_commands ;
175
174
}
176
175
@@ -224,6 +223,9 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
224
223
mp_raise_ValueError_varg (MP_ERROR_TEXT ("Invalid %q and %q" ), MP_QSTR_width , MP_QSTR_height );
225
224
}
226
225
226
+ self -> dma_command_channel = -1 ;
227
+ self -> dma_pixel_channel = -1 ;
228
+
227
229
if (width % 160 == 0 ) {
228
230
self -> output_width = 640 ;
229
231
} else {
@@ -258,24 +260,18 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
258
260
259
261
self -> width = width ;
260
262
self -> height = height ;
261
- self -> pitch = (self -> width * color_depth ) / 8 ;
262
263
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 );
268
268
size_t framebuffer_size = self -> pitch * self -> height ;
269
269
270
270
// We check that allocations aren't in PSRAM because we haven't added XIP
271
271
// streaming support.
272
272
self -> framebuffer = (uint32_t * )port_malloc (framebuffer_size * sizeof (uint32_t ), true);
273
273
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 );
279
275
m_malloc_fail (framebuffer_size * sizeof (uint32_t ));
280
276
return ;
281
277
}
@@ -296,26 +292,26 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
296
292
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 ;
297
293
}
298
294
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 );
301
297
m_malloc_fail (self -> dma_commands_len * sizeof (uint32_t ));
302
298
return ;
303
299
}
304
300
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.
310
307
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 );
314
312
mp_raise_RuntimeError (MP_ERROR_TEXT ("Internal resource(s) in use" ));
315
313
return ;
316
314
}
317
- self -> dma_pixel_channel = dma_pixel_channel_maybe ;
318
- self -> dma_command_channel = dma_command_channel_maybe ;
319
315
320
316
size_t command_word = 0 ;
321
317
size_t frontporch_start ;
@@ -582,7 +578,10 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
582
578
dma_irq_handler ();
583
579
}
584
580
585
- static void _turn_off_dma (uint8_t channel ) {
581
+ static void _turn_off_dma (int channel ) {
582
+ if (channel < 0 ) {
583
+ return ;
584
+ }
586
585
dma_channel_config c = dma_channel_get_default_config (channel );
587
586
channel_config_set_enable (& c , false);
588
587
dma_channel_set_config (channel , & c , false /* trigger */ );
@@ -605,6 +604,8 @@ void common_hal_picodvi_framebuffer_deinit(picodvi_framebuffer_obj_t *self) {
605
604
606
605
_turn_off_dma (self -> dma_pixel_channel );
607
606
_turn_off_dma (self -> dma_command_channel );
607
+ self -> dma_pixel_channel = -1 ;
608
+ self -> dma_command_channel = -1 ;
608
609
609
610
active_picodvi = NULL ;
610
611
0 commit comments