4

I am working with STM32F103C8T6 and would like to use CMSIS, which is essentially just register definitions and no code, to make my life easier while still staying at a low level. The problem is that I have no idea how to install the library for use on the command line with Makefile. All documentation seems to be bound with a vendor-specific IDE like STM32CubeIDE.

I suppose the first thing to do is to download the CMSIS library, which I found on GitHub. However, after unzipping ARM.CMSIS.5.6.0.pack I found no files named stm32f10x.h. I spend some more time and found a CMSIS pack for the specific MCU I'm using, but it doesn't contain core_cm3.h, which however presents in ARM.CMSIS.5.6.0.pack. The document says I need to include both to my project, so do I need to copy the files downloaded from different places to my project, or what?

As a bonus question: what is the relationship between CMSIS and Keli? The device-specific CMSIS pack is downloaded from www.keil.com, but I don't want to use Keil MDK for now, as it appears to be a commercial product, and the GNU Arm toolchain is serving me pretty well.


Edit: I should have been more specific from the beginning, but now let's focus on how to build the Basic CMSIS Example as a minimal, complete and verifiable example.

What I have done:

  1. Download and unzip CMSIS-Core and CMSIS-DFP to /Users/nalzok/Developer/CMSIS/ARM.CMSIS.5.6.0/ and /Users/nalzok/Developer/CMSIS/Packs/Keil.STM32F1xx_DFP.2.3.0/, respectively.
  2. Create a file named main.c, and copy the content of the basic example to it.
  3. Add #define STM32F10X_MD on the very first line to specify the chip.
  4. Fix typos: replace the : on line 31 to ;, and replace line 33 to timer1_init (42);.
  5. Build and get an error

/tmp $ arm-none-eabi-gcc -I/Users/nalzok/Developer/CMSIS/ARM.CMSIS.5.6.0/CMSIS/Include/ -I/Users/nalzok/Developer/CMSIS/Packs/Keil.STM32F1xx_DFP.2.3.0/Device/Include/ main.c
main.c: In function 'main':
main.c:42:5: warning: implicit declaration of function 'Get_InputValues' [-Wimplicit-function-declaration]
   42 |     Get_InputValues ();                          // Read Values
      |     ^~~~~~~~~~~~~~~
main.c:44:5: warning: implicit declaration of function 'Calculation_Response' [-Wimplicit-function-declaration]
   44 |     Calculation_Response ();                     // Calculate Results
      |     ^~~~~~~~~~~~~~~~~~~~
main.c:45:5: warning: implicit declaration of function 'Output_Response' [-Wimplicit-function-declaration]
   45 |     Output_Response ();                          // Output Results
      |     ^~~~~~~~~~~~~~~
/var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//cc1ZVBaH.s: Assembler messages:
/var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//cc1ZVBaH.s:197: Error: selected processor does not support `wfe' in ARM mode
/var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//cc1ZVBaH.s:310: Error: selected processor does not support `cpsid i' in ARM mode
/var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//cc1ZVBaH.s:318: Error: selected processor does not support `cpsie i' in ARM mode

As per @KamilCuk's comment below, I added more options and commented out the functions Get_InputValues, Calculation_Response, and Output_Response, but now I am having some different errors.

