Tutorial: Creating Bare-bare Embedded Projects with CMake, with Eclipse included

MCU vendors offer SDKs and configuration tools: that’s a good thing, because that way I can get started quickly and get something up and running ideally in a few minutes. But this gets you into a dependency on tools, SDK and configuration tools too: changing later from one MCU to another can be difficult and time consuming. So why not get started with a ‘bare’ project, using general available tools, just with a basic initialization (clocking, startup code, CMSIS), even with the silicon vendor provided IDE and basic support files?

In this case, I show how you easily can do this with CMake, make and Eclipse, without the (direct) need of an SDK.

NXP LPC55S69-EVK with LoRa Shield

Outline

In this this tutorial I show how to create a ‘bare-bare’ project for the LPC55S69-EVK board, without the config tools and the SDK. I still use some copied files from the SDK as I don’t want to re-invent things, but these things are very generic and don’t force you to continue using the SDK if you don’t want. But you can continue later on using the SDK files too.

The project can be built from the command line, but I’m using Eclipse here as IDE too. Of course you can substitute Eclipse with anything else, as long as it is supports CMake, for example Visual Studio Code.

I’m using CMake in this tutorial, because in my experience many developers struggle using it, so I want to give them here an easy start as well.

As hardware I’m using the NXP LPC55S69-EVK board:

The project and files for this tutorial are on GitHub: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/MCUXpresso/LPC55S69-EVK/LPC55S69_CMake_Template

The files on GitHub are can be used as a template for your own project.

I’m using Windows 10 as host machine, but you can easily use/adapt things for Linux/MacOS too.

If you want to see CMake with Eclipse for the Raspberry Pi Pico RP2040, I have covered you here: Getting Started: Raspberry Pi Pico RP2040 with Eclipse and J-Link. And if you want to use Visual Studio Code instead of Eclipse, I have a full series of tutorial for this as well: Visual Studio Code for C/C++ with ARM Cortex-M: Part 1 – Installation.

Software and Tools

I’m using the following software and tools:

Process

Assuming all the above tools are installed: The process and steps to create the project is very simple:

  • Copy the template folder and files
  • Run CMake initialization file to create make files and project files
  • Import the project into Eclipse

Template Files and Directory Structure

The files on GitHub serve as as template

Template files and folder

The template folder contains following files and folders:

  • src: contains all sources and CMake files for the project.
  • .gitignore: git ignore files
  • cmake.clean.bat: batch file to clean and remove all generated files
  • cmake.init.bat: batch file to create project files to be used with CMake and Eclipse
  • readme.txt: readme file with instructions and links

The ‘src’ folder of the template contains following:

Source Folder of Template

💡 The source folder ‘src’ has to be a sibling of the CMake output folder (e.g. ‘debug’) we will create later.

  • CMSIS: ARM CMSIS Core library files
  • device: device specific files, including linker file
  • startup: startup code files
  • arm-none-eabi-gcc.cmake: CMake toolchain definition
  • CMakeLists.txt: CMake project file
  • main.c: main() implementation

Creating Project

To create a new project from the template, simply copy the folder ‘LPC55S69_CMake_Template’. Of course you can work with that template folder directly too.

Changing Project Settings

The most important file and settings are in arm-none-eabi-gcc.cmake. Depending on your toolchain and location of it, you have to change/update the ARM_TOOLCHAIN_DIR variable in it:

ARM Toolchain Directory

The other thing likely to change is the project name: this is with the project() setting inside the CMakeLists.txt:

CMake Project Name

Initializing CMake project

Then open a console in that folder and run the ‘cmake.init.bat’ batch file: This initializes all the CMake files, creates the Eclipse project file and creates a ‘debug’ folder for the output:

C:\Users\erich\Data\GitRepos\McuOnEclipse\Examples\MCUXpresso\LPC55S69-EVK\LPC55S69_CMake>cmake.init.bat
C:\Users\erich\Data\GitRepos\McuOnEclipse\Examples\MCUXpresso\LPC55S69-EVK\LPC55S69_CMake>mkdir debug
C:\Users\erich\Data\GitRepos\McuOnEclipse\Examples\MCUXpresso\LPC55S69-EVK\LPC55S69_CMake>cd debug
C:\Users\erich\Data\GitRepos\McuOnEclipse\Examples\MCUXpresso\LPC55S69-EVK\LPC55S69_CMake\debug>cmake -G "Eclipse CDT4 - Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_ECLIPSE_VERSION="4.5" -DCMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT=TRUE -DCMAKE_ECLIPSE_MAKE_ARGUMENTS=-j8 ../src
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Eclipse version is set to 4.5. Adjust CMAKE_ECLIPSE_VERSION if this is wrong.
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2020-q4-major/bin/arm-none-eabi-gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2020-q4-major/bin/arm-none-eabi-g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- The ASM compiler identification is GNU
-- Found assembler: C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2020-q4-major/bin/arm-none-eabi-gcc.exe
-- CMAKE_TOOLCHAIN_FILE is: C:/Users/erich/Data/GitRepos/McuOnEclipse/Examples/MCUXpresso/LPC55S69-EVK/LPC55S69_CMake/src/arm-none-eabi-gcc.cmake
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/erich/Data/GitRepos/McuOnEclipse/Examples/MCUXpresso/LPC55S69-EVK/LPC55S69_CMake/debug

