99#include " hardware/structs/ioqspi.h"
1010#include " hardware/structs/qmi.h"
1111#include " hardware/structs/xip_ctrl.h"
12+ #include " hardware/irq.h"
1213
1314
1415using namespace pimoroni ;
@@ -57,7 +58,6 @@ typedef struct _Presto_obj_t {
5758 uint16_t width;
5859 uint16_t height;
5960 bool using_palette;
60- volatile bool exit_core1;
6161
6262 // Automatic ambient backlight control
6363 volatile bool auto_ambient_leds;
@@ -76,6 +76,12 @@ typedef struct _ModPicoGraphics_obj_t {
7676// Micropython object to prevent GC freeing it.
7777static _Presto_obj_t *presto_obj;
7878
79+ static volatile bool exit_core1;
80+
81+ // ST7701 must be allocated into SRAM (not PSRAM), so reserve a buffer
82+ // for it here - Presto_make_new will placement new into this buffer.
83+ __attribute__ ((section(" .uninitialized_data" ))) static uint32_t st7701_buffer[sizeof(ST7701) / sizeof(uint32_t )];
84+
7985#define NUM_LEDS 7
8086
8187// These must be tweaked together
@@ -94,7 +100,7 @@ static void __no_inline_not_in_flash_func(update_backlight_leds)() {
94100 { 0 , presto_obj->height - SAMPLE_RANGE }
95101 };
96102
97- while (!presto_obj-> exit_core1 ) {
103+ while (!exit_core1) {
98104 if (presto_obj->auto_ambient_leds ) {
99105 for (int i = 0 ; i < NUM_LEDS; ++i) {
100106 uint32_t r = presto_obj->led_values [i].r ;
@@ -132,7 +138,7 @@ static void __no_inline_not_in_flash_func(update_backlight_leds)() {
132138
133139 presto_obj->presto ->wait_for_vsync ();
134140
135- if (presto_obj-> exit_core1 ) break ;
141+ if (exit_core1) break ;
136142
137143 // Note this section calls into code that executes from flash
138144 // It's important this is done during vsync to avoid artifacts,
@@ -161,24 +167,58 @@ static void __no_inline_not_in_flash_func(update_backlight_leds)() {
161167 multicore_fifo_push_blocking (1 );
162168}
163169
170+ #define LOCKOUT_MAGIC_START 0x73a8831eu
171+ #define LOCKOUT_MAGIC_END (~LOCKOUT_MAGIC_START)
172+
173+ // Alternative version of the lockout handler which does not disable interrupts
174+ // We know that all interrupts running on core1 will not access flash or PSRAM, so this is safe.
175+ static void __isr __not_in_flash_func (presto_core1_lockout_handler)(void ) {
176+ multicore_fifo_clear_irq ();
177+ while (multicore_fifo_rvalid ()) {
178+ if (sio_hw->fifo_rd == LOCKOUT_MAGIC_START) {
179+ sio_hw->fifo_wr = LOCKOUT_MAGIC_START;
180+ __sev ();
181+ while (multicore_fifo_pop_blocking_inline () != LOCKOUT_MAGIC_END) {
182+ tight_loop_contents (); // not tight but endless potentially
183+ }
184+ sio_hw->fifo_wr = LOCKOUT_MAGIC_END;
185+ __sev ();
186+ }
187+ }
188+ }
189+
190+ static bool ever_inited = false ;
191+
164192void presto_core1_entry () {
165193 // The multicore lockout uses the FIFO, so we use just use sev and volatile flags to signal this core
166194 multicore_lockout_victim_init ();
167195
196+ // Replace the lockout handler
197+ irq_handler_t sdk_handler = irq_get_exclusive_handler (SIO_IRQ_FIFO);
198+ irq_remove_handler (SIO_IRQ_FIFO, sdk_handler);
199+ irq_set_exclusive_handler (SIO_IRQ_FIFO, presto_core1_lockout_handler);
200+
201+ ever_inited = true ;
202+
168203 presto_obj->presto ->init ();
169204
170205 multicore_fifo_push_blocking (0 ); // Todo handle issues here?*/
171206
172207 // Presto is now running the display using interrupts on this core.
173208 // We can also drive the backlight if requested.
174- while (!presto_obj-> exit_core1 ) {
175- if (!presto_obj-> exit_core1 ) {
209+ while (!exit_core1) {
210+ if (!exit_core1) {
176211 update_backlight_leds ();
177212 }
178213 }
179214
180215 presto_obj->presto ->cleanup ();
181216
217+ // Restore the original lockout handler and deinit.
218+ irq_remove_handler (SIO_IRQ_FIFO, presto_core1_lockout_handler);
219+ irq_set_exclusive_handler (SIO_IRQ_FIFO, sdk_handler);
220+ multicore_lockout_victim_deinit ();
221+
182222 multicore_fifo_push_blocking (0 );
183223}
184224
@@ -219,14 +259,14 @@ mp_obj_t Presto_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
219259 self->using_palette = args[ARG_palette].u_bool ;
220260
221261 presto_debug (" m_new_class(ST7701...\n " );
222- self->presto = m_new_class (ST7701, self->width , self->height , ROTATE_0,
262+ self->presto = new (st7701_buffer) ST7701 ( self->width , self->height , ROTATE_0,
223263 SPIPins{spi1, LCD_CS, LCD_CLK, LCD_DAT, PIN_UNUSED, LCD_DC, BACKLIGHT},
224264 presto_buffer, self->using_palette ? presto_palette : nullptr ,
225265 LCD_D0);
226266
227267 presto_debug (" launch core1\n " );
228268 multicore_reset_core1 ();
229- self-> exit_core1 = false ;
269+ exit_core1 = false ;
230270 self->auto_ambient_leds = false ;
231271
232272 WS2812::RGB* buffer = m_new (WS2812::RGB, NUM_LEDS);
@@ -430,20 +470,20 @@ mp_obj_t Presto___del__(mp_obj_t self_in) {
430470 }
431471
432472 presto_debug (" stop core1\n " );
433- presto_obj-> exit_core1 = true ;
473+ exit_core1 = true ;
434474 __sev ();
435475
436- int fifo_code;
476+ uint32_t fifo_code;
437477 do {
438- fifo_code = multicore_fifo_pop_blocking ();
478+ while (! multicore_fifo_pop_timeout_us ( 1000 , &fifo_code)) __sev ();
439479 if (fifo_code == 1 ) {
440480 cleanup_leds ();
441481 }
442482 } while (fifo_code != 0 );
443483
444484 presto_debug (" core1 stopped\n " );
445485
446- m_del_class (ST7701, presto_obj->presto );
486+ presto_obj->presto -> ~ST7701 ( );
447487 presto_obj->presto = nullptr ;
448488 presto_obj = nullptr ;
449489
0 commit comments