We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

Showing results for 
Search instead for 
Did you mean: 

Adam Taylor’s MicroZed Chronicles, Part 167: Interfacing to Servos – Generating PWM signals in software

Xilinx Employee
Xilinx Employee
0 0 42.1K


By Adam Taylor


Last week we explained how the servos we will be using worked and completed the hardware build in Vivado to control the servos with the TTC (triple timer/counter) in the Zynq SoC. All that remains now is to write software to configure the TTCs to generate the servo-control waveforms.


Within the hardware definition we included all the TTC components, breaking out all the wave outputs to EMIO pins in the Zynq SoC’s PL (programmable logic). So, when we look within the xparameters.h file, we find all of the device ID’s:





Definitions for TTC0 and TTC1 in the xparameters.h file



The software architecture we are going to follow will be a simple interrupt-based system. We need an interrupt-based system to ensure that we can drive the connected servos independently. If we don’t use an interrupt-based system and instead base our design on delays—like usleep provided by unistd.h—then the system won’t be adequately responsive. We must drive the servos independently if we want to anything remotely useful with them (e.g. steering and speed control).


We will structure the program as follows:



  1. Initialize the number of TTC’s we wish to use in our design. For this example we will use two.
  2. Set up both TTCs to generate a 50Hz waveform. We can control the generated waveform’s duty cycle using the match register.
  3. Configure the Generic Interrupt Controller (GIC) and enable both the match and interval interrupts for each TTC used.
  4. Write the interrupt service routine to be called for each TTC when an interrupt occurs. Each ISR will:
    1. Read the TTC Interrupt status register.
    2. If the interrupt source is an interval interrupt, then update the match register value to the desired position value to update the servo position.
    3. Clear the Interrupt Status.



For this simple example, each ISR will move the servo between its extreme positions and neutral. To do this, we need to change the waveform duty cycle for that servo during the ISR. The wave out signal for a TTC changes polarity when it matches the value contained within the match register, assuming the wave out is not disabled in the timer options. We can use the options to define the initial polarity as well, providing granular control over the wave out behavior. For us to move the servo between extreme positions and neutral, we need pulse widths between 0.5msec and 2.5msec with 1.5msec being the servo’s neutral position.


From last week we know this equates to either 2.5%, 7.5% or 12.5% of the 20msec waveform. We use the XTtcPs_CalcIntervalFromFreq()function, which takes the desired frequency and TTC clock frequency declared in the xparameters.h to determine what the interval and pre-scale of the TTC.


With this calculated we then apply these to the TTC and set it running once we have enabled the interrupts. To generate the correct pulse widths for the servo positions, we need to know the interval count and then we use that to set the pulse width accordingly. We can determine what the interval is one of two ways. In our application, we can use the XTtcPs_GetInterval() function or we can directly access the timer set up structure.


With the code written we can see that the interrupts for both servos in this example are handled independently of each other, allowing each servo to move to a different position as commanded.


Connecting a Digilent Analog Discovery to the two servo outputs, you can see the different pulse widths both repeating at 20msec (50Hz). The top trace shows the 1.5msec neutral-position value while the bottom waveform shows the extreme 2.5msec position.








When I connected this code to the servos, I recorded the following simple video showing the servos working as expected.





Having done this, we now understand not only how to drive simple servos but also, and just as importantly, how we can use the TTC to generate a PWM (Pulse-Width Modulated) output. Within embedded design, the ability to generate PWM waveforms can be very useful and has a number of different applications including analog signal generation.



Code is available on Github as always.


If you want E book or hardback versions of previous MicroZed chronicle blogs, you can get them below.




  • First Year E Book here
  • First Year Hardback here.




MicroZed Chronicles hardcopy.jpg 



  • Second Year E Book here
  • Second Year Hardback here




MicroZed Chronicles Second Year.jpg 




All of Adam Taylor’s MicroZed Chronicles are cataloged here.