C:\Users\erich\Data\GitRepos\McuOnEclipse\Examples\MCUXpresso\LPC55S69-EVK\LPC55S69_CMake\debug>cd ..

C:\Users\erich\Data\GitRepos\McuOnEclipse\Examples\MCUXpresso\LPC55S69-EVK\LPC55S69_CMake>

Building

To build the project from the command line, ‘cd’ into the ‘debug’ folder and run the make file:

Building with the Console

Eclipse IDE

Beside of building from the command line (which is great for automation of the build process), I can use an IDE like Eclipse.The generated CMake project is usable with an Eclipse based IDE like the NXP MCUXpresso IDE.

The IDE itself is not used to create the CMake project. Instead, the Eclipse CDT project is crated by CMake and then imported into Eclipse.

To import the project into the IDE, use the menu File > Import:

Import Menu in Eclipse

Import as ‘existing project’:

Import existing Project

In the next step, make sure you select the project in the build output (debug) folder and press finish:

Import the generated Eclipse project in the debug folder

With this, the project is added to the Project Explorer:

Imported project in the Eclipse Explorer

To build the project, use the ‘Build Targets’ which then generates all the different output files as specified in the CMakeLists.txt.

Build Makefile targets

For debugging, I can use the Eclipse CDT support for J-Link or the P&E Multilink.

There is a catch: the NXP LinkServer connection cannot be used directly (at least of now), because it depends on the SDK manifest information. So I recommend using a J-Link or P&E Multilink, or using a ‘dummy’ project for a LinkServer connection.

Because the MCU information is not coming from the SDK, I can specify it directly in the launch configuration:

J-Link Device Setting

With this, I can debug my target :-):

Summary

The power of CMake can be easily used with Eclipse, and allows full freedom of software and tools, including the SDK. The limitation of the MCUXpresso SDK to migrate projects between different SDKs can be simplified with the approach not to tie it to any SDK: instead, the project is just based on CMake, startup code and linker file. With this, the project is open to for any software addition or device changes, with simple changes in the CMake files. Best of all: both command line tools (without any IDE) can be used with this approach, but everything is accessible with an IDE too. Kind of using the best of both worlds :-).

Happy bare-baring 🙂

Links

