Skip to content

Commit 9cdf5e1

Browse files
authored
Merge pull request #2879 from jepler/background-callback
Use a linked list of background tasks to perform
2 parents 88d8956 + 98eef79 commit 9cdf5e1

File tree

41 files changed

+506
-340
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+506
-340
lines changed

main.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
#include "background.h"
4747
#include "mpconfigboard.h"
48+
#include "supervisor/background_callback.h"
4849
#include "supervisor/cpu.h"
4950
#include "supervisor/memory.h"
5051
#include "supervisor/port.h"
@@ -100,8 +101,6 @@ void start_mp(supervisor_allocation* heap) {
100101
reset_status_led();
101102
autoreload_stop();
102103

103-
background_tasks_reset();
104-
105104
// Stack limit should be less than real stack size, so we have a chance
106105
// to recover from limit hit. (Limit is measured in bytes.)
107106
mp_stack_ctrl_init();
@@ -161,6 +160,8 @@ void stop_mp(void) {
161160
MP_STATE_VM(vfs_cur) = vfs;
162161
#endif
163162

163+
background_callback_reset();
164+
164165
gc_deinit();
165166
}
166167

@@ -492,6 +493,8 @@ void gc_collect(void) {
492493
// have lost their references in the VM even though they are mounted.
493494
gc_collect_root((void**)&MP_STATE_VM(vfs_mount_table), sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t));
494495

496+
background_callback_gc_collect();
497+
495498
#if CIRCUITPY_DISPLAYIO
496499
displayio_gc_collect();
497500
#endif

ports/atmel-samd/audio_dma.c

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
#include "shared-bindings/audiocore/RawSample.h"
3333
#include "shared-bindings/audiocore/WaveFile.h"
34-
#include "supervisor/shared/tick.h"
34+
#include "supervisor/background_callback.h"
3535

3636
#include "py/mpstate.h"
3737
#include "py/runtime.h"
@@ -61,7 +61,6 @@ void audio_dma_free_channel(uint8_t channel) {
6161
assert(audio_dma_allocated[channel]);
6262
audio_dma_disable_channel(channel);
6363
audio_dma_allocated[channel] = false;
64-
supervisor_disable_tick();
6564
}
6665

6766
void audio_dma_disable_channel(uint8_t channel) {
@@ -73,7 +72,6 @@ void audio_dma_disable_channel(uint8_t channel) {
7372
void audio_dma_enable_channel(uint8_t channel) {
7473
if (channel >= AUDIO_DMA_CHANNEL_COUNT)
7574
return;
76-
supervisor_enable_tick();
7775
dma_enable_channel(channel);
7876
}
7977

@@ -259,6 +257,15 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
259257
dma->beat_size *= 2;
260258
}
261259

260+
#ifdef SAM_D5X_E5X
261+
int irq = dma->event_channel < 4 ? EVSYS_0_IRQn + dma->event_channel : EVSYS_4_IRQn;
262+
#else
263+
int irq = EVSYS_IRQn;
264+
#endif
265+
266+
NVIC_DisableIRQ(irq);
267+
NVIC_ClearPendingIRQ(irq);
268+
262269
DmacDescriptor* first_descriptor = dma_descriptor(dma_channel);
263270
setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address);
264271
if (single_buffer) {
@@ -281,6 +288,8 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
281288
dma_configure(dma_channel, dma_trigger_source, true);
282289
audio_dma_enable_channel(dma_channel);
283290

291+
NVIC_EnableIRQ(irq);
292+
284293
return AUDIO_DMA_OK;
285294
}
286295

@@ -321,9 +330,6 @@ void audio_dma_reset(void) {
321330
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
322331
audio_dma_state[i] = NULL;
323332
audio_dma_pending[i] = false;
324-
if (audio_dma_allocated[i]) {
325-
supervisor_disable_tick();
326-
}
327333
audio_dma_allocated[i] = false;
328334
audio_dma_disable_channel(i);
329335
dma_descriptor(i)->BTCTRL.bit.VALID = false;
@@ -343,29 +349,39 @@ bool audio_dma_get_playing(audio_dma_t* dma) {
343349
return (status & DMAC_CHINTFLAG_TERR) == 0;
344350
}
345351

346-
// WARN(tannewt): DO NOT print from here. Printing calls background tasks such as this and causes a
347-
// stack overflow.
352+
// WARN(tannewt): DO NOT print from here, or anything it calls. Printing calls
353+
// background tasks such as this and causes a stack overflow.
354+
STATIC void dma_callback_fun(void *arg) {
355+
audio_dma_t* dma = arg;
356+
if (dma == NULL) {
357+
return;
358+
}
359+
360+
audio_dma_load_next_block(dma);
361+
}
348362

349-
void audio_dma_background(void) {
363+
void evsyshandler_common(void) {
350364
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
351-
if (audio_dma_pending[i]) {
352-
continue;
353-
}
354365
audio_dma_t* dma = audio_dma_state[i];
355366
if (dma == NULL) {
356367
continue;
357368
}
358-
359369
bool block_done = event_interrupt_active(dma->event_channel);
360370
if (!block_done) {
361371
continue;
362372
}
363-
364-
// audio_dma_load_next_block() can call Python code, which can call audio_dma_background()
365-
// recursively at the next background processing time. So disallow recursive calls to here.
366-
audio_dma_pending[i] = true;
367-
audio_dma_load_next_block(dma);
368-
audio_dma_pending[i] = false;
373+
background_callback_add(&dma->callback, dma_callback_fun, (void*)dma);
369374
}
370375
}
376+
377+
#ifdef SAM_D5X_E5X
378+
void EVSYS_0_Handler(void) { evsyshandler_common(); }
379+
void EVSYS_1_Handler(void) { evsyshandler_common(); }
380+
void EVSYS_2_Handler(void) { evsyshandler_common(); }
381+
void EVSYS_3_Handler(void) { evsyshandler_common(); }
382+
void EVSYS_4_Handler(void) { evsyshandler_common(); }
383+
#else
384+
void EVSYS_Handler(void) { evsyshandler_common(); }
385+
#endif
386+
371387
#endif

ports/atmel-samd/audio_dma.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "py/obj.h"
3232
#include "shared-module/audiocore/RawSample.h"
3333
#include "shared-module/audiocore/WaveFile.h"
34+
#include "supervisor/background_callback.h"
3435

3536
typedef struct {
3637
mp_obj_t sample;
@@ -49,6 +50,7 @@ typedef struct {
4950
uint8_t* second_buffer;
5051
bool first_descriptor_free;
5152
DmacDescriptor* second_descriptor;
53+
background_callback_t callback;
5254
} audio_dma_t;
5355

5456
typedef enum {

ports/atmel-samd/background.c

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -39,63 +39,21 @@
3939
#include "shared-module/displayio/__init__.h"
4040
#endif
4141

42-
volatile uint64_t last_finished_tick = 0;
43-
44-
bool stack_ok_so_far = true;
45-
46-
static bool running_background_tasks = false;
47-
4842
#ifdef MONITOR_BACKGROUND_TASKS
4943
// PB03 is physical pin "SCL" on the Metro M4 express
5044
// so you can't use this code AND an i2c peripheral
5145
// at the same time unless you change this
52-
STATIC void start_background_task(void) {
46+
void port_start_background_task(void) {
5347
REG_PORT_DIRSET1 = (1<<3);
5448
REG_PORT_OUTSET1 = (1<<3);
5549
}
5650

57-
STATIC void finish_background_task(void) {
51+
void port_finish_background_task(void) {
5852
REG_PORT_OUTCLR1 = (1<<3);
5953
}
6054
#else
61-
STATIC void start_background_task(void) {}
62-
STATIC void finish_background_task(void) {}
55+
void port_start_background_task(void) {}
56+
void port_finish_background_task(void) {}
6357
#endif
6458

65-
void background_tasks_reset(void) {
66-
running_background_tasks = false;
67-
}
68-
69-
void run_background_tasks(void) {
70-
// Don't call ourselves recursively.
71-
if (running_background_tasks) {
72-
return;
73-
}
74-
75-
start_background_task();
76-
77-
assert_heap_ok();
78-
running_background_tasks = true;
79-
80-
#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
81-
audio_dma_background();
82-
#endif
83-
#if CIRCUITPY_DISPLAYIO
84-
displayio_background();
85-
#endif
86-
87-
#if CIRCUITPY_NETWORK
88-
network_module_background();
89-
#endif
90-
filesystem_background();
91-
usb_background();
92-
running_background_tasks = false;
93-
assert_heap_ok();
94-
95-
last_finished_tick = port_get_raw_ticks(NULL);
96-
finish_background_task();
97-
}
98-
99-
bool background_tasks_ok(void) {
100-
return port_get_raw_ticks(NULL) - last_finished_tick < 1024;
101-
}
59+
void port_background_task(void) {}

ports/atmel-samd/background.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,4 @@
2929

3030
#include <stdbool.h>
3131

32-
void background_tasks_reset(void);
33-
void run_background_tasks(void);
34-
void run_background_vm_tasks(void);
35-
bool background_tasks_ok(void);
36-
3732
#endif // MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H

ports/atmel-samd/boards/uchip/mpconfigboard.mk

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,10 @@ CHIP_FAMILY = samd21
99
INTERNAL_FLASH_FILESYSTEM = 1
1010
LONGINT_IMPL = NONE
1111
CIRCUITPY_FULL_BUILD = 0
12+
13+
# Tweak inlining depending on language.
14+
ifeq ($(TRANSLATION), zh_Latn_pinyin)
15+
CFLAGS_INLINE_LIMIT = 45
16+
else
17+
CFLAGS_INLINE_LIMIT = 70
18+
endif

ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "hpl_gclk_config.h"
4747

4848
#include "shared-bindings/time/__init__.h"
49+
#include "supervisor/shared/tick.h"
4950
#include "supervisor/shared/translate.h"
5051

5152
#ifdef SAMD21
@@ -132,7 +133,7 @@ void frequencyin_interrupt_handler(uint8_t index) {
132133
}
133134

134135
// Check if we've reached the upper limit of detection
135-
if (!background_tasks_ok() || self->errored_too_fast) {
136+
if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
136137
self->errored_too_fast = true;
137138
frequencyin_emergency_cancel_capture(i);
138139
}

ports/atmel-samd/common-hal/pulseio/PulseIn.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "samd/timers.h"
4343
#include "shared-bindings/microcontroller/__init__.h"
4444
#include "shared-bindings/pulseio/PulseIn.h"
45+
#include "supervisor/shared/tick.h"
4546
#include "supervisor/shared/translate.h"
4647

4748
// This timer is shared amongst all PulseIn objects as a higher resolution clock.
@@ -87,7 +88,7 @@ void pulsein_interrupt_handler(uint8_t channel) {
8788
uint32_t current_count = tc->COUNT16.COUNT.reg;
8889

8990
pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
90-
if (!background_tasks_ok() || self->errored_too_fast) {
91+
if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
9192
self->errored_too_fast = true;
9293
common_hal_pulseio_pulsein_pause(self);
9394
return;

ports/atmel-samd/supervisor/usb.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "hpl/gclk/hpl_gclk_base.h"
3030
#include "hal_gpio.h"
3131
#include "lib/tinyusb/src/device/usbd.h"
32+
#include "supervisor/background_callback.h"
33+
#include "supervisor/usb.h"
3234

3335
void init_usb_hardware(void) {
3436
#ifdef SAMD21
@@ -61,24 +63,24 @@ void init_usb_hardware(void) {
6163

6264
#ifdef SAMD21
6365
void USB_Handler(void) {
64-
tud_int_handler(0);
66+
usb_irq_handler();
6567
}
6668
#endif
6769

6870
#ifdef SAM_D5X_E5X
6971
void USB_0_Handler (void) {
70-
tud_int_handler(0);
72+
usb_irq_handler();
7173
}
7274

7375
void USB_1_Handler (void) {
74-
tud_int_handler(0);
76+
usb_irq_handler();
7577
}
7678

7779
void USB_2_Handler (void) {
78-
tud_int_handler(0);
80+
usb_irq_handler();
7981
}
8082

8183
void USB_3_Handler (void) {
82-
tud_int_handler(0);
84+
usb_irq_handler();
8385
}
8486
#endif

ports/cxd56/background.c

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,6 @@
3030
#include "supervisor/filesystem.h"
3131
#include "supervisor/shared/stack.h"
3232

33-
static bool running_background_tasks = false;
34-
35-
void background_tasks_reset(void) {
36-
running_background_tasks = false;
37-
}
38-
39-
void run_background_tasks(void) {
40-
// Don't call ourselves recursively.
41-
if (running_background_tasks) {
42-
return;
43-
}
44-
45-
assert_heap_ok();
46-
running_background_tasks = true;
47-
48-
usb_background();
49-
filesystem_background();
50-
51-
running_background_tasks = false;
52-
assert_heap_ok();
53-
}
33+
void port_background_task(void) {}
34+
void port_start_background_task(void) {}
35+
void port_finish_background_task(void) {}

ports/cxd56/background.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,4 @@
2727
#ifndef MICROPY_INCLUDED_CXD56_BACKGROUND_H
2828
#define MICROPY_INCLUDED_CXD56_BACKGROUND_H
2929

30-
void background_tasks_reset(void);
31-
void run_background_tasks(void);
32-
3330
#endif // MICROPY_INCLUDED_CXD56_BACKGROUND_H

ports/esp32s2/background.c

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,12 @@
3535
#include "shared-module/displayio/__init__.h"
3636
#endif
3737

38-
static bool running_background_tasks = false;
39-
40-
void background_tasks_reset(void) {
41-
running_background_tasks = false;
42-
}
43-
44-
void run_background_tasks(void) {
45-
// Don't call ourselves recursively.
46-
if (running_background_tasks) {
47-
return;
48-
}
4938

39+
void port_background_task(void) {
5040
// Zero delay in case FreeRTOS wants to switch to something else.
5141
vTaskDelay(0);
52-
running_background_tasks = true;
53-
filesystem_background();
42+
}
5443

55-
#if CIRCUITPY_DISPLAYIO
56-
displayio_background();
57-
#endif
58-
running_background_tasks = false;
44+
void port_start_background_task(void) {}
5945

60-
assert_heap_ok();
61-
}
46+
void port_finish_background_task(void) {}

0 commit comments

Comments
 (0)