SimpleFOC BLDC Motor Drivers

Several months, ago, I stumbled across the “Smartknob” project by ScottBez1. The idea is really interesting and quite captivating for people who love interfaces. In essence, a magnetic encoder is used to sense the rotary position of a knob. However, the knob is actually a small motor- a special type called a brushless DC motor “BLDC”. Because it’s a motor, we can drive it towards or away from points – both continuously and discretely – to provide ‘haptic textures’ and user feedback. So, this opens up many doors to different user experiences- springing knobs, clicky, knobs that keeps spinning after you let go- very cool things.

A benefit of brushless motors is that there are no contacting parts like the carbon brush on brushed DC motors. However, in order to create the commutation pattern without a brush, it requires both more complex construction (three magnetic phases) and electrical control. A benefit of this increased complexity in the design phase is that the efficiency of BLDCs is considerably higher, especially so for complicated control schemes like Field Oriented Control (FOC).

The most primitive way to drive a three-phase BLDC is something called 6-step. In this control scheme, two of the three phases are turned on at a time, with all of the phases staggered. This has the effect of creating a magnetic torque which drives the motor in one direction or the other. By switching which phases are on, or by swapping two of the phases, you can change the direction of the motor. However, this is not the most efficient way to drive the motor.

Mathematically, it turns out the most efficient way to do this is using sine waves, where all of the phases are separated by 120 degrees – so called Field Oriented Control. However, creating these drive signals is complicated because the frequency is dependent on the velocity and other factors. Thankfully, a group of people have written an Arduino library called SimpleFOC which allows you to easily implement the motor control algorithm with a variety of control schemes (torque, velocity, angle). This library can be implemented on arbitrary hardware as long as some criteria are met. I thought this would be an interesting time to explore using some chips that I wanted to get more familiar with.

Additionally, at this point I was working with some offshore manufacturing for work. I had been involved with quality and manufacturing review of PCB assemblies and board-stuffing. I got curious about this and decided to try and see if I could get the assembly services provided by some of the cheap Chinese boardhouses working.

EASY-ESC (RP2040)

This was the first board that I developed for work with SimpleFOC. This board also can’t be used for “true” FOC as it is not encoded – all the motor control is open loop. However, this served as an interesting introduction into working with the library and using the new-ish RP2040 chip from Raspberry Pi. This board was only partially assembled – I manually placed the TMC6300 motor driver, as well as the connectors and capacitors. The nice thing about the rp2040 is that it is dual core- so you can run the motor algorithm self contained on one core, and on the other you can run display or networks tasks for various applications. Working with this chip is really great- the datasheet is very thorough and it’s very easy to find the peripherals to map things out to. Routing is also very easy for this chip. The biggest benefit to me was the lack of need for a programmer. Unlike STM32, the rp2040 comes with a USB bootloader and can be flashed directly over USB using pico-tool. To re-flash, you can just press the reset and boot buttons at the same time. The biggest downsides to working with the RP2040 is the high external parts cost. It requires external flash (which I wired wrong and had to bodge together) as well as a number of other pullups and crystals and what have you. I do like the cost at just about $1. This was also my first board designed using 0402 parts (since I wasn’t doing the assembly by hand!)

Github and project files

STM32F103-NCP81155-MT6701

What a mouthful, right? This was the second board that I made for use with SimpleFOC. This one was an effort in BOM optimization- I tried to strictly use parts from the JLC basic parts library, and for the most part have succeeded. The main MCU is now replaced with an STM32F103, which is a basic component at JLC. Although many STM32 chips do not require a crystal, this one does- it is a fairly old design and has some quirks (like requiring a 1.5k pullup on D+ in order to be detected on a USB port). I also ditched the integrated TMC6300 driver for a fully discrete design: using 3x MOSFET gate drivers NCP81155 driving 2x AO3400A MOSFETS (also in the basic library). This works but did not provide any obvious advantage other than being cheap, although the price you pay in board footprint is pretty significant. This board also was designed for support of current-sense amplifiers but due to cost restrictions on the design I did not populate them, although they are there. This one also is encoded, using the not-that-cheap-but-cheaper-than-most MT6701 from MagnTek. This is a really weird magnetic encoder that features ABZ output for emulating traditional UVW style optical encoders, but also has a serial interface (both SPI and I2C) for digital readout. I was planning to use the ABZ output but also tried to mangle together some hardware so that I would be able to access both serial busses- this did not work. In the end, I had to settle for just I2C. On arrival, it seems that the default resolution for the ABZ is incredibly poor- 2ppr ! This is not enough to do any meaningful closed loop work. However, I could not program the registers in order to access the higher ABZ resolution- this chip has a weird quirk that the I2C registers can only be programmed if you are using a 5V Vcc for the chip – so this is locked to read-only for now. Outside of this, board bringup for this was pretty straightforward and I am happy with the results.

To my surprise, there actually is no I2C driver for the MT6701. I have modified the SimpleFOC code to add my own- you can find it in the lib folder of my project on Github.

Part of this project was to start working on a hardware platform that would support connecting multiple motors together, and then unifying them under a PC interface. The code for this has been started and is also located in the same repo but will probably get moved out to it’s own eventually.

