How to create an application and use the Open IoT SDK
This document will walk you through the process of creating a simple application that prints Hello world
to Corstone-300's serial terminal. It aims to give you a basic idea of how to create a CMake project and use components from the Open IoT SDK.
Overview
A project for an application that runs on a microcontroller often consists of the following items:
- Application code
- Libraries, such as
- HAL (hardware abstraction layer) and drivers
- Real-time Operating System (RTOS)
- Middleware components, such as cloud clients
- Others
- Linker scripts
- Additional firmware components, such as Trusted-Firmware M (if enabled)
- Build scripts
Some of those items are optional. For example, the simple "Hello world" application that we will be creating in this document will be bare-metal (no RTOS), not connecting any cloud services (no cloud clients) and without Trusted-Firmware M enabled.
The Open IoT SDK is capable of fetching and enabling a number of components (i.e. libraries as well as Trusted-Firmware M) and pre-integrating some of those components together. The way to specify which components to enable will be described later in the document. The user can also add their own libraries as needed.
Currently, the application's build scripts need to be provided in CMake, because the Open IoT SDK is a CMake based project.
Creating a CMake project for your application
To start, you need to create a new CMake project:
- Create a new directory for the project and navigate to the directory.
-
In the newly created directory, create a file named
CMakeLists.txt
, and begin the file with the following line:It specifies the minimum CMake version that is supported by the Open IoT SDK.
Adding toolchain support
Currently, the Open IoT SDK project provides support for Arm Compiler 6 and GNU Arm Toolchain. It does so by providing a set of CMake files that set toolchain flags specific to each of them.
-
Fetch toolchain support, by adding the following lines to
CMakeLists.txt
:include(FetchContent) FetchContent_Declare(iotsdk-toolchains GIT_REPOSITORY https://git.gitlab.arm.com/iot/open-iot-sdk/toolchain.git GIT_TAG main SOURCE_DIR ${CMAKE_BINARY_DIR}/toolchains ) FetchContent_MakeAvailable(iotsdk-toolchains)
You can inspect the CMake toolchain files (
toolchain-armclang.cmake
andtoolchain-arm-none-eabi-gcc.cmake
) by opening the URL in the snippet above. -
Set the processor of your MCU target, in lowercase.
For example, the processor of the Corstone-300 platform is
cortex-m55
. Add the following line toCMakeLists.txt
: -
Declare your project with a name of your choice. For example, add the following line to
CMakeLists.txt
:Note
This must be done after you have added toolchain support and set the target processor, because CMake processes toolchain and processor options during the
project()
call.
Specifying software components
The Open IoT SDK is capable of fetching and adding a number of software components from other repositories. Your application project needs to tell the SDK which components to fetch. To do so,
- Go to the Open IoT SDK's cmake/DeclareSdkComponents.cmake file to see which components are supported. The first argument of each
FetchContent_Declare()
is the name of the component. -
Note down the component(s) you would like to use.
In this simple example, we will only print a
Hello
message to Corstone-300's serial terminal, and the repository containing hardware support including serial support for Corstone-300 iscmsis-pack-utils
.Note
CMSIS-Pack-Utils is always available in the Open-IoT-SDK, therefore we do not need to include it in the
IOTSDK_FETCH_LIST
variable. -
Go back to your own project's
CMakeLists.txt
which you have created earlier, and set theIOTSDK_FETCH_LIST
variable to a list of components you would like to fetch.
Adding the Open IoT SDK
First, we need to set a correct device identifier, SSE-300-MPS3
.
Add the Open IoT SDK, by adding the following lines to your CMakeLists.txt
:
set(CMSIS_PACK_PLATFORM_DEVICE_NAME SSE-300-MPS3)
FetchContent_Declare(
open-iot-sdk
GIT_REPOSITORY https://git.gitlab.arm.com/iot/open-iot-sdk/sdk.git
GIT_TAG main
)
FetchContent_MakeAvailable(open-iot-sdk)
list(APPEND CMAKE_MODULE_PATH ${open-iot-sdk_SOURCE_DIR}/cmake)
This will also cause the components you have listed in IOTSDK_FETCH_LIST
to be fetched and added automatically when you build the project.
Specifying libraries delivered via CMSIS-Packs
We will provide hardware support for Corstone-300 via the dedicated, platform-specific Open-CMSIS-Pack named V2M_MPS3_SSE_300_BSP
. To have it available for our project, we will call add_cmsis_library()
that is delivered by cmsis-pack-utils
component. Please, take a look at How to use section for more details.
Several Open-CMSIS-Pack components are necessary for our demo:
- From ARM::CMSIS@5.9.0
package:
- ARM::CMSIS:CORE@5.6.0
CMSIS-CORE for all Cortex-M, including Cortex-M55,
- From ARM::V2M_MPS3_SSE_300_BSP@1.3.0
package:
- ARM::Device:Definition@1.2.0
SSE-300-MPS3 device definitions,
- ARM::Device:Startup&Baremetal@1.2.0
Secure System and Startup for ARM SSE-300-MPS3 device,
- ARM::Native Driver:SysCounter@1.1.0
Native SysCounter driver for SSE-300,
- ARM::Native Driver:SysTimer@1.1.0
Native SysTimer driver for SSE-300,
- ARM::Native Driver:Timeout@1.0.0
Systimer timeout driver for SSE-300,
- ARM::Native Driver:UART@1.1.0
Native UART driver for SSE-300,
- ARM::CMSIS Driver:USART@1.0.0
USART driver for SSE-300.
Add the following lines to your project's CMakeLists.txt
:
set(OPEN_CMSIS_PACKS_TO_FETCH
"ARM::CMSIS@5.9.0"
"ARM::V2M_MPS3_SSE_300_BSP@1.3.0"
)
set(OPEN_CMSIS_PACK_COMPONENTS
"ARM::CMSIS Driver:USART@1.0.0"
"ARM::CMSIS:CORE@5.6.0"
"ARM::Device:Definition@1.2.0"
"ARM::Device:Startup&Baremetal@1.2.0"
"ARM::Native Driver:SysCounter@1.1.0"
"ARM::Native Driver:SysTimer@1.1.0"
"ARM::Native Driver:Timeout@1.0.0"
"ARM::Native Driver:UART@1.1.0"
)
add_cmsis_library(
corstone-300-hardware-support
${CMSIS_PACK_PLATFORM_DEVICE_NAME}
AC6
OPEN_CMSIS_PACKS_TO_FETCH
OPEN_CMSIS_PACK_COMPONENTS
)
(If you would like to use GNU Arm Toolchain instead, replace AC6
with GCC
in the code snippet above.)
The result of add_cmsis_library()
is a CMake library target named corstone-300-hardware-support
.
Creating an application
At minimum, you need a C file containing the main()
function and a linker script containing the memory layout:
-
Inside your project's directory, create a
main.c
file with the following content: -
Download armclang.sct (for Arm Compiler 6) and/or gcc.ld (for GNU Arm Toolchain).
-
Move the file(s) you have just downloaded into your project's directory.
Note
To keep this tutorial as simple as possible, we do not write our own linker scripts here because they are relatively complex.
-
Declare your application and add the source file, by adding the following to your project's
CMakeLists.txt
: -
Link your application against libraries it needs.
In this example, we need *
iotsdk-serial-retarget
, which retargetsprintf()
to the serial output. This library is defined in the SDK's utils/CMakeLists.txt. *corstone-300-hardware-support
, which provides the startup file needed for the boot sequence and interrupt handling, and CMSIS-Drivers implementation (including the serial) for Corstone-300. This is provided with the use ofcmsis-pack-utils
tool as we have specified above.Add the following lines to your project's
CMakeLists.txt
: -
Link required libraries against their dependencies.
The
iotsdk-serial-retarget
library also depends on platform-specific CMSIS-Driver implementation.Add the following lines to your project's
CMakeLists.txt
: -
Finally, set the linker flags to use the linker scripts:
if(CMAKE_C_COMPILER_ID STREQUAL "GNU") set(linker_script ${CMAKE_CURRENT_LIST_DIR}/gcc.ld) target_link_options(my_application PRIVATE -T ${linker_script}) elseif(CMAKE_C_COMPILER_ID STREQUAL "ARMClang") set(linker_script ${CMAKE_CURRENT_LIST_DIR}/armclang.sct) target_link_options(my_application PRIVATE --scatter=${linker_script}) endif() set_target_properties(my_application PROPERTIES LINK_DEPENDS ${linker_script})
Note
The
elseif
code block is not needed if you do not have Arm Compiler 6.At build time, CMake will set
CMAKE_C_COMPILER_ID
depending on which toolchain you use, and the snippet above will set the linker flag accordingly.${CMAKE_CURRENT_LIST_DIR}/
is prepended to the linker scripts to make the paths absolute, because the build process will take place in a different working directory. Theset_target_properties()
directive ensures that CMake reruns the linker if the linker script has been modified since the last build.
Building and running the application
To configure this example using Arm Compiler 6:
(If you would like to use GNU Arm Toolchain instead, replace toolchains/toolchain-armclang.cmake
with toolchains/toolchain-arm-none-eabi-gcc.cmake
in the command above.)
Once the command above has completed, run the build command:
Once the build is done, run the application:
The FVP should open a serial terminal and print:
Next steps
Having created and built your own project, you can go on to read advanced tips on building CMake based projects.
You can also have a look at the examples for the Open IoT SDK for more complex CMake projects that use various software components supported by the Open IoT SDK.