Skip to content

Commit 44c56fd

Browse files
authored
Merge pull request #98 from MichaelBell/fix-flash-write
Keep display running while writing to flash
2 parents f2ab2ba + 922b3eb commit 44c56fd

File tree

3 files changed

+61
-18
lines changed

3 files changed

+61
-18
lines changed

drivers/st7701/st7701.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ namespace pimoroni {
9898
static ST7701* st7701_inst;
9999

100100
// This ISR is triggered whenever the timing SM's FIFO is not full
101-
void __no_inline_not_in_flash_func(timing_isr)() {
101+
void __isr __no_inline_not_in_flash_func(timing_isr)() {
102102
st7701_inst->drive_timing();
103103
}
104104

105-
void __no_inline_not_in_flash_func(ST7701::drive_timing)()
105+
void __not_in_flash_func(ST7701::drive_timing)()
106106
{
107107
while (!pio_sm_is_tx_fifo_full(st_pio, timing_sm)) {
108108
uint32_t instr;
@@ -153,17 +153,17 @@ void __no_inline_not_in_flash_func(ST7701::drive_timing)()
153153
}
154154

155155
// This ISR is triggered at the end of each line transferred
156-
void __no_inline_not_in_flash_func(end_of_line_isr()) {
156+
void __isr __no_inline_not_in_flash_func(end_of_line_isr)() {
157157
st7701_inst->handle_end_of_line();
158158
}
159159

160-
void __no_inline_not_in_flash_func(ST7701::handle_end_of_line())
160+
void __not_in_flash_func(ST7701::handle_end_of_line)()
161161
{
162162
if (st_pio->irq & 0x2) start_frame_xfer();
163163
else start_line_xfer();
164164
}
165165

166-
void __no_inline_not_in_flash_func(ST7701::start_line_xfer())
166+
void __not_in_flash_func(ST7701::start_line_xfer)()
167167
{
168168
hw_clear_bits(&st_pio->irq, 0x1);
169169

@@ -173,7 +173,7 @@ void __no_inline_not_in_flash_func(ST7701::start_line_xfer())
173173
else next_line_addr = &framebuffer[width * (display_row >> row_shift)];
174174
}
175175

176-
void ST7701::start_frame_xfer()
176+
void __not_in_flash_func(ST7701::start_frame_xfer)()
177177
{
178178
hw_clear_bits(&st_pio->irq, 0x2);
179179

@@ -385,13 +385,15 @@ void ST7701::start_frame_xfer()
385385
current = irq_get_exclusive_handler(pio_get_irq_num(st_pio, 1));
386386
if(current) irq_remove_handler(pio_get_irq_num(st_pio, 1), current);
387387
irq_set_exclusive_handler(pio_get_irq_num(st_pio, 1), timing_isr);
388+
irq_set_priority(pio_get_irq_num(st_pio, 1), 0x40);
388389
irq_set_enabled(pio_get_irq_num(st_pio, 1), true);
389390

390391
hw_set_bits(&st_pio->inte0, 0x300); // IRQ 0
391392
// Remove the MicroPython handler if it's set
392393
current = irq_get_exclusive_handler(pio_get_irq_num(st_pio, 0));
393394
if(current) irq_remove_handler(pio_get_irq_num(st_pio, 0), current);
394395
irq_set_exclusive_handler(pio_get_irq_num(st_pio, 0), end_of_line_isr);
396+
irq_set_priority(pio_get_irq_num(st_pio, 0), 0x40);
395397
irq_set_enabled(pio_get_irq_num(st_pio, 0), true);
396398
}
397399

@@ -524,7 +526,7 @@ void ST7701::start_frame_xfer()
524526
pio_sm_unclaim(st_pio, timing_sm);
525527
}
526528

527-
if(pio_sm_is_claimed(st_pio, palette_sm)) {
529+
if(palette && pio_sm_is_claimed(st_pio, palette_sm)) {
528530
pio_sm_set_enabled(st_pio, palette_sm, false);
529531
pio_sm_clear_fifos(st_pio, palette_sm);
530532
pio_sm_unclaim(st_pio, palette_sm);

drivers/st7701/st7701.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ namespace pimoroni {
5353
// Parallel init
5454
ST7701(uint16_t width, uint16_t height, Rotation rotation, SPIPins control_pins, uint16_t* framebuffer, uint32_t* palette = nullptr,
5555
uint d0=1, uint hsync=19, uint vsync=20, uint lcd_de = 21, uint lcd_dot_clk = 22);
56+
virtual ~ST7701() {}
5657

5758
void init();
5859
void cleanup() override;

modules/c/presto/presto.cpp

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
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

1415
using 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.
7777
static _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+
164192
void 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

Comments
 (0)