Skip to content

Commit

Permalink
Add SMP template port and example (#900)
Browse files Browse the repository at this point in the history
* Add SMP template port and example
* Add readme file for smp configuration
* Update SMP build flow and add CI build

---------

Co-authored-by: Soren Ptak <[email protected]>
Co-authored-by: Rahul Kar <[email protected]>
  • Loading branch information
3 people authored Dec 4, 2023
1 parent f8ef5f6 commit c0ce725
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 24 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/kernel-demos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ jobs:
cmake -S . -B build
cmake --build build
- name: Build CMake SMP Example Demo
shell: bash
working-directory: examples/cmake_example
run: |
cmake -S . -B build -DFREERTOS_SMP_EXAMPLE=1
cmake --build build
MSP430-GCC:
name: GNU MSP430 Toolchain
runs-on: ubuntu-latest
Expand Down
17 changes: 13 additions & 4 deletions examples/cmake_example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@ set(FREERTOS_KERNEL_PATH "../../")
# Add the freertos_config for FreeRTOS-Kernel
add_library(freertos_config INTERFACE)

target_include_directories(freertos_config
INTERFACE
../sample_configuration
)
if (DEFINED FREERTOS_SMP_EXAMPLE AND FREERTOS_SMP_EXAMPLE STREQUAL "1")
message(STATUS "Build FreeRTOS SMP example")
target_include_directories(freertos_config
INTERFACE
"../sample_configuration/smp"
)
else()
message(STATUS "Build FreeRTOS example")
target_include_directories(freertos_config
INTERFACE
"../sample_configuration"
)
endif()

# Select the heap port. values between 1-4 will pick a heap.
set(FREERTOS_HEAP "4" CACHE STRING "" FORCE)
Expand Down
65 changes: 65 additions & 0 deletions examples/sample_configuration/smp/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/

/*******************************************************************************
* This file provides an example FreeRTOSConfig.h header file, inclusive of an
* abbreviated explanation of each configuration item. Online and reference
* documentation provides more information.
* https://www.freertos.org/a00110.html
*
* Constant values enclosed in square brackets ('[' and ']') must be completed
* before this file will build.
*
* Use the FreeRTOSConfig.h supplied with the RTOS port in use rather than this
* generic file, if one is available.
******************************************************************************/

#ifndef __FREERTOS_CONFIG_SMP_H__
#define __FREERTOS_CONFIG_SMP_H__

#include "../FreeRTOSConfig.h"

/******************************************************************************/
/* Scheduling behaviour related definitions. **********************************/
/******************************************************************************/

/* Set configNUMBER_OF_CORES to greater than 1 to enable running one instance of
* FreeRTOS kernel to schedule tasks across multiple identical processor cores. */
#define configNUMBER_OF_CORES 2

/******************************************************************************/
/* Hook and callback function related definitions. ****************************/
/******************************************************************************/

/* Set the following configUSE_* constants to 1 to include the named hook
* functionality in the build. Set to 0 to exclude the hook functionality from the
* build. The application writer is responsible for providing the hook function
* for any set to 1. See https://www.freertos.org/a00016.html */
#define configUSE_PASSIVE_IDLE_HOOK 0

#endif /* __FREERTOS_CONFIG_SMP_H__ */
10 changes: 10 additions & 0 deletions examples/sample_configuration/smp/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Configuration support for FreeRTOS SMP

## Overview
The FreeRTOSConfig.h provided in this folder is a sample configuration that will
assist you in preparing the configuration to enable SMP support in the FreeRTOS
Kernel for your application.

Based on single core sample configuration file, this configuration file is created
with minimal configuration change. More SMP scheduler configurations can be found
in [Symmetric Multiprocessing (SMP) with FreeRTOS](https://freertos.org/symmetric-multiprocessing-introduction.html)
42 changes: 37 additions & 5 deletions portable/template/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,18 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
void vPortYield( void )
{
/* Save the current Context */

/* Switch to the highest priority task that is ready to run. */
vTaskSwitchContext();
#if ( configNUMBER_OF_CORES == 1 )
{
vTaskSwitchContext();
}
#else
{
vTaskSwitchContext( portGET_CORE_ID() );
}
#endif

/* Start executing the task we have just switched to. */
}

Expand All @@ -35,12 +45,34 @@ static void prvTickISR( void )
/* Interrupts must have been enabled for the ISR to fire, so we have to
* save the context with interrupts enabled. */

/* Maintain the tick count. */
if( xTaskIncrementTick() != pdFALSE )
#if ( configNUMBER_OF_CORES == 1 )
{
/* Switch to the highest priority task that is ready to run. */
vTaskSwitchContext();
/* Maintain the tick count. */
if( xTaskIncrementTick() != pdFALSE )
{
/* Switch to the highest priority task that is ready to run. */
vTaskSwitchContext();
}
}
#else
{
UBaseType_t ulPreviousMask;

/* Tasks or ISRs running on other cores may still in critical section in
* multiple cores environment. Incrementing tick needs to performed in
* critical section. */
ulPreviousMask = taskENTER_CRITICAL_FROM_ISR();

/* Maintain the tick count. */
if( xTaskIncrementTick() != pdFALSE )
{
/* Switch to the highest priority task that is ready to run. */
vTaskSwitchContext( portGET_CORE_ID() );
}

taskEXIT_CRITICAL_FROM_ISR( ulPreviousMask );
}
#endif /* if ( configNUMBER_OF_CORES == 1 ) */

/* start executing the new task */
}
77 changes: 62 additions & 15 deletions portable/template/portmacro.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,42 @@ typedef unsigned char UBaseType_t;
/*-----------------------------------------------------------*/

#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) \
{ \
do { \
uxTopPriority = 0; \
} \
while( 0 )
} while( 0 )

#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

#define portDISABLE_INTERRUPTS() \
{ /* Disable the interrupts */ \
}
#define portENABLE_INTERRUPTS() \
{ /* Enable the interrupts */ \
}
/* Disable the interrupts */
#define portDISABLE_INTERRUPTS() do {} while( 0 )

#define portENTER_CRITICAL() \
{ /* preserve current interrupt state and then disable interrupts */ \
}
#define portEXIT_CRITICAL() \
{ /* restore previously preserved interrupt state */ \
}
/* Enable the interrupts */
#define portENABLE_INTERRUPTS() do {} while( 0 )

#if ( configNUMBER_OF_CORES == 1 )
/* preserve current interrupt state and then disable interrupts */
#define portENTER_CRITICAL() do {} while( 0 )

/* restore previously preserved interrupt state */
#define portEXIT_CRITICAL() do {} while( 0 )
#else

/* The port can maintain the critical nesting count in TCB or maintain the critical
* nesting count in the port. */
#define portCRITICAL_NESTING_IN_TCB 1

/* vTaskEnterCritical and vTaskExitCritical should be used in the implementation
* of portENTER/EXIT_CRITICAL if the number of cores is more than 1 in the system. */
#define portENTER_CRITICAL vTaskEnterCritical
#define portEXIT_CRITICAL vTaskExitCritical

/* vTaskEnterCriticalFromISR and vTaskExitCriticalFromISR should be used in the
* implementation of portENTER/EXIT_CRITICAL_FROM_ISR if the number of cores is
* more than 1 in the system. */
#define portENTER_CRITICAL_FROM_ISR vTaskEnterCriticalFromISR
#define portEXIT_CRITICAL_FROM_ISR vTaskExitCriticalFromISR

#endif /* if ( configNUMBER_OF_CORES == 1 ) */

extern void vPortYield( void );
#define portYIELD() vPortYield()
Expand All @@ -92,4 +108,35 @@ extern void vPortYield( void );
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )

