STM32F4 – Object-oriented Programming with Embedded Systems (C++ /w STL)

In this tutorial I demonstrate that object-oriented programming can be used with embedded system using open source tools and the C++ language. Furthermore, I demonstrate the use of the STL library with C++11 features. Sneak peak, here, here and here.

CppAustinPowers

I base this tutorial on the “Hello World!” project. I provide the following.

  • An example to demonstrate the use of C++ objects and the use of Standard Template Library (STL). The library provides, among others, an abundance of generic algorithms and containers, which is always nice to have at your disposal.
  • A Makefile that automagically finds appropriate C, C++, Asm sources. You can even use this Makefile as a template for your projects.

1. Prerequisites

cd ~
# Remove the official package
sudo apt-get purge binutils-arm-none-eabi \
                   gcc-arm-none-eabi \
                   gdb-arm-none-eabi \
                   libnewlib-arm-none-eabi

# Add 3rd party repository
sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded
sudo apt-get update
# Check the GCC package version in the PPA repository
sudo apt-cache policy gcc-arm-none-eabi

# Install software requirements
sudo apt-get install build-essential git openocd \
 gcc-arm-none-eabi qemu-system-arm \
 symlinks expect

# Clone my git repository & init submodules
git clone https://github.com/istarc/stm32.git
cd ~/stm32
git submodule update --init

2. Build the OOP Project

Build the OOP project using provided Makefile.

cd ~/stm32/examples/OOP

make clean
make release
#  text data  bss    dec   hex filename
# 96712 2324 3728 102764 1916c bin/outp.elf

sudo make deploy

You will notice the binary code increase roughly by the factor of 12 compared to the Hello world! project (100 KB). 😯 Despite of this, STMF4 Discovery has more than enough memory capacity to deploy the project. You may build with size optimization (-Os) as follows, which will decrease the code size to 76 KB. For more advanced optimizations, where I decrease the code size to merely 3.4 KB, see my next post.

make clean
make release-memopt
#   text data  bss   dec  hex filename
#  72232 2320 3696 78248 131a8 bin/outp.elf

sudo make deploy

STM32F4-HelloWorld-pub

Q: Deployment fails repeatedly due to some OpenOCD issue. 😦 Is there a workaround?
A: Yes, the current official Ubuntu package (Aug 2014) contains a prehistoric OpenOCD version. You should build a newer version from scratch. I provide step-by-step instructions here (2nd section, it takes less than 3 minutes to build it). When you are done, just return here and continue as nothing happened. It will work out of the box. 🙂

3. Object-oriented Programming

First, I copied and renamed Template Project with Generic Makefile‘s main.c file to main.cpp. To handle dynamic LED toggling I use TimeDelay class (defined in TimeDelay.h and TimeDelay.cpp, see the file tree structure below).

tree
# .
# ├── bin
# ├── inc
# │   ├── CMSIS/Include
# │   ├── stm32f4_discovery.h
# │   ├── STM32F4xx/Include
# │   ├── stm32f4xx_conf.h
# │   ├── stm32f4xx_it.h
# │   ├── STM32F4xx_StdPeriph_Driver/inc
# │   └── TimeDelay.h # NEW FILE
# ├── Makefile #UPDATED
# ├── src
# │   ├── main.cpp #RENAMED (main.c) AND UPDATED
# │   ├── misc.c
# │   ├── startup_stm32f4xx.s
# │   ├── stm32f4_discovery.c
# │   ├── stm32f4xx_exti.c
# │   ├── stm32f4xx_gpio.c
# │   ├── stm32f4xx_it.c
# │   ├── stm32f4xx_rcc.c
# │   ├── stm32f4xx_syscfg.c
# │   ├── system_stm32f4xx.c
# │   └── TimeDelay.cpp # NEW FILE
# └── stm32_flash.ld

The TimeDelay (see .cpp and .h code snippets below) object is used in the main function. It draws a (pseudo) random number from a given range. This values is in turn used as a delay function argument and it manifest itself as the LED toggling delay.

The TimeDelay class has the following attributes:

  • The queue is a generic container from the standard template library (STL). When an object is instantiated, 4 unique delay values are inserted in the queue. When a process calls the getter function, the front item is removed from the queue and later returned.
  • Mersenne twister pseudo-random number generator (prng) is used to generate a (pseudo) random number between 0 and 0xFFFFF and insert it at the beginning of the queue. No coding whatsoever was needed for the PRNG implementation. I simply used the appropriate PRNG template provided by the C++11 standard. C++ templates can really ease your life (if used carefully)! 🙂
// From TimeDelay.h
#include <queue>
#include <list>
#include <random>

using namespace std;

class TimeDelay {
private:
        list<int> l;
        queue<int,list<int>> q;

