Skip to content

Commit

Permalink
CMSIS RTOS feature
Browse files Browse the repository at this point in the history
Adds the full features set for CMSIS RTOS support, with a lot
work provided by g-arjones. Builds on ObKo#190
and ObKo#189.

It allows to use the CMSIS support provided in the STM32 cube
repository.

Also adds documentation and an updated freertos example with the
same architecture as ObKo#225
  • Loading branch information
robamu committed Aug 1, 2021
1 parent 22339cc commit ddabe51
Show file tree
Hide file tree
Showing 10 changed files with 1,428 additions and 717 deletions.
78 changes: 55 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,24 @@ It uses cmake and GCC, along with newlib (libc), STM32Cube. Supports F0 F1 F2 F3
* `fetch-cube` ([examples/fetch-cube](examples/fetch-cube)) - example of using FetchContent for fetching STM32Cube from ST's git.
* `fetch-cmsis-hal` ([examples/fetch-cmsis-hal](examples/fetch-cmsis-hal)) - example of using FetchContent for fetching STM32 CMSIS and HAL from ST's git.
* `blinky` ([examples/blinky](examples/blinky)) - blink led using STM32 HAL library and SysTick.
It will compile a project for the `F4` family by default, but you can also compile for the
`L0` and `F1` family by passing `L0_EXAMPLE=ON` or `F1_EXAMPLE=ON` to the CMake generation call.
It will compile a project for the `F4` family by default, but you can also compile for the
`L0` and `F1` family by passing `BLINKY_L0_EXAMPLE=ON` or `BLINKY_F1_EXAMPLE=ON` to the CMake
generation call.
* `freertos` ([examples/freertos](examples/freertos)) - blink led using STM32 HAL library and FreeRTOS.
You need to specify at least one board by passing `FREERTOS_<BOARD>_EXAMPLE=ON` to CMake.
Currently, the example can be built for the `H743ZI` and `F407VG` board targets.
You can opt to use the FreeRTOS CMSIS implementation provided by the Cube repository by supplying
`USE_CMSIS_RTOS=ON` or `USE_CMSIS_RTOS_V2` to CMake.

# Usage

First of all you need to configure toolchain and library paths using CMake variables. There are
generally three ways to do this:

1. Pass the variables through command line during cmake run with passed to CMake with
1. Pass the variables through command line during cmake run with passed to CMake with
`-D<VAR_NAME>=...`
2. Set the variables inside your `CMakeLists.txt`
3. Pass these variables to CMake by setting them as environmental variables.
3. Pass these variables to CMake by setting them as environmental variables.

The most important set of variables which needs to be set can be found in the following section.

Expand Down Expand Up @@ -208,45 +213,72 @@ stm32-cmake contains additional CMake modules for finding and configuring variou
FreeRTOS-Kernel (usually located in the subfolder `FreeRTOS` on a downloaded release).
You can supply `FREERTOS_PATH` as an environmental variable as well.

Typical usage:
You can either use the FreeRTOS kernel provided in the Cube repositories, or a separate
FreeRTOS kernel. The Cube repository also provides the CMSIS RTOS and CMSIS RTOS V2 implementations.
If you like to use the CMSIS implementations, it is recommended to also use the FreeRTOS sources
provided in the Cube repository because the CMSIS port might be incompatible to newer kernel
versions.

You can specify to use CMSIS with a `CMSIS` target and by finding the CMSIS `RTOS` package.
To select which FreeRTOS to use, you can find the package for a specific FreeRTOS port and then
link against that port target within a specific namespace.

Typical usage for a H7 device when using the M7 core, using an external kernel without CMSIS
support. The FreeRTOS namespace is set to `FreeRTOS` and the `ARM_CM7` port is used:

```cmake
find_package(FreeRTOS COMPONENTS ARM_CM4F REQUIRED)
find_package(CMSIS COMPONENTS STM32H743ZI STM32H7_M7 REQUIRED)
find_package(FreeRTOS ARM_CM7 REQUIRED)
target_link_libraries(${TARGET_NAME} PRIVATE
...
FreeRTOS::ARM_CM4F
FreeRTOS::ARM_CM7
)
```

The following FreeRTOS ports are supported: `ARM_CM0`, `ARM_CM3`, `ARM_CM4F`, `ARM_CM7`.
Typical usage for a F4 device, using an external kernel without CMSIS support.
The FreeRTOS namespace is set to `FreeRTOS` and the `ARM_CM4F` port is used:

Other FreeRTOS libraries:

* `FreeRTOS::Coroutine` - co-routines (`croutines.c`)
* `FreeRTOS::EventGroups` - event groups (`event_groups.c`)
* `FreeRTOS::StreamBuffer` - stream buffer (`stream_buffer.c`)
* `FreeRTOS::Timers` - timers (`timers.c`)
* `FreeRTOS::Heap::<N>` - heap implementation (`heap_<N>.c`), `<N>`: [1-5]

The STM32Cube packages can contain the FreeRTOS source package and a CMSIS RTOS and RTOS_V2
implementation. You can specify to use CMSIS with a `CMSIS` target and by finding the CMSIS
`RTOS` package.
```cmake
find_package(FreeRTOS COMPONENTS ARM_CM4F REQUIRED)
target_link_libraries(${TARGET_NAME} PRIVATE
...
FreeRTOS::ARM_CM4F
)
```

Typical usage for a H7 device when using the M7 core with CMSIS `RTOS`:
Another typical usage using the FreeRTOS provided in the Cube repository and the CMSIS support.
The FreeRTOS namespace is set to `FreeRTOS::STM32::<FAMILY>` and the `ARM_CM7` port is used:

```cmake
find_package(CMSIS COMPONENTS STM32H743ZI STM32H7_M7 RTOS REQUIRED)
find_package(FreeRTOS COMPONENTS ARM_CM7 STM32H7 REQUIRED)
target_link_libraries(${TARGET_NAME} PRIVATE
...
FreeRTOS::ARM_CM7
FreeRTOS::STM32::H7::M7::ARM_CM7
CMSIS::STM32::H7::M7::RTOS
)
```

The following targets are available in general:
The following CMSIS targets are available in general:

* `CMSIS::STM32::<Family>::RTOS`
* `CMSIS::STM32::<Family>::RTOS_V2`

The following additional FreeRTOS targets are available in general to use the FreeRTOS provided
in the Cube repository

* `FreeRTOS::STM32::<Family>`

For the multi-core architectures, you have to specify both family and core like specified in the
example.
example above.

The following FreeRTOS ports are supported in general: `ARM_CM0`, `ARM_CM3`, `ARM_CM4F`, `ARM_CM7`,
`ARM_CM3_MPU`, `ARM_CM4_MPU`, `ARM_CM7_MPU`.

Other FreeRTOS libraries, with `FREERTOS_NAMESPACE` being set as specified in the examples above:

* `${FREERTOS_NAMESPACE}::Coroutine` - co-routines (`croutines.c`)
* `${FREERTOS_NAMESPACE}::EventGroups` - event groups (`event_groups.c`)
* `${FREERTOS_NAMESPACE}::StreamBuffer` - stream buffer (`stream_buffer.c`)
* `${FREERTOS_NAMESPACE}::Timers` - timers (`timers.c`)
* `${FREERTOS_NAMESPACE}::Heap::<N>` - heap implementation (`heap_<N>.c`), `<N>`: [1-5]
3 changes: 3 additions & 0 deletions cmake/FindCMSIS.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@ if(STM32H7 IN_LIST CMSIS_FIND_COMPONENTS)
endif()
list(REMOVE_DUPLICATES CMSIS_FIND_COMPONENTS)

# This section fills the RTOS or family components list
foreach(COMP ${CMSIS_FIND_COMPONENTS})
string(TOLOWER ${COMP} COMP_L)
string(TOUPPER ${COMP} COMP)

# Component is RTOS component
if(${COMP} IN_LIST CMSIS_RTOS)
list(APPEND CMSIS_FIND_COMPONENTS_RTOS ${COMP})
continue()
endif()

# Component is not RTOS component, so check whether it is a family component
string(REGEX MATCH "^STM32([A-Z][0-9])([0-9A-Z][0-9][A-Z][0-9A-Z])?_?(M[47])?.*$" COMP ${COMP})
if(CMAKE_MATCH_1)
list(APPEND CMSIS_FIND_COMPONENTS_FAMILIES ${COMP})
Expand Down
92 changes: 42 additions & 50 deletions cmake/FindFreeRTOS.cmake
Original file line number Diff line number Diff line change
@@ -1,57 +1,42 @@
set(FreeRTOS_PORTS ARM_CM0 ARM_CM3 ARM_CM4F ARM_CM7)
set(FreeRTOS_PORTS ARM_CM0 ARM_CM3 ARM_CM4F ARM_CM7 ARM_CM4_MPU ARM_CM3_MPU ARM_CM7_MPU)
if(NOT FreeRTOS_FIND_COMPONENTS)
set(FreeRTOS_FIND_COMPONENTS ${FreeRTOS_PORTS})
endif()

set(FreeRTOS_HEAPS 1 2 3 4 5)
list(REMOVE_DUPLICATES FreeRTOS_FIND_COMPONENTS)

if((NOT FREERTOS_PATH) AND (DEFINED ENV{FREERTOS_PATH}))
set(FREERTOS_PATH $ENV{FREERTOS_PATH} CACHE PATH "Path to FreeRTOS")
message(STATUS "ENV FREERTOS_PATH specified, using FREERTOS_PATH: ${FREERTOS_PATH}")
endif()

if(NOT FREERTOS_PATH)
set(FREERTOS_PATH /opt/FreeRTOS CACHE PATH "Path to FreeRTOS")
message(STATUS "No FREERTOS_PATH specified using default: ${FREERTOS_PATH}")
endif()

find_path(FreeRTOS_COMMON_INCLUDE
NAMES FreeRTOS.h
PATHS "${FREERTOS_PATH}" "${FREERTOS_PATH}/FreeRTOS"
PATH_SUFFIXES "Source/include" "include"
NO_DEFAULT_PATH
)

if(NOT FreeRTOS_COMMON_INCLUDE)
message(WARNING "FreeRTOS common include path not found, build might fail")
set(DEFAULT_FREERTOS_PATH "/opt/FreeRTOS")
if(EXISTS ${DEFAULT_FREERTOS_PATH})
set(FREERTOS_PATH ${DEFAULT_FREERTOS_PATH} CACHE PATH "Path to FreeRTOS")
message(STATUS "No FREERTOS_PATH specified using default: ${DEFAULT_FREERTOS_PATH}")
else()
message(STATUS
"No FreeRTOS folder found at default location ${DEFAULT_FREERTOS_PATH}. "
"Leaving empty"
)
endif()
endif()

list(APPEND FreeRTOS_INCLUDE_DIRS "${FreeRTOS_COMMON_INCLUDE}")

find_path(FreeRTOS_SOURCE_DIR
NAMES tasks.c
PATHS "${FREERTOS_PATH}" "${FREERTOS_PATH}/FreeRTOS"
PATH_SUFFIXES "Source"
NO_DEFAULT_PATH
)
if(NOT (TARGET FreeRTOS))
add_library(FreeRTOS INTERFACE IMPORTED)
target_sources(FreeRTOS INTERFACE
"${FreeRTOS_SOURCE_DIR}/tasks.c"
"${FreeRTOS_SOURCE_DIR}/list.c"
"${FreeRTOS_SOURCE_DIR}/queue.c"
)
target_include_directories(FreeRTOS INTERFACE "${FreeRTOS_COMMON_INCLUDE}")
if(STM32H7 IN_LIST FreeRTOS_FIND_COMPONENTS)
list(REMOVE_ITEM FreeRTOS_FIND_COMPONENTS STM32H7)
list(APPEND FreeRTOS_FIND_COMPONENTS STM32H7_M7 STM32H7_M4)
endif()

# This section fills the family and ports components list
foreach(COMP ${FreeRTOS_FIND_COMPONENTS})
string(TOUPPER ${COMP} COMP)
string(REGEX MATCH "^STM32([A-Z][0-9])([0-9A-Z][0-9][A-Z][0-9A-Z])?_?(M[47])?.*$" FAMILY_COMP ${COMP})
# Valid family component, so add it (e.g. STM32H7)
if(CMAKE_MATCH_1)
list(APPEND FreeRTOS_FIND_COMPONENTS_FAMILIES ${FAMILY_COMP})
continue()
endif()

# Was not a family component, so add it to the port list
list(APPEND FreeRTOS_FIND_COMPONENTS_PORTS ${COMP})
endforeach()

Expand All @@ -69,23 +54,20 @@ macro(stm32_find_freertos FreeRTOS_NAMESPACE FREERTOS_PATH)
find_path(FreeRTOS_COMMON_INCLUDE
NAMES FreeRTOS.h
PATHS "${FREERTOS_PATH}" "${FREERTOS_PATH}/FreeRTOS"
PATH_SUFFIXES
"portable/GCC/${PORT}/r0p1"
"portable/GCC/${PORT}"
"Source/portable/GCC/${PORT}"
"Source/portable/GCC/${PORT}/r0p1"
PATH_SUFFIXES "Source/include" "include"
NO_DEFAULT_PATH
)

if(NOT FreeRTOS_${PORT}_PATH)
message(WARNING "FreeRTOS port path not found, build might fail")
if(NOT FreeRTOS_COMMON_INCLUDE)
message(WARNING "FreeRTOS common include path not found, build might fail")
endif()

list(APPEND FreeRTOS_INCLUDE_DIRS "${FreeRTOS_${PORT}_PATH}")

find_file(FreeRTOS_${PORT}_SOURCE
NAMES port.c
PATHS "${FreeRTOS_${PORT}_PATH}"
list(APPEND FreeRTOS_INCLUDE_DIRS "${FreeRTOS_COMMON_INCLUDE}")

find_path(FreeRTOS_SOURCE_DIR
NAMES tasks.c
PATHS "${FREERTOS_PATH}" "${FREERTOS_PATH}/FreeRTOS"
PATH_SUFFIXES "Source"
NO_DEFAULT_PATH
)
if(NOT (TARGET FreeRTOS))
Expand Down Expand Up @@ -134,9 +116,18 @@ macro(stm32_find_freertos FreeRTOS_NAMESPACE FREERTOS_PATH)
find_path(FreeRTOS_${PORT}_PATH
NAMES portmacro.h
PATHS "${FREERTOS_PATH}" "${FREERTOS_PATH}/FreeRTOS"
PATH_SUFFIXES "Source/portable/GCC/${PORT}" "Source/portable/GCC/${PORT}/r0p1"
PATH_SUFFIXES
"portable/GCC/${PORT}/r0p1"
"portable/GCC/${PORT}"
"Source/portable/GCC/${PORT}"
"Source/portable/GCC/${PORT}/r0p1"
NO_DEFAULT_PATH
)

if(NOT FreeRTOS_${PORT}_PATH)
message(WARNING "FreeRTOS port path not found, build might fail")
endif()

list(APPEND FreeRTOS_INCLUDE_DIRS "${FreeRTOS_${PORT}_PATH}")

find_file(FreeRTOS_${PORT}_SOURCE
Expand All @@ -162,15 +153,16 @@ macro(stm32_find_freertos FreeRTOS_NAMESPACE FREERTOS_PATH)
endforeach()
endmacro()

message(STATUS "Search for FreeRTOS ports: ${FreeRTOS_FIND_COMPONENTS_PORTS}")

if(NOT FreeRTOS_FIND_COMPONENTS_FAMILIES)
if(NOT FREERTOS_PATH)
set(FREERTOS_PATH /opt/FreeRTOS CACHE PATH "Path to FreeRTOS")
message(STATUS "No FREERTOS_PATH specified using default: ${FREERTOS_PATH}")
message(STATUS "No FREERTOS_PATH specified, using default: ${FREERTOS_PATH}")
endif()
stm32_find_freertos(FreeRTOS ${FREERTOS_PATH})
else()
message(STATUS "Search for FreeRTOS families: ${FreeRTOS_FIND_COMPONENTS_FAMILIES}")
message(STATUS "Search for FreeRTOS ports: ${FreeRTOS_FIND_COMPONENTS_PORTS}")

foreach(COMP ${FreeRTOS_FIND_COMPONENTS_FAMILIES})
string(TOLOWER ${COMP} COMP_L)
Expand All @@ -184,10 +176,10 @@ else()

if(CMAKE_MATCH_2)
set(FAMILY ${CMAKE_MATCH_1})
set(DEVICES "${CMAKE_MATCH_1}${CMAKE_MATCH_2}")
set(STM_DEVICES "${CMAKE_MATCH_1}${CMAKE_MATCH_2}")
else()
set(FAMILY ${CMAKE_MATCH_1})
stm32_get_devices_by_family(DEVICES FAMILY ${FAMILY} CORE ${CORE})
stm32_get_devices_by_family(STM_DEVICES FAMILY ${FAMILY})
endif()

if(CMAKE_MATCH_3)
Expand Down
2 changes: 1 addition & 1 deletion cmake/stm32/devices.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1145,7 +1145,7 @@ function(stm32_get_devices_by_family STM_DEVICES)
# No family argument, so get list of all devices
set(RESULTING_DEV_LIST ${STM32_ALL_DEVICES})
endif()

set(${STM_DEVICES} ${RESULTING_DEV_LIST} PARENT_SCOPE)
endfunction()

Expand Down
Loading

0 comments on commit ddabe51

Please sign in to comment.