#if ( configNUMBER_OF_CORES > 1 )
/* Return the core ID on which the code is running. */
#define portGET_CORE_ID() 0

/* Set the interrupt mask. */
#define portSET_INTERRUPT_MASK() 0

/* Clear the interrupt mask. */
#define portCLEAR_INTERRUPT_MASK( x ) ( ( void ) ( x ) )

/* Request the core ID x to yield. */
#define portYIELD_CORE( x ) do {} while( 0 )

/* Acquire the TASK lock. TASK lock is a recursive lock.
* It should be able to be locked by the same core multiple times. */
#define portGET_TASK_LOCK() do {} while( 0 )

/* Release the TASK lock. If a TASK lock is locked by the same core multiple times,
* it should be released as many times as it is locked. */
#define portRELEASE_TASK_LOCK() do {} while( 0 )

/* Acquire the ISR lock. ISR lock is a recursive lock.
* It should be able to be locked by the same core multiple times. */
#define portGET_ISR_LOCK() do {} while( 0 )

/* Release the ISR lock. If a ISR lock is locked by the same core multiple times, \
* it should be released as many times as it is locked. */
#define portRELEASE_ISR_LOCK() do {} while( 0 )

#endif /* if ( configNUMBER_OF_CORES > 1 ) */

#endif /* PORTMACRO_H */

0 comments on commit c0ce725

Please sign in to comment.