You are on page 1of 13

NCC

Using CubeMX with CoIDE


Powerful tools for FREE to develop on
inexpensive Demo boards from ST Micro
Aaron Bauch
11/20/2015

CoIDE from CooCox.org is a full function, free IDE. However it is not directly supported by ST
Microelectronics in their development tools and examples for their ARM Microcontrollers. This tutorial
demonstrates how to use STs CubeMX configuration utility to create initialization code and then use
CoIDE as the software development environment taking full advantage of STs tools.

Overview
In the early days of microcontroller software design, configuring and communicating with the few
simple peripherals integrated on chip with the CPU was a fairly straightforward process. As
semiconductor process geometries have shrunk it has become quite cost effective to integrate full
complex I/O systems on chip along with high performance processors and memory. The downside to
this bounty of inexpensive computing and I/O control is the fact that setting up, communicating with
and controlling these peripherals can be a complex task. Even configuring the internal clocking options
and the I/O pins that use the peripherals can be challenging.
Recognizing this problem, most microcontroller manufacturers have attempted to provide design
support in their tools to make this process of just getting off the ground with their complex products less
daunting so that their customers can get to the task of building their products and getting to production
as quickly as possible. To this end, ST Microelectronics has moved to provide a universal configuration
tool for their line of ARM Cortex tm microcontrollers called CubeMX. This graphical tool makes it almost
simple to configure the pins, clocking and all on-chip peripherals for their complex microcontrollers. In
addition the tool recognizes a number of development boards as targets so that it can pre-select
baseline clocking and pin-assignment options as implemented on these specific designs.
After the designer makes their selection in the tool, a complete project directory structure is created,
populated with all of the source files needed to initialize and run the project. It also creates project
configuration files for several toolchains which ST supports directly with their tools. Unfortunately all of
the supported toolchains are commercial products with free versions that are either code size limited,
function limited, or time limited. This makes perfect sense from STs perspective since these for-fee
tools provide excellent support staff to back them up, reducing the support load on ST for their
customer base. However there are some good quality Integrated Development Environments out there
that work well with various ARM processors and are available at no cost without function or time
limitations. This tutorial focuses on one such environment: CoIDE from CooCox.org.

Why the HAL?


Over the years, ST has provided example setup code and libraries in well structured source modules.
While these have been helpful as a start point, they often suffered from a lack of consistency from one
example project to the next in I/O routine naming and configuration. In addition they often differed
greatly from one processor to another.
Along with the introduction of the CubeMX tool environment, ST has moved to a Hardware Abstraction
Layer, or HAL model for providing low-level interfaces to the on-chip peripherals in their microcontroller
family. Each family group, such as F3, F4 etc. has its own HAL implementation. This provides an
extremely consistent programming API among a huge number of microcontrollers which may have
similar but not identical I/O controllers on chip. For example; pretty much all of the microcontrollers
might have some kind of UART on chip. The actual hardware, register map, etc. may be quite different

from chip to chip. However, by using the provided HAL interface, the software designer can use
consistent routine names and parameters to initialize the UART, to send and receive data, and even to
use interrupts and DMA with the peripheral. This makes porting code from one family member to
another much simpler and less error-prone. While the UART is a simple example, this consistency is
carried to complex peripherals such as USB and Ethernet controllers.

Setting up the tools


The first step is to download the tools from STs website, from CooCoxs website and other support tools
and documents that are needed for the environment. If you already have the CooCox IDE installed on
your system please re-install with the following link for use with this tutorial. Some of the older versions
have a bug when replacing the default linker file.
Download and install CooCox CoIDE (see comment below)
http://www.coocox.org/download/Tools/CoIDE-V2Beta-20150810.exe
Download and install ARM embedded gcc toolchain
https://launchpad.net/gcc-arm-embedded/+download
Download and install ST CubeMX tool
http://www.st.com/web/en/catalog/tools/PF259242
Download and install relevant CubeMX processor family modules:

F4
o

http://www.st.com/web/en/catalog/tools/PF259243

http://www.st.com/web/en/catalog/tools/PF260613

F3

Also it is quite useful to download a copy of the Hardware Abstraction Layer reference manual which
details the API for all of the function calls available to control and use all of the on-chip peripherals
which CubeMX is initializing for you. By communicating with the peripherals through these HAL calls
you can create reliable code which is easily portable between different systems using different
underlying CPUs. For this example we are targeting an STM32F407 processor which will use the F4 HAL,
the user manual, UM1725 can be found at:
http://www.st.com/st-webui/static/active/en/resource/technical/document/user_manual/DM00105879.pdf

