Skip to content

Commit 47c1fed

Browse files
committed
RP2040 updates for SMP
1 parent 128eb3e commit 47c1fed

File tree

5 files changed

+314
-172
lines changed

5 files changed

+314
-172
lines changed

portable/ThirdParty/GCC/RP2040/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
## Overview
22

3-
This directory provides a FreeRTOS-Kernel port that can be used with the Raspberry Pi Pico SDK. It supports:
3+
This directory provides an SMP FreeRTOS-Kernel port that can be used with the Raspberry Pi Pico SDK. It supports:
44

55
* Simple CMake INTERFACE libraries, to provide the FreeRTOS-Kernel and also the individual allocator types, without copying code into the user's project.
6-
* Running the FreeRTOS-Kernel and tasks on either core 0 or core 1
7-
* Use of SDK synchronization primitives (such as mutexes, semaphores, queues from pico_sync) between FreeRTOS tasks and code executing on the other core, or in IRQ handlers.
6+
* Running the FreeRTOS-Kernel and tasks on either core 0 or core 1, or both.
7+
* Use of SDK synchronization primitives (such as mutexes, semaphores, queues from pico_sync) between FreeRTOS tasks and code executing on a non FreeRTOS core, or in IRQ handlers.
88

9-
Note that a FreeRTOS SMP version of this port is also available in the FreeRTOS-Kernel smp branch, which additionally supports utilizing both RP2040 CPU cores for FreeRTOS tasks simultaneously.
9+
Note that whilst this SMP version can be run on just a single (either) core, it is probably
10+
more efficient to use the non SMP version in the main FreeRTOS-Kernel branch in that case.
1011

1112
## Using this port
1213

portable/ThirdParty/GCC/RP2040/include/portmacro.h

Lines changed: 95 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#endif
3636

3737
#include "pico.h"
38+
#include "hardware/sync.h"
39+
3840
/*-----------------------------------------------------------
3941
* Port specific definitions.
4042
*
@@ -80,7 +82,7 @@
8082
* as our FreeRTOSConfig.h header cannot be included by ASM code - which is what this affects in the SDK */
8183
#define portUSE_DIVIDER_SAVE_RESTORE !PICO_DIVIDER_DISABLE_INTERRUPTS
8284
#if portUSE_DIVIDER_SAVE_RESTORE
83-
#define portSTACK_LIMIT_PADDING 4
85+
#define portSTACK_LIMIT_PADDING 4
8486
#endif
8587

8688
/*-----------------------------------------------------------*/
@@ -104,28 +106,111 @@
104106
#define xPortSysTickHandler isr_systick
105107
#endif
106108

109+
/*-----------------------------------------------------------*/
110+
111+
/* Multi-core */
112+
#define portSUPPORT_SMP 1 /* this is an SMP build which means configNUM_CORES is relevant */
113+
#define portMAX_CORE_COUNT 2
114+
#ifndef configNUM_CORES
115+
#define configNUM_CORES 2
116+
#endif
117+
118+
/* Requires for SMP */
119+
#define portCRITICAL_NESTING_IN_TCB 1
120+
121+
/*-----------------------------------------------------------*/
122+
123+
124+
/* Check validity of number of cores specified in config */
125+
#if ( configNUM_CORES < 1 || portMAX_CORE_COUNT < configNUM_CORES )
126+
#error "Invalid number of cores specified in config!"
127+
#endif
128+
129+
#if ( configTICK_CORE < 0 || configTICK_CORE > configNUM_CORES )
130+
#error "Invalid tick core specified in config!"
131+
#endif
132+
133+
/* FreeRTOS core id is always zero based, so always 0 if we're running on only one core */
134+
#if configNUM_CORES == portMAX_CORE_COUNT
135+
#define portGET_CORE_ID() get_core_num()
136+
#else
137+
#define portGET_CORE_ID() 0
138+
#endif
139+
107140
#define portCHECK_IF_IN_ISR() ({ \
108141
uint32_t ulIPSR; \
109142
__asm volatile ("mrs %0, IPSR" : "=r" (ulIPSR)::); \
110143
((uint8_t)ulIPSR)>0;})
111144

145+
void vYieldCore(int xCoreID);
146+
#define portYIELD_CORE(a) vYieldCore(a)
147+
#define portRESTORE_INTERRUPTS(ulState) __asm volatile ("msr PRIMASK,%0"::"r" (ulState) : )
148+
112149
/*-----------------------------------------------------------*/
113150

114151
/* Critical section management. */
115-
extern uint32_t ulSetInterruptMaskFromISR( void ) __attribute__( ( naked ) );
116-
extern void vClearInterruptMaskFromISR( uint32_t ulMask ) __attribute__( ( naked ) );
117-
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR()
118-
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMaskFromISR( x )
119152

120-
#define portDISABLE_INTERRUPTS() __asm volatile ( " cpsid i " ::: "memory" )
153+
#define portSET_INTERRUPT_MASK_FROM_ISR() ({ uint32_t ulStateISR = portDISABLE_INTERRUPTS(); vTaskEnterCritical(); ulStateISR; })
154+
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) do { vTaskExitCritical(); portRESTORE_INTERRUPTS( x ); } while (0)
155+
156+
#define portDISABLE_INTERRUPTS() ({ \
157+
uint32_t ulState; \
158+
__asm volatile ("mrs %0, PRIMASK" : "=r" (ulState)::); \
159+
__asm volatile ( " cpsid i " ::: "memory" ); \
160+
ulState;})
121161

