Add SMP template port and example (#900)

* 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 <ptaksoren@gmail.com>
Co-authored-by: Rahul Kar <118818625+kar-rahul-aws@users.noreply.github.com>
This commit is contained in:
chinglee-iot 2023-12-04 10:49:41 +08:00 committed by GitHub
parent f8ef5f605b
commit c0ce725293
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 194 additions and 24 deletions

View file

@ -111,6 +111,13 @@ jobs:
cmake -S . -B build cmake -S . -B build
cmake --build 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: MSP430-GCC:
name: GNU MSP430 Toolchain name: GNU MSP430 Toolchain
runs-on: ubuntu-latest runs-on: ubuntu-latest

View file

@ -7,10 +7,19 @@ set(FREERTOS_KERNEL_PATH "../../")
# Add the freertos_config for FreeRTOS-Kernel # Add the freertos_config for FreeRTOS-Kernel
add_library(freertos_config INTERFACE) add_library(freertos_config INTERFACE)
target_include_directories(freertos_config if (DEFINED FREERTOS_SMP_EXAMPLE AND FREERTOS_SMP_EXAMPLE STREQUAL "1")
message(STATUS "Build FreeRTOS SMP example")
target_include_directories(freertos_config
INTERFACE INTERFACE
../sample_configuration "../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. # Select the heap port. values between 1-4 will pick a heap.
set(FREERTOS_HEAP "4" CACHE STRING "" FORCE) set(FREERTOS_HEAP "4" CACHE STRING "" FORCE)

View file

@ -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__ */

View file

@ -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)

View file

@ -25,8 +25,18 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
void vPortYield( void ) void vPortYield( void )
{ {
/* Save the current Context */ /* Save the current Context */
/* Switch to the highest priority task that is ready to run. */ /* Switch to the highest priority task that is ready to run. */
#if ( configNUMBER_OF_CORES == 1 )
{
vTaskSwitchContext(); vTaskSwitchContext();
}
#else
{
vTaskSwitchContext( portGET_CORE_ID() );
}
#endif
/* Start executing the task we have just switched to. */ /* Start executing the task we have just switched to. */
} }
@ -35,12 +45,34 @@ static void prvTickISR( void )
/* Interrupts must have been enabled for the ISR to fire, so we have to /* Interrupts must have been enabled for the ISR to fire, so we have to
* save the context with interrupts enabled. */ * save the context with interrupts enabled. */
#if ( configNUMBER_OF_CORES == 1 )
{
/* Maintain the tick count. */ /* Maintain the tick count. */
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
{ {
/* Switch to the highest priority task that is ready to run. */ /* Switch to the highest priority task that is ready to run. */
vTaskSwitchContext(); 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 */ /* start executing the new task */
} }

View file

@ -64,26 +64,42 @@ typedef unsigned char UBaseType_t;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) \ #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) \
{ \ do { \
uxTopPriority = 0; \ uxTopPriority = 0; \
} \ } while( 0 )
while( 0 )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
#define portDISABLE_INTERRUPTS() \ /* Disable the interrupts */
{ /* Disable the interrupts */ \ #define portDISABLE_INTERRUPTS() do {} while( 0 )
}
#define portENABLE_INTERRUPTS() \
{ /* Enable the interrupts */ \
}
#define portENTER_CRITICAL() \ /* Enable the interrupts */
{ /* preserve current interrupt state and then disable interrupts */ \ #define portENABLE_INTERRUPTS() do {} while( 0 )
}
#define portEXIT_CRITICAL() \ #if ( configNUMBER_OF_CORES == 1 )
{ /* restore previously preserved interrupt state */ \ /* 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 ); extern void vPortYield( void );
#define portYIELD() vPortYield() #define portYIELD() vPortYield()
@ -92,4 +108,35 @@ extern void vPortYield( void );
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( 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 */ #endif /* PORTMACRO_H */