/tmp $ arm-none-eabi-gcc -I/Users/nalzok/Developer/CMSIS/ARM.CMSIS.5.6.0/CMSIS/Include/ -I/Users/nalzok/Developer/CMSIS/Packs/Keil.STM32F1xx_DFP.2.3.0/Device/Include/ -D STM32F1 -D STM32F103x6 -mthumb -mcpu=cortex-m3 main.c
/Users/nalzok/opt/xPacks/arm-none-eabi-gcc/9.2.1-1.1/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: /Users/nalzok/opt/xPacks/arm-none-eabi-gcc/9.2.1-1.1/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libc.a(lib_a-exit.o): in function `exit':
exit.c:(.text.exit+0x16): undefined reference to `_exit'
/Users/nalzok/opt/xPacks/arm-none-eabi-gcc/9.2.1-1.1/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: /var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//ccqfC5LA.o: in function `Device_Initialization':
main.c:(.text+0x164): undefined reference to `SystemCoreClock'
collect2: error: ld returned 1 exit status
nalzok
  • 14,965
  • 21
  • 72
  • 139
  • The source is on github. Ex. [CMSIS_5](https://github.com/ARM-software/CMSIS_5). `how to install the library for use on the command line with Makefile` - you don't "install", you compile from sources and add include paths to your compiler, there is no installation. – KamilCuk Feb 11 '20 at 00:02
  • So basically, building something specific to e.g. STM32 requires `-I` to the path of CMSIS-Core and the corresponding STM32 DFP, whereas developing for generic Arm Processors only calls for `-I` to the former? The [examples](https://www.keil.com/pack/doc/CMSIS/Core/html/using_CMSIS.html) unfortunately doesn't specify the compiler options to build it. – nalzok Feb 11 '20 at 00:24
  • The compiler options are specific to compiler, not to the library you use. I really don't understand what exactly you ask about. Like with any other library you would add to your project from the source code, link with object files compiled from the library and add include paths. You ask about makefile, so I assume you are aware how to do those things (are you?). I recommend using `cmake` for easier scripting and managing. The examples show how to use the library, not how to compile with it. With recent STM32CubeMX you can generate makefiles, if you want. – KamilCuk Feb 11 '20 at 00:39
  • `relationship between CMSIS and Keli?` - CMSIS is a library designed by ARM (the company "Arm Holdings"). Keil is a company that was acquired by ARM in 2005 and still exists and still offers producets. One is a library, the other is a company. Keil MDK, a product made by the company Keil, uses CMSIS as a library. – KamilCuk Feb 11 '20 at 00:46
  • It's easy to for example to google "cmake cmsis github" and fine [ready projects that use cmsis](https://github.com/JBerg60/stm32-cmake-cmsis). Note that [STM32CubeXX packages](https://github.com/STMicroelectronics/STM32CubeF1) are also (since recently) available on github and if you google "STM32CubeF1 cmake github" you'll find results too. STM32CubeXX packages contain CMSIS sources inside them. – KamilCuk Feb 11 '20 at 00:48
  • @KamilCuk I realized my question is too vague, and have updated it with a specific error. I will take a look at the linked project, but it requires Windows 10 (while I am working on macOS) and I actually prefer Makefile for its transparency. – nalzok Feb 11 '20 at 01:03
  • `now let's focus on how` that's a separate question. You should open a separate question for it. The errors come because you configured your compiler incorrectly.... Add at least `-D STM32F1 -D STM32F103x6 -mthumb -mcpu=cortex-m3` to your compiler.... – KamilCuk Feb 11 '20 at 01:07
  • @KamilCuk I respectfully disagree. The original question asks about `How do you use CMSIS without an IDE?`, and the amendment simply narrows down its scope by focusing on building a minimal example by CMSIS without an IDE. If a separate question is posted, I fear it would be closed as a duplicate of this one. – nalzok Feb 11 '20 at 01:11
  • The functions `Get_InputValues()` and `Calculation_Response()` and `Output_Response()` seems to be functions that the user (you) should implement. Also you need to specify linker file and (at best) startup file in the compilation. – KamilCuk Feb 11 '20 at 01:13
  • @KamilCuk I have updated my question after applying your advice. Now I'm getting some `undefined reference` errors, so there should be some more `.c` files that I need to pass to the compiler. In other examples the user is setting the variable `SystemCoreClock`, but what about `_exit`? – nalzok Feb 11 '20 at 01:21
  • `SystemCoreClock` should be defined by the vendor. You can use [the template](https://github.com/ARM-software/CMSIS/blob/master/Device/_Template_Vendor/Vendor/Device/Source/system_Device.c#L65) I think. The `_exit` function should be implemented by you. Or you can link with the [newlib nosys implementation of `_exit`](https://github.com/littlekernel/newlib/blob/master/libgloss/libnosys/_exit.c) (ie. `-specs=nosys.specs`). – KamilCuk Feb 11 '20 at 01:45
  • 1
    And you need the [linker file](https://github.com/ARM-software/CMSIS/blob/master/Device/ARM/ARMCM3/Source/GCC/gcc_arm.ld) and [startup script](https://github.com/ARM-software/CMSIS/blob/master/Device/ARM/ARMCM3/Source/GCC/startup_ARMCM3.S), otherwise wrong memory regions will be flashed and interrupts vectors will not be handled. – KamilCuk Feb 11 '20 at 01:46
  • @KamilCuk Ah thank you! That’s really helpful. Do you mind writing an answer to help others who might see this question in the future? I will definitely upvote and very likely accept it. – nalzok Feb 11 '20 at 01:49

2 Answers2

5

For the latest device headers, I suggest downloading STM32CubeF1 package from the ST website. Among other things (Middlewares, HAL etc.), this package contains the required device headers in /Drivers/CMSIS/Device folder. You need STM32F103xB symbol defined for stm32f1xx.h header to work correctly.

Of course, STM32CubeF1 package also contains CMSIS libraries but they are generally a little bit outdated. I prefer to download them as .pack files from the github repo you mentioned. You need the headers in /CMSIS/Core at least. You may add additional parts of the CMSIS if you wish. Some of them (like DSP) may also need you to add static libraries provided in /Lib folders.

Please be aware that if you clone the CMSIS repo from github instead of downloading the .pack file, you end up with placeholder versions of the static libraries, as the project uses git LFS. You can't use these static library files (.a files) directly as they are just some kind of pointers. I'm not familiar with git LFS, but I guess you need some git commands (maybe checkout) to tell your PC to download the actual .a files.

Also note that sometimes CMSIS folder structure changes from version to version. The folder structure you get in STM32CubeF1 may be different from the one you download from the official CMSIS repo.

I forgot to mention: Other than CMSIS and ST device headers, you also need the following files:

  • system_stm32f1xx.c (STM32CubeF1 package /Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates folder)
  • startup_stm32f103xb.s (STM32CubeF1 package /Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc folder)
  • A linker script from STM32CubeF1 package /Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc/linker folder. Strangely, there is none for STM32F103x8, so you probably need to pick STM32F103xB and modify it. I use an IDE generated one.

Update:

Here you can find a minimal project created in STM32CubeIDE. I created an empty C project. The IDE provides a linker script and a startup file (.s) but I deleted them and used the ones included in the STM32CubeF1 package. I also deleted unrelated header files from the /Drivers/Device/ST/STM32F1xx/Include directory. But I didn't touched the ones in the /Drivers/CMSIS/Core/Include although there are lots of unrelated files there, as it's harder to determine which ones are needed and which ones are not.

I know that you look for a solution without an IDE, but I think this example project can at least give you some clues about the required files and the project structure.

Note: The example project name is blinky.cube but there is no Cube in the project. I use this naming convention just to specify the IDE I use, which is STM32CubeIDE in this case.

Tagli
  • 2,412
  • 2
  • 11
  • 14
  • Let's see... are you suggesting me to use STM32CubeF1 as the CMSIS-DFP, or as a replacement of CMSIS? I'm not familiar with the terms like "device header" so I'm a little confused. – nalzok Feb 11 '20 at 06:29
  • Actually, I'm suggesting it not for the CMSIS files, but for the STM32 specific files. These are 3 include files residing in `/Drivers/CMSIS/Device/ST/STM32F1xx/Include` (there are more files here, but related to other devices), the linker script, `system_stm32f1xx.c` and `startup_stm32f103xb.s` which I added to my answer. – Tagli Feb 11 '20 at 06:49
  • I see... do you happen to have an example project to show me? It could be as simple as an empty `main` function, but I really want to see how these pieces fit together. It has been hours and I have yet to build my first CMSIS project. I'm constantly getting errors due to incompatibility between different libraries/compilers/versions... – nalzok Feb 11 '20 at 06:59
  • 1
    I use TrueStudio or STM32CubeIDE to create empty projects and then manually add the ST headers and CMSIS files by hand. So this may not suit your *no-IDE* approach. But I will create an example blinky project in STM32CubeIDE and update my answer with the link of the repo. Maybe it can give you some clues. – Tagli Feb 11 '20 at 07:12
  • Awww that's really neat. Just one more question: do you know how to build it on the command line (i.e. which toolchain to use with which parameters), or do I need TrueStudio/STM32CubeIDE to build it? – nalzok Feb 11 '20 at 18:16
  • 1
    Unfortunately, I don't have any experience with that. For this project, you need IDE for the build. But after you build from IDE once, it also creates some makefiles in `/Debug` folder. It seems the build system consists of multiple files which are auto-generated and included by the main makefile. Then you can invoke make from the command line. If you open the main makefile there, you can see the commands needed for the build. – Tagli Feb 11 '20 at 21:23
3

For the part of CMSIS your are referring to, some is supplied by ARM (CMSIS core) and some is supplied by your chip vendor (Device Family Pack). As you have discovered, CMSIS software packs are just zip files by another name. You may unzip them wherever you wish. As you are aware, core CMSIS and most of the vendor specific part consists of just header files. It is then necessary to include the proper directories in the compiler include path, typically using -I... command line options.

One type of vendor software pack is called a Device Family Pack. In addition to vendor specific peripheral definitions, they usually contain start up code and often times linker scripts that match the layout of the SOC memory. These are worth finding and will save the work of vector table layout and other such low level code.

For the bonus: Keil is a maker of software tools and is owned by ARM. The nicer features of CMSIS software packs, like distributing and updating them over a network, are supported by the Keil IDE and Keil maintains a repository of common SOC packs. I also usually use the GNU compiler, but have used Keil and its built-in CMSIS awareness and software pack availablity to good effect. I have even built a few software packs for custom work. I suggest a continued reading of the CMSIS documentation paying some attention to the section on packs. You don't have to have an IDE that manages the packs for you. Since they are simply zip files, you undertake that task yourself.

andy mango
  • 1,526
  • 1
  • 8
  • 13
  • I see... so I need to manually merge the CMSIS-Core by ARM and the CMSIS-DFP by the chip vendor to build the [Basic CMSIS Example](http://www.keil.com/pack/doc/CMSIS_Dev/Core/html/using_CMSIS.html)? Just curious, can CMSIS-Core do anything useful at its own? Now I am under the impression that DFP could have been conveniently shipped with the content of Core, thus eliminating the need of downloading two files. – nalzok Feb 11 '20 at 00:19
  • 1
    The CMSIS core and vendor DFP's are usually separate because they are created by two different organizations and it is easier to let each evolve separately as needed. CMSIS core is useful on its own if you are doing system programming of registers defined in the ARM architecture. You may try merging them if you like, but I've never found that particularly useful especially when one may be updated at a different time than the other. – andy mango Feb 11 '20 at 01:49