Jun 29

Running an STM32CubeF4 template on the STM34F4-Discovery

Led by The Definitive Guide to ARM® Cortex®-M4…, we have quite easily managed to compile and run a sample from GNU Tools for ARM Embedded Processors (see earlier post). However, we only got a generic Cortex-M4 startup assembly file and corresponding linker script from the sample. According to The Definitive Guide to ARM® Cortex®-M4…, there is more we can get from our vendor, ST in this case (HAL headers and code, drivers, and more generally, all sort of boilerplate code we want to have when we make full use of the board’s resources, instead of reinventing the wheel). STM32CubeF4 is just that, and quite a lot more (especially plenty of example applications and templates). It complies to The ARM CMSIS, Cortex Microcontroller Software Interface Standard, a vendor-independent hardware abstraction layer for the Cortex-M processor series that also specifies debugger interfaces.
What I am most interested in is the contents of Projects/STM32F4-Discovery/Templates/, as it should contain exactly what we need to develop applications for the board (although I am not sure whether it includes support for C++ compilation, which I intend use, but the ARM variant used in an earlier post did have such support, so it should be easy enough to copy/paste).
Projects/STM32F4-Discovery/Templates/ contains project files for several development environments, but no Makefile. One of the supported environment is TrueSTUDIO, that seems to make use of a GNU chain, which is good for us.
I might as well take the opportunity to digress a little about the development environment topic. I won’t apologize for loving open source. No single software vendor has a chance to have nearly as many reviewers as an open source tool. Many reviewers just means higher quality, it’s that simple. Using a GNU toolchain is not even a topic of discussion for me. Using openocd, including its integration with GDB has been very positive so far, so I do not see a reason for looking elsewhere. What is left to choose is:

  • The editor.
  • The debugger GUI (living without a debugger GUI is not really an alternative).
  • Last but not least: the build tool.

Concerning point 1, although I have used Emacs many years, I am leaning towards Eclipse because it is the de facto standard. The reason is that I also develop software for a living, and Eclipse is probably preferable for a potential customer. It is easier to get a consensus around it. The debugger GUI issue is then solved as well (with the right plugins). When it comes to the build tool, I want to be able to build both inside and outside of Eclipse. I reckon that will ease the generation of production binaries, and I also reckon that GNU make and its Makefile are the natural solution for that issue.

GNU ARM Eclipse
I have investigated the fastest way to get a blinking LED example running/debugged under Eclipse:

  • Download Eclipse from Eclipse IDE for C/C++ Developers. Unpack it wherever you like and start it from there.
  • Install GNU ARM Eclipse, as documented under GNU ARM Eclipse plugins installation. GNU ARM Eclipse is a set of plugins, quoting the site: “currently maintained by Liviu Ionescu, a senior IT engineer, with expertise in operating systems, compilers, embedded systems and Internet technologies”.

GNU ARM Eclipse is certainly impressive. Once that was installed, using the documentation from the same site, GNU Tools for ARM Embedded Processors, and OpenOCD, I could run/debug a LED blinking example and see printouts from the program in an Eclipse console in no time, without even using STM32CubeF4. It should be however noted that some code in the plugin, I guess most of what is specific to ST MCUs and boards, comes from STM32CubeF4.

Jun 28

Running ARM samples on the STM32F4-Discovery

Now that we have an original flash image that we know how to restore, it is time to start building and running our own software on the board.

When it comes to the toolchain, I started with the version provided by Manjaro, but I ran into an issue related to Newlib-Nano, which is the C library that is supposed to be used with that toolchain. After a few other tries, I was finally successful with the toolchain provided by ARM and located at GNU Tools for ARM Embedded Processors, that the arch/Manjaro packages are built on anyway. As mentioned in a previous post, the installation is not more intrusive than unpacking a compressed folder and pointing to it in my PATH.
Led by The Definitive Guide to ARM® Cortex®-M4…, who recommended the use of linker scripts provided by ARM in their toolchain samples, I decided to start by building and running the actual samples.
To start with, I reuse the exact code structure provided by ARM in their samples. My purpose was to be able to just run make after as few adaptations as possible. The structure is the following:

The dump directory is mine. The rest is a copy/paste of the contents of ARM’s sample folder.
Under ldscripts, I have modified the contents of the mem.ld file to match my board:

Since gcc.ld (used in most samples) and nokeep.ld had the same rows, I replaced the redundancy by some INCLUDE commands:

The default processor in the samples being a Cortex-M0, I also change the processor to a Cortex-M4:
[nilo@floor arm-none-eabi]$ head src/makefile.conf

And then, under the src directory, I just ran make. :-)
Here for the short version:

The simplest of these examples being minimum, that is the one I decided to test.

Under openocd telnet:

The PC and the MSP match the disassembled image:

Now debugging in gdb (openocd still started, telnet closed, gdb connected instead):

Jun 28

Useful commands in Manjaro Linux

List files included in an installed package:

Upgrading all packages:

Installing an AUR package:

Updating an AUR package:

List block devices and their mount points:

Jun 28

Restoring original flash contents to the STM32F4-Discovery

Now we will test restoring the binary image that we earlier got from dumping the original contents of the flash memory.
Our unique flash bank looks as follows:

We can first verify the image file:

We can then naively test to restore the image without first erasing the bank:

This is not surprising, although I have seen it go through without an error message before (I am not sure what really happened in that case).
Lets now try to first erase the whole bank.
We check the contents of the first word:

We recognize the first word from earlier. Now we erase the whole bank (i.e. the whole flash memory):

It does look like the flash memory is erased. Now lets restore the original image:

This worked too! After the reset, the LEDs are flashing as they did before, instead of staying unlit when I run reset just after the erasing.

Jun 27

Disassembling original flash contents from the STM32F4-Discovery

To work with bare metal ARM programming, I need a bare metal ARM toolchain. Being a Manjaro Linux user, I first installed the following packages from the regular repositories:
– arm-none-eabi-binutils
– arm-none-eabi-gcc
– arm-none-eabi-gdb
This works well enough for what I am doing in this post. However, when trying to compile some samples from ARM it complains as follows:

Newlib-Nano was produced as part of ARM’s “GNU Tools for ARM Embedded Processors” initiative in order to provide a version of Newlib focused on code size. The error is apparently a known issue in arch/Manjaro. The easiest solution I found was to uninstall the packages above, unpack the pre-built toolchain provided by ARM at GNU Tools for ARM Embedded Processors to my home folder and to adapt my PATH to that location, as mentioned in readme.txt.
Now, we disassemble the binary we previously got in openocd:

The -Mforce-thumb option is required because this version of objdump, although recent (binutils 2.24) does not have an explicit armv7 option or equivalent. Cortex-M4 processors implement the ARMv7-M architecture that uses the Thumb-2 instruction set architecture, i.e. a seamless mix of 16 and 32-bit instructions. Without the -Mforce-thumb option, objdump interprets the binary as 32-bit instructions only, which is totally incorrect. In fact, most of the instructions in that binary happen to be 16-bit wide.
As a matter of fact, openocd can disassemble too:

That is a straight disassembly of the first ten instructions located at address 0x00000000 which, as mentioned in an earlier post, is mapped to the start of the internal flash. It seems that opendocd does not need to be instructed about the detailed architecture, probably because that information already is contained in the configuration files used when starting the program.
So, the processor starts by executing lsrs r0, r0, #0x12, right? Wrong. As explained in The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4 Processors, Third Edition, the first thing the processor does when it comes out of reset, is fetching the MSP value (Main Stack Pointer) from address 0x0000 0000, i.e. a 32-bit address, in our case 0x2000 0c80, which unsurprisingly lies in SRAM (0x2000 0000 - 2001 FFFF) according to the STM32F407VG datasheet. The stack grows downwards, so that address is the top of the stack.
Next, the processor fetches the reset vector from address 0x0000 0004. In our case 0800 422d, which is in flash (0x0800 0000 - 0x080F FFFF according to the same datasheet).
The processor then starts to execute the program from the reset vector address and begins normal operations:

The reason why the fetched vector address ends with 422d instead of 422c is because vector addresses in the vector table should have their LSB set to 1 to indicate that they are Thumb code.
The first instruction loads the value located at address 0x0800 4240, that is 0xe000 ed88 to r0 (the disassembler interprets it as a 32-bit unknown instruction, assuming that the first word is most significant, which explains the half word inversion in presentation). The ARMv7-M ARM (Architecture Reference Manual) tells us that 0xe000 ed88 is the address of the Coprocessor Access Control Register (CPACR). The three following instructions set the so-called CP10 and CP11 bit fields to 0b11, which give full access to the floating point coprocessor.

Jun 25

Fetching original flash contents from the STM32F4-Discovery

Before, reprogramming the flash memory with my own software, I want to fetch the original contents, for two purposes:

  • Disassembling and study
  • Backup

Connect to the board with openocd:

Connect to the openocd telnet server:

For some reason, I have to first use the flash info command in order for the other flash display commands to work correctly (otherwise they show zero addresses and sizes):

Now, we are ready to dump the whole flash to a binary image and to exit:

Perfect! Ready for disassembling! :-)

Jun 21

Discovering the STM32F4-Discovery

The official page is at STM32F4DISCOVERY. The board features:

  • An STM32F407VGT6 microcontroller featuring 32-bit ARM Cortex-M4F core, 1 MB Flash, 192 KB RAM, a frequency of up to 168 MHz, in an LQFP100 package.

That MCU has two boot pins that control where it boots from. For some strange reason, I was not able to find a complete specification of those pins in ST’s documentation. However, it looks like the information located at stm32-arm-cortex-bootloader is correct:

BOOT0 BOOT1 Boot Mode
0 X Boot from user flash
1 0 Boot from System Memory
1 1 Boot from embedded RAM

According to the STM32F407VG datasheet, system memory is apparently some kind of PROM, where a serial boot loader is located, that can be used to reprogram the flash. My intention is to rather boot from flash, and use the openocd over the ST-LINK/V2 interface, probably integrated in Eclipse at some point, to reprogram the flash.
According to the STM32F407 user manual, the standard BOOT0/BOOT1 configuration is 0/1, which is fine for me (booting from flash).

Jun 21

Starting talking to STM32F4-Discovery from Linux

Used host:

First, I add the udev rule corresponding to the ST-LINK/V2 interface in the newly created file /etc/udev/rules.d/99-stlink.rules (thanks PulkoMandy):

Then, I trigger the new udev rule:

Then I install openocd 0.8.0-2 from the Community repository, resulting in:

Then, I connect the board’s Mini-USB connector to my computer. It will both give power to the board, and make the ST-LINK/V2 interface accessible. The ST-LINK/V2 interface appears as a USB device:

Then, I say hello to my little board:

What more would a nerd require to be happy? :-)