8000 Frambuffer in PSRAM, initial check-in. · eightycc/circuitpython@483eda0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 483eda0

Browse files
committed
Frambuffer in PSRAM, initial check-in.
1 parent a0b482c commit 483eda0

File tree

5 files changed

+110
-31
lines changed

5 files changed

+110
-31
lines changed

ports/raspberrypi/bindings/picodvi/Framebuffer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,5 @@ int common_hal_picodvi_framebuffer_get_color_depth(picodvi_framebuffer_obj_t *se
3232
int common_hal_picodvi_framebuffer_get_native_frames_per_second(picodvi_framebuffer_obj_t *self);
3333
bool common_hal_picodvi_framebuffer_get_grayscale(picodvi_framebuffer_obj_t *self);
3434
mp_int_t common_hal_picodvi_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
35+
void common_hal_picodvi_framebuffer_flash_pre_write(void);
36+
void common_hal_picodvi_framebuffer_flash_post_write(void);

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ static void __not_in_flash_func(core1_scanline_callback)(void) {
106106
}
107107
}
108108

109+
void common_hal_picodvi_framebuffer_pre_write() {
110+
}
111+
112+
void common_hal_picodvi_framebuffer_post_write() {
113+
}
114+
109115
extern uint8_t dvi_vertical_repeat;
110116
extern bool dvi_monochrome_tmds;
111117

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

Lines changed: 92 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
#include "sdk/src/rp2350/hardware_structs/include/hardware/structs/bus_ctrl.h"< 8000 /span>
4040
#include "sdk/src/rp2350/hardware_structs/include/hardware/structs/hstx_ctrl.h"
4141
#include "sdk/src/rp2350/hardware_structs/include/hardware/structs/hstx_fifo.h"
42-
42+
#include "sdk/src/rp2350/hardware_structs/include/hardware/structs/xip_ctrl.h"
4343
// ----------------------------------------------------------------------------
4444
// DVI constants
4545

@@ -158,19 +158,82 @@ static uint32_t vactive_line720[VACTIVE_LEN] = {
158158
HSTX_CMD_TMDS | MODE_720_H_ACTIVE_PIXELS
159159
};
160160

161-
picodvi_framebuffer_obj_t *active_picodvi = NULL;
161+
static picodvi_framebuffer_obj_t *_active_picodvi = NULL;
162162

