New Year's Resolution: No More Bugs
Years ago I worked for a major semiconductor manufacturer doing failure analysis on CPUs. Someone fairly senior once told me that my job (and all my colleagues) should be eventually eliminated because they were an unnecessary expense. Instead, he said, it would be cheaper to never have any failures.
White PapersMore >>
- Building a Strategy for Detection and Response
- 5 Steps to Integrate SAST into the DevSecOps Pipeline
I wasn't smart enough in those days not to laugh openly at something that crazy, which is part of the reason why I don't work there anymore. I've gotten a little more circumspect with my opinion since then.
The reality is, even if my New Year's resolution is to not create any more bugs, they are still inevitable. That's why I wish the Arduino had better debugging support (although I hear that may be on its way). The underlying AVR chip, of course, has fine debugging facilities if you have the hardware (which doesn't have to be much). Most vendors have some kind of on-chip debugging either through a proprietary interface or something like JTAG. It is getting harder to justify a full-blown emulator unless you think you need to troubleshoot problems during reset or something else exotic.
Last year I was setting up the STM32 development environment using a small board from ETT and an Olimex JTAG adapter (click here for details). I made some progress over the holidays, although I will confess most of my time was consumed playing with a new 3D printer (a topic I will return to later in the year).
If you use an IDE, chances are debugging is built in. The NXP board I looked at a few weeks ago did a nice job of that using Eclipse and its proprietary debugging protocol. The ST, though, doesn't officially support an open source or vendor-provided IDE. You can get demos of commercial offerings, of course. If you want to buy something, there are plenty of options. Some of those are nice, but there is also something to be said for having one set of tools for everything, as much as possible (even if that is Eclipse).
As I mentioned last month, I started with the ST files for the RIDE IDE, which is very close to a stock GCC toolchain. Then I grabbed a few example makefiles (from Peter Harrison at www.micromouseonline.com) and started hacking them to the way I like it — at least, for the most part. In general, I prefer to put things I will frequently change up front (by frequently, I mean once per project). Then I will put things that I will rarely or never change — things like the paths to tools, for example. Once you get them right, you'll probably never change them.
I assumed you would copy the interrupt table file from the library (stm32f10x_it.c in my case) to the working directory. After all, you will want to install your own interrupt handlers unless you are doing something really basic. But most of the other library files I left in the original locations.
Unfortunately, a lot of the ST files assume headers are in the current directory and I didn't want to modify it too much. So currently you need the following files in a "blank" project:
- main.c — The main program (you can change this, of course).
- stm32f10x_conf.h — You can comment out (or uncomment) different STM libraries you want to use in this project here.
- stm32f10x.h — This header should be a system header but there are too many things that refer to it in the local directory so for now I just left it.
- stm32f10x_it.c (and .h) — You may want to modify the interrupt handlers, so you might as well have a copy of this file.
- Stm32f10x_flash_hd.ld — The link script.
You'll also want openocd.cfg when you use JTAG debugging (something I'll talk about later).
The locations are set by the
STLIB variable in the makefile. I also borrowed an .ld file from the Internet and put it in the working directory — you might want to tweak that one too. To keep from making the makefile too ugly, I used
vpath in the file to tell the compilers to look in the library directories for .c and .s files:
vpath %.c $(DRIVERS)/src $(CM3) $(CM3D) vpath %.s $(STARTUPDIR)
One nice side effect of this is that you can add ST libraries by just naming them. For example, I am using the RCC and GPIO library files in this project so:
# Add any ST libraries you call here as well and they can stay where they are SRC += stm32f10x_gpio.c SRC += stm32f10x_rcc.c
You can change a variable near the top of the makefile to pick the ETT bootloader or the OpenOCD JTAG to program. I'll talk more about the JTAG interface next time. For now, you can use
FLASH_TOOL = BOOT and make changes to the
BOOTCMD variable to set, for example, your serial port. The stm32ld program communicates with the bootloader. The bootloader worked OK at 19200 and 57600 baud.
The rest of it is pretty much hands off unless you need to make special changes. I left provisions for using different optimization levels, but I found the CM3 core code had trouble compiling when using anything other than OPT=0. I haven't taken the time to find out why yet.
I'm including a dump of my working directory with the online listings. The simple program is the proverbial blinking LED (on GPIO pin 7). If you want to try it yourself, you'll need to edit the paths, serial ports, and anything else peculiar to my installation.
If you are haven't broken into embedded ARM programming, this is a pretty inexpensive way to make that a New Year's resolution. The board itself isn't much, the software tools that I'm showing are all free, and you don't absolutely have to spend on the JTAG adapter if all you want to do is program the part since the board has the built-in bootloader. As handy as the bootloader is, you really want the JTAG debugging. As inexpensive as the Olimex adapter is, chasing down one bug will make it pay for itself. I'll talk more about debugging specifics next time.