STM_10: Controlling standard servo

You will learn how to control a standard miniature servo with the STM32 System on Chip. Standard miniature analogue servo is controlled with a PWM signal of frequency 50Hz with a duty cycle period between 1 ms (rotate to 0) and 2 ms (rotate to 180 degrees), where 1.5 ms corresponds to 90 degrees. Some servos have other duty cycle minimum and maximum values, always refer to the documentation.

Do not keep the servo rotating when leaving the lab. Implement your code as non-repeating. A servo that remains rotating for a long time may easily wear out its gears, overheat and even burn!

A servo has a red arrow presenting the gauge's current position.

Note that servos tend to have relatively high implementation inaccuracy. Moreover, as the arrow is not in the centre of view of the camera but instead to the corner, the reading may be subject to error because of the parallaxes and lens distortion.

The servo is an example of a physical actuator. It requires some time to operate and change the position. Please give it time to set a new position between consecutive changes of the control PWM signal. Moreover, because of the observation via camera, too quick rotation may not be observable at all depending on the video stream fps. A gap of 2s between consecutive rotations is usually a reasonable choice.


A good understanding of the PWM signal and duty cycle is necessary. In this scenario, we use built-in timers to control the PWM hardware channels of the STM32WB55 chip. In this case, we do not use any external library; instead, we use the hardware timer library built in the Arduino Core STM32 framework for STM32WB55 (stm32duino)[1] so that no additional external libraries will be included in the project.
Some servos tend to go below 1 ms and above 2 ms to achieve a full 180-degree rotation range. For example, the servo in our laboratory (MG90/SG90) accepts values starting from 500 ms, and ending at 2500 ms. If there is a need for a high accuracy of rotation, it is possible to fine-tune the minimum and maximum duty cycle values.

Suggested Readings and Knowledge Resources

Hands-on Lab Scenario

Task to be implemented

Rotate the servo to the following angles: 0, 90, 180, 135, 45 and back to 0 degrees.

Do not keep the servo rotating when leaving the lab. Implement your code as non-repeating. A servo that remains rotating for a long time may easily wear out its gears, overheat and even burn!


In the laboratory equipment, the servo and the fan are connected to the same hardware timer instance. It means that both elements use the same base frequency of the PWM signal. If you use a fan and servo in the same project the frequency of the PMW signal needs to match the servo requirements.
The hardware timer library implements functions which allow us to control the duty cycle of the PWM signal and express it in different formats, including percentages. In the case of setting the PWM duty cycle expressed in percentages, the minimum value is 0, and the maximum is 100. We can also express the duty cycle in microseconds which is easier to calculate for the servo.


Write your application all in the setup() function, leaving loop() empty.

Do not keep the servo rotating when leaving the lab. Implement your code as non-repeating. A servo that remains rotating for a long time may easily wear out its gears, overheat and even burn!

Step 1

Include Arduino and timer libraries, specific to STM32. The servo is controlled with GPIO PA_10 (the PA_10 name is the STM Nucleo naming convention). Define the pin name constant.

#include "Arduino.h"
#include <HardwareTimer.h>

We will also need some variables:

// PWM variables definitions
TIM_TypeDef *SRVInstance;        //General hardware instance
uint32_t channelSRV;             //2 channel for the servo
HardwareTimer *MyTimServo;       //Hardware Timer class for Servo PWM

Step 2

The hardware timer library uses internal timer modules and allows us to define channels attached to the timer. Channels represent the output pins connected to the hardware elements. Our laboratory board uses the same timer to control the servo and fan. In this example, we will use one channel for the servo only setting the proper PWM frequency of the timer. The channel connected to the servo controls the PWM duty cycle.

Create the timer instance type based on the servo pin:

TIM_TypeDef *SRVInstance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(SERVO_PWM_PIN), PinMap_PWM);
The same timer is used for the fan in the scenario STM_1A.

Define the channel for servo:

channelSRV = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(SERVO_PWM_PIN), PinMap_PWM));

Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished.

MyTimServo = new HardwareTimer(SRVInstance);

Configure and start PWM

MyTimServo->setPWM(channelSRV, SERVO_PWM_PIN, 50, 5); // 50 Hertz, 5% dutycycle.

Step 3

MG 90 servos that we use in our lab are specific. As mentioned above, to achieve a full 180-degree rotation range, their minimum and maximum duty cycle timings go far beyond standards. We will create a function for calculating the duty cycle for the servo with the angle as the input parameter.

void fSrvSet(int pAngle)
  if (pAngle<0) pAngle=0;        //check boudaries of angle
  if (pAngle>180) pAngle=180;
  int i_srv=500+(200*pAngle)/18; //minimal duty cycle is 0,5ms, maximal 2,5ms
  MyTimServo->setCaptureCompare(channelSRV, i_srv, MICROSEC_COMPARE_FORMAT);  //modify duty cycle

Step 4

Rotating a servo is as easy as calling our function with the desired angle as the parameter, e.g.:



How do I know minimum and maximum values for the timings for servo operation?: Those parameters are provided along with servo technical documentation, so you should refer to them. Our configuration reflects the servos we use (MG90/SG90), and as you can see, it goes far beyond the standard servo rotation control that is a minimum of 1000us and a maximum of 2000us. Using standard configuration, your servo won't rotate at full 180 degrees but at a shorter rotation range. Would it be possible to control the servo and fan with the same program?: Yes, but you have to remember that servo has very strict timing requirements. Because both elements share the same timer, they also share the same frequency which must be set according to the servo requirements.

Result validation

Observe the red arrow to rotate accordingly. Remember to give the servo some time to operate.

Project information

This Intellectual Output was implemented under the Erasmus+ KA2.
Project IOT-OPEN.EU Reloaded – Education-based strengthening of the European universities, companies and labour force in the global IoT market.
Project number: 2022-1-PL01-KA220-HED-000085090.

Erasmus+ Disclaimer
This project has been funded with support from the European Commission.
This publication reflects the views of only the author, and the Commission cannot be held responsible for any use that may be made of the information contained therein.

Copyright Notice
This content was created by the IOT-OPEN.EU Reloaded consortium, 2022,2024.
The content is Copyrighted and distributed under CC BY-NC Creative Commons Licence, free for Non-Commercial use.

en/iot-open/practical/hardware/sut/stm32/emb10_1.txt · Last modified: 2024/04/10 19:09 by ktokarz
CC Attribution-Share Alike 4.0 International Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0