Hacker News new | past | comments | ask | show | jobs | submit login
Bare Metal STM32 Programming and a Quadcopters Awakening (timakro.de)
124 points by timakro on March 5, 2019 | hide | past | favorite | 55 comments

Hi, interesting article, but I would like to suggest you something. While it's OK to do bare metal just using the memory locations like you did:

    *(uint32_t *)0x40021018 = 0x00000004;
after a few days, it will become tiresome to read and to remember all those addresses. I suggest you to use the header [0] that the ST provides for STM32F1, which is included in packages such as STMCubeF1 [1], STMCubeF0, etc.

For instance, instead of using the memory address directly, you could just do

so it's easier to remember what is what. STMCubeF1 is a big package, but you won't be using the API/drivers ST provides (such as HAL and LL), just the header. As I understand, the STM32 community kind of rejects this API as "bloated".

I have some examples here if you would like to take a look:



[0] https://github.com/dbolgheroni/arm-makefile/blob/master/stm3... [1] https://www.st.com/en/embedded-software/stm32cubef1.html

>but you won't be using the API/drivers ST provides (such as HAL and LL), just the header. As I understand, the STM32 community kind of rejects this API as "bloated".

If you're not making millions of something (cost sensitive), and not running into performance issues with the HAL, just pick a microcontroller with more than enough flash and use the HAL provided by ST. It's faster to develop with, relatively robust, good performance, and it will make your code more portable. Writing directly to registers is the perfect example of premature optimization.

I've spent the last ~7 years writing firmware on the NXP LPC8xx/18xx and the STM32 L0/L4/F7/H7. In that time I've only found a couple of errors in the HALs provided, and only once or twice needed to re-write some HAL code to increase performance. Using the HALs from the vendor saved me an immense amount of development time and made porting code between chips trivial.

    *(uint32_t *)0x40021018 = 0x00000004;

Actually that line is not ok. But for another reason. Without "volatile" in there, the compiler may reorder this access with others, or remove it, or combine it with others. None of that is good.

That's a very important call-out. This is the kind of tear-your-hair-out stuff that's going to be very difficult to track down unless you get it exactly right. I echo that using the definitions makes the code infinitely more readable and writeable, and makes zero difference in terms of performance.

Thanks, I updated the post.

To be fair, the last paragraph of the post mentions CMSIS, which provides proper headers with register names at least.

The HAL is very complete, but a bit hard to read because it supports all the (sometimes very subtle, possibly even undocumented) variations in the STM32 feature blocks. These variations have accumulated over the years.

Edit: also, the STMCube tool is a great help for configuring the chips of that family. It can configure IO pins, function blocks, the sometimes insanely flexible clock tree, generate project skeletons, estimate power consumption, etc... it is actually quite useful.

Curious if anyone has experience with ChibiOS/HAL instead of the ST provided HAL.


Ok, this drives me nuts

ARGH! Seriously? The STM32F103? Crazy (or should that be Craze) hobbyists using "blue pill" boards because they are cheap (and they are, like $3 on ebay) which use this bastard chip of the ST Cortex-M line and they say "gee, its a really simple circuit and since they sell for so cheap on ebay it should be a good idea to use this chip!" BZZZZZZT!

ST Micro makes much better CPUs that would be ideal for this application, they have things like on board DSP instructions in their floating point units, and can run at internal clock rates of 180 MHz with a megabyte of Flash and 384K of RAM, some of it very high performance (core coupled memory). These CPUs are no harder to put onto a PCB than the STM32F103 and they are so much more capable. And sure, they are $10 apiece instead of $1 apiece which is fine if you're making BILLIONS of these things, but a bespoke quadcopter?

Oh but its Open Source, cool, except I can't find the PCB files anywhere, if I could I could pull out that crap chip and put in a real CPU and have OSHPark make me a few. I did find the software repo : https://github.com/Crazepony and yeah, another budget quadcopter maker with a bunch of things they want to sell and an "open source" tag to try to get people to come and look. Fair enough, it made me look. It is sort of the 'freemium' hardware company model.

Sigh. I'd love something bigger than the Crazflie[1] which is like real open source (PCB and everything) and smaller than a DJI Phantom that I could play around with.

