Skip to content

Commit 55078ed

Browse files
committed
RP2040 updates for SMP
1 parent 3926638 commit 55078ed

File tree

5 files changed

+315
-172
lines changed

5 files changed

+315
-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: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#endif
3939

4040
#include "pico.h"
41+
#include "hardware/sync.h"
42+
4143
/*-----------------------------------------------------------
4244
* Port specific definitions.
4345
*
@@ -83,7 +85,7 @@
8385
* as our FreeRTOSConfig.h header cannot be included by ASM code - which is what this affects in the SDK */
8486
#define portUSE_DIVIDER_SAVE_RESTORE !PICO_DIVIDER_DISABLE_INTERRUPTS
8587
#if portUSE_DIVIDER_SAVE_RESTORE
86-
#define portSTACK_LIMIT_PADDING 4
88+
#define portSTACK_LIMIT_PADDING 4
8789
#endif
8890

8991
/*-----------------------------------------------------------*/
@@ -107,28 +109,113 @@
107109
#define xPortSysTickHandler isr_systick
108110
#endif
109111

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

148+
void vYieldCore(int xCoreID);
149+
#define portYIELD_CORE(a) vYieldCore(a)
150+
#define portRESTORE_INTERRUPTS(ulState) __asm volatile ("msr PRIMASK,%0"::"r" (ulState) : )
151+
115152
/*-----------------------------------------------------------*/
116153

117154
/* Critical section management. */
118-
extern uint32_t ulSetInterruptMaskFromISR( void ) __attribute__( ( naked ) );
119-
extern void vClearInterruptMaskFromISR( uint32_t ulMask ) __attribute__( ( naked ) );
120-
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR()
121-
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMaskFromISR( x )
122155

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

125165
extern void vPortEnableInterrupts();
126166
#define portENABLE_INTERRUPTS() vPortEnableInterrupts()
127167

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

133220
/*-----------------------------------------------------------*/
134221

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,24 @@ extern "C" {
6666
#endif
6767
#endif
6868

69+
#if (configNUM_CORES > 1)
70+
/* configTICK_CORE indicates which core should handle the SysTick
71+
* interrupts */
72+
#ifndef configTICK_CORE
73+
#define configTICK_CORE 0
74+
#endif
75+
#endif
76+
77+
/* This SMP port requires two spin locks, which are claimed from the SDK.
78+
* the spin lock numbers to be used are defined statically and defaulted here */
79+
#ifndef configSMP_SPINLOCK_0
80+
#define configSMP_SPINLOCK_0 30
81+
#endif
82+
83+
#ifndef configSMP_SPINLOCK_1
84+
#define configSMP_SPINLOCK_1 31
85+
#endif
86+
6987
#ifdef __cplusplus
7088
};
7189
#endif

portable/ThirdParty/GCC/RP2040/library.cmake

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,14 @@ target_include_directories(FreeRTOS-Kernel INTERFACE
3232
target_link_libraries(FreeRTOS-Kernel INTERFACE
3333
FreeRTOS-Kernel-Core
3434
pico_base_headers
35-
hardware_exception)
35+
hardware_clocks
36+
hardware_exception
37+
pico_multicore
38+
)
3639

3740
target_compile_definitions(FreeRTOS-Kernel INTERFACE
3841
LIB_FREERTOS_KERNEL=1
39-
FREE_RTOS_KERNEL_SMP=0
42+
FREE_RTOS_KERNEL_SMP=1
4043
)
4144

4245
add_library(FreeRTOS-Kernel-Static INTERFACE)

0 commit comments

Comments
 (0)