Skip to content

Commit e8fc44a

Browse files
committed
Make nesting_count update atomic by disabling interrupts.
Fix miscellaneous memory leaks. Minor code cleanup in RP2350 framebuffer. Factor teardown of partially constructed Framebuffer object.
1 parent 4c6ef4e commit e8fc44a

File tree

4 files changed

+35
-32
lines changed

4 files changed

+35
-32
lines changed

ports/raspberrypi/bindings/picodvi/Framebuffer.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@
5151
//| The framebuffer pixel format varies depending on color_depth:
5252
//|
5353
//| * 1 - Each bit is a pixel. Either white (1) or black (0).
54-
//| * 2 - Each 2 bits is a pixels. Grayscale between white (0x3) and black (0x0).
55-
//| * 4 - Each nibble is a pixels in RGB format. The fourth bit is ignored. (RP2350 only)
56-
//| * 8 - Each byte is a pixels in RGB332 format.
57-
//| * 16 - Each two bytes are a pixel in RGB565 format.
58-
//| * 32 - Each four bytes are a pixel in RGB888 format. The top byte is ignored.
54+
//| * 2 - Each two bits is a pixel. Grayscale between white (0x3) and black (0x0).
55+
//| * 4 - Each nibble is a pixel in RGB format. The fourth bit is ignored. (RP2350 only)
56+
//| * 8 - Each byte is a pixel in RGB332 format.
57+
//| * 16 - Each two bytes is a pixel in RGB565 format.
58+
//| * 32 - Each four bytes is a pixel in RGB888 format. The top byte is ignored.
5959
//|
6060
//| Output resolution support varies between the RP2040 and RP2350.
6161
//|

ports/raspberrypi/common-hal/microcontroller/__init__.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ void common_hal_mcu_enable_interrupts(void) {
5555
#define PICO_ELEVATED_IRQ_PRIORITY (0x60) // between PICO_DEFAULT and PIOCO_HIGHEST_IRQ_PRIORITY
5656
static uint32_t oldBasePri = 0; // 0 (default) masks nothing, other values mask equal-or-larger priority values
5757
void common_hal_mcu_disable_interrupts(void) {
58+
uint32_t my_interrupts = save_and_disable_interrupts();
5859
if (nesting_count == 0) {
5960
// We must keep DMA_IRQ_1 (reserved for pico dvi) enabled at all times,
6061
// including during flash writes. Do this by setting the priority mask (BASEPRI
@@ -66,6 +67,7 @@ void common_hal_mcu_disable_interrupts(void) {
6667
__isb(); // Instruction synchronization barrier
6768
}
6869
nesting_count++;
70+
restore_interrupts(my_interrupts);
6971
}
7072

7173
void common_hal_mcu_enable_interrupts(void) {

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

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}
@@ -297,25 +293,25 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
297293
}
298294
self->dma_commands = (uint32_t *)port_malloc(self->dma_commands_len * sizeof(uint32_t), true);
299295
if (self->dma_commands == NULL || ((size_t)self->framebuffer & 0xf0000000) == 0x10000000) {
300-
port_free(self->framebuffer);
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

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@ typedef struct {
3939
mp_uint_t output_width;
4040
uint16_t pitch; // Number of words between rows. (May be more than a width's worth.)
4141
uint8_t color_depth;
42-
uint8_t dma_pixel_channel;
43-
uint8_t dma_command_channel;
42+
int dma_pixel_channel;
43+
int dma_command_channel;
4444
} picodvi_framebuffer_obj_t;

0 commit comments

Comments
 (0)