163-
static void __not_in_flash_func(dma_irq_handler)(void) {
164-
if (active_picodvi == NULL) {
163+
static void __not_in_flash_func(_dma_irq_handler)(void) {
164+
if (_active_picodvi == NULL || _active_picodvi->dma_paused) {
165+
return;
166+
}
167+
if (_active_picodvi->dma_pausing) {
168+
// Disable command and pixel DMA channels to ensure no asynchronous transfers,
169+
// triggers, or interrupts occur while paused.
170+
dma_channel_hw_t *pix_ch = &dma_hw->ch[_active_picodvi->dma_pixel_channel];
171+
dma_channel_hw_t *cmd_ch = &dma_hw->ch[_active_picodvi->dma_command_channel];
172+
pix_ch->al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS;
173+
cmd_ch->al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS;
174+
_active_picodvi->dma_pausing = false;
175+
_active_picodvi->dma_paused = true;
165176
return;
166177
}
167-
uint ch_num = active_picodvi->dma_pixel_channel;
178+
uint ch_num = _active_picodvi->dma_pixel_channel;
168179
dma_hw->intr = 1u << ch_num;
169180

170181
// Set the read_addr back to the start and trigger the first transfer (which
171182
// will trigger the pixel channel).
172-
dma_channel_hw_t *ch = &dma_hw->ch[active_picodvi->dma_command_channel];
173-
ch->al3_read_addr_trig = (uintptr_t)active_picodvi->dma_commands;
183+
dma_channel_hw_t *ch = &dma_hw->ch[_active_picodvi->dma_command_channel];
184+
ch->al3_read_addr_trig = (uintptr_t)_active_picodvi->dma_commands;
185+
}
186+
187+
static void _pause_picodvi_dma(picodvi_framebuffer_obj_t *self, bool pause) {
188+
if (pause) {
189+
// Synchronize with end of the current frame.
190+
// TODO: Presently we stop feeding the HSTX FIFO at the end of the current
191+
// frame. Because the TMDS output stops when the HSTX FIFO empties, the monitor
192+
// may lose synchronization leading to a blank screen for an extended period
193+
// of time. As an alternative, consider switching to a fake framebuffer of
194+
// all black pixels to maintain monitor synchronization.
195+
self->dma_pausing = true;
196+
// Wait for the DMA IRQ handler to pause the DMA channels
197+
while (!self->dma_paused) {
198+
tight_loop_contents();
199+
}
200+
assert(!self->dma_pausing);
201+
assert(self->dma_paused);
202+
assert(!dma_channel_is_busy(self->dma_pixel_channel));
203+
assert(!dma_channel_is_busy(self->dma_command_channel));
204+
} else {
205+
self->dma_paused = false;
206+
_dma_irq_handler();
207+
}
208+
}
209+
210+
static void _turn_off_dma(int channel) {
211+
if (channel < 0) {
212+
return;
213+
}
214+
dma_channel_config c = dma_channel_get_default_config(channel);
215+
channel_config_set_enable(&c, false);
216+
dma_channel_set_config(channel, &c, false /* trigger */);
217+
218+
if (dma_channel_is_busy(channel)) {
219+
dma_channel_abort(channel);
220+
}
221+
dma_channel_set_irq1_enabled(channel, false);
222+
dma_channel_unclaim(channel);
223+
}
224+
225+
void common_hal_picodvi_framebuffer_flash_pre_write() {
226+
if (_active_picodvi == NULL || !_active_picodvi->framebuffer_in_psram) {
227+
return;
228+
}
229+
_pause_picodvi_dma(_active_picodvi, true);
230+
}
231+
232+
void common_hal_picodvi_framebuffer_flash_post_write() {
233+
if (_active_picodvi == NULL || !_active_picodvi->framebuffer_in_psram) {
234+
return;
235+
}
236+
_pause_picodvi_dma(_active_picodvi, false);
174237
}
175238

176239
bool common_hal_picodvi_framebuffer_preflight(
@@ -215,7 +278,7 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
215278
const mcu_pin_obj_t *green_dp, const mcu_pin_obj_t *green_dn,
216279
const mcu_pin_obj_t *blue_dp, const mcu_pin_obj_t *blue_dn,
217280
mp_uint_t color_depth) {
218-
if (active_picodvi != NULL) {
281+
if (_active_picodvi != NULL) {
219282
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("%q in use"), MP_QSTR_picodvi);
220283
}
221284

@@ -267,10 +330,16 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
267330
self->pitch = (pitch_bytes + sizeof(uint32_t) - 1) / sizeof(uint32_t);
268331
size_t framebuffer_size = self->pitch * self->height;
269332

270-
// We check that allocations aren't in PSRAM because we haven't added XIP
271-
// streaming support.
272-
self->framebuffer = (uint32_t *)port_malloc(framebuffer_size * sizeof(uint32_t), true);
273-
if (self->framebuffer == NULL || ((size_t)self->framebuffer & 0xf0000000) == 0x10000000) {
333+
// A framebuffer that exceeds the capacity of the SRAM will be allocated in PSRAM.
334+
// If the framebuffer is in PSRAM, HSTX output will be paused during flash writes,
335+
// resulting in a blank screen for the duration of the flash write.
336+
//
337+
// For testing purposes, add 1MB to the framebuffer allocation size to force it into PSRAM.
338+
// NOTE: the dma_capable parameter of port_malloc() does nothing.
339+
size_t framebuffer_alloc_size = framebuffer_size * sizeof(uint32_t) + 1024 * 1024;
340+
self->framebuffer = (uint32_t *)port_malloc(framebuffer_alloc_size, true);
341+
self->framebuffer_in_psram = ((size_t)self->framebuffer & 0xf0000000) == 0x10000000;
342+
if (self->framebuffer == NULL) {
274343
common_hal_picodvi_framebuffer_deinit(self);
275344
m_malloc_fail(framebuffer_size * sizeof(uint32_t));
276345
return;
@@ -563,34 +632,20 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
563632

564633
dma_hw->ints1 = (1u << self->dma_pixel_channel);
565634
dma_hw->inte1 = (1u << self->dma_pixel_channel);
566-
irq_set_exclusive_handler(DMA_IRQ_1, dma_irq_handler);
635+
irq_set_exclusive_handler(DMA_IRQ_1, _dma_irq_handler);
567636
irq_set_enabled(DMA_IRQ_1, true);
568637
irq_set_priority(DMA_IRQ_1, PICO_HIGHEST_IRQ_PRIORITY);
638+
self->dma_irq_handler_installed = true;
569639

570640
bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS;
571641

572642
// For the output.
573643
self->framebuffer_len = framebuffer_size;
574644

575-
active_picodvi = self;
645+
_active_picodvi = self;
576646

577647
common_hal_picodvi_framebuffer_refresh(self);
578-
dma_irq_handler();
579-
}
580-
581-
static void _turn_off_dma(int channel) {
582-
if (channel < 0) {
583-
return;
584-
}
585-
d 10000 ma_channel_config c = dma_channel_get_default_config(channel);
586-
channel_config_set_enable(&c, false);
587-
dma_channel_set_config(channel, &c, false /* trigger */);
588-
589-
if (dma_channel_is_busy(channel)) {
590-
dma_channel_abort(channel);
591-
}
592-
dma_channel_set_irq1_enabled(channel, false);
593-
dma_channel_unclaim(channel);
648+
_dma_irq_handler();
594649
}
595650

596651
void common_hal_picodvi_framebuffer_deinit(picodvi_framebuffer_obj_t *self) {
@@ -607,7 +662,13 @@ void common_hal_picodvi_framebuffer_deinit(picodvi_framebuffer_obj_t *self) {
607662
self->dma_pixel_channel = -1;
608663
self->dma_command_channel = -1;
609664

610-
active_picodvi = NULL;
665+
if (self->dma_irq_handler_installed) {
666+
irq_set_enabled(DMA_IRQ_1, false);
667+
irq_remove_handler(DMA_IRQ_1, _dma_irq_handler);
668+
self->dma_irq_handler_installed = false;
669+
}
670+
671+
_active_picodvi = NULL;
611672

612673
port_free(self->framebuffer);
613674
self->framebuffer = NULL;

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,10 @@ typedef struct {
4141
uint8_t color_depth;
4242
int dma_pixel_channel;
4343
int dma_command_channel;
44+
bool framebuffer_in_psram;
45+
bool dma_irq_handler_installed;
46+
// Command and pixel DMA channel pause handshake controls. Volatile because they
47+
// are used to communicate between main thread and DMA IRQ handler.
48+
volatile bool dma_pausing;
49+
volatile bool dma_paused;
4450
} picodvi_framebuffer_obj_t;

ports/raspberrypi/supervisor/internal_flash.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "supervisor/flash.h"
2424
#include "supervisor/usb.h"
2525

26+
#include "bindings/picodvi/Framebuffer.h"
27+
2628
#ifdef PICO_RP2350
2729
#include "src/rp2350/hardware_structs/include/hardware/structs/qmi.h"
2830
#endif
@@ -47,6 +49,7 @@ static uint32_t _audio_channel_mask;
4749
void supervisor_flash_pre_write(void) {
4850
// Disable interrupts. XIP accesses will fault during flash writes.
4951
common_hal_mcu_disable_interrupts();
52+
common_hal_picodvi_framebuffer_flash_pre_write();
5053
#if CIRCUITPY_AUDIOCORE
5154
// Pause audio DMA to avoid noise while interrupts are disabled.
5255
_audio_channel_mask = audio_dma_pause_all();
@@ -58,6 +61,7 @@ void supervisor_flash_post_write(void) {
5861
// Unpause audio DMA.
5962
audio_dma_unpause_mask(_audio_channel_mask);
6063
#endif
64+
common_hal_picodvi_framebuffer_flash_post_write();
6165
// Re-enable interrupts.
6266
common_hal_mcu_enable_interrupts();
6367
}

0 commit comments

Comments
 (0)
0