Home STM32 STM32 HAL How to Control a Servo Motor with STM32 using PWM (HAL + CubeMX Tutorial)

Controlling a Servo Motor with STM32 Using PWM (Step-by-Step Guide with HAL and CubeMX)

Controlling a servo motor with an STM32 microcontroller is a fundamental task in embedded systems and robotics. In this tutorial, we’ll show you how to use PWM (Pulse Width Modulation) to precisely control the angle of a standard servo motor using STM32 and the HAL library via STM32CubeMX. You’ll learn how to configure timers, generate PWM signals, and write simple code to rotate the servo from 0 to 180 degrees. Whether you’re working on a robotic arm, automation system, or DIY electronics project, this guide will help you get started with servo control using STM32 boards effectively.

Controlling a Servo Motor with STM32 Using PWM

This tutorial demonstrates how to control a regular servo motor (0°–180°) using PWM with STM32. It builds upon our previous guide on PWM in STM32, showing one of its most common applications.

Servo motors use internal feedback to maintain precise shaft positions, making them ideal for robotics and automation—such as moving arms, sensors, or rotating objects with high accuracy.

Standard servo motors have three wires:

  • Black/Brown – Ground
  • Red – Power (≈5V)
  • Yellow/White – PWM signal

Related Tutorials:

VIDEO TUTORIAL

You can check the video to see the complete explanation and working of this project.

Check out the Video Below

Introducing Servo Motor

A servo motor is a rotary actuator that allows for precise control of angular position, speed, and acceleration. It uses a feedback system to continuously monitor the shaft position and adjust it based on the input PWM signal. In embedded systems and robotics, servo motors are widely used for moving mechanical parts like arms, sensors, or wheels with high accuracy.

Servo motor

Some of its important features are:

  • Precise Position Control – Can rotate to a specific angle, typically between 0° and 180° or more.
  • Built-in Feedback Mechanism – Uses a potentiometer or encoder to detect shaft position and adjust accordingly.
  • Quick Response and High Torque – Offers fast and powerful movement, suitable for robotic arms and motion control.
  • Simple 3-Wire Interface – Operates using just Power, Ground, and a PWM signal input.

Why should you use the servo motor ?

Servo motors are ideal when you need precise, controlled motion in your project. Unlike regular DC motors, servos allow you to move to an exact angle and hold that position accurately. This makes them perfect for applications like:

  • Moving robotic arms or grippers
  • Controlling pan/tilt mechanisms for cameras or sensors
  • Adjusting valves, levers, or mechanical joints
  • Animating parts in models or mechatronics projects

They are easy to control using PWM, require only three wires, and provide high torque and quick response, making them a go-to choice for embedded and robotic systems.

How the Servo Motor works

Regular servos can go from 0° to 180° depending on the width of the pulse signal. Basically you need to keep the pulse (+5v) high  for a particular amount of time. Some of the important timings are mentioned below.

  •  0.5 milliseconds pulse width corresponds to .
  • 1.5 milliseconds pulse width corresponds to 90°.
  • 2.5 milliseconds pulse width corresponds to 180°.

The period of the PWM signal must be 20ms or we can say the frequency of the signal must be 50 Hz.

As the Pulse increases from 0.5ms to 1.5ms, the Angular displacement increases from 0 to 90°. The motor reaches 90° when the pulse width is 1.5ms. When the pulse width further increases from 1.5ms to 2.5ms, the Angular displacement further increases from 90° to 180°.

Servo motor rotation vs pulse width

STM32CubeMX Configuration

In this section, we’ll configure the STM32 microcontroller using STM32CubeMX. This includes setting up the PWM output using a timer, selecting the appropriate GPIO pin for the servo signal, and adjusting the prescaler and auto-reload values to generate a 50Hz PWM signal. These settings are essential to ensure smooth and accurate control of the servo motor.

Clock Configuration

The clock configuration for this project is shown below.

STM32 Clock configuration
  • External Crystal (8MHz) is used to provide the clock via the PLL.
  • The system is running at 180MHz.
  • I am going to use the TIM2 for the PWM, which is connected to the APB1 Bus (Check this Image).
  • The APB1 Timer clock is at 45MHz right now.

Timer Configuration

The TIM2 configuration is shown below.

STM32 Timer PWM configuration
  • Select the PWM channel for the Timer, I am using Channel 1.
  • Set the Clock source as internal clock, which is at 45 MHz (same as APB1).
  • Pin PA0 is set as the PWM output Pin and we will connect it to the Servo Motor Signal pin.

The output Frequency of the PWM signal depends on 3 parameters, Timer Clock, ARR and Prescaler.

STM32 PWM Frequency formula

Out of these parameters, the Timer Clock will remain constant at 45MHz throughout the project. We want to generate the PWM signal with the Frequency of 50Hz. To do so, I am setting the Prescaler and ARR values as shown below.

STM32 PWM Frequency calculation

Here the Prescaler value is not as important but the ARR plays a very important role. We will see this in details below.

Note that the Pres and ARR input values must be 1 less than the actual values. This is because the library add a 1 to this value at the register level, so we must keep it 1 less than the value we want to pass.

Setting the PWM Pulse Width for Servo Control

The servo motor responds for the pulse width of 0.5ms to 2.5ms. Also the pulse period is 20ms, so in terms of Duty%, the pulse width for the extreme ends can be calculated as shown below.

Calculating PWM Pulse width

Now keeping the above duty cycles in mind, our choice of ARR affects the variations available for the pulse width.

For eg- Let’s assume we choose the ARR of 100.

  • To generate a duty cycle of 2.5%, we need to set the value 2.5 to the Compare Register (CCR).
  • Similarly to generate a duty cycle of 12.5%, we need to set the value 2.5 to the Compare Register (CCR).