Shoot the Crazepony people an email and ask about the PCB design files for their 'open source' quadcopter?

I did one better than that, I shot my ST Micro rep an email and asked them if they would like a open source design on the web that showcased their new STM32F4 series with built in Wireless support and their new STSPIN BLDC controllers with built in Cortex-M0s. He was quite taken with the idea :-)

Quadcopter pilots have been using STM32F3 for years. Check out: https://github.com/betaflight/betaflight one of the more popular flight control projects. They've been supporting STM32F4 and STM32F7 for quite some time.

A typical quad flight controller with an STM32F4 and a decent MPU will set you back less than $30.

Yeah, the same kind of fake "we're Open Source" seems to happen with kickstarter projects fairly often too. eg DoBot. Grrr.

One place which has done it correctly though is Dorna:


They kickstarted (successfully, shipping to their backers etc), now have an online store, and all of the files (both software + hardware designs) are downloadable for everyone. :)

Damn, sometimes reading comments can be soo expensive :-)

Heh Heh Heh. Yeah. :)

Fair enough, my first idea was actually to use MicroPython. With a megabyte of Flash that would have been possible, but 64K is just not enough.

A micropython based flight control system would be a really cool project.

I think it's going to happen sooner that we'd expect, with the OpenPilot Revolution board being considered for a port: https://github.com/micropython/micropython/wiki/Boards-Summa...

hmm, watching your copter crash during Pythons garbage-collection cycle might be an issue....

Python != realtime, flight-control == hard real-time

The interesting difference here is that these things have a bunch of processors on them. So the 'pilot' process can be essentially an interrupt service routine that keeps things sane on an interrupt that cant be masked by the Python code. So during garbage collection your UAV might stop and hover, but it would be unlikely to crash in that scenario.

Further, my experience with Micropython so far has shown it to be pretty fluid. But I would be the first to tell you I haven't challenged it all that much.

Do you want to carry a payload or fly in wind? otherwise, I strongly recommend the Crazyflie, it is a good product with a vibrant community. It has an STM32F405 with FPU that is surprisingly powerful - nontrivial math in the fast control loop is no problem.

I have three of them :-) And I would like something with just a bit more payload. In particular I have been fascinated by the papers on cooperative work by multiple quad copters when driven by a supervising computer vision system.

Little bit off topic, but if anyone is on the fence about STM32, I strongly suggest trying out STM32 Black pill 3.3V version (https://wiki.stm32duino.com/images/5/52/Black_Pill_Schematic...). It's an amazing board, Arduino-compatible, 72MHz, i/o, adc and pwm pins, uart and i2c.

You can get it cheaper and just solder the header yourself. Even has a micro USB support.

Truly remarkable board.

I ordered one from here, if anyone else is looking: https://www.aliexpress.com/item/STM32F103C8T6-ARM-STM32-Mini...

I can't vouch for the product or the seller, but for $2 shipped, the price is right.

I'm not an expert wrt. the clocking of these boards, how does it achieve the 72MHz? In that datasheet it looks like the onboard crystal is just 8MHz.

Does it use some kind of internal clock multiplier to achieve 72MHz? Would such a magnified 8MHz to 72MHz provide a good stable clock?

The clock source is typically generated by a phase locked loop from the external crystal oscillator. There's a PLL multiplier and divider value that you can set obtain the desired frequency.

I think the MCU starts running at a low speed from an internal RC oscillator, and then setting up the high speed clock source happens early in the initialization code. This code can be generated by ST's STM32Cube software, which is useful as a reference implementation even if you don't use the generated code in your project.

As mentioned it uses PLL. The chip boots using the internal 8MHz oscillator, and you can then enable the external crystal using code.

The clock configuration is actually a bit complex, you can see an example from the STM32CubeMX configuration code generator tool here: https://imgur.com/S9L6U37

HS means high-speed and is used for the system clock and peripherals, while LS is low-speed and is used for the real-time clock. Peripherals have limits, like the ADC clock is shown to be 36MHz, but the maximum is 14MHz. The tool is not complaining because the ADC was not enabled for that project. Otherwise I would have to change the ADC prescaler, which take values like 2, 4, 6 etc. Thus had I enabled the ADC, I would have been forced to use a prescaler of 6, making the ADC clock 12MHz, below maximum.

To get the maximum ADC frequency of 14Mhz, I would have to lower the system clock to 56Mhz.

Other peripherals, like USB, also has some strict limits.

Pretty much all clocks in modern electronics above a few MHz are generated by PLL synthesis. The synthesizers are referenced to a slower clock crystal or something along those lines. You can go way beyond just multiplication, as well, with fractional synthesis. Check out the Si5351 for a chip that packs a couple of these synthesizers.


wow, thanks for that..

Looks like a nice write-up!

ST actually sells an evaluation board for learning about drone control; it has a BTLE module, four small FETs, sensors for pressure and a 9-axis IMU, a 1S battery charging circuit, and source code for some example firmware on Github. Search for 'STEVAL-FCU001V1'.

I've also seen a lot of cheap STM32-based FCU boards from the same places you'd get one of these 'blue pill' boards.

These are very useful chips to learn about, because they come in all shapes and sizes. Some focus on power efficiency, others on speed, others on connectivity or signal processing, and there aren't too many differences that you need to account for in your code.

Also, you can program and debug these using OpenOCD with a generic "ST-Link" module; they only cost a few bucks from cheap sources, or many of ST's evaluation boards have a built-in STLink probe which you can use. That lets you connect to the chip from GDB and step through your code like a normal C program, which is often a lifesaver.

The ST-Link interfaces are damned cheap for a debugging interface and pretty reliable, too. They worked better for me than then much pricier IAR probes. There are two versions of the dongle: with and without protective circuitry. The protected one is significantly more expensive (but still cheap), but you should probably go for it if you have a real risk of frying components.

On-chip debugging with OpenOCD was actually one of the next things I wanted to try out with my drone. I need to get an ST-Link dongle because the drone doesn't have one on board.

I'm not sure if JTAG will even work or if they connected a pin to some sensor or similar on the board. SWD will work for sure, I saw the two SWCLK and SWDIO connectors on the board.

Cool, good luck! If you end up wanting a more 'official' STLink probe which is still pretty cheap, the ones on their 'discovery kit' and larger 'nucleo' boards can be disconnected from the main board and used with other targets.

They're a little bulky, but if you're interested in bare-metal programming, the embedded Rust ebook[1] currently uses an STM32F3 discovery kit[2] as a target, and that board's user manual has instructions for using its ST-Link to program/debug an external application[3] like your drone.

[1]: https://rust-embedded.github.io/book/

[2]: https://octopart.com/stm32f3discovery-stmicroelectronics-241...

[3]: https://www.st.com/resource/en/user_manual/dm00063382.pdf (PDF, see section 6.2 for STLink info)

If SWCLK and SWDIO signals are present, there are great chances that SWD will work. In any case, you can control with registers if you want to enable full JTAG, SWD, or nothing, and reuse those pins as you wish.

You can use JTAG probes that implement the CMSIS-DAP (also called DAPLink) protocol, so you get a probe that doesn't need any driver as is seen as an HID USB device. I ran through some problems when trying to use the ST-LINK/V2 with Linux, but that was some years ago and I don't know if things have changed since then.

CMSIS-DAP: https://os.mbed.com/handbook/CMSIS-DAP

Some probes: https://www.adafruit.com/product/2764


I have no idea about the load carrying capacity of the drone, but it would be an awfully cool project to add an ultrasound sensor(s) and write a program for flying it around randomly indoors without hitting walls. A fancy feature might be to solve a real-life maze by flying through it. Would such a thing be possible?

Not ultrasound but at one point in my life I made this: https://www.youtube.com/watch?v=ig8IRTejn8A

(I'm even piloting in this video)

Very cool. Thank you for sharing!

Check out PX4/Avoidance on Github.

Just FYI, I don't recommend charging LiIon or LiPo batteries in parallel, as shown in one of the pictures.

There's a greater risk of fire or just general damage to the capacity of the batteries.

For the small 1S batteries you can get this style of charger for $16 that will charge in parallel: https://www.amazon.com/Happymodel-Battery-Charger-Mobula7-Qu...

But for bigger batteries I recommend buying a charger that can handle 4 or more separate batteries at a time like the SkyRC Q200 or the Turnigy TQ4, or just do like me, charge each battery individually.

STM32 chips are used on a lot of quadcopter flight controllers, often using open source firmware like Betaflight


I am tracking this issue: https://github.com/betaflight/betaflight/issues/5516

I can't wait to see how a STM32H7 will perform on a quadcopter, and what it will allow for :)

Betaflight is oriented towards racing drones, there are a whole slew of open source autopilot firwares available.






Each is oriented towards different types of audiences based on features and license.

Keil has a completely free version of their compiler for STM32F0, STM32G0, and STM32L0 micros: https://www2.keil.com/stmicroelectronics-stm32/mdk

I cannot reccomend against Kiel, iar, and atollic enough. They are garbage ide's (can only do string based auto complete, no dark theme, very poor window management), yet still cost a small fortune if you want to go above 32KB of flash usage or whatever other the free versions do. They also have their version of a linker script which is even worse than normal linker scripts, and if you are forced to use their compiler then often it doesn't even handle c++11. Or if it does have c++, the auto complete doesn't.

Go for gcc or clang with cmake (or even just make) and use qt creator or visual studio code or others. You will get cmake based auto complete, access to a proper IDE color scheme of your choice, get to use your own compiler (clang, gcc, etc), and it's much more flexible. And for debugging be able to use a much more capable ozone from segger, or even gdb enabled backend in qt creator or clion.

My work flow for example is cmake and gcc regarding tooling, qt creator or visual studio code which works with cmake to give me proper context aware auto complete, and clang-tidy as a linter running in the background. I am incredibly productive with this, and am able to make use of c++17's features to go for true zero cost abstractions, while shifting checks from runtime to the compiler via types and static asserts and whatnot.

Plus, this is far more portable. No longer having to worry about project files working across diffirent versions of keil (this bit me in the ass at my last company). It's just a simple text file.

Unfortunately, iffy IDEs are pretty common in the embedded world. I too dislike Keil's uVision IDE, but sometimes you need to take the bad with the good. At work I use Keil + MDK-Pro and now and again also use ETM trace for debugging really tricky problems. AFAIK armcc also produces higher performing binaries than arm gcc (but this probably irrelevant in a lot of use cases).

Yes, gcc and clang are overwhelmingly superior for all purposes.

Let me advise against growing dependent on IDEs. They make it easy to get started, but soon begin to hold you back. Vim, meanwhile, takes some practice, but it repays so much, year in and year out. I have never heard of anyone who learned and then abandoned it.

FWIW, Atollic was bought by ST [0], that IDE is now free, including professional features [1].

[0] https://www.electronicsweekly.com/news/business/st-buys-2017...

[1] https://atollic.com/truestudio/

Atollic TrueSTUDIO is completely free without limitations since ST bought it and it uses GCC and normal linker description files AFAIK.

My personal preference is to use VS Code with the GNU Arm Embedded Toolchain as well though.

With regards to tooling, if you like Visual Studio and are working on ARM processors, I can't recommend VisualGDB enough: https://visualgdb.com/

It's not free ($189), but it removes so much friction from the embedded development process.

I'm not affiliated with the company, just a happy customer.

So does GCC!

I can't help but wonder whether quadcopters will be where governments finally legislate control over general computation. Having access to bare metal means nobody can stop inexpensive and socially-disruptive quadcopter applications. How many years before quadcopters join rats and pigeons as the scourge of urban life, always on the prowl for unguarded power outlets or perches on power lines?

Governments and/or corporations have control of the bottom layer of cell phones and TCP/IP networking. Not so for firmware and cryptography, though not for lack of trying.

Thanks for sharing the article! I think it would make a good addition to my WeeklyRobotics[1] series. Would you mind if I reshare it there?

[1] http://weeklyrobotics.com/

Nice series you got there, I just took a look and found some really interesting projects. I would be honored for my article to be featured there!

I'm glad you found some interesting projects, it means I'm doing some things right!

I'll most probably feature your article in the issue coming out this Sunday or a week after.


What tools did you use to make the drawings in the post? They look great!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact