Using the CMSIS DSP Library in a ModusToolbox Project


Cypress’s ModusToolbox was recently released to accompany their latest addition to the PSoC family: the PSoC 6. Targeting the IoT space, this line of MCUs has been designed to provide a balance between low-power and high-performance application requirements with an emphasis on flexibility and security. Currently supporting every PSoC 6 device as well as the CYW20819 Bluetooth SoC, ModusToolbox integrates the Eclipse-based ModusToolbox IDE with Cypress’s Software Development Kits (SDKs) via several built-in configurators. This allows the user to easily configure the device, its peripherals, and several available middleware components (i.e. CapSense, Bluetooth, USB, RTOS, etc). One lacking feature, however, is a built-in library/middleware that would allow the user to easily take advantage of the DSP extension of the PSoC 6’s Cortex-M4 instruction set. This would greatly expedite the development of applications that require any mathematically intensive algorithms to be implemented (e.g. the FFT or a digital filter). Arguably, the reason for this is that Arm has already developed such a library as part of their Cortex Microcontroller Software Interface Standard (CMSIS).

What is CMSIS?

CMSIS is a hardware abstraction layer developed by Arm with the help of several silicon and software vendors. It makes it possible to simply and consistently interface with any Cortex-M processor and its peripherals, enabling software reusability and a reduced learning curve for developers. CMSIS is an open standard, meaning the source code for its multiple components is freely available for anyone to download. The most well-known of these components is CMSIS-Core as it defines a set of APIs for accessing the features of the Cortex-M processor, including the Nested Vector Interrupt Controller (NVIC), the system tick timer (SysTick), and optional Memory Protection Unit (MPU) [1]. The full list of CMSIS components, which continues to grow as CMSIS evolves, can be found in its documentation. As previously alluded to, the CMSIS-DSP library is the component that provides an extensive suite of functions ranging from basic math to advanced filtering, all of which take advantage of the Cortex-M4’s extended instruction set.

The DSP library

Arm’s Cortex-M4 (which is utilized by the PSoC 6), Cortex-M7, Cortex-M33, and Cortex-M35P processors all include additional instructions not found on the Cortex-M0(+) or Cortex-M3. These are the Single Instruction Multiple Data (SIMD) and Multiply and Accumulate (MAC) instructions, which allow for the efficient execution of computationally intensive DSP functions and algorithms. To take full advantage of these instructions would require a great deal of DSP and embedded programming expertise were it not for the CMSIS-DSP library. The library’s source code is written mostly in C (utilizing several idioms and intrinsics) and a bit of assembly language to fully optimize it for the higher-end cores. Note that the CMSIS-DSP library will function correctly on the lower-end Cortex-M0(+) and Cortex-M3 cores, but not nearly as efficiently. The library contains over 60 functions that operate on several data types (i.e. q7, q15, q32, and single precision floating-point) split into the following categories:

  • Basic math functions
  • Fast math functions
  • Complex math functions
  • Filters
  • Matrix functions
  • Transform functions
  • Motor control functions
  • Statistical functions
  • Support functions
  • Interpolation functions

The library’s documentation very concisely explains how to use it in a project:

The library functions are declared in the public file arm_math.h which is placed in the Include folder. Simply include this file and link the appropriate library in the application and begin calling the library functions.

For those who have less experience with embedded development, these instructions may be too brief to be of any help. The following section will explore this procedure in far greater detail, using ModusToolbox as the development platform.

Using the library

For this tutorial, the PSoC 6 Wi-Fi BT Prototyping Kit was selected as the target board for the project. The MCU featured on this board (the CY8C624ABZI-D44) contains a Cortex-M4 processor with floating-point unit (FPU). Since the ModusToolbox IDE is Eclipse-based, most of this procedure should work on other Eclipse-based IDEs as well (e.g. TrueSTUDIO, CoIDE, CCStudio, etc.) if you happen to be working with an MCU from another vendor.

Step 0: Open or create a project