        mt19937 prng;
        uniform_int_distribution<int> dist;

public:
        TimeDelay();
        ~TimeDelay();
        int get();
};
// From TimeDelay.cpp
TimeDelay::TimeDelay() {
        l = list<int> {0x3FFFFF,
                       0x7FFFFF,
                       0xBFFFFF,
                       0xFFFFFF};
        q = queue<int,list<int>> (l);
        dist = uniform_int_distribution<int> (0x1,
                                              0xFFFFFF);
}

TimeDelay::~TimeDelay() {
}

int TimeDelay::get() {
        int retVal=q.front();
        q.pop();
        q.push(dist(prng));
        return retVal;
}

4. C++ Pitfalls in Embedded Software Design

On the one hand, the C++ language offers numerous benefits compared to the C, among others it is object-oriented language, supports exception handling, enforces compile-time type checking, supports generic programming through templates and comes with a large standard template library (STL).

On the other hand, these features come at a certain price. Some are more expensive than others in terms computational- and space-complexity. Furthermore, these features may reduce timing predictability, which is problematic for hard real-time systems, where missing a deadline leads to a total system failure. Troubles can even go from bad to worse! Some problems may manifest in run-time rather than compile-time (e.g. dynamic memory fragmentation), so use C++ features with care and when appropriate.

5. Further Reading

Check “Five [Debunked] Popular Myths about C++” by Bjarne Stroustrup and learn some new C++11, C++14 features. [1, 2, 3]

About istarc

Embedded Systems Developer.
This entry was posted in Embedded Systems, STM32F4 and tagged , , , , , , . Bookmark the permalink.

5 Responses to STM32F4 – Object-oriented Programming with Embedded Systems (C++ /w STL)

  1. Dennis says:

    Hi Iztok,
    thank you for this great looking tutorial! I tried to follow it and I successfully built my binary of the OOP example.
    When it comes to flashing I tried to follow your way of updating openocd in the in-circuit-debugging-tutorial and it worked.
    “openocd –version” gives me 0.9.0-dev-00161-g9c47dc9 (2014-10-01-19:01)
    Although: When I do “make deploy” I get the same error as if no Board is connected at all:
    http://pastebin.com/gjXv7GwE
    with the important lines:

    Error: open failed
    in procedure ‘program’
    in procedure ‘init’ called at file “embedded:startup.tcl”, line 459
    in procedure ‘ocd_bouncer’
    in procedure ‘transport’
    ** OpenOCD init Failed **

    dmesg | grep usb shows me that the stm32 is found twice because I connected both USB.
    I’m on Ubuntu 14.04 LTS 64bit.
    Can you please give me any hint?

    • Dennis says:

      Update:
      I red you first “Hello World” Tutorial and saw that you do the openocd-call with sudo.
      After trying it “sudo make deploy” it works perfect!
      Thank you soo much for these tutorials! I will give more feedback when I managed to write my first little embedded-program 🙂

      • istarc says:

        Hi Dennis,

        I am glad you found the solution by yourself.

        Depending on your host system settings OpenOCD may connect to the STM32F4-Discovery board without superuser privileges (i.e. /wo sudo). However, after the blog was posted, I realized this is not enabled by default, so thx for pointing this out. I will fix it. 🙂

        PS. You may use the OOP project as a template project. Just add appropriate files in the src and inc folders. It will build automagically. Or you can start from scratch using the project wizard. 🙂

        PPS. I also recommend you to try the VirtualBox image with already set up development environment (be sure to check out test automation via BuildBot).

  2. Dennis says:

    Hi Iztok,
    I tried to Debug using QTCreator instead of your Eclipse solution and had trouble because Terrys PPA gcc-arm-none-eabi=4-8-2014q2-0trusty10 was built without python.
    I raised a question on launchpad and he built a new version trusty11 within hours where Python is enabled in GDB.
    Just wanted to let you know that there is a new version available now.
    Here was my question which might contain interesting links on how to set up the Debugger in QTCreator or other IDEs: https://answers.launchpad.net/gcc-arm-embedded/+question/255548
    BTW: Can I send you Text/Code in another way than wordpress-comments? 😉 I used your excellent tutorials to write a non-blocking RS232 communication fifo queue and want to share with you if you are interested. I’m not the guy to start another STM32 blog.
    Thanks again for your great tutorials!

    • istarc says:

      Hi Dennis,

      Thanks for the feedback and the info regarding the gcc-arm-none-eabi package version number. I have already updated my posts and some files in the repository.

      I encourage you to share your code. It may be useful to others. 🙂 Just fork my stm32 git repository, clone it to your local environment, add your code, commit and push back.

      Then you can send me the link to your repo and I will open a special “3rd Party Examples” section to add your project. 🙂 Soon, I will provide a tutorial on how to do this in less than 30 minutes.

Leave a reply to Dennis Cancel reply