Skip to content

Commit cd7301c

Browse files
Use doorbell on RP2350 to freeze the cores (#3161)
Free up the hardware FIFO by using the new hardware doorbell registers present on the RP2350.
1 parent ded8a8a commit cd7301c

File tree

3 files changed

+113
-7
lines changed

3 files changed

+113
-7
lines changed

cores/rp2040/RP2040Support.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ void RP2040::enableDoubleResetBootloader() {
3535
boot_double_tap_check();
3636
}
3737
}
38+
#endif
3839

40+
#ifdef PICO_RP2350
41+
uint8_t _MFIFO::_doorbell = 0;
3942
#endif
4043

4144
#ifdef __PROFILE

cores/rp2040/RP2040Support.h

Lines changed: 105 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
#include "PIOProgram.h"
4343
#include "ccount.pio.h"
4444
#include <malloc.h>
45-
4645
#include "_freertos.h"
4746

4847
extern "C" volatile bool __otherCoreIdled;
@@ -54,6 +53,110 @@ extern "C" {
5453
#endif
5554
}
5655

56+
57+
#ifdef PICO_RP2350
58+
class _MFIFO {
59+
public:
60+
_MFIFO() { /* noop */ };
61+
~_MFIFO() { /* noop */ };
62+
63+
void begin(int cores) {
64+
if (cores == 1) {
65+
_multicore = false;
66+
return;
67+
}
68+
_doorbell = multicore_doorbell_claim_unused(0b11, true);
69+
_multicore = true;
70+
__otherCoreIdled = false;
71+
}
72+
73+
void registerCore() {
74+
#ifndef __FREERTOS
75+
multicore_doorbell_clear_current_core(_doorbell);
76+
uint32_t irq = multicore_doorbell_irq_num(_doorbell);
77+
irq_add_shared_handler(irq, _irq, 128);
78+
irq_set_enabled(irq, true);
79+
#else
80+
// FreeRTOS port.c will handle the IRQ hooking
81+
#endif
82+
}
83+
84+
void push(uint32_t val) {
85+
multicore_fifo_push_blocking_inline(val);
86+
}
87+
88+
bool push_nb(uint32_t val) {
89+
if (multicore_fifo_wready()) {
90+
multicore_fifo_push_blocking_inline(val);
91+
return true;
92+
}
93+
return false;
94+
}
95+
96+
uint32_t pop() {
97+
return multicore_fifo_pop_blocking_inline();
98+
}
99+
100+
bool pop_nb(uint32_t *val) {
101+
if (multicore_fifo_rvalid()) {
102+
*val = multicore_fifo_pop_blocking_inline();
103+
return true;
104+
}
105+
return false;
106+
}
107+
108+
int available() {
109+
return multicore_fifo_rvalid() ? 1 : 0; // Can't really say how many, but at least one is there
110+
}
111+
112+
void clear() {
113+
multicore_fifo_drain();
114+
}
115+
116+
void idleOtherCore() {
117+
if (!_multicore) {
118+
return;
119+
}
120+
#ifdef __FREERTOS
121+
__freertos_idle_other_core();
122+
#else
123+
__otherCoreIdled = false;
124+
multicore_doorbell_set_other_core(_doorbell);
125+
while (!__otherCoreIdled) { /* noop */ }
126+
#endif
127+
}
128+
129+
void resumeOtherCore() {
130+
if (!_multicore) {
131+
return;
132+
}
133+
__otherCoreIdled = false;
134+
#ifdef __FREERTOS
135+
__freertos_resume_other_core();
136+
#endif
137+
// Other core will exit busy-loop and return to operation
138+
// once __otherCoreIdled == false.
139+
}
140+
141+
static uint8_t _doorbell;
142+
143+
private:
144+
static void __no_inline_not_in_flash_func(_irq)() {
145+
#ifndef __FREERTOS
146+
if (multicore_doorbell_is_set_current_core(_doorbell)) {
147+
noInterrupts(); // We need total control, can't run anything
148+
__otherCoreIdled = true;
149+
while (__otherCoreIdled) { /* noop */ }
150+
interrupts();
151+
multicore_doorbell_clear_current_core(_doorbell);
152+
}
153+
#endif
154+
}
155+
156+
bool _multicore = false;
157+
};
158+
159+
#else
57160
class _MFIFO {
58161
public:
59162
_MFIFO() { /* noop */ };
@@ -75,13 +178,8 @@ class _MFIFO {
75178
void registerCore() {
76179
#ifndef __FREERTOS
77180
multicore_fifo_clear_irq();
78-
#ifdef PICO_RP2350
79-
irq_set_exclusive_handler(SIO_IRQ_FIFO, _irq);
80-
irq_set_enabled(SIO_IRQ_FIFO, true);
81-
#else
82181
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
83182
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
84-
#endif
85183
#else
86184
// FreeRTOS port.c will handle the IRQ hooking
87185
#endif
@@ -172,7 +270,7 @@ class _MFIFO {
172270
queue_t *_queue; // Only allocated as [2] if multicore
173271
static constexpr uint32_t _GOTOSLEEP = 0xC0DED02E;
174272
};
175-
273+
#endif
176274

177275
class RP2040;
178276
extern RP2040 rp2040;

docs/multicore.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ use the following functions to access a software-managed, multicore safe
9999
FIFO. There are two FIFOs, one written to by core 0 and read by core 1, and
100100
the other written to by core 1 and read by core 0.
101101

102+
On the RP2350, the hardware FIFO is available for use using the SDK APIs
103+
or the calls below (which just wrap the SDK APIs very lightly). This is
104+
because the idle/resume calls above are implemented using a hardware doorbell
105+
on the RP2350, not the hardware FIFO.
106+
102107
You can (and probably should) use shared memory (such as ``volatile`` globals)
103108
or other normal multiprocessor communication algorithms to transfer data or
104109
work between cores, but for simple tasks these FIFO routines can suffice.

0 commit comments

Comments
 (0)