Tag Archives: stm32

CAN bootloader for moteus r4.x

One final piece of porting that needed to happen for the moteus controller r4.x series was the bootloader.  The r3.x series has a bootloader, which allowed re-flashing the device over the normal data link, but that was largely specific to the RS485 and mjlib/multiplex framing format.  Thus, while not particularly challenging, I needed to update it for the FD-CAN interface used on the r4.x board.

The update itself was straightforward: https://github.com/mjbots/moteus/compare/406f01…1123a9

For now, on the assumption I will in the not too distant future deprecate the r3.x series, just duplicated the entire bootloader, replacing all the communication bits with FDCAN and stm32g4 appropriate pieces.  As before, this bootloader is designed to only operate after the normal firmware has initialized the device, and also is required to be completely standalone.  To make code size easier to manage, it makes no calls to any ST HAL library and manipulates everything it needs purely through the register definitions.

Thankfully, the ST HAL sources are BSD licensed, otherwise I’m not sure I could have gotten the FD-CAN and flash peripherals to work just given the reference manual.  With it, copying out the necessary constants made for an easy solution.

 

Bringing up the fdcanusb

I introduced the fdcanusb previously, now I’ll describe some of the process and challenges in getting it to work.

Hardware

My initial challenges were around the PCB design and manufacturing.  To begin with, my very first revision was sent out for manufacturing with the same incorrect pinout as the moteus controller r4.0 and thus was only really usable as a paperweight.  Second, the supply of STM32G474 chips seems to be spotty now, so for r2 I had to scavenge chips from the boards that had broken pinouts.

The r2 boards did have a DB9 pinout that was not industry standard, this time due to Eagle’s DB9 footprint being broken, but that will be easy enough to fix in r2.1.

Software

The software had three things that needed to work, FDCAN, USB, and the finally all the glue logic.  Getting FDCAN to work was remarkably easy:  I just used the STM HAL APIs and was basically done.

USB was harder.  The last time I made a virtual serial port for the STM32, the mjmech gimbal board, I used the STM provided CDC libraries.  However, those are released only under a rather restrictive license, confusingly named the “Ultimate Liberty Software License Agreement”.  Despite the claims in the title, you actually have very little liberty, in that the software can only be used on STM controllers and has notice provisions as well.  As with the rest of the moteus universe, I wanted to be able to release this firmware under a permissive license so needed to look elsewhere.

Github and google found a number of candidates, and the one that I ended up starting from was dmitrystu/libusb_stm32.  It was already licensed under the Apache 2.0, and supported controllers which looked like they would be very similar to the STM32G4.  Sure enough, the STM32L433 has an identical USB peripheral and was already supported.

I ended up forking that repository into the fdcanusb one and modifying it slightly to be usable with C++ and mbed.  Also, interestingly, the CDC demo used the same endpoint for RX and TX, which the linux drivers didn’t seem to like so I just gave them separate endpoints like I’ve done before.  I then implemented a wrapper for the CDC class which presents the same asynchronous serial interface as everything else in mjbots/mjlib and was set to go.

The final piece of the software was all the glue and application logic.  I just used PersistentConfig and CommandManager from mjlib, which gave a human readable ASCII interface out of the box.  Then I wrote up the application logic in CanManager, which didn’t have to do much at this point.

Next steps

In its current state, the fdcanusb firmware is capable of communicating with the moteus r4.X series controllers just fine.  Next I’ll get a few more made to distribute with moteus development kits and see if there is any more demand for them.

 

fdcanusb

One of the necessary pieces for bringing up the moteus brushless controller and for ongoing development with it is being able to communicate with the device on the desk.  There aren’t many options for desktop FDCAN communication currently, and certainly none that are in the affordable range occupied by the CANUSB family of devices which I’ve used before and was very happy with.  Thus I created “fdcanusb”, a USB to FDCAN converter that allows one to communicate with FDCAN devices via a USB interface using a documented protocol, no drivers necessary.

The notable features:

  • USB 2.0 full speed host interface
  • ISO 11898-1: 2015 FDCAN interface on industry standard DB9 connector
  • Standards compliant bitrates up to 1/5Mbps supported
  • Software controllable termination
  • Frame sizes up to 64 bytes
  • Non-standards compliant bitrates allowed
  • Documented CDC ACM based host protocol (virtual COM port)
  • Apache 2.0 licensed firmware based on the STM32G474 controller

All for an expected sales prices of around $100.

This does come with some caveats: For one there is no galvanic or optoisolation, you get a common mode range of around +- 12V.  Another is that using just a USB 2.0 full speed interface means it may not be able to keep a FDCAN bus fully saturated at high bitrates.  Finally, the firmware will start out with just the bare bones capabilities, but can be extended to support features such as error injection, triggers, buffering, and more compact protocols in the future.

I’ve got the first functioning prototypes of these boards in hand now:

fdcanusb_r2
PCB render
dsc_2026
Set up for test

Next up I’ll describe bringing up this board.

More adventures in STM32G4 bringup

Last time I had an actually hard problem…, a mis-aligned stack which caused randomly misbehaving software.  This time, I had a more prosaic problem.  One that while not necessarily as interesting, was even more time consuming and frustrating.

The serial port wouldn’t work.  I had copied the module I used for DMA based receive and transmit from the STM32F4 and it just wasn’t working.  Nothing was written and nothing was received.  I carefully inspected the software many times.  I looked at the registers in the debugger and nothing seemed obviously amiss.  I read the datasheet to look for subtle differences in the theory of operation between the STM32F4 and STM32G4 but came up empty.

Eventually, I went completely out of the box and compiled one of the STM provided UART examples from STM32CubeMX.  That did work!  But how?  I once again carefully inspected its source and mine and saw no obvious differences.

Then, I took the ultimate slow path in debugging and binary searched, gradually transforming the STM provided example into my code half by half to figure out which transformation was the ultimate cause.  This did do the trick.  The final fix:

-  huart_.Init.WordLength = 8;
-  huart_.Init.StopBits = 1;
+  huart_.Init.WordLength = UART_WORDLENGTH_8B;
+  huart_.Init.StopBits = UART_STOPBITS_1;

That’s it.  In the old version, I passed in to the HAL the word size and number of stop bits as integers.  Somehow this actually worked, despite being documented as requiring the necessary #defines even in that version.

Notch another win up to: “it sure would be nice if there was less undefined behavior in C/C++”.

Adventures in bringing up the STM32G4

In my continued quest to bring up the STM32G4 for the moteus controller r4.1 and other efforts, I get to discover and learn about the million and one ways in which things don’t work on my path to find the one or two ways in which they can work.  I recently had an interesting enough problem that it is worth it to signal amplify google searches on the matter for the next unfortunate soul.

First, the symptom: snprintf of 32 bit floating point values gave seemingly random results.  The diagnostics and configuration functions of the moteus controller can in some modes render values into ASCII for human readable interactions.  In this particular instance, I was enumerating the full set of configurable values and saw that all of the floating point values read bogus values, like “0.00000”, “-0.00000”, “2.00001”, etc, no matter what actual value they were set to.  Integral types seemed to work fine, and the debugger showed that parsing floating values when setting the configurable values was working just fine.

I had a similar problem not too long ago, when a linker script mis-configuration resulted in an overlap between the RAM based interrupt vector table and the first few global variables resulted in state necessary for C library functions being corrupted during early boot.  Thus, I began investigating under that assumption.  However, the linker script definitely had enough room (I allocated 0x200, where the datasheet shows that the final entry is only 0x1c4).  Just to be sure it wasn’t some other global memory corruption issue, I stepped through the first 5,000 or so assembly instructions of an snprintf call, inspecting all RAM that was accessed and making sure that it wasn’t corrupted.  I did notice that my 32 bit floating point value had been promoted to a 64 bit value when passed to snprintf, but didn’t think any more of it at that point.

Despite all that debugging, I found nothing of interest and turned to my choice of last resort, googling for the original symptom.  Usually this doesn’t find much, because the set of root causes for any one particular failure is so vast and many problems are the result of simple misconfiguration.  However, in this case, I hit the jackpot after digging through an hour worth of junk results.

The problem ultimately was one of stack alignment.

When I ported mbed to the stm32g4, I created the initial linker script from the STM32F446 that I had been using, but made the interrupt table bigger so that I wouldn’t have to worry about it at all.  However, I managed to goof it up and ended up with the top of the stack aligned only to 4 bytes, not 8 bytes.  Since 32 bit floats are promoted to doubles when passed through a variadic function, this resulted in the double being not 8 byte aligned when passed on the stack.

Once the problem was identified, the fix was easy enough:

moteus controller r4.1

Another step in my plan for the next revision of the moteus servo mk2, is an updated controller board.  As mentioned in my roadmap, I wanted to revise this board to make improvements in a number of domains:

  • Communications: Now instead of RS485, the primary communications interface is FD-CAN.  This supports data rates of up to 8 Mbit and packet lengths up to 64 bytes.  The header is nominally at the original CAN bit rate, but I have no need to be standards compliant and am running very short busses so I may run everything at the higher rate.
  • Connectors: Now there exist power connectors, in the form of XT30 right angle connectors and they are also daisy chainable like the data connectors.  Additionally, all the connectors exit from the bottom of the board to make routing easier in configurations like the full rotation leg.
  • Controller: This uses the relatively new STM32G4 controller series.  It is lower power than the STM32F4, supports FD-CAN, and also supports closely coupled memory, which may allow me to improve the speed of the primary control loop execution by 3 times.
  • Voltage range: This board now has 40V main FETS, with all other components at 50V rating or higher.  Thus it should be safe with inputs up to 8S (34V or so).
moteus_r41
moteus r4.1 rendering

It still maintains a number of the capabilities of the moteus r3.1 controller:

  • Integrated FOC encoder: An AS5048 encoder is mounted in the center of the back, which allows direct mounting above the rotor for FOC control.
  • Form factor: The entire board is 45x54mm, with M2.5 mounting holes.  It is smaller than a 60mm BLDC motor and much smaller than an 80mm one.
  • Integrated current sensing: It uses a DRV8323 to drive the FETS, which includes current sensing for closed loop current control.