122162
extern void vPortEnableInterrupts();
123163
#define portENABLE_INTERRUPTS() vPortEnableInterrupts()
124164

125-
extern void vPortEnterCritical( void );
126-
extern void vPortExitCritical( void );
127-
#define portENTER_CRITICAL() vPortEnterCritical()
128-
#define portEXIT_CRITICAL() vPortExitCritical()
165+
void vTaskEnterCritical(void);
166+
void vTaskExitCritical(void);
167+
#define portENTER_CRITICAL() vTaskEnterCritical()
168+
#define portEXIT_CRITICAL() vTaskExitCritical()
169+
170+
#define portRTOS_SPINLOCK_COUNT 2
171+
172+
/* Note this is a single method with uxAcquire parameter since we have
173+
* static vars, the method is always called with a compile time constant for
174+
* uxAcquire, and the compiler should dothe right thing! */
175+
static inline void vPortRecursiveLock(uint32_t ulLockNum, spin_lock_t *pxSpinLock, BaseType_t uxAcquire) {
176+
static uint8_t ucOwnedByCore[ portMAX_CORE_COUNT ];
177+
static uint8_t ucRecursionCountByLock[ portRTOS_SPINLOCK_COUNT ];
178+
configASSERT(ulLockNum >= 0 && ulLockNum < portRTOS_SPINLOCK_COUNT );
179+
uint32_t ulCoreNum = get_core_num();
180+
uint32_t ulLockBit = 1u << ulLockNum;
181+
configASSERT(ulLockBit < 256u );
182+
if( uxAcquire )
183+
{
184+
if( __builtin_expect( !*pxSpinLock, 0 ) )
185+
{
186+
if( ucOwnedByCore[ulCoreNum] & ulLockBit )
187+
{
188+
configASSERT(ucRecursionCountByLock[ulLockNum] != 255u );
189+
ucRecursionCountByLock[ulLockNum]++;
190+
return;
191+
}
192+
while ( __builtin_expect( !*pxSpinLock, 0 ) );
193+
}
194+
__mem_fence_acquire();
195+
configASSERT(ucRecursionCountByLock[ulLockNum] == 0 );
196+
ucRecursionCountByLock[ulLockNum] = 1;
197+
ucOwnedByCore[ulCoreNum] |= ulLockBit;
198+
} else {
199+
configASSERT((ucOwnedByCore[ulCoreNum] & ulLockBit) != 0 );
200+
configASSERT(ucRecursionCountByLock[ulLockNum] != 0 );
201+
if( !--ucRecursionCountByLock[ulLockNum] )
202+
{
203+
ucOwnedByCore[ulCoreNum] &= ~ulLockBit;
204+
__mem_fence_release();
205+
*pxSpinLock = 1;
206+
}
207+
}
208+
}
209+
210+
#define portGET_ISR_LOCK() vPortRecursiveLock(0, spin_lock_instance(configSMP_SPINLOCK_0), pdTRUE)
211+
#define portRELEASE_ISR_LOCK() vPortRecursiveLock(0, spin_lock_instance(configSMP_SPINLOCK_0), pdFALSE)
212+
#define portGET_TASK_LOCK() vPortRecursiveLock(1, spin_lock_instance(configSMP_SPINLOCK_1), pdTRUE)
213+
#define portRELEASE_TASK_LOCK() vPortRecursiveLock(1, spin_lock_instance(configSMP_SPINLOCK_1), pdFALSE)
129214

130215
/*-----------------------------------------------------------*/
131216

portable/ThirdParty/GCC/RP2040/include/rp2040_config.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,25 @@ extern "C" {
6363
#endif
6464
#endif
6565

66+
#if (configNUM_CORES > 1)
67+
/* configTICK_CORE indicates which core should handle the SysTick
68+
* interrupts */
69+
#ifndef configTICK_CORE
70+
#define configTICK_CORE 0
71+
#endif
72+
#endif
73+
74+
/* This SMP port requires two spin locks, which are claimed from the SDK.
75+
* the spin lock numbers to be used are defined statically and defaulted here
76+
* to the values nominally set aside for RTOS by the SDK */
77+
#ifndef configSMP_SPINLOCK_0
78+
#define configSMP_SPINLOCK_0 PICO_SPINLOCK_ID_OS1
79+
#endif
80+
81+
#ifndef configSMP_SPINLOCK_1
82+
#define configSMP_SPINLOCK_1 PICO_SPINLOCK_ID_OS2
83+
#endif
84+
6685
#ifdef __cplusplus
6786
};
6887
#endif

portable/ThirdParty/GCC/RP2040/library.cmake

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ target_include_directories(FreeRTOS-Kernel INTERFACE
2727
target_link_libraries(FreeRTOS-Kernel INTERFACE
2828
FreeRTOS-Kernel-Core
2929
pico_base_headers
30-
hardware_exception)
30+
hardware_clocks
31+
hardware_exception
32+
pico_multicore
33+
)
3134

3235
target_compile_definitions(FreeRTOS-Kernel INTERFACE
3336
LIB_FREERTOS_KERNEL=1
34-
FREERTOS_KERNEL_SMP=0
37+
FREE_RTOS_KERNEL_SMP=1
3538
)
3639

3740
add_library(FreeRTOS-Kernel-Static INTERFACE)

0 commit comments

Comments
 (0)