2828#include "py/mpconfig.h"
2929#include "py/mpthread.h"
3030#include "pendsv.h"
31+ #include "hardware/irq.h"
3132
3233#if PICO_RP2040
3334#include "RP2040.h"
@@ -45,6 +46,9 @@ static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
4546
4647static inline void pendsv_resume_run_dispatch (void );
4748
49+ // PendSV IRQ priority, to run system-level tasks that preempt the main thread.
50+ #define IRQ_PRI_PENDSV PICO_LOWEST_IRQ_PRIORITY
51+
4852void PendSV_Handler (void );
4953
5054#if MICROPY_PY_THREAD
@@ -53,8 +57,14 @@ void PendSV_Handler(void);
5357// loop of mp_wfe_or_timeout(), where we don't want the CPU event bit to be set.
5458static mp_thread_recursive_mutex_t pendsv_mutex ;
5559
60+ // Called from CPU0 during boot, but may be called later when CPU1 wakes up
5661void 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
5868}
5969
6070void pendsv_suspend (void ) {
@@ -117,11 +127,13 @@ static inline void pendsv_resume_run_dispatch(void) {
117127
118128void pendsv_schedule_dispatch (size_t slot , pendsv_dispatch_t f ) {
119129 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().
120133 if (pendsv_suspend_count () == 0 ) {
121134 #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.
125137 SCB -> ICSR = SCB_ICSR_PENDSVSET_Msk ;
126138 #elif PICO_RISCV
127139 struct timespec ts ;
@@ -136,15 +148,19 @@ void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
136148}
137149
138150// 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).
139155void PendSV_Handler (void ) {
140156
141157 #if MICROPY_PY_THREAD
142158 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().
145161 return ;
146162 }
147- // Core 0 should not already have locked pendsv_mutex
163+ // This core should not already have locked pendsv_mutex
148164 assert (pendsv_mutex .mutex .enter_count == 1 );
149165 #else
150166 assert (pendsv_suspend_count () == 0 );
0 commit comments