If you don’t already have a ModusToolbox project started, you will need to either create one or open an existing one. For those unfamiliar with ModusToolbox IDE, Cypress provides several helpful documents on their website including a Quick Start Guide and a more detailed User Guide. They also provide several example projects that users can use as a starting point. For the purpose of this article, I created a bare-bones example project named “DSP_test” where the target hardware was the CY8CPROTO-062-4343W board and the “EmptyPSoC6App” was chosen as the starter application. Notice that ModusToolbox creates two projects: an _mainapp project which contains the application source code and a psoc6pdl_Cortex-M4 project which contains the source code for the peripheral drivers. I will refer to these throughout the rest of the tutorial as the “mainapp” project and the “psoc6pdl” project respectively.

Step 1: Download the CMSIS pack files

Since ModusToolbox includes the CMSIS Pack Manager, we will use it to easily download our desired library files and keep them up to date. To open the CMSIS Pack Manager perspective, choose Window > Perspective > Open Perspective > Other from the main menu bar (Figure 1a). Choose CMSIS Pack Manager from the dialog box and click Open (Figure 1b). This will open the perspective and add a new perspective icon to the upper right-hand corner of the window as shown in Figure 1c. You can easily switch back to the ModusToolbox perspective by clicking the ModusToolbox icon to the left of the CMSIS Pack Manager icon.

a) Open a new perspective

b) Choose CMSIS Pack Manager

c) The perspective opens and its icon is added to the upper right-hand corner of the screen

Figure 1: Opening the CMSIS Pack Manager perspective

We can’t do anything in the Pack Manager until we specify the CMSIS Pack Root folder. This folder will contain information about the online pack repositories as well as the files provided by any packs we choose to install. Click the “open preferences page” link (Figure 1c) and choose a folder on your system to be the root folder. This can be any folder you like but note that if you happen to have Keil’s µVision IDE installed on your system, then you can use the same root folder it uses. When I recently installed µVision V5.27.1.0, the installer chose C:\Users\Matt\AppData\Local\Arm\Packs as the root folder (whereas on my previous system, the root folder was C:\Keil_v5\ARM\PACK ). Whatever folder you choose, it can later be referenced in Eclipse with the path variable ${cmsis_pack_root} . When I add the folder path to the preferences as shown in Figure 2a and click Apply and Close , the perspective will become populated with all available packs. This is because I chose the same root folder as my µVision install. Had I chosen an empty folder, the CMSIS Pack Manager would first ask me to download the CMSIS pack index. Notice in Figure 2b that several packs are already installed, including ARM.CMSIS, because these were installed when I last used µVision. If ARM.CMSIS is not installed in your root folder, simply click the Install button. At the time of writing, the latest version of CMSIS is 5.5.1.

a) Specify the root folder

b) Install the ARM.CMSIS pack

Figure 2: The contents of the CMSIS directory

Installing the ARM.CMSIS pack downloads the CMSIS components (including the DSP library) to the ${cmsis_pack_root}/ARM/CMSIS/5.5.1/CMSIS directory, shown below in Figure 3. If for any reason you are unable to install the ARM.CMSIS pack using the Eclipse Pack Manager or if you would like to simply download the files yourself, they are available in the CMSIS GitHub repository: GitHub - ARM-software/CMSIS_5: CMSIS Version 5 Development Repository.

Figure 3: The contents of the CMSIS directory after the ARM.CMSIS pack is installed

Step 2: Include arm_math.h

Once the pack files are downloaded, you can return to the ModusToolbox perspective. The CMSIS-DSP functions are declared in the file arm_math.h , so we will need to include this file. Open the main.c file located in the Source folder in the “mainapp” project. As shown in Figure 4a, add the line #include "arm_math.h" to the file. At this point, if you were to place your cursor over the file name and hit F3, the arm_math.h file would open in a new tab. The highlighted portion in Figure 4b, however, demonstrates that this is the incorrect file. ModusToolbox includes several CMSIS header files in the Peripheral Driver Library (PDL), and this was one of them. Comparing this file to the file we downloaded in the previous step (Figure 4c), we see that the one provided by the PDL is an older version. To correct this, we must modify the project include paths to tell the compiler which file it should use.

a) Add #include "arm_math.h" to main.c

b) The version of arm_math.h provided by ModusToolbox is v1.5.3

c) The version of arm_math.h provided by CMSIS is v1.6.0