My first attempt at this, “r4”, came back from fabrication in an nonredeemable state.  I used the digikey supplied footprint for the STM32G4 UQFN part, which looked mostly correct on the surface.  However, while the footprint was good, the pinout was for the TQFP variant!  This resulted in me shorting out several power pins to ground right next to the exposed pad in a way I couldn’t easily rework.

r4.1 seems to be in better shape so far.  It powers up, and I now have blinking lights!

dsc_1958
moteus r4.1 as built

Next up is actually porting the control software to the new controller and communications interface.

Bringing up FD-CAN on the STM32G4

To verify that I could make FD-CAN work in the next revision of the moteus controller, I made a simple desk setup between two NUCLEO-G474RE boards.  I started by soldering up some breakout boards for the TCAN334G CAN transceiver I’m planning on using:

dsc_1549

dsc_1553.jpg

And then wired those up with a lot of jumper wires:

dsc_1555

After a fair amount of fiddling, bisecting against the ST CUBE example project, and fixing some problems with my STM32G4 support in rules_mbed, I ended up with some 16 byte CAN frames being sent and received with a data rate of ~4Mbit.

whole_frame
A whole frame
single_bit
A single bit within the data part of the frame

STM32G4 for mbed

While working on the next revision of the moteus controller, I started by bringing up a software toolchain on a NUCLEO-G474RE board.  Unfortunately, even the most recent mbed 5.14 doesn’t yet support that processor.  Thus, I have a half-baked solution which pulls in the ST CUBE sources for that controller into the mbed tree as a patch.

https://github.com/mjbots/rules_mbed/blob/master/tools/workspace/mbed/stm32g4.patch

The patch only implements wrappers for the things I care about, so it isn’t a complete solution. Since I am not really using any mbed libraries anymore in any project, that isn’t a whole lot.  Right now I’m just using it for the one function that sets up the board, a linker script, and the pin mappings.  I will probably eventually just make a rules_stm32 and ditch mbed entirely but for now that is more work than it is worth.

 

OpenOCD for STM32G4

While bringing up an STM32G4 for the new revision of the moteus controller, I wanted to be able to flash and debug the system, and thus needed a working OpenOCD installation.  The NUCLEO-G474RE board has an ST-LINK-V3 debug interface, which no released version of OpenOCD supports, although thankfully that is working just fine at HEAD in git.  However, to make the STM32G4 work I had to pull some patches from the sysprogs/openocd tree.

My resulting work can be found at: https://github.com/mjbots/openocd

Hopefully the dependent OpenOCD gerrit review will eventually land: http://openocd.zylin.com/#/c/4932/ which will clear the way for getting G4 support into master there.

For now, I’ll just live with a custom compiled OpenOCD.

 

rules_mbed – bazel for mbed

When working on the firmware for Super Mega Microbot’s improved actuators, I decided to try using mbed-os from ARM for the STM32 libraries instead of the HAL libraries.  I always found that the HAL libraries had a terrible API, and yet they still required that any non-trivial usage of the hardware devolve into register twiddling to be effective.  mbed presents a pretty nice C++ API for the features they do support, which is only a little less capable than HAL, but still makes it trivial to drop down to register twiddling when necessary (and includes all of the HAL by reference).

Most people probably use mbed through their online IDE.  While this is a remarkable convenience, I am a big fan of reproducibility of builds and also of host based testing.  mbed provides mbed-cli which gets part of the way there by letting you build offline.  Unfortunately, it still doesn’t provide great support for projects that both deploy to a target and have automated unit tests.  It actually has zero support for unit tests that can run on the host.

Enter bazel

As many have guessed, I’m a big fan of bazel https://bazel.build, for building software projects.  Despite being raw around the edges, it does a lot of things right.  Its philosophy is to be fast, correct, and reproducible.  While it doesn’t support flagless multi-platform builds yet (#6519), it does provide some minimal multi-platform support.  It also has robust capabilities for pulling in external projects, including entire toolchains and build environments.  Finally, it has excellent support for host based unit tests.

To make it work, you do have to configure a toolchain though.  That I’ve now done for at least STM32F4 based mbed targets.  It is published under an Apache 2.0 license at: https://github.com/mjbots/rules_mbed

rules_mbed features

  • Seamless toolchain provisioning: It configures bazel to automatically download a recent GNU gcc toolchain from ARM (2018q2).
  • Processor support: Currently all STM32F4 processors are supported, although others could be added with minimal effort.
  • Host based testing: Common modules that rely only on the standard library can have unit tests run on the host using any C/C++ testing tools such as boost::test.
  • Simultaneous multi-target configuration: Multiple targets (currently limited to the same CPU family) can be built with a single bazel command.  Multiple families can be configured within the same source tree.

Once you have it installed in a project, building all host based tests is as simple as:

tools/bazel test //...

and building all binary output files is as simple as:

tools/bazel test -c opt --cpu=stm32f4 //...