This example is using CoIDE V2Beta Version 2.0.3.1 20150810 which is newer that the standard build
you will find on the main page of the coocox.org website. This is necessary because the default version
has a bug that does not let you change the linker script file. This is very important because we will be
using the linker file generated by the CubeMX tool to keep the configurations consistent with the code
generated by the tool.

Setting up your first CubeMX project

1. Create the CoIDE project FIRST!!


a. openCoIDE
b. Select the target processor
i. For Discovery F4 this is STM32F407VG
ii. For Discovery F3 this is STM32F303VC
iii. For Discovery F401 this is STM32F401VC
c. Select CreateProject
i. Name the project (ie Binky407)
ii. Either leave the default workspace location or change it to meet your needs.
Either way make note of where it is- youll want this later to put the CubeMX
files in the same place for convenience
iii. Create it- CoIDE creates the project directory and places the base project
structure and files in it
d. Once the base framework is created and loaded, delete the main.c file link that CoIDE
provides
i. Right click on the file in the project view
ii. Select Delete
iii. Answer yes when it asks if you really mean it
iv. This will be replaced later by the main.c file that CubeMX creates as part of the
chip initialization code structure.
e. You can leave CoIDE open while you now create the related CubeMX project. Shrink it
to get it out of the way for now.
2. Create the CubeMX init code
a. Open CubeMX
b. Select New Project
i. It will bring up a target selection matrix
ii. At the top select the tab for Board rather than Chip(default)
iii. Select the appropriate board for your project. In my Case DiscoveryF4 with
STM32F407VG processor
iv. Select OK
c. The project will be created and you should get a view of the Pinout of the target
processor. Since you selected the board rather than the chip many of the pins have

been pre-configured for you. GPIO pins as output to drive LEDs, input to sense user
pushbutton etc. Only the base I/O is configured however. Ie: no I2C or SPI to drive onboard peripherals, no USB etc. These get configured if you enable these peripherals.
d. Click on the clock configuration tab to see a graphical view of the clock tree of the
microprocessor.
i. This is somewhat complex, but take some time to get familiar with what its
doing. Keep in mind that if the tool didnt do this for you, you would have to get
very familiar with all of this and correctly set up your clock sources, route them

to all internal busses and peripherals, and check all internal points for proper
values.
ii. If you dont check this yourself and correct any errors, later when you go to
build the project, CubeMX will warn you if the clock tree or pins seem to be
incorrectly configured.
e. Click on the configuration tab to see the peripheral configuration details
i. Note that the GPIO icon is yellow rather than green. This is just warning you
that not all of the pins are configured, but the ones we need are fine.
ii. Click on the GPIO icon to see that the relevant I/O pins for the LEDs and
Pushbutton have been configured.
iii. In this simple example you do not need to do anything but it is good to get
familiar with this view. It will be critical when you add more I/O functionality to
your project.
iv. if you are not using a supported board you may need to select and configure the
ports for the I/O pins you are using. If so, refer to the CubeMX documentation
to enable the pins you need.
f. Before we build the configuration we need to set the working directory where all the
files and structures will be placed

