28
28
#include "py/mpconfig.h"
29
29
#include "py/mpthread.h"
30
30
#include "pendsv.h"
31
+ #include "hardware/irq.h"
31
32
32
33
#if PICO_RP2040
33
34
#include "RP2040.h"
@@ -45,6 +46,9 @@ static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
45
46
46
47
static inline void pendsv_resume_run_dispatch (void );
47
48
49
+ // PendSV IRQ priority, to run system-level tasks that preempt the main thread.
50
+ #define IRQ_PRI_PENDSV PICO_LOWEST_IRQ_PRIORITY
51
+
48
52
void PendSV_Handler (void );
49
53
50
54
#if MICROPY_PY_THREAD
@@ -53,8 +57,14 @@ void PendSV_Handler(void);
53
57
// loop of mp_wfe_or_timeout(), where we don't want the CPU event bit to be set.
54
58
static mp_thread_recursive_mutex_t pendsv_mutex ;
55
59
60
+ // Called from CPU0 during boot, but may be called later when CPU1 wakes up
56
61
void pendsv_init (void ) {
57
- mp_thread_recursive_mutex_init (& pendsv_mutex );
62
+ if (get_core_num () == 0 ) {
63
+ mp_thread_recursive_mutex_init (& pendsv_mutex );
64
+ }
65
+ #if !defined(__riscv )
66
+ NVIC_SetPriority (PendSV_IRQn , IRQ_PRI_PENDSV );
67
+ #endif
58
68
}
59
69
60
70
void pendsv_suspend (void ) {
@@ -117,11 +127,13 @@ static inline void pendsv_resume_run_dispatch(void) {
117
127
118
128
void pendsv_schedule_dispatch (size_t slot , pendsv_dispatch_t f ) {
119
129
pendsv_dispatch_table [slot ] = f ;
130
+ // There is a race here where other core calls pendsv_suspend() before ISR
131
+ // can execute so this check fails, but dispatch will happen later when
132
+ // other core calls pendsv_resume().
120
133
if (pendsv_suspend_count () == 0 ) {
121
134
#if PICO_ARM
122
- // There is a race here where other core calls pendsv_suspend() before
123
- // ISR can execute, but dispatch will happen later when other core
124
- // calls pendsv_resume().
135
+ // Note this register is part of each CPU core, so setting it on CPUx
136
+ // will set the IRQ and run PendSV_Handler on CPUx only.
125
137
SCB -> ICSR = SCB_ICSR_PENDSVSET_Msk ;
126
138
#elif PICO_RISCV
127
139
struct timespec ts ;
@@ -136,15 +148,19 @@ void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
136
148
}
137
149
138
150
// PendSV interrupt handler to perform background processing.
151
+ //
152
+ // Handler can execute on either CPU if MICROPY_PY_THREAD is set (no code on
153
+ // CPU1 calls pendsv_schedule_dispatch(), but CPU1 can call pendsv_resume()
154
+ // which will trigger it).
139
155
void PendSV_Handler (void ) {
140
156
141
157
#if MICROPY_PY_THREAD
142
158
if (!mp_thread_recursive_mutex_lock (& pendsv_mutex , 0 )) {
143
- // Failure here means core 1 holds pendsv_mutex. ISR will
144
- // run again after core 1 calls pendsv_resume().
159
+ // Failure here means other core holds pendsv_mutex. ISR will
160
+ // run again after that core calls pendsv_resume().
145
161
return ;
146
162
}
147
- // Core 0 should not already have locked pendsv_mutex
163
+ // This core should not already have locked pendsv_mutex
148
164
assert (pendsv_mutex .mutex .enter_count == 1 );
149
165
#else
150
166
assert (pendsv_suspend_count () == 0 );
0 commit comments