I was excited to see recently that ARM announced their new Cortex-M7 microcontroller core, and that ST announced their line using that core, the STM32F7. I had briefly played around with the STM32 before, and I talked about how I was going to start using it — I never followed up on that post, but I got some example programs working, built a custom board, didn’t get that to work immediately, and then got side-tracked by other projects. With the release of the Cortex M7 and the STM32F7, I thought it’d be a good time to get back into it and work through some of the issues I had been running into.
First of all though, why do I find these chips exciting? Because they present a tremendous value opportunity, with a range of competitive chips from extremely low-priced options to extremely powerful options.
The comparison point here is the ATmega328: the microcontroller used on the Arduino, and what I’ve been using in most of my projects. They currently cost $3.28 [all prices are for single quantities on digikey], for which you get a nice 20MHz 8-bit microcontroller with 32KB of flash and 2KB of ram. You can go cheaper by getting the ATmega48 which costs $2.54, but you only get 4KB of program space and 512B of ram, which can start to be limiting. There aren’t any higher-performance options in this line, though I believe that Atmel makes some other lines (AVR32) that could potentially satisfy that, and they also make their own line of ARM-based chips. I won’t try to evaluate those other lines, though, since I’m not familiar with them and they don’t have the stature of the ATmegas.
Side note — so far I’m talking about CPU core, clock speeds, flash and ram, since for my purposes those are the major differentiators. There are other factors that can be important for other projects — peripheral support, the number of GPIOs, power usage — but for all of those factors, all of these chips are far far more than adequate for me so I don’t typically think about them.
The STM32 line has quite a few entries in it, which challenge the ATmega328 on multiple sides. On the low side, there’s the F0 series: for $1.58, you can get a 48MHz 32-bit microcontroller (Cortex M0) with 32KB of flash and 4KB of RAM. This seems like a pretty direct competitor to the ATmega328: get your ATmega power (and more) at less than half the price. It even comes in the same package, for what that’s worth.
At slightly more than the cost of an ATmega, you can move up to the F3 family, and get quite a bit better performance. For $4.14 you can get a 72MHz Cortex M3 with 64KB of flash and 16KB of RAM.
One of the most exciting things to me is just how much higher we can keep going: you can get a 100MHz chip for $7.08, a 120MHz chip for $8.26, a 168MHz chip for $10.99, and — if you really want it — a 180MHz chip for $17.33. The STM32F7 has recently been announced and there’s no pricing, but is supposed to be 200MHz (with a faster core than the M4) and is yet another step up.
When I saw this, I was pretty swayed: assuming that the chips are at least somewhat compatible (but who knows — read on), if you learn about this line, you can get access to a huge number of chips that you can start using in many different situations.
But if these chips are so great, why doesn’t everyone already use them? As I dig into trying to use it myself, I think I’m starting to learn why. I think some of it has to do with the technical features of these chips, but it’s mostly due to the ecosystem around them, or lack thereof.
Working with the STM32 and the STM32F3 Discovery board I have (their eval board), I’m gaining a lot of appreciation for what Arduino has done. In the past I’ve haven’t been too impressed — it seems like every hobbyist puts together their own clone, so it can’t be too hard, right?
So yes, maybe putting together the hardware for such a board isn’t too bad. But I already have working hardware for my STM32, and I *still* had to do quite a bit of work to get anything running on it. This has shown me that there is much more to making these platforms successful than just getting the hardware to work.
The Arduino takes some fairly simple technology (ATmega) and turns it into a very good product: something very versatile and easy to use. There doesn’t seem to be anything corresponding for the STM32: the technology is all there, and probably better than the ATmega technology, but the products are intensely lacking.
Ok so I’ve been pretty vague about saying it’s harder to use, so what actually causes that?
Family compatibility issues
One of the most interesting aspects of the STM32 family is its extensiveness; it’s very compelling to think that you can switch up and down this line, either within a project or for different projects, with relatively little migration cost. It’s exciting to think that with one ramp-up cost, you gain access to both $1.58 microcontrollers and 168MHz microcontrollers.
I’ve found this to actually be fairly lackluster in practice — quite a bit changes as you move between the different major lines (ex: F3 vs F4). Within a single line, things seem to be pretty compatible — it looks like everything in the “F30X” family is code-compatible. It also looks like they’ve tried hard to maintain pin-compatibility for different footprints between different lines, so it looks like (at a hardware level) you can take an existing piece of hardware and simply put a different microcontroller onto it. I’ve learned the hard way that pin compatibility in no way has to imply software compatibility — I thought pin compatibility would have been a stricter criteria than software compatibility, but they’re just not related.
To be fair, even the ATmegas aren’t perfect when it comes to compatibility. I’ve gotten bitten by the fact that even though the ATmega88 and ATmega328 are supposed to be simple variations on the same part (they have only a single datasheet), there some differences there. There’s also probably much more of a difference between the ATmegaX8 and the other ATmegas, and even more of a difference with their other lines (XMEGA, AVR32).
For the ATmegas, people seem to have somewhat standardized on the ATmegaX8, which keeps things simple. For the STM32, people seem to be pretty split between the different lines, which leads to a large amount of incompatible projects out there. Even if you’re just trying to focus on a single chip, the family incompatibilities can hurt you even if you’re not trying to port code — it means that the STM32 “community” ends up being fragmented more than it potentially could be, with lots of incompatible example code out there. It means the community for any particular chip is essentially smaller due to the fragmentation.
What exactly is different between lines? Pretty much all the registers can be different, the interactions with the core architecture can be different (peripherals are put on different buses, etc). This means that either 1) you have different code for different families, or 2) you use a compatibility library that masks the differences. #1 seems to be the common case at least for small projects, and mostly works but it makes porting hard, and it can be hard to find example code for your particular processor. Option #2 (using a library) presents its own set of issues.
Lack of good firmware libraries
This issue of software differences seems like the kind of problem that a layer of abstraction could solve. Arduino has done a great job of doing this with their set of standardized libraries — I think the interfaces even get copied to unrelated projects that want to provide “Arduino-compatibility”.
For the STM32, there is an interesting situation: there are too many library options. None of them are great, presumably because none of them have gained enough traction to have a sustainable community. ST themselves provide some libraries, but there are a number of issues (licensing, general usability) and people don’t seem to use it. I have tried libopencm3, and it seems quite good, but it has been defunct for a year or so. There are a number of other libraries such as libmaple, but none of them seem to be taking off.
Interestingly, this doesn’t seem to be a problem for more complex chips, such as the Allwinner Cortex-A’s I have been playing with — despite the fact that they are far more complicated, people have standardized on a single “firmware library” called Linux, so we don’t have this same fragmentation.
So what did I do about this problem of there being too many options leading to none of them being good? Decide to create my own, of course. I don’t expect mine homebrew version to take off or be competitive with existing libraries (even the defunct ones), but it should be educational and hopefully rewarding. If you have any tips about other libraries I would love to hear them.
Down the rabbit hole…
Complexity of minimal usage
I managed to get some simple examples working on my own framework, but it was surprisingly complicated (and hence that’s all I’ve managed to do so far). I won’t go into all the details — you can check out the code in my github — but there are quite a few things to get right, most of which are not well advertised. I ended up using some of the startup code from the STM32 example projects, but I ended up running into a bug in the linker script (yes you read that right) which was causing things to crash due to an improper setting of the initial stack pointer. I had to set up and learn to use GDB to remotely debug the STM32 — immensely useful, but much harder than what you need to do for an Arduino. The bug in the linker script was because it had hardcoded the stack pointer as 64KB into the sram, but the chip I’m using only has 40KB of sram; this was an easy fix, so I don’t know why they hardcoded that, especially since it was in the “generic” part of the linker script. I was really hoping to avoid having to mess with linker scripts to get an LED to blink.
Once I fixed that bug, I got the LEDs to blink and was happy. I was messing with the code and having it blink in different patterns, and noticed that sometimes it “didn’t work” — the LEDS wouldn’t flash at all. The changes that caused it seemed entirely unrelated — I would change the number of initial flashes, and suddenly get no flashes at all.
It seems like the issue is that I needed to add a delay between the enabling of the GPIO port (and the enabling of the corresponding clock) and the setting of the mode registers that control that port. Otherwise, the mode register would get re-reset, causing all the pins get set back to inputs instead of outputs. I guess this is the kind of issues that one runs into when working at this level on a chip of this complexity.
So overall, the STM32 chips are way, way more complicated to use than the ATmegas. I was able to build custom ATmega circuits and boards very easily and switch away from the Arduino libraries and IDE without too much hassle, but I’m still struggling to do that with the STM32 despite having spent more time and now having more experience on the subject. I really hope that someone will come along and clean up this situation, since I think the chips look great. ST seems like they are trying to offer more libraries and software, but I just don’t get an optimistic sense from looking at it.
So, I’m back where I was a few months ago: I got some LEDs to blink on an evaluation board. Except now it’s running on my own framework (or lack thereof), and I have a far better understanding of how it all works.
The next steps are to move this setup to my custom board, which uses a slightly different microcontroller (F4 instead of F3) and get those LEDs to blink. Then I want to learn how to use the USB driver, and use that to implement a USB-based virtual serial port. The whole goal of this exercise is to get the 168MHz chip working and use that as a replacement for my arduino-like microcontroller that runs my other projects, which ends up getting both CPU and bandwidth limited.
10 responses to “Getting started with STM32 microcontrollers”
Thank you for this nice (but slightly unfair) presentation of the stm32 chips .
Like you, i started with AVR and designed several boards and wrote my own libraries for almost every peripheral but when i decided that the power of 8-bit microcontroller is simply not enough and switched to ARM chips and specifically the STM32 i found it at first “impossible to work with” , but when i dig deeper i settled with the CooCox IDE with CMSIS library , things become easier and i begun to familiarize my self with these much powerful chips and i vowed never use AVR again .
BTW , the price is much cheaper on aliexpress (i bought 50 pcs. of STM32F030F4P6 for just $28 or $0.56/piece).
Hi Kevin, I can recommend you to have a look at the TIVA family from Texas Instruments, there’s a lot of projects and tutorials out there using the Launchpad evaluation kit. Like you I started embedded development using Atmega88P.
I’ve been reading your blog for a while(I follow you via RSS) and I notice that you can measure stuff such as CPU load, bandwidth, etc. Could you please tell me about documentation or books where I can learn such techniques to actually get key metrics about my projects? My background is in EE, but I feel like being able to do is a step to stop being a beginner. Thanks in advance.
Ok, I’ll take a look!
I don’t know of any books, but this seems to be a pretty decent list of useful utilities:
Hi Kevin, thanks for the very insightful post. Like many many other people, I also went through the same struggles with the STM32 line (compounded by the fact that my first hardware used the F373–which is less common and even quite architecturally different from the F30x’s, and there were just about no friendly example libraries).
So of course, I had “roll my own” as well and created this http://avikde.me/koduino/html/ to hopefully make it simple to use these chips from Arduino.
I am hoping that it is easy to extend across devices using the ST libraries as an interface layer (although I already am aware of incompatibilities between F3 and F4, but hopefully they are few). Look here https://github.com/avikde/koduino/issues/1 for some details on this.
Of course, if anyone wants to spare development time to a project of this sort, I would love to collaborate!
Thanks for the informative post.
I thought I’d add some more comparisons between STM32 and AVR. First off, some of the boards that ST produces are real bargains. The STM32F429I-DISCO for example is under $25 US. For that you get a 180 MHz processor with 256Kb RAM and 2GB flash. The board includes an LCD with touch, 2GB SDRAM, gyroscope, USB (2 ports) and LEDs and buttons. It also supports Stlink over USB which provides full debugging capabilities without the need to purchase a Jtag debugger. That’s all at a cost comparable to an Arduino UNO.
On the tool chain front, ST provides the STM32CubeMX tool which can be used to configure peripherals, interrupts, clocks and so on and generate initialization code for various IDEs. It’s often buggy but still provides a great launching point for any project. It makes configuring peripherals, using interrupts and DMA nearly trivial.
The STM boards lose out when it comes to the hobbyist community and development environment. The community fostered by Arduino is IMO the biggest single factor in Arduino popularity. It is particularly helpful for starters who may not know the ropes when it comes to programming. The community around the STM32 products tends to be professionally oriented and the discourse on the ST forums is appropriate for that.
When it comes to tool chains, It is super that the Arduino IDE is up and running in a couple minutes. Furthermore, it runs equally well on Windows, Linux and OS X. The down side to the simple Arduino IDE is that there is no debugging aside from serial output to the console.
The tool chains for the STM32 processors are mostly Windows oriented. They can be troublesome to install, requiring licensing and providing crippled versions only for hobbyist use. They do all support full debugging capabilities either using Slink or Jtag debuggers. At present (summer of ’15) development hosted on Linux is almost there. Stlink and openocd are both well supported as is the GCC compiler suite. OpenSTM32 (ac6) is working on integrating ‘MX projects into eclipse and that seems the most promising IDE at the moment.
Lastly, there is a difference between AVR and STM architecture that makes a difference for data intensive embedded systems. AVR requires special addressing modes to access data stored in flash, hence the PROGMEM machinations on the Arduino. On the ST, any data declared const can be put in flash and accessed using the same instructions which would work for RAM.
Hello,First of all i agree with both of you ,STM products will never be as easy as Arduino to use because the STM company doesnt want everyday people to be able to program and use there products because they sell to the military, once they lose there mil status then they will change there methods of teaching others to use there products , TI used to be the same way. anyway someone needs to sit down and write an arduino style book on how to program the development boards out there with the STM32F1XXXX devices ,as they are always avail on ebay and look like alot of fun….WCH
[…] ARM quick start ST Application note – STM32 microcontroller system memory boot mode (PDF) Kevin’s blog – Getting started with STM32 microcontrollers STM32 tutorial part.1 – Set up a project in KEIL μVision (YouTube) Getting started with […]
A very interesting ebook about STM32: https://leanpub.com/mastering-stm32
The free version contains a step-by-step guide to install Eclipse IDE. I tried it, and it works.
Mastering Microcontroller with Embedded Driver Development – good online course which covers STM32 in a good way.
I agree with the above comments. I have 15 years of experiences working with microcontrollers in ASM and C with high speed/low power requirements. We did not use STM parts. In my new company the STMF32 was already chosen. It has been a bear to even get an LED to blink. STM documentation looks good on the surface and it may qualify as a reference guide BUT I cannot find any low level “how to set” what registers. All help wants you to use the HAL or CMSIS or the CubeMX software package. With the PIC parts there is always info in the product specs that shows the registers and order to use their part’s internal devices.