i. If you do not do this, the first time you go to build it, the tool will prompt you to
set the project options
ii. In the top menu, select Project ->Settings
iii. Set the Project Location by browsing to the CoIDE workspace folder (CoIDE
default is <username>\CoIDE\workspace
1. Note- this is the parent of the folder where Cube MX will deposit the
actual project structure and files
2. The folder where the files are placed is a folder under this Project
Folder with the folder name that is entered in the next step
iv. In the Project Name field enter the exact same name as you used for your CoIDE
project (ie Blinky407)
1. Case IS relevant
2. This folder was created by CoIDE in the previous process. CubeMX will
find the same directory and put its generated files there. It is done in
this order for a reason
a. CoIDE uses a default workspace directory (\CoIDE\workspace)
and creates subdirectories named for each project you create
b. If the project subdirectory already exists, CoIDE will not create a
new project with that name and will not create the project until
you give it a name for which a directory does not yet exist.
c. By letting CoIDE create the directory structure, and then having
CubeMX use it, everyone is happy.
v. Note that the Project Folder field now contains \CoIDE\workspace\Blinky407
or whatever equivalent location if you are placing it elsewhere
vi. Select the tool chain/IDE to be SW4STM32. This toolchain uses the GNU ARM
toolchain as does CoIDE so that the files it generates will be compatible.
vii. Now at the top of the project settings window select the second tab for Code
Generator settings
1. at the top change the selection from Copy all used libraries to the
second one down Copy only the necessary library files
2. This ensures that when we bring the source files into the project in
CoIDE some redundant template files will be eliminated and avoid
causing problems with the compiler later on

viii. OK out of the Project Settings window.

g. Build the CubeMX project


i. Select the gear icon from the toolbar OR
ii. Select from the top menu Project-> Generate Code
iii. This will take a minute. When done it will give you up to three options:
1. Open Project- If you selected the SW4STM tool option this will not be
there since CubeMX will not load this directly. However the other
toolchains can be launched directly from CubeMX using this option.
2. Open Folder: This should open the directory where the files and
structures for the CubeMX project were created. This is the most
convenient option for the following steps if it works on your system.
3. Close: This is the safest option since it always works. If the Open
Folder option does not work for you, select this and open the project
folder manually.
h. We are now done with CubeMX and have created all of the base startup files and
structures that will enable you to run your project and use high level HAL calls for I/O
functions and have all of the base configurations and initializations done for you. You
can now either just shrink the CubeMX window or close it. For the purpose of this
project we will not need it again.
3. Go back to the CoIDE project
a. Now that CubeMX has created all the stuff we need for our base project, we need to
include it in our CoIDE framework
i. If we were using one of the CubeMX supported toolchains (which are either
code size limited, time limited or costs $$$) This project framework would be
created for us and we could just blindly start the tool.
ii. Since we are not using a supported IDE, we will build our own project folder
structure based on the folders that CubeMX placed in the project directory on
the disk. This is relatively simple and straightforward.
b. In the project window we will now build the folder structure for the project
i. This is done by dragging the folders of files that CubeMX created for us into the
project window.
ii. Notice the top folder in the CoIDE project view at the left

That is the folder where you will drag the file folders with the CubeMX
generated sources.

iii. Open the project directory (ie ..workspace\Blinky407) if Cube MX did not
already do it for you in the last step. Its contents should look like the above
image. Some of these files and folders were placed there by CoIDE when it
created the project folder structure and others are the files copied there by
CubeMX. It is these latter ones that we will now add to the CoIDE project so
that they are visible to the compiler.
iv. Drag the folder called Drivers over the project folder in CoIDE (Blinky407 in
this example) until the project folder becomes highlighted. When it lights up,
drop the Drivers folder into the project. CoIDE will query whether you want
to add these files to the project and you just answer yes.
v. Do the same thing with the Inc and Src folders and you should end up with a
populated project structure in CoIDE that looks like this

vi. Each of the folders now contain pointers to the subfolders and files as they exist
in the project directory on the disk. Note that these are pointers, and not the
actual files. This means that you can delete them from this project structure
without changing the files on the disk. However if you open them in the editor
and add or modify code, the actual files on disk are modified to their new
versions.
vii. you now have a project structure in CoIDE populated with the files generated by
the CubeMX tool for your project.
c. You now need to configure the CoIDE environment for your specific processor
i. Find the file Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h and
open it (or the equivalent file for the chip you are using if different)
ii. Find the group of commented out #define statements, one per line, each
related to a specific family member of the chip you are using. This is located
somewhere around line 70 in the current example environment for the F4XX.
1. Find the line that corresponds to your chip. For example, in the current
system, for the 407 we are using the line that looks like this:
a. /* #define STM32F407xx */ /*!< STM32F407VG, STM3
2. Note the EXACT defined entity, including case of all characters (note in
the above example the xx are lower case, the rest are upper).
3. Open the CoIDE configuration page, go to the Compiler tab
a. In the Defined Symbols box add the term found above ie;
STM32F407xx in our case.

add the symbol to CoIDEs defined symbols.

iii. Explanation: while the files included in this configuration are selected by
CubeMX for the family you are using (ie F4XX) it selects the specific family
member with defines included into the compiler invocation scripts which it
generates for the supported IDEs. Since CoIDE has its own compiler invocation
defaults that do not include this, this is an easy way to fill in the needed switch.
Without this the compiler will choke on an infinite number of unrecognized
references and you will have to probably kill it in task manager to recover.
iv. Configure the linker
1. Open the configuration window in CoIDE
2. Go to the Link tab
3. Deselect the Use Memory Layout from Memory Window button.
a. note: if you are not using the newer version of CoIDE this will
not work. see earlier version of this tutorial.

4. Scroll down to the Scatter File block, click the button and browse in

your project directory into the configuration directory that CubeMX


created called sw4stm32. Continue into each subdirectory until you
come to a file with a .ld extension and select this file.
5. Explanation: The CoIDE default linker file uses some different variable
names for memory sections than those generated by the CubeMX tool.
Also, if there are sections modified by CubeMX for heap and stack
parameters being aware of the code generated, I would rather use the
ST project generated linker file to take advantage of this.

Using the Environment


So now the environment is completely set up to build a program that does absolutely nothing. If you
like you can build the project and see that it compiles and generates output that can be downloaded to
your target board.
At this time you should take a look at the main.c file that CubeMX created for your project. It is located
in your Src group folder. It is organized in such a way that the program framework is set up with all of
the necessary pieces that are needed to configure and run the processor chip. In addition there are
several places in the code bracketed by comments allocating places where user code can be inserted.
These are scattered through the code in such a way that user additions can be placed such that they
make sense relative to the structure set up by the CubeMX code generator. For example there are
places to add user code after the Cube generated sections for #includes, for private variable definitions,
for function definitions, and at several points within the main routine. As long as your code is added
within these comment bracketed areas, they will be preserved and left alone by the CubeMX tool if you
re-generate the configuration code.
This is very useful if you like to build your project incrementally. For example, this code which we just
generated provides a very simple startup project with the GPIO pins configured so we can blink some
LEDs. Once we have this working, we might want to go and start using one or more of the other on-chip
peripherals such as an RS232 controller, an SPI port or perhaps the USB controller. This can be done by
going back to the CubeMX tool, opening the cube project we created for this example and adding or
modifying the peripherals we would like to use. When you re-generate the project all of your user code
that you added to the cube-generated files (like main.c) will be left in place and carried forward to the
new file as long as the user code was entered within these constraints.
OK, so back to Blinky. Lets add a little code to make it do something. First open the main.c file in the
user group to edit. Scroll through and get familiar with what Cube put there for you. The first sections
contain all of the global and private definitions needed by the overall project with appropriate places for
user code additions. Then the main function starts with Cube-generated code that calls initialization
functions that set up the core, the HAL itself and any peripherals that are being used. Again there are
convenient holes for user code in case you want to do some external or system initialization functions in

the midst of these routines. Then there is an infinite loop in the main function which is inside a user
code section so you can add code here if you would like it to be a repeating function for the chip. This is
where we will place our Blinky code.
After the end of the main function each of the peripheral initialization routines are instantiated. In this
case only GPIO is initialized and set up but if you were using other peripherals this is where their
initialization routines would reside (mostly with some exceptions) and the GPIO setup code would also
be enhanced to include whatever pin configurations might be necessary for the alternate pin functions
of the I/O devices selected in CubeMX.

Now lets make it do something: inside of the main() function, inside of the while(1) endless loop
brackets add the following two simple lines of code:
HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_12);
HAL_Delay(200);
This uses two very simple and intuitive Hardware Abstraction Layer function calls. The first toggles pin
number 12 on GPIO port D, which happens to be configured as a push-pull output pin and is connected
to a green LED on the F4 Discovery board.
The next line is pretty self-explanatory, the parameter is the number of ticks to delay, in this case a tick
should be about 1mS.
You can now build the project again, if you like just download it to the board and it will start blinking if
everything is ok. Or you can debug it and step through the code as it initializes the hardware and blinks
the LED.
Congratulations on configuring your environment to run CubeMX-generated code. While this example
project is quite trivial, you have set up a CoIDE project structure which can form the basis of quite
complex projects using the powerful CubeMX and HAL Hardware Abstraction Layer provided by ST as
the basis and start point. Additional tutorials will build on this foundation to provide very powerful start
points for useful projects.
I have included a little quick reference outline as Appendix 1 below. Now that you have gone through
the setup process and understand the details and steps, this may serve as a brief reminder of the steps
needed to set up subsequent projects.
Hopefully you have found this package useful. If you would like to comment, provide feedback or
corrections and suggestions I would love to hear from you at:
Aaron Bauch
aaron@AaronBauch.com
Enjoy! and happy creating.

Appendix 1
CoIDE CubeMX project Setup Quick Reference

1. Create new project under CoIDE, set folder name


2. Delete main.c reference
3. Create CubeMX project
a. Select target device
b. Project Settings, point Project Location to CoIDE workspace
c. Set Project Name to CoIDE Project Name exactly
d. Select sw4stm toolchain
e. select and configure peripherals
4. In CoIDE
a. Drag the CubeMX generated folders into the main project folder
b. add compiler directive found in
Drivers\CMSIS\Device\ST\STM32F..\Include\stm32f4xx.h
i. STM32F407xx for example
c. change linker .ld file to CubeMX generated script file
d. add code that does something useful

You might also like