When developing for the STM32F4, setting up a new project can be a pain. Without some kind of wizard or configuration tool, there are always loads of obscure settings that have to me made each time. The easiest way around this is to make a simple template for the STM32F4 that has all the basic features set up already and then copy or clone it every time you start a new project.
For my STM32F4 development I use Rowley’s Crossworks for ARM. This is a commercial, fully supported environment that is available for non-profit use at a reasonable price. All the other commercial products are either too expensive or too constrained for me. The free environments are just too much like hard work. Ideally, some kind soul would build some equivalent of the Microchip MPLABX environment around Netbeans. Meantime, I need to build my projects in Crossworks.
I have made several attempts at a proper template in the past but always got lazy and messed around with the template until I no longer knew what was what. This time, I decided to create a project and have it managed by the git source control software. Furthermore, I have made it available in a public repository so that others can use it and so that I can easily clone or download a copy as a starter. Upgrading settings or library versions is now trackable and I will be able to go back and check out previous versions if needed.
The starter projects was inspired by the way that the CooCox IDE creates STM32F4 projects. Rather than retain the complicated folder structure used by the ST Standard Peripheral Libraries, it just copies all of the CMSIS headers into one place and all the library files into another. Now there are fewer paths to keep track of and everything is much neater.
The version of Crossworks used for this project is 2.3 which is current at the time of writing. Crossworks does not use a makefile or linker script for its builds. This is a little annoying and reduces the general usefulness of the starter project for other development environments. Still, I have listed the project settings below so that you can see how everything is configured. The Crossworks project file holds all this information in XML format so that it is easily edited even without using the CrossStudio IDE tools.
The STM32F4 processor
The template is intended to run on the STM32F4Discovery board although the processor is set as the larger STM32F405RG for compatibility with my micromouse. This just gives more memory so it is unlikely to be a big problem in most cases. The STM32F4 devices are all reasonably similar.
The internal oscillator on the STM32F4 is used because I want the project to be more portable and there is no need for any better accuracy in my project. The processor is running at 72MHz as a reasonable compromise between performance and current consumption.
Code is included to set up and blink the four coloured LEDs found on the STM32F4Discovery so that there is an immediate indication that it is running. My board sits on a prototyping board with an extra LED connected to PB.2 which is also the BOOT1 pin. Unless you want to boot your processor to RAM, this pin can always be held low and an LED does that nicely. As that pin has no other function that I want, I use the LED as a status indicator. On the micromouse, it is turned on at the start of every systick event and turned off at the end. That way the brightness of the LED serves as a guide to system load and if it is ever on (or off) continuously, I know the code has crashed. Here I just toggle the LED at each tick. A global boolean, crashed, lets me override the status LED behaviour and will be useful elsewhere in the micromouse code.
The DEBUG configuration (only) has USE_FULL_ASSERT defined and the Rowley cross_studio_io.h header is included. There is also a software timing-loop delay function that can count off microseconds. With these features, I can make full use of the ASSERT macros and, when there is an ASSERT failure, a message is printed to the debug console and the status LED blinks distinctively – even if systick is still trying to flash it normally. In fact, if the target is not actively being debugged, the debug_printf() function seems not to return so this could do with some more thought
Inside the systick event, a millisecond counter is maintained – to be used by a millisecond delay function, delay_ms(). This is a 32-bit counter so it will not overflow for over 1000 hours. Plenty for my purposes.
By default, Crossworks eliminates unused code so it is safe to allow all the libraries to be built. Only the functions used by the program will be included in the binary image downloaded to the target.
The stack for the STM32F4 is set to a size of 2048. The default stack size in Crossworks is only 128 bytes which is pretty small. These STM32F4 devices have a lot of available memory so there is no reason to be mean. As a generally useful extra check, the preprocessor define INITIALIZE_STACK ensures that the startup code fills the stack with the value 0xCC so that we can always look and see how much of the stack has been used when debugging.
I have also set a heap of 4096 bytes. Just in case I want one. Again, there is plenty of space.
The preprocessor define USE_STDPERIPH_DRIVER is used by the CMSIS and library code so it is included for correct behaviour.
Another Rowley feature is the preprocessor define STARTUP_FROM_RESET. This is needed in any production code or the startup routines will sit in an endless loop, waiting for the debugger to connect. I define it for both debug and release configurations just because it annoys me otherwise. However, doing do may be the reason why, sometimes, I am unable to get easy control of the target. I cannot help but feel this is a bit of a hack but I am sure there is good reason for it.
Since the STM32F4 devices have a hardware FPU unit, that is turned on and active. It would be a shame not to use it or, worse, to forget to turn it on and wonder why the code ran so poorly.
On the subject of floating point, I have enabled the use of floating point in printf(). While many frown upon printf() and its related functions for their bloat and slowness, this is a fast processor with plenty of code memory. You can easily afford the convenience that standard I/O functions can bring to the program. Note that printf() is useless without a way to get characters off the chip but that is a problem for another post. This template does not set up the USART.
By the time you read this, I may have sorted that out. The template now has initialisation for USART1 so that printf() will work. As will getchar(), putchar() and others.
I like my code to be kept reasonably neat and tidy so I have a copy of astyle installed on my desktop machine. Crossworks allows an external executable to be called at several stages during the build. I call astyle just before the link. It runs through all the files and reformats them according to my preferred style. This is very handy when you are using a source control system as it is pretty annotying to have the repository filled with whitespace changes. So long as I have completed a build just before a commit (and why wouldn’t you), then the code will be neat and tidy. Of course, you probably do not have astyle installed so you will want to remove this option. Sorry for your loss. The command is held in the linker_pre_build_command configuration variable and the line entered is:
/usr/local/bin/astyle “$(ProjectDir)/*.h” “$(ProjectDir)/*.c”
For some reason, Crossworks does not assume anything at all about project include directories and will not be able to find header files even if they are in the same folder as the source files. To make all that happy, the following three paths are added to the user include directories:
Get Your Own Copy
To get a copy of the complete project, you can clone or download it from github:
Let me know if you find any serious errors.
There is more about the USART on the STM32 processors here:
There should be only minor differences between the USART on the STM32F4xx and on the STM32F1xx processors.