Showing posts with label libopencm3. Show all posts
Showing posts with label libopencm3. Show all posts

Friday, January 10, 2014

Developing STM32 microcontroller code on Linux (Part 5 of 8, building libopencm3)

The first post of this series covered the steps to build and run code for the STM32. The second post covered how to build a cross-compiler for the STM32. The third post covered how to build a debugger for the STM32. The fourth post covered building and configuring OpenOCD for your development environment. This post will cover building the device library, libopencm3.

As mentioned in the introductory post, it makes our life a lot easier if we use a device library. This is a library that abstracts the low-level details of the hardware registers away from us, and gives us a nice consistent API to use. While ST provides one these directly, it is not open-source (or more specifically, it's open-source status is murky). Luckily there is libopencm3, an open-source re-implementation that is also a better library in my opinion. As usual, I'm going to compile a certain version of libopencm3; newer or later versions may or may not work better for you.

As before, we start out by exporting some environment variables:

$ export TOPDIR=~/cross-src
$ export TARGET=arm-none-eabi
$ export PREFIX=~/opt/cross
$ export BUILDPROCS=$( getconf _NPROCESSORS_ONLN )
$ export PATH=$PREFIX/bin:$PATH
The TOPDIR environment variable is the directory in which the sources are stored. The TARGET environment variable is the architecture that we want our compiler to emit code for. For ARM chips without an operating system (like the STM32), we want arm-none-eabi. The PREFIX environment variable is the location we want our cross-compile tools to end up in; feel free to change this to something more suitable. The BUILDPROCS environment variable is the number of processors that we can use; we will use all of them while building to substantially speed up the build process. Finally, we need to add the location of the cross-compile binaries to our PATH so that later building stages can find it.

Now that we have our environment set up, we can get the code. Note that unlike most of the other tools covered in this tutorial, libopencm3 does not do releases. They expect (more specifically, require) that you clone the latest version and use that. That's what we are going to do here. As of this writing, the latest libopencm3 git hash tag is a909b5ca9e18f802e3caef19e63d38861662c128. Since the libopencm3 developers don't guarantee API stability, all of the steps below will assume the API as of that hash tag. If you decide to use a newer version of libopencm3, you may have to update the example code I give you to conform to the new API. With that out of the way, let's get it:

$ sudo yum install git
$ cd $TOPDIR
$ git clone git://github.com/libopencm3/libopencm3.git
$ cd libopencm3
$ git checkout -b clalancette-tutorial \
a909b5ca9e18f802e3caef19e63d38861662c128
What we've done here is to clone the repository, then checkout a new branch with the head at hash a909b5ca9e18f802e3caef19e63d38861662c128. This ensures that even if the library moves forward in the future, we will always use that hash tag for the purposes of this tutorial. Next we build the library:

$ unset PREFIX
$ make DETECT_TOOLCHAIN=1
$ make DETECT_TOOLCHAIN=1 install
$ export PREFIX=~/opt/cross
Here we need to unset PREFIX because libopencm3 uses PREFIX for the toolchain name prefix (arm-none-eabi), not the path prefix. Once we've done that, we can tell libopencm3 to detect the toolchain, and then use it to build libopencm3. Finally we use the install target to install the headers and the static libraries (.a files) to our toolchain. Assuming this is successful, everything necessary should be in ~/opt/cross/arm-none-eabi/, with the libraries in lib/libopencm3* and the header files in include/libopencm3. Note that there is one .a file per chip that is supported by libopencm3; we'll return to this later when we start building code for our chip.

Monday, January 6, 2014

Developing STM32 microcontroller code on Linux (Part 1 of 8, introduction)

Recently I've been playing with the STM32, which is a small microcontroller made by ST. These seem to be pretty great microcontroller chips; they are relatively fast (depending on what model you get), have a decent amount of flash (up to 1MB), and have a decent amount of memory (up to 192KB). It is also easy to get development boards for them; there is a line of boards called the STM32DISCOVERY boards that are really cheap and easy to get. It is possible to work on these chips entirely with open source tools, which is important to me.

This series of posts will go through all of the steps necessary to develop on these boards. Note that all of this is covered elsewhere on the web, but a lot of the information is either outdated or scattered. I'll build all of the pieces from the ground up to get a working set of tools and binaries that you can use to develop your own STM32 applications.

To start with, I'm going to describe my hardware setup. I have a laptop running Fedora 19 x86_64. This is my main development machine, and this is going to be the host for everything I do with the STM32. For an STM32 board, I have an STM32F3DISCOVERY board, as shown here. However, note that for most of the posts, the exact board that you have isn't that important. As long as it is one of the STM32F*DISCOVERY boards, the steps below will mostly apply. The differences will become more important when we start to actually write code that deals with the GPIOs (as the GPIOs differ per board), but for the development environment they are really all quite similar.

This series of posts will do the steps in the following order:
  1. In order to do anything, we need a cross compiler. This is a set of tools that runs on our development environment (Fedora 19 x86_64), but emit instructions for our target hardware (STM32 ARM). Besides the C/C++ compiler, this also includes things like the assembler and linker. Part of the cross-compile toolchain also includes a minimal libc-like environment to program in, which gives you access to <stdio.h> and other familiar header files and functions. We will build a cross compile environment from binutils, gcc, and newlib.
  2. Once we have a cross-compiler, we need some way to debug the programs we write. The simplest thing to do here is to build gdb, the GNU debugger. Unfortunately we can't just use the system gdb, as that generally only understands how to debug and disassemble code on your development machine architecture. So we'll build our own version of gdb that understands ARM.
  3. With the debugger finished, we need some way to take the compiled version of our code and put it onto the target device. The STM32 devices use something called STLinkV2, which is a multi-purpose communication protocol (generally over USB). In order to upload our code to the device, we need a piece of software the speaks this protocol. Luckily there is OpenOCD, the Swiss Army Knife of communication protocols. We'll need to build a version of this that runs on our development machine, but knows how to speak STLinkV2. In this step we'll also build a configuration file that can communicate over STLinkV2.
  4. With the communications taken care of, we need a device library. This is basically an abstraction layer that allows us to talk directly to the hardware on the target device. For the purposes of these posts we are going to use libopencm3. This step will build libopencm3 for the target device.
  5. Once we have libopencm3 built, we have to know how to link programs so that they run on the STM32. This step will discuss linker scripts and command-line directives necessary to build programs that run on the STM32.
  6. Here we build our first simple program, upload it to the STM32, and watch it run! Finally!
  7. For bonus, I discuss running a simple Real-Time Operating System on the STM32, FreeRTOS. Using this will allow you to define several tasks and have the RTOS switch between them, much like tasks on a full-fledged OS. This opens up new possibilities and new problems, some of which will be discussed.
Whew, that's a lot of steps just to get the equivalent of "Hello World" running on the board. However, it should be educational and collect a lot of this information together in one place.