1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _PICO_MULTICORE_H
8 #define _PICO_MULTICORE_H
9 
10 #include "pico/types.h"
11 #include "pico/sync.h"
12 #include "hardware/structs/sio.h"
13 
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17 
18 /** \file multicore.h
19  *  \defgroup pico_multicore pico_multicore
20  * Adds support for running code on the second processor core (core 1)
21  *
22  * \subsection multicore_example Example
23  * \addtogroup pico_multicore
24  * \include multicore.c
25 */
26 
27 // PICO_CONFIG: PICO_CORE1_STACK_SIZE, Stack size for core 1, min=0x100, max=0x10000, default=PICO_STACK_SIZE (0x800), group=pico_multicore
28 #ifndef PICO_CORE1_STACK_SIZE
29 #ifdef PICO_STACK_SIZE
30 #define PICO_CORE1_STACK_SIZE PICO_STACK_SIZE
31 #else
32 #define PICO_CORE1_STACK_SIZE 0x800
33 #endif
34 #endif
35 
36 /*! \brief  Reset core 1
37  *  \ingroup pico_multicore
38  *
39  * This function can be used to reset core 1 into its initial state (ready for launching code against via \ref multicore_launch_core1 and similar methods)
40  *
41  * \note this function should only be called from core 0
42  */
43 void multicore_reset_core1(void);
44 
45 /*! \brief  Run code on core 1
46  *  \ingroup pico_multicore
47  *
48  * Wake up (a previously reset) core 1 and enter the given function on core 1 using the default core 1 stack (below core 0 stack).
49  *
50  * core 1 must previously have been reset either as a result of a system reset or by calling \ref multicore_reset_core1
51  *
52  * core 1 will use the same vector table as core 0
53  *
54  * \param entry Function entry point
55  * \see multicore_reset_core1
56  */
57 void multicore_launch_core1(void (*entry)(void));
58 
59 /*! \brief  Launch code on core 1 with stack
60  *  \ingroup pico_multicore
61  *
62  * Wake up (a previously reset) core 1 and enter the given function on core 1 using the passed stack for core 1
63  *
64  * core 1 must previously have been reset either as a result of a system reset or by calling \ref multicore_reset_core1
65  *
66  * core 1 will use the same vector table as core 0
67  *
68  * \param entry Function entry point
69  * \param stack_bottom The bottom (lowest address) of the stack
70  * \param stack_size_bytes The size of the stack in bytes (must be a multiple of 4)
71  * \see multicore_reset_core1
72  */
73 void multicore_launch_core1_with_stack(void (*entry)(void), uint32_t *stack_bottom, size_t stack_size_bytes);
74 
75 /*! \brief  Launch code on core 1 with no stack protection
76  *  \ingroup pico_multicore
77  *
78  * Wake up (a previously reset) core 1 and start it executing with a specific entry point, stack pointer
79  * and vector table.
80  *
81  * This is a low level function that does not provide a stack guard even if USE_STACK_GUARDS is defined
82  *
83  * core 1 must previously have been reset either as a result of a system reset or by calling \ref multicore_reset_core1
84  *
85  * \param entry Function entry point
86  * \param sp Pointer to the top of the core 1 stack
87  * \param vector_table address of the vector table to use for core 1
88  * \see multicore_reset_core1
89  */
90 void multicore_launch_core1_raw(void (*entry)(void), uint32_t *sp, uint32_t vector_table);
91 
92 /*!
93  * \defgroup multicore_fifo fifo
94  * \ingroup pico_multicore
95  * \brief Functions for the inter-core FIFOs
96  *
97  * The RP2040 contains two FIFOs for passing data, messages or ordered events between the two cores. Each FIFO is 32 bits
98  * wide, and 8 entries deep. One of the FIFOs can only be written by core 0, and read by core 1. The other can only be written
99  * by core 1, and read by core 0.
100  *
101  * \note The inter-core FIFOs are a very precious resource and are frequently used for SDK functionality (e.g. during
102  * core 1 launch or by the \ref multicore_lockout functions). Additionally they are often required for the exclusive use
103  * of an RTOS (e.g. FreeRTOS SMP). For these reasons it is suggested that you do not use the FIFO for your own purposes
104  * unless none of the above concerns apply; the majority of cases for transferring data between cores can be eqaully
105  * well handled  by using a \ref queue
106  */
107 
108 /*! \brief Check the read FIFO to see if there is data available (sent by the other core)
109  *  \ingroup multicore_fifo
110  *
111  * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
112  *
113  * \return true if the FIFO has data in it, false otherwise
114  */
multicore_fifo_rvalid(void)115 static inline bool multicore_fifo_rvalid(void) {
116     return !!(sio_hw->fifo_st & SIO_FIFO_ST_VLD_BITS);
117 }
118 
119 /*! \brief Check the write FIFO to see if it has space for more data
120  *  \ingroup multicore_fifo
121  *
122  * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
123  *
124  *  @return true if the FIFO has room for more data, false otherwise
125  */
multicore_fifo_wready(void)126 static inline bool multicore_fifo_wready(void) {
127     return !!(sio_hw->fifo_st & SIO_FIFO_ST_RDY_BITS);
128 }
129 
130 /*! \brief Push data on to the write FIFO (data to the other core).
131  *  \ingroup multicore_fifo
132  *
133  * This function will block until there is space for the data to be sent.
134  * Use multicore_fifo_wready() to check if it is possible to write to the
135  * FIFO if you don't want to block.
136  *
137  * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
138  *
139  * \param data A 32 bit value to push on to the FIFO
140  */
141 void multicore_fifo_push_blocking(uint32_t data);
142 
143 /*! \brief Push data on to the write FIFO (data to the other core) with timeout.
144  *  \ingroup multicore_fifo
145  *
146  * This function will block until there is space for the data to be sent
147  * or the timeout is reached
148  *
149  * \param data A 32 bit value to push on to the FIFO
150  * \param timeout_us the timeout in microseconds
151  * \return true if the data was pushed, false if the timeout occurred before data could be pushed
152  */
153 bool multicore_fifo_push_timeout_us(uint32_t data, uint64_t timeout_us);
154 
155 /*! \brief Pop data from the read FIFO (data from the other core).
156  *  \ingroup multicore_fifo
157  *
158  * This function will block until there is data ready to be read
159  * Use multicore_fifo_rvalid() to check if data is ready to be read if you don't
160  * want to block.
161  *
162  * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
163  *
164  * \return 32 bit data from the read FIFO.
165  */
166 uint32_t multicore_fifo_pop_blocking(void);
167 
168 /*! \brief Pop data from the read FIFO (data from the other core) with timeout.
169  *  \ingroup multicore_fifo
170  *
171  * This function will block until there is data ready to be read or the timeout is reached
172  *
173  * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
174  *
175  * \param timeout_us the timeout in microseconds
176  * \param out the location to store the popped data if available
177  * \return true if the data was popped and a value copied into `out`, false if the timeout occurred before data could be popped
178  */
179 bool multicore_fifo_pop_timeout_us(uint64_t timeout_us, uint32_t *out);
180 
181 /*! \brief Discard any data in the read FIFO
182  *  \ingroup multicore_fifo
183  *
184  * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
185  */
multicore_fifo_drain(void)186 static inline void multicore_fifo_drain(void) {
187     while (multicore_fifo_rvalid())
188         (void) sio_hw->fifo_rd;
189 }
190 
191 /*! \brief Clear FIFO interrupt
192  *  \ingroup multicore_fifo
193  *
194  * Note that this only clears an interrupt that was caused by the ROE or WOF flags.
195  * To clear the VLD flag you need to use one of the 'pop' or 'drain' functions.
196  *
197  * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
198  *
199  * \see multicore_fifo_get_status
200 */
multicore_fifo_clear_irq(void)201 static inline void multicore_fifo_clear_irq(void) {
202     // Write any value to clear the error flags
203     sio_hw->fifo_st = 0xff;
204 }
205 
206 /*! \brief Get FIFO statuses
207  *  \ingroup multicore_fifo
208  *
209  * \return The statuses as a bitfield
210  *
211  * Bit | Description
212  * ----|------------
213  * 3 | Sticky flag indicating the RX FIFO was read when empty (ROE). This read was ignored by the FIFO.
214  * 2 | Sticky flag indicating the TX FIFO was written when full (WOF). This write was ignored by the FIFO.
215  * 1 | Value is 1 if this core’s TX FIFO is not full (i.e. if FIFO_WR is ready for more data)
216  * 0 | Value is 1 if this core’s RX FIFO is not empty (i.e. if FIFO_RD is valid)
217  *
218  * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
219  *
220 */
multicore_fifo_get_status(void)221 static inline uint32_t multicore_fifo_get_status(void) {
222     return sio_hw->fifo_st;
223 }
224 
225 /*!
226  * \defgroup multicore_lockout lockout
227  * \ingroup pico_multicore
228  * \brief Functions to enable one core to force the other core to pause execution in a known state.
229  *
230  * Sometimes it is useful to enter a critical section on both cores at once. On a single
231  * core system a critical section can trivially be entered by disabling interrupts, however on a multi-core
232  * system that is not sufficient, and unless the other core is polling in some way, then it will need to be interrupted
233  * in order to cooperatively enter a blocked state.
234  *
235  * These "lockout" functions use the inter core FIFOs to cause an interrupt on one core from the other, and manage
236  * waiting for the other core to enter the "locked out" state.
237  *
238  * The usage is that the "victim" core ... i.e the core that can be "locked out" by the other core calls
239  * \ref multicore_lockout_victim_init to hook the FIFO interrupt. Note that either or both cores may do this.
240  *
241  * \note When "locked out" the victim core is paused (it is actually executing a tight loop with code in RAM) and has interrupts disabled.
242  * This makes the lockout functions suitable for use by code that wants to write to flash (at which point no code may be executing
243  * from flash)
244  *
245  * The core which wishes to lockout the other core calls \ref multicore_lockout_start_blocking or
246  * \ref multicore_lockout_start_timeout_us to interrupt the other "victim" core and wait for it to be in a
247  * "locked out" state. Once the lockout is no longer needed it calls \ref multicore_lockout_end_blocking or
248  * \ref multicore_lockout_end_timeout_us to release the lockout and wait for confirmation.
249  *
250  * \note Because multicore lockout uses the intercore FIFOs, the FIFOs <b>cannot</b> be used for any other purpose
251  */
252 
253 /*! \brief Initialize the current core such that it can be a "victim" of lockout (i.e. forced to pause in a known state by the other core)
254  *  \ingroup multicore_lockout
255  *
256  * This code hooks the intercore FIFO IRQ, and the FIFO may not be used for any other purpose after this.
257  */
258 void multicore_lockout_victim_init(void);
259 
260 /*! \brief Determine if \ref multicore_victim_init() has been called on the specified core.
261  *  \ingroup multicore_lockout
262  *
263  * \note this state persists even if the core is subsequently reset; therefore you are advised to
264  * always call \ref multicore_lockout_victim_init() again after resetting a core, which had previously
265  * been initialized.
266  *
267  * \param core_num the core number (0 or 1)
268  * \return true if \ref multicore_victim_init() has been called on the specified core, false otherwise.
269  */
270 bool multicore_lockout_victim_is_initialized(uint core_num);
271 
272 /*! \brief Request the other core to pause in a known state and wait for it to do so
273  *  \ingroup multicore_lockout
274  *
275  * The other (victim) core must have previously executed \ref multicore_lockout_victim_init()
276  *
277  * \note multicore_lockout_start_ functions are not nestable, and must be paired with a call to a corresponding
278  * \ref multicore_lockout_end_blocking
279  */
280 void multicore_lockout_start_blocking(void);
281 
282 /*! \brief Request the other core to pause in a known state and wait up to a time limit for it to do so
283  *  \ingroup multicore_lockout
284  *
285  * The other core must have previously executed \ref multicore_lockout_victim_init()
286  *
287  * \note multicore_lockout_start_ functions are not nestable, and must be paired with a call to a corresponding
288  * \ref multicore_lockout_end_blocking
289  *
290  * \param timeout_us the timeout in microseconds
291  * \return true if the other core entered the locked out state within the timeout, false otherwise
292  */
293 bool multicore_lockout_start_timeout_us(uint64_t timeout_us);
294 
295 /*! \brief Release the other core from a locked out state amd wait for it to acknowledge
296  *  \ingroup multicore_lockout
297  *
298  * \note The other core must previously have been "locked out" by calling a `multicore_lockout_start_` function
299  * from this core
300  */
301 void multicore_lockout_end_blocking(void);
302 
303 /*! \brief Release the other core from a locked out state amd wait up to a time limit for it to acknowledge
304  *  \ingroup multicore_lockout
305  *
306  * The other core must previously have been "locked out" by calling a `multicore_lockout_start_` function
307  * from this core
308  *
309  * \note be very careful using small timeout values, as a timeout here will leave the "lockout" functionality
310  * in a bad state. It is probably preferable to use \ref multicore_lockout_end_blocking anyway as if you have
311  * already waited for the victim core to enter the lockout state, then the victim core will be ready to exit
312  * the lockout state very quickly.
313  *
314  * \param timeout_us the timeout in microseconds
315  * \return true if the other core successfully exited locked out state within the timeout, false otherwise
316  */
317 bool multicore_lockout_end_timeout_us(uint64_t timeout_us);
318 
319 #ifdef __cplusplus
320 }
321 #endif
322 #endif
323