STM32 BLDC Motor Control

Introduction

ST offers quite a broad BLDC controller portfolio, but the most interesting to me seems the STSPIN family of controllers. They include mostly anything except the MOSFETs to drive a BLDC, including a ST32 Microcontroller, a DC/DC-Converter (with external passives), the MOSFET drivers,…

Steps of designing a BLDC control circuit with STM32

First step is to find one or some BLDC motors for your specific need. The available motors range from cheap no-name motors (~4000 rpm) to high performance high turn ratio (>60000 rpm) and from a few watts up to kilo-watts of power. For CNC applications, you can find HF spindles with 2200W and 30000 rpm.

When you have your BLDC, it’s time to find the right controller for your application. When you go with STSPIN, you should think about getting the STEVAL-SPIN320x for prototyping your application, but additionally, you should always get the NUCLEO board with an appropriate BLDC driver hat. Why? Because the STM Motor Profiler Tool only runs with a few specific boards. To find the right board, install the ST Motor Control SDK and open the Motor Profiler Tool. Then you can browse through the supported kits to do Motor Profiling.

For further hands-on example, I will use a „Generic BLDC Motor“ with very poor documentation and quite low performance. It looks like a stepper motor and has the following (known) performance characteristics:

  • 8 pole pairs
  • 4000 rpm
  • 24V

We also measures some characteristics that have not been given by the specs, most important: The winding resistance. Set your power supply to current limiting mode with approx 5% of the nominal current of the motor. Then connect it to two wires of the motor. In our example, the power supply showed 0,36V / 0,3A = 1,2 Ohms, this gives, taking the circuit of three windings in star configuration (we have a simple series configuration of two windings) into account, 0,6 Ohm (1,2 Ohm / 2 = 0.6). Applied with above power, you can easily determine the pole-pair count by turning the shaft a full turn counting the ripples, you should feel the while turning. It will be easier to use a pen to mark the positions. Apply the power only for a minute, otherwise, you could damage the motor…

With above data, you can select the appropriate BLDC controller board. For smaller motors, the X-NUCLEO-IHM16M1 should serve well. For larger types, the X-NUCLEO-IHM08M1 is a good choice. But always be aware, that for every power hat board, there is only a limited set of compatible nucleos.

To be continued…

STM32 UART Continuous Receive with Interrupt

My last post is quite some time ago, due to vacations and high workload. But now I encountered some problem within an embedded project, I want to share the solution with you. Continuously receive data using interrupts on UART is complicated (or even impossible) in HAL. Most approaches I found crawling the internet are using the LL library to achieve this and many discussions around HAL do not end in satisfaction. Some work around the problems with dirty approaches (e.g. changing the HAL code itself), other step back from interrupt and use a polling approach.

To be honest, the high levels of HAL do not offer such a solutions. Instead, it offers functions to receive a special amount of data using a non-blocking interrupt approach, handling all the difficulties with tracking the state in the instance stucture (huartX) and entering a callback for the diverse states of the reception/transmission, e.g.
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) or
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)

Using HAL_UART_Receive_IT (not recommended)

A nearby approach without touching HAL code itself is, to call HAL_UART_Receive_IT(&huart3, &rxbuf, 1) once after initalization and at the end of the RxCpltCallback, to retrigger the reception, but this leads to some undesired lock (possibly a HAL-Bug), when transmitting data using HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size), which could also not be the desired behaviour and the beginning of endless debug sessions and frustration.

Simply Enable the IRQ

The best solution in my opinion instead is really simple. Don’t use the high level receive functions at all for the continuous RX behaviour, since you do not want to receive a special amount of data but be called at each reception. So, configure the UART with interrupt in CubeMX and after it’s initalization, enable the interrupt itself, never calling the HAL_UART_Receive_IT or any other UART receive function (it will disable the IT after finishing).

In the section of the appropriate instance in void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle), add the following line of code:

__HAL_UART_ENABLE_IT(&huartX, UART_IT_RXNE);

In stm32xxx_it.c do:

void USART3_IRQHandler(void)  {    
    /* USER CODE BEGIN USART3_IRQn 0 */
    CallMyCodeHere();
    return;  // To avoid calling the handler at all 
             // (in case you want to save the time)
    /* USER CODE END USART3_IRQn 0 */
    HAL_UART_IRQHandler(&huart3);
    /* USER CODE BEGIN USART3_IRQn 1 */
    /* USER CODE END USART3_IRQn 1 */ 
}

The return statement will avoid calling the HAL IRQ handler. I did not try during transmit, but it seems not disturbing anything. If you plan to use the HAL_UART_Receive_IT functions in parallel, you could try to put your code below the handler. I did not test it, but there is a good chance that it works.

Since this approach only touches the user code functions, none of your code will be destroyed by code re-generation of CubeMX.

This is all you need… Happy UART processing 😉

If Timestamping is Needed

Simple Millisecond Timestamps

If you want to trigger on inactive time durations (some serial protocols use it as a synchronisation condition), save a timestamp (e.g. HAL_GetTick()) within the UART-RX-Interrupt and look at the difference to the previous one (subtract the duration of a byte to get the real inactive time).

High Resolution Timestamps

If sub-milli-second resolution is required, run a timer with a prescaler of desired resolution and take the counter value of the timer instead of the tick counter. (you can get it with __HAL_TIM_GET_COUNTER(&htimX)).

Hope this helps in your next project using UART 🙂

Getting Started Embedded – Part I – The Toolchain

Introduction

For getting started with any embedded development, the most important piece is the toolchain.

Many people suggest to use Keil, IAR, or some other fancy, professional, rocket-sience (and very expensive) IDE. In my opinion, that is just rubbish.

In former days, when tiny embedded controllers just have not been designed with compilers in mind, it was good to have some highly optimized compilers that could transfer a piece of C code to the ASM of these devices.

Nowadays, processors are designed with compilers in mind. Therefore, I would highly recommend to use GCC not only because of its low price tag (0 $), but because of its stunning community and active development. Since the community and many companies still putting so much effort into this piece of software, no single company can compete with an own closed source product.

Installing the ARM toolchain

There are many possible sources, where you can get GCC and all the tools you need to start. You can compile ARM-GCC yourself using your platform GCC, download the one from ARM directly, take a release from GNU MCU Eclipse and many many more…

Don’t know what to do? Just get kickstarted, and give XPM (a node/npm module) a try. Download and install node.js. The version does not matter too much. If you are not developing with node.js itself, better stick to the stable version.

When node.js is installed, install xpm and the ARM GCC toolchain (same for Windows, Linux & macOS):

me@diggerVM:~$ npm install xpm
me@diggerVM:~$ xpm install --global @gnu-mcu-eclipse/arm-none-eabi-gcc
me@diggerVM:~$ arm-none-eabi-gcc -v

OK, that was easy… If this worked, you maybe need some supporting tools. Best practice differs a bit, depending on your platform. For Linux, just install the build-essentials package (Debian dn ubuntu call it like this).

me@diggerVM:~$ sudo apt-get install build-essentials

For Windows (would also work for Linux, but I prefer the OS provided package), you can use xpm again:

C:\Users\me\>xpm install --global @gnu-mcu-eclipse/windows-build-tools

After this has finished, you possibly need to add the build tools to your PATH environment. You will find it in %APPDATA%\xPacks\@gnu-mcu-eclipse\windows-build-tools\2.11.1-1\.content\bin.

Testing your Toolchain

To test your setup, just clone, download,… the STM32 example project. Open a command line prompt, cd to the project directory and fire make:

me@diggerVM:~/GIT/stm32-example$ make

If this worked without errors, you have your toolchain up and running. Congratulations!

What’s next…

The next post will explain, how to setup STM32CubeMX and the Eclipse IDE to start developing own embedded applications effectively. Until now, there is not much difference to commercial IDEs and Toolchains from a workflow point of view. But don’t worry, we still have automation in mind and the goal is to have a CI-Pipeline running soon.