Figure 4: Including arm_math.h

The include paths tell the compiler where to look for header files. In the project explorer (shown on the left-hand side of Figure 4a), make sure the “mainapp” project is selected. Then, from the main menu bar choose Project > Properties . On the left-hand side of the Properties window, choose Settings under C/C++ Build . Next, under the Tool Settings tab, choose Includes under the GNU ARM Cross C Compiler settings. In the Include paths (-I) window, click the Add… icon and add the path to the CMSIS Include folder (shown in Figure 3). As Figure 5 demonstrates, you can use the path variable ${cmsis_root_path} if you installed the ARM.CMSIS pack using the CMSIS Pack Manager in step 1. Since the compiler will search these folders in the order they appear on this list, be sure the path we just added is above the ${cy_skd_install_dir}/libraries/psoc6sw-1.1/components/psoc6pdl/cmsis/include path using the Move Up icon. Now, when searching for arm_math.h , the compiler will find it in the ${cmsis_pack_root} path before the ${cy_skd_install_dir} path and use it instead. You can either click Apply and Close or leave the Properties window open for the next step.

Figure 5: Adding the CMSIS Include folder to the include path

Step 3: Linking the library

Inside the DSP/Lib folder (see Figure 3) are precompiled versions of the libraries. Since ModusToolbox uses GCC as its preferred toolchain, we look in the GCC folder and see the library files shown in Figure 6a. The file you choose will depend on the core utilized by your MCU. As previously mentioned, the CY8C624ABZI-D44 contains a Cortex-M4 core with an FPU. Therefore, the library I need to link with my project is libarm_cortexM4lf_math.a (note that the ‘l’ denotes little endian and ‘f’ denotes FPU presence). Linking the library is very similar to adding an include path like we did in the previous step. With the “mainapp” project selected, choose Project > Properties from the main menu bar. On the left-hand side of the Properties window, choose Settings under C/C++ Build . Under the Tool Settings tab, choose Libraries under the GNU ARM Cross C Linker settings. In the Libraries (-l) window, add the name of the library you want to link. This does not include the “lib” prefix or the “.a” suffix. Then, in the Library search path (-L) window, add the path of the library file. In my case, the path was ${cmsis_pack_root}/ARM/CMSIS/5.5.1/CMSIS/DSP/Lib/GCC . The final configuration is shown in Figure 6b. Click Apply and Close .

a) Prebuilt versions of the CMSIS-DSP library

b) Providing the name and path of the required library

Figure 6: Linking the required library to the project

Step 4: Use the same floating-point ABI as the linked library

You can skip this step if you are using an MCU without an FPU. The libraries listed in Figure 6a which have an ‘f’ in their name were compiled with the GCC compiler flag -mfloat-abi=hard , whereas ModusToolbox compiles the project with the flag -mfloat-abi=softfp (assuming the target MCU has an FPU). Both of these flags tell the compiler to utilize the processor’s floating-point instruction set, but with different calling conventions. Therefore, if you don’t complete this step, you will receive an error when compiling that looks like this:

<library_path>\libarm_cortexM4lf_math.a(<function>.o) uses VFP register arguments, DSP_test_mainapp.elf does not ,

indicating that the library is not compatible with the application. To correct this, the application must be compiled with the -mfloat-abi=hard flag as well. Select the “mainapp” project and choose Project > Properties from the main menu bar. On the left-hand side of the Properties window, choose Settings under C/C++ Build . Under the Tool Settings tab, open the Target Processor settings. Select “FP instructions (hard)” from the Float ABI dropdown and click Apply and Close . Repeat this procedure for the “psoc6pdl” project by selecting it in the project explorer before opening the Properties window.

Figure 7: Changing the Float ABI compiler option from “Library with FP (softfp)” to “FP instructions (hard)”

At this point, you should be able to successfully begin calling functions from the CMSIS-DSP library. You can find the complete documentation for this library in the Documentation folder (see Figure 3) or online here. The example code is a particularly useful place to get started if you need help understanding how the functions work in a practical context.


[1] J. Yiu, The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors, 3rd ed., Waltham, MA: Elsevier Inc., 2014.