It would be nice to start with a simple LED flashing, blinky type application. Well simple is a bit of an overstatement. The code to blink an LED is easy enough but those nice folk at ST have provided a special peripheral driver library. This library abstracts much of the hardware from the user and should make for more portable code. The library sources are all in standard C and are supposed to compile up just like anything. Even with the benefit if an IDE, this would be a bit tricky to set up. Without one, it means a lot of messing about with makefiles, linker scripts and startup code. This is how I set up mine on a Mac. Much the same arrangement will work just fine on a PC. Included is a project template to speed things up…
While most code examples out there use the ST Firmware Library Version 2, I thought I would base my stuff on the newer Peripheral Driver Library V3. It makes little difference to me since I have nothing invested in the earlier version and the programming interface is supposed to be the same in V3 as it was in V2. We shall see. You can download the library here:
When unpacked, the installation structure is a bit overwhelming. There are lots of folders.
Various essential parts of the library are in different places in this structure. The main driver code and header files live in the STM32F10x_StdPeriph_Driver folder and, apart from an unpleasant looking path name, are neatly arranged. To build a program with these files, you will also need to include in your project a few other files. These are mostly in the path
and comprise the following files:
system_stm32f10x.h stm32f10x.h core_cm3.h system_stm32f10x.c core_cm3.c
Like the actual driver files, they can be left where they are if you make sure that they can be found by your project makefile. There are two lines in stm32f10x.h that will want changing to set the processor type and to make use of the Peripheral Driver Library. If those settings are different from one project to the next, you will need to make a local copy of the file in your project folder and ensure that it is found first. As it will be the first #included file in main.c, that should not be a problem
In the startup/gcc folder, you will find three more C files which are the startup code for the three families of STM32 processor. My processor of choice is the STM32F103RBT6 which is a medium density device so I will be using the startup_stm32f10x_md.c file. You can make a local copy of that or you can make sure that the Makefile can find it during a build.
So that the Makefile can locate the C files needed by the project, I have added their location to the vpath variable in the file thus:
LIBSTM32 = /Applications/arm/stm32f10x_stdperiph_lib_v3.0.0/Libraries CM3 = $(LIBSTM32)/CMSIS/Core/CM3 STARTUP = $(CM3)/startup/gcc
DRIVERS = $(LIBSTM32)/STM32F10x_StdPeriph_Driver vpath %.c $(DRIVERS)/src $(CM3) $(STARTUP)
The penultimate piece we will need is a linker script so the linker can find out where all the bits of our program will go. The only one in the library is part of the Template project, intended for use with the Raisonance Ride7 IDE. You can find it here:
The settings are not quite what we want but it can be edited to sort out the small differences required later. These are mostly, I think, limited to the memory sizes and locations. I had some trouble with very large binary images being produced by objcopy. This seems to be a result of the LMA of sections not being generated correctly when the .data section was empty. Adding a KEEP() directive to those sections seems to have fixed it. The linker script (stm32f10x_flash_md.ld) is part of this archive:
The archive file contains a complete, blank template for a project set up with the information above in a folder.
This folder contains all the files needed for a project template when building a C project using the CodeSourcery GNU ARM compiler. It is based on the 2008q3 distribution although nothing in here should depend upon the exact version.
The Makefile is in two parts to make it easier to edit only that part needed by most projects. The Makefile itself simply defines the source files and the target name and then includes makefile.mk for all the actual work.
The project assumes you will be using the ST Peripheral Driver Library V3. The installation location for this library is defined in makefile.mk
The folder should contain at least the following files:
main.c Makefile makefile.mk README.TXT stm32f10x.h stm32f10x_conf.h stm32f10x_flash_md.ld stm32f10x_it.c stm32f10x_it.h
The template is a complete, but completely useless, program in its own right. It will build and produce output files so that you can test your toolchain setup.
To start a specific project, copy all this into a new folder with an appropriate name. Change to that folder and run make. If everything is set up correctly, you should get a bunch of object files, a couple of listings and, by default, a .bin file containing the image to be written to the processor. The settings in the linker script and makefile.mk assume the use of the STM32F103RBT6 processor. Note that the Makefile will create all the object files for the libraries in the project folder. At some point, I will try and bild the peripheral driver as a library but, for now, this will do.
A simple ‘make’ will build the project, ‘make clean’ will tidy out the objects, listings and binary, ‘make program’ will try and build the program if necessary and then load the binary to your target but you will need the stm32loader.py script for that. See this post for more details.
Assuming you want to use the Peripheral Driver Library, open stm32f10x_conf.h and uncomment the lines corresponding to the subsystems you wish to use.
The interrupt handlers are defined in the stm32f103x_it.c file. If you have a look in the startup code in startup_stm32f10x.c, you will see that al the interrupt handlers are defined there with the WEAK attribute and they all point to a default handler that just runs an endless loop. The WEAK attribute means that you are able to define another interrupt handler of the same name in another source file and it will override the one in the startup code. this is how the stm32f103x_it.c file is able to have apparently duplicate interrupt handlers to the startup code.
If it is more convenient, individual handlers could be placed in their own source files.
I think I now have all the pieces needed to start building applications for the STM32. the next step will be to translate some of the examples provided with the library for my development boards.