24 thoughts on “Tutorial: Creating Bare-bare Embedded Projects with CMake, with Eclipse included

  1. Thanks Erich, that’s a very useful article.

    If one modifies CMakeLists.txt, perhaps by adding additional source files, is it necessary to reimport the project into Eclipse?

    Liked by 1 person

    • Hi David,
      you only have to import the project one time. If you are adding source files, simply edit the CMakeLists.txt (add it), then run make: the project will be automatically reconfigured, so no need to re-do an import :-).

      Like

      • Hi Erich, thanks for your reply. I’m not able to do the import in the way you show above.

        Your screenshot of the Import Projects dialog shows:

        “Select a directory to search for existing Eclipse projects”

        Instead mine shows:

        “No projects are found to import”

        Mine seems reasonable as the CMake build directory doesn’t contain Eclipse project files. So no import is possible.

        Any thoughts please?

        Liked by 1 person

  2. @erich, when i am debugging the code, a message is shown as “Break at address “0x201″ with no debug information available, or outside of program code”

    Like

        • So my guess is that you did build the binary without debug information? Did you check you have for example -g3 added to the command line? What does the linker map say about the address range in question?

          Like

        • I didn’t get it, where can I see -g3, it is also not visible in this tutorial you provided. It is saying “Break at address “0x5ac3c35a” with no debug information available, or outside of program code”

          Like

        • The option -g3 is inside the CMakeLists.txt I have shared on GitHub.
          Have you checked the the binary created is indeed for your target system (It looks you are not using my example and target)?

          Like

        • Yes, G3 is enabled, you have written example on lpcexpresso55s69 but i am using expresso lpc55s28 board. Please suggest me what else can I do modifications to make it work

          Like

        • I don’t have or know the s28, but here you will need to update the compiler switches in the CMakeLists.txt, using the SDK for the s28 instead of the s69, using the linker file for the s28 instead of the s69, and so on. So you need to change all the settings from s28 to s69, otherwise things won’t work.
          I suggest you look at the simple blinky example generated for the MCUXpresso IDE and SDK, and use the settings and files from there. This is what I did for the s69.

          Like

        • Hello, I tried to modify the cmake.list file and made it according to Expresso lpc55s28 but now I am getting the errors:
          c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: cannot find libcr_nohost_nf.a
          c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: cannot find libcr_c.a
          c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: cannot find libcr_eabihelpers.a
          collect2.exe: error: ld returned 1 exit status
          make[2]: *** [CMakeFiles/LPC55S69_CMake_Template.elf.dir/build.make:144: LPC55S69_CMake_Template.elf] Error 1
          make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/LPC55S69_CMake_Template.elf.dir/all] Error 2
          make: *** [Makefile:91: all] Error 2

          my modified cmake.list is as follows:
          # CMake template file
          # Use this file with
          # mkdir build
          # cd build
          # cmake -G “Eclipse CDT4 – Unix Makefiles” -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_ECLIPSE_VERSION=”4.5″ -DCMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT=TRUE -DCMAKE_ECLIPSE_MAKE_ARGUMENTS=-j8 -DCMAKE_ECLIPSE_EXECUTABLE=”C:\NXP\MCUXpressoIDE_11.6.0_8187\ide\mcuxpressoide.exe” ../src
          #

          cmake_minimum_required(VERSION 3.15.3)

          # Optional: print out extra messages to see what is going on. Comment it to have less verbose messages
          set(CMAKE_VERBOSE_MAKEFILE ON)

          # Path to toolchain file. This one has to be before ‘project()’ below
          set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/arm-none-eabi-gcc.cmake)

          # Setup project, output and linker file
          set(BUILD_FOLDER ./debug)
          project(LPC55S69_CMake_Template)
          set(EXECUTABLE ${PROJECT_NAME}.elf)
          set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/../debug)
          set(LINKER_FILE ${CMAKE_SOURCE_DIR}/device/LPC55S28.ld)

          enable_language(C ASM)
          set(CMAKE_C_STANDARD 99)
          set(CMAKE_C_STANDARD_REQUIRED ON)
          set(CMAKE_C_EXTENSIONS OFF)

          # Optional: issue a message to be sure it uses the correct toolchain file.
          message(STATUS “CMAKE_TOOLCHAIN_FILE is: ${CMAKE_TOOLCHAIN_FILE}”)

          # List of source files
          set(SRC_FILES
          main.c
          startup/startup_lpc55s28.c
          startup/boot_multicore_slave.c
          device/system_LPC55S28.c
          )

          # Build the executable based on the source files
          add_executable(${EXECUTABLE} ${SRC_FILES})

          # List of compiler defines, prefix with -D compiler option
          target_compile_definitions(${EXECUTABLE} PRIVATE
          -DCPU_LPC55S28JBD100_cm33_core0
          -DCPU_LPC55S28JBD100
          -DCPU_LPC55S28JBD100_cm33
          -D__MULTICORE_MASTER
          )

          # List of includ directories
          target_include_directories(${EXECUTABLE} PRIVATE
          .
          device
          startup
          CMSIS
          )

          # Compiler options
          target_compile_options(${EXECUTABLE} PRIVATE
          -mcpu=cortex-m33
          -mthumb
          -mfpu=fpv5-sp-d16
          -mfloat-abi=hard

          -fdata-sections
          -ffunction-sections

          -Wall
          -O0
          -g3
          )

          # Linker options
          target_link_options(${EXECUTABLE} PRIVATE
          -T${LINKER_FILE}
          -mcpu=cortex-m33
          -mthumb
          -mfpu=fpv5-sp-d16
          -mfloat-abi=hard
          -specs=nano.specs
          -specs=nosys.specs
          -lc
          -lm
          -Wl,-Map=${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME}.map,–cref
          -Wl,–gc-sections
          -Xlinker -print-memory-usage -Xlinker
          )

          # Optional: Print executable size as part of the post build process
          add_custom_command(TARGET ${EXECUTABLE}
          POST_BUILD
          COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE})

          # Optional: Create hex, bin and S-Record files after the build
          add_custom_command(TARGET ${EXECUTABLE}
          POST_BUILD
          COMMAND ${CMAKE_OBJCOPY} -O srec –srec-len=64 “${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE}” “${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME}.s19”
          COMMAND ${CMAKE_OBJCOPY} -O ihex “${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE}” “${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME}.hex”
          COMMAND ${CMAKE_OBJCOPY} -O binary “${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE}” “${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME}.bin”
          )

          Like

        • Hello, I have seen your linker file and compared with mine. You are using libraries:
          GROUP (
          “libgcc.a”
          “libc_nano.a”
          “libm.a”
          )
          But I am using libraries:
          GROUP (
          “libcr_nohost_nf.a”
          “libcr_c.a”
          “libcr_eabihelpers.a”
          “libgcc.a”
          )

          So may be linker is not able to find these libraries. After that I also tried replacing my libraries to your libraries and used the same linker file as you provided and I also changed the ram, rom starting address and size according to my microcontroller. But still the debug folder is created properly. Then I imported the code in expresso ide, but still code hangs, it breaks at certain address. Please help me where i can find these libraries and how to solve this proble,.

          Like

        • Not sure from where you have this list of libraries? Keep in mind that if you are using a linker file from the IDE, it uses the libraries from that compiler version bundled with the IDE.
          So if you take the list of libraries from the IDE project, you have to use the same compiler as the IDE does.
          In that case you have to specify the compiler/tools/libraries you have in your IDE in your CMake environment. You find the tool chain and all the related files in C:\NXP\MCUXpressoIDExxx\ide\tools

          Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.