This will give us only 10 steps (12.5 – 2.5) of variations between the extreme positions. Each step will result in a large variation in the Angular Displacement of the motor.

Here in the project I chose the ARR value of 1000. The Compare Register value depends on the ARR, so the values for the Duty cycles are as follows:

Calculating PWM Pulse width

This set up will result in 100 steps (125 – 25) of variations between the extreme ends. We will have more variations for the Angular Displacement.

Wiring Diagram

Below is the image showing the connection between the STM32 and the servo motor.

STM32 Servo motor connection

I am powering the motor from the STM32 board itself.

  • Black/Brown ground wire from the motor connects with the Ground of the board.
  • Red power wire from motor connects to the 5V of the board.
  • Yellow or White PWM wire from motor connects to the pin PA0 of the STM32. This is TIM2 CH1, which we have configured as the PWM out pin.

STM32 Code for Servo Motor Control

Initialize the timer in PWM mode to begin generating the signal. In this example, Timer 2 Channel 1 is used to output the PWM required to control the servo motor.

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
while (1)
  {
	  htim2.Instance->CCR1 = 25;  // duty cycle is .5 ms
	  HAL_Delay(2000);
	  htim2.Instance->CCR1 = 75;  // duty cycle is 1.5 ms
	  HAL_Delay(2000);
	  htim2.Instance->CCR1 = 125;  // duty cycle is 2.5 ms
	  HAL_Delay(2000);
  }

Inside the while loop, we will update the timer’s compare register to control the servo angle:

  • First, set the compare value to 25, which moves the servo to .
  • After a 2-second delay, update the compare value to 75, rotating the servo to 90°.
  • Wait another 2 seconds, then set the value to 125, positioning the servo at 180°.

This loop continues indefinitely, causing the servo to rotate between 0°, 90°, and 180°, with a 2-second pause at each position before moving to the next.

RESULT

This section shows the servo motor rotating to , 90°, and 180° based on the PWM signal from STM32. The smooth movement and timed delays confirm that the PWM configuration is working correctly.

0° Rotation

Below is the image showing the servo positioned at 0° when the CCR value is set to 25, basically a Duty Cycle of 0.5ms.

Servo motor at 0° position

90° Rotation

Below is the image showing the servo positioned at 90° when the CCR value is set to 75, basically a Duty Cycle of 1.5ms.

Servo motor at 90° position

180° Rotation

Below is the image showing the servo positioned at 180° when the CCR value is set to 125, basically a Duty Cycle of 2.5ms.

Servo motor at 180° position

Controlling the Angle of Rotation using PWM

As I have already mentioned, the regular servo works between a pulse of width 0.5ms to 2.5ms. This means the servo covers the angle of 180° in 2ms Pulse difference.

We can use this to calculate the pulse width required for each 1° increment in the angle. I have tried to explain it in the picture below

Servo motor angle calculation

So we have the CCR (Capture Compare Register) value of 5.55 for rotation of the servo motor. Please Note that this calculation is done with the ARR value of 10000.

We first need to configure the timer with the new ARR and Prescaler values. Below is the image showing the cubeMX configuration.

STM32 Timer PWM Configuration

Since we have increased the ARR from 1000 to 10000, we need to reduce the prescaler from 900 to 90. This is to make sure that the output frequency of the PWM signal remains 50Hz.

STM32 PWM Frequency calculation

The pulse values also change as per the ARR. Below are the pulse values for the extreme ends.

Calculating PWM Pulse width

For the pulse value of 250, the motor will be at 0° and for the value of 1250, the motor will be at 180°. We can rotate the motor to any angle between between these values, but remeber that the pulse value needs to be higher than 250.

#define per_deg 5.55  //pulse value for 1° Rotation
int main()
{
  ....
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
  int angle = 5;  //5°
  int pulse = 250 + (5*per_deg);  // calculate pulse value, starting from 250
  __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pulse);  // TIM2->CCR1 = pulse
  while (1)
  {}
}

Here we will simply calculate the pulse value for the respective angle. And then pass the value to the Compare Register of the timer. The pulse value of 250 represents the 0° rotation, hence the pulse for any angle will be calculated above this value.

In this tutorial, we learned how to control a regular servo motor using STM32 and PWM. By configuring a timer in PWM mode and adjusting the compare register values, we rotated the servo to 0°, 90°, and 180° with precise timing. The setup was done using STM32CubeMX and HAL libraries, making it easy to replicate. This example demonstrates a practical application of PWM in embedded systems and provides a foundation for more advanced motion control projects using servo motors.

PROJECT DOWNLOAD

Info

You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.

Project FAQs

You May Also Like

Subscribe
Notify of

8 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Andreas
2 years ago

(45 MHz/50 Hz) = 900 KHz. no… its 900k. No Hz.

salih
2 years ago

Hello,
I want to control 2 servo motors. How can I do that? I opened 2 timer but it isnt work.

salih
Reply to  salih
2 years ago

I opened 1 timer and 2 chanlles but isnt work still

mbd
3 years ago

why it doesnt happen when i make timer clock 90 MHz and double prescaler to 1800 -1 and keep arr 1000 -1

shumon
4 years ago

Great post, I think people should learn a lot from this weblog it’s rattling user genial. So much great information on here.

arjun
4 years ago

Hi Great WORK!

mmd
5 years ago

Hi
what a rich site!
tnx a lot
sorry I have a question:
1)is there any usefull sources to learn Stm32 with cube and Hal library with its detail?
I know them to some extent but I want to learn completely
tnx a lot.

keyboard_arrow_up