Github and project files

AIOLI-FOC

Third time is the charm right?

This is my latest rev of boards in this project. This one is probably the closest to what I actually need out of the hardware. Funny enough, I did not go into this project expecting for it to be the cheapest board, since I was targeting that in the STM32F103 board, but due to the lower parts count for this one, it actually ended up being cheaper!

This board features the newly-cheap STM32G431 which is a microcontroller that is favored for motor control and has a huge host of great peripherals, including built-in CANbus, USB DFU bootloader, crystal-less USB, and no need for external flash on board. I am keeping the same MT6701 magnetic encoder from the board, although this time I kept it simple and just wired it for SSI mode (similar to SPI). This should give good performance and make routing a lot easier. However, instead of going with the full triple discrete driver design, I found a part between the TMC6300 and the NCP81155 + AO3400A, which is the STSPIN233. This is not a 6-PWM driver like the TMC6300, but instead is very similar to the 3PWM 3EN drive that I was using on the STM32F103 project. Only needing a single chip for the driver was great and simplified both the parts count and cost and made routing easier.

I also included a CAN transceiver so that the boards can be linked together in order to create a network of drivers. The idea is that they will all connect to each other over CAN, but then the node on the end will connect to the PC via USB and that will provide the translation from the two networks. There also is a set of FPC pads available to solder on a GC9A01 TFT display if desired- maybe I will do this, maybe not- I have not decided.

Something I decided to do for this board was also to migrate to a 4-layer PCB. This was my first 4-layer design, but after reading about some design rules online, I found it very intuitive to route and produce production files. The stackup I have seen recommended most is:

  • Top Signals + ground pour
  • Ground pour
  • Vcc pour
  • Bottom signals + ground pour

This made routing so so so easy and for small boards, it does not increase the production cost at all over 2-layer! I will be sticking with this in the future for the benefits of a distinct ground plane and routing ease.

Note: While this chip supports crystal-less USB, I still left that and the STLINK connector on in case anything goes wrong in prototyping. If this board was to ever hit production, I would probably take those off to save board space.

Note Note: I found this great KiCad and Blender plugin to do this amazing board render.

Github and project files

SimpleFOC hardware requirements

Designing driver boards for compatibility with SimpleFOC is pretty straightforward. There are a few basic things:

Microcontroller

The microcontroller selection can make a big difference. Something modern should be picked, which has at least a few hardware timers that are available for PWM generation. It also helps to have a high clock speed and hardware peripherals as well – anything that can give you more time in the main loop running the motor control algorithm.

For STM32 mcus, setting them up is very easy. You can use the configurator like STM32CubeMX to select your chip, then just enable all the peripherals that you need. This will give you a pinout that you can start using in schematic capture that you know will work later when you start working on the firmware. CubeMX also lets you tinker with the clock tree, which can let you get very high peripheral and base clocks from internal or external sources. However, since the SimpleFOC library is written for Arduino, we will use the STM32_Arduino compatibility HAL (in PlatformIO) so we will not be writing any code inside CubeMX or CubeIDE.

For this library, STM32 seems to be the most popular choice for motor control. Classic Arduino chips, like the ATMega 328P do not have enough power to really even run a single instance of SimpleFOC, or will run it with very poor performance. On ESP3w, the MCPWM peripheral is a bit dated for some reason, and the newer C3 does not have it at all. It will still work but the performance is lower, although having the second core does help a lot for running additional application code. On RP2040, it just seems this platform has not gotten much love yet. The microcontroller is good, although the built in ADC has very poor performance, so it may not be good for applications which require current sense. However, low power motors like the ones I intend to use for this project do not require any current sense so depending on your application it may not be an issue. The RP2040 also has two cores.

Motor driver

The motor driver is a key part of getting good performance from your board. However, at lower power levels, it does not seem to be particularly important which driver you pick. I have tried fully-integrated and fully-discrete designs and for low powers (< 1A) it does not matter. However, if you are targeting higher power motors then this can cause a lot of issues for you. I would recommend asking on the SimpleFOC community forum about recommended drivers for different power levels.

I like the STSPIN233 as it is fully integrated, very cheap ($0.70) and easy to route out. I will likely be sticking with this for the foreseeable future.

Encoder

There are many different encoder types- you could use triple hall-sensors for UVW sensing, or optical disks, or magnetic sensors. I like the magnetic sensors because they give you higher resolution than the hall sensors, and they are compact and don’t require any mounting hardware, like optical sensors.

The MT6701 has some pretty weird quirks, but is not too hard to work around. It is 12-bit but there is a bigger 21-bit big brother, the MT6835, which is also substantially more expensive. There are a few other companies which make magnetic sensors but I have not tried any of them. The only thing that is really important is that you have a hardware driver for whatever type of sensor you plan to use- the reads need to be quick and reliable – you cannot bitbang for this purpose. However, MagnTek is located in China and it seems difficult to find their chips outside of there. If you are building boards with the intent to build them yourself sourcing from Mouser or Digikey, I would avoid them.