Creating a Miniaturized Analog Controlled Servo

By Solutions Cubed

Contributed By Digi-Key Electronics

Position control on a small scale

Advanced position control systems have been used in industrial control applications for decades. Often these systems are complex and expensive, as well as necessary. In today’s electronic marketplace options exist that allow for very small and inexpensive position control systems. It is now possible to affordably provide advanced control systems on a small scale, and even customize multiple designs around a fixed piece of electronic hardware. This creates many options for enhanced manufacturing control, which in turn reduces material loss and saves time and money. This article describes a simple design that was later built upon to create a powerful miniaturized motion control system.

A Miniaturized Servo Controller

Using Microchip’s dsPIC family of 16-bit microcontrollers allows for sophisticated control schemes to be developed with very low hardware costs. For this application, the dsPIC33FJ64MC802-I/MM-ND part was selected as an appropriate controller. Significant reasons for the selection of this part are as follows:
  • 64K x 8 of flash based memory, 16K x 8 RAM
  • Free evaluation version of MPLAB C from Microchip
  • Low cost debugger/programmer via MPLAB ICD3
  • Up to 40MIPS operating speed
In addition to these factors, the dsPIC33FJ64MC802-I/MM-ND has a multitude of useful peripherals, making it perfect for many control applications. These peripherals include timers, quadrature encoder hardware, 10 or 12-bit analog-to-digital converters, UART, SPI, I2C, PWM modules designed for motor control, a watch-dog-timer, an internal oscillator with PLL, and many interrupt driven features. A number of the peripherals may be mapped to various IC pads allowing for simplified routing of printed circuit boards.

The robust Freescale MC33926PNB-ND was selected to provide an interface between the microcontroller and the DC motor in this servo design. However, virtually any H-bridge IC could be inserted into this design, allowing the motor size to be easily scaled once the control system is perfected. The MC33926PNB was selected for the following reasons:
  • Fault and load current feedback is available on the IC
  • Operates from 5 to 28 VDC
  • PWM signal up to 20 KHz is possible
  • Multiple internal protections including short circuit
A simplified design example

Previously we discussed the major parts selected to create a miniaturized servo system. To provide more detail, we will design a closed-loop proportional controller based on these parts (see Figure 1). Using the dsPIC33 AD and PWM modules, we can quickly produce a 12-bit analog control and analog feedback system. Additional money can be saved by using the internal RC oscillator and PLL to operate at a speedy 36.85 MIPS, with a 250 µS control loop.

The dsPIC33 firmware will also monitor the fault and current feedback from the H-bridge IC. If a fault condition exists, the microcontroller will attempt to reset the H-bridge at every control loop. If the motor load current exceeds approximately 2 A, the dsPIC33 firmware will turn off the PWM signal.

Operating the dsPIC33 PWM module at 20 KHz allows for a PWM value between 0 (0% duty cycle) and 3685 (100% duty cycle). This is nearly 12-bits of resolution, and closely matches our 12-bit analog measurements. The PWM signal is generated by multiplying the error signal (analog control measurement – analog feedback measurement) by a proportional term constant. Selecting the proportional term value was done by trial and error, and a variety of values provided smooth control.

PWM Output = Proportional Term * (Analog Control – Analog Feedback)

The PWM output must be limited to no more than +3685 and no less than -3685 to keep it within the boundary of the PWM module’s 100% duty cycle value (at 20 KHz). This is also handled in the firmware.

In addition to protections built into the MC33926PNB-ND, the load current is monitored to shut the motor down if it exceeds approximately 2 A. The MC33926PNB-ND provides a proportional feedback current of 0.24% of the motor’s load current. A 270 ohm resistor converts the feedback current to a voltage that is monitored by the dsPIC33. At 2 A, this voltage is 1.296 V, or 1608 bits with the 12-bit AD on the dsPIC33 (3.3V/4096 = 0.805mV per bit). The feedback current is a gross measurement, with an accuracy of only ±20% above 500 mA. However, it is still useful for protecting the control system.

Closed-Loop Proportional Controller Example

Figure 1: Closed-loop proportional controller example.

When testing this design, we used a Pittman GM9236S025-R1 12 V gearhead motor with a 65.5:1 gear ratio. The gear ratio prevented fast response, as shown in the following ramp waveform test signal (Figure 3), but otherwise created a powerful servo system. Feedback was delivered via a potentiometer attached directly to the motor shaft. The 12 V motor voltage was stepped down by a 5 V linear regulator (not shown in schematic), which in turn supplied power to the on-board 3.3 V linear regulator.

Servo Response to a Sinusoidal Control Signal

Figure 2: Servo response to a sinusoidal control signal.

Servo Response to a Ramp Control Signal

Figure 3: Servo response to a ramp control signal.

Physical prototype

The prototype for this design was placed into a 24 pin, 600 mil wide, DIP package (Figure 4). The 2-layer board was routed to include a serial communication port, connections for limit switch inputs, a quadrature encoder port, and the ability to read pulses from 5 µs to 20 ms in duration.

Also routed on the board are connections to allow for debugging with a variety of Microchip’s tools. This design was completed using the MPLAB ICD3 debugger/programmer.

Prototype Circuit Package

Figure 4: Prototype circuit package.


The firmware for this design was written using a free evaluation version of Microchip’s C30 C compiler (version 3.25). The MPLAB IDE version was used as a development environment. Debugging and programming was accomplished using the MPLAB ICD3 running on firmware revision 1.26.52.

The firmware listed here performs a simple motion control system with analog control input and analog feedback. Proportional control, as well as over-temperature, over-current, and under-voltage protection, are implemented, either in firmware or hardware. The firmware, provided below, can be used as a starting point for more complex systems using the same hardware.

In fact, this hardware is used to implement a full PID control algorithm with a serial command interface and a variety of control and feedback options. This design is currently being manufactured by Solutions Cubed, LLC as the Synaptron Micro Motion Controller.

// The following files should be included in the MPLAB project:
// synaptron_opensource_01.c -- Main source code file
// traps.c -- Explicit definitions of dsPIC33F Traps
// p33FJ64MC802.h -- Header file for dsPIC
// p33FJ64MC802.gld -- Linker script file
// Revision History
// 1/10/12 -- synaptron_opensource_01.c -- initial implementation
#define FCY 36850000ULL
#include "p33FJ64MC802.h" // register an bit definitions are here



/* oscillator setup */


/* power-on-reset */


/* watchdog timer */


/* code protection */


/* program/debug */


/* Application Define statements, variables, constants */

#define FAULT PORTBbits.RB12
#define ENABLE PORTBbits.RB13

#define PWMSTATE_STOPPED 0x0000

#define PWMSTATE_FORWARD 0x0201
#define PWMSTATE_REVERSE 0x0102

unsigned int AnalogControl = 0;

unsigned int AnalogFeedback = 0;
unsigned int AnalogCurrent = 0;

unsigned int ProportionalTerm = 0;

int PWMOutput = 0;


Function: InitTimer5
Description: Initialize Timer5 for a 250uS timer without interrupts
void InitTimer5( void )
T5CON = 0; // ensure Timer 5 is in reset state
IFS1bits.T5IF = 0; // reset Timer 5 interrupt flag
IPC7bits.T5IP = 5; // set Timer5 interrupt priority level to 5
PR5 = 9212; // set Timer5 period register
T5CONbits.TCKPS1 = 0; // select Timer5 Input Clock Prescale 1:1
T5CONbits.TCS = 0; // select external timer clock
T5CONbits.TON = 1; // enable Timer 5 and start the count
IEC1bits.T5IE = 0; // disable Timer 5 interrupt


Function: InitPLL()
Description: Initializes the oscillator and PLL settings and waits for lock. Processor will run at 36.85MIPS.
void InitPLL()
// 7.37MHz / 2 * 40 / 2 FCY = FOSC/2 = 36.85MIPS
CLKDIVbits.PLLPRE = 0; //N1 = 2 VCO divider = /2
PLLFBDbits.PLLDIV = 38; //40x multiplier
CLKDIVbits.PLLPOST = 0; //N2 = 2 PLL input divider = 2
while(OSCCONbits.LOCK != 1);

/********************************************************************* Function: InitIO()

Description: Initializes pin directions(input/output) and voltages.
void InitIO()
TRISAbits.TRISA0 = 1; // Control voltage input
TRISAbits.TRISA1 = 1; // Feedback voltage input

TRISBbits.TRISB2 = 1; // unused

TRISBbits.TRISB3 = 1; // Current voltage input
TRISBbits.TRISB4 = 1; // unused
TRISBbits.TRISB5 = 1; // unused
TRISBbits.TRISB6 = 1; // unused
TRISBbits.TRISB7 = 1; // unused
TRISBbits.TRISB8 = 1; // unused
TRISBbits.TRISB9 = 1; // unused
TRISBbits.TRISB10 = 1; // unused
TRISBbits.TRISB11 = 1; // unused
TRISBbits.TRISB12 = 1; // FAULT input
TRISBbits.TRISB13 = 0; // ENABLE output
TRISBbits.TRISB14 = 0; // PWM1L output
TRISBbits.TRISB15 = 0; // PWM1H output
LATB = 0x1FFF;


Function: InitADC()
Description: Initialize ADC module for 12-bit operation with
void InitADC( void )
AD1CON1 = 0; // Clear control registers
AD1CON2 = 0;
AD1CON3 = 0;
AD1CHS0 = 0x0000; // Channel select AN0

AD1PCFGL = 0xFFFF; // Analog inputs configured as digital

AD1PCFGLbits.PCFG0 = 0; // AN0 analog
AD1PCFGLbits.PCFG1 = 0; // AN1 analog
AD1PCFGLbits.PCFG5 = 0; // AN5 analog

AD1CON1bits.AD12B = 1; // 12-bit, 1 channel operation

AD1CON1bits.FORM = 0; // Integer result
AD1CON1bits.SSRC = 0; // Clearing sample bit starts conv.
AD1CON1bits.ASAM = 0; // Sampling when sample bit is set

AD1CON2bits.CSCNA = 0; // Disable channel scanning

AD1CON2bits.VCFG = 0; // AVDD and AVSS are references

AD1CON3bits.ADRC = 0; // Clock derived from system clock

AD1CON3bits.ADCS = 0x2f; // ADC conversion clock

AD1CON1bits.ADON = 1; // Turn on ADC module



Function: void InitMCPWM(void)
Description: Initialize motor control pulse-width modulation module to 20KHz.
void InitMCPWM(void)
P1TCON = 0x8000; // PWM as free running mode, 1:1 TCY
PWM1CON1 = 0x0111; // Enable PWM1L and PWM1H
// configure them for independent mode
PWM1CON2 = 0x0000; // achieving 20 kHz
P1DTCON1 = 0x0028; // 2 us of dead time
P1DTCON2 = 0x0000;
P1FLTACON = 0x0000; // Initialize Fault Controls
PTPER = FCY/20000 - 1; // Compute Period
P1OVDCON = PWMSTATE_STOPPED; // Disable PWM1 outputs.
P1DC1 = 0; // Set duty cycle to 0
Function: ReadAnalog()
Description: Collects analog values and performs proportional multiplication of the error signal. Also measures the motor current and shuts down the motor drive if it exceeds 2A +/- 20%.
void ReadAnalog(void)
unsigned int SampleTime = 0;

AD1CHS0 = 0x0000; // Channel select AN0 (pin RA0)

AD1CON1bits.SAMP = 1;
while (SampleTime < 100) // Provide >5uS for sample time
AD1CON1bits.SAMP = 0;
AnalogControl = ADC1BUF0; // Store conversion in register

AD1CHS0 = 0x0001; // Channel select AN1 (pin RA1)

AD1CON1bits.SAMP = 1;
SampleTime = 0; // Provide >5uS for sample time while (SampleTime < 100)
AD1CON1bits.SAMP = 0;
AnalogFeedback = ADC1BUF0; // Store conversion in register

AD1CHS0 = 0x0005; // Channel select AN5 (pin RB3)

AD1CON1bits.SAMP = 1;
SampleTime = 0; // Provide >5uS for sample time while (SampleTime < 100)
AD1CON1bits.SAMP = 0;
AnalogCurrent = ADC1BUF0; // Store conversion in register
ProportionalTerm = 10; // Set proportional value
// Ensure PWM signal does not exceed 100%
if (PWMOutput > 3685)
PWMOutput = 3685;
if (PWMOutput < -3685)
PWMOutput = -3685;

if (AnalogCurrent > 1600) // 1600 is approximately equal to 2A.

PWMOutput = 0;


Function: MotorControl()
Description: This subroutine checks for fault conditions and if a fault is present disables the H-bridge. If there is no fault condition the H-bridge module is configured for the appropriate direction and the PWM signal in PWMOutput is applied to the motor. Note that the PWM value is inverted to apply the appropriate output signals, and if a fault occurs the H-bridge is re-enabled after the control loop timer elapses.
void MotorControl(void)
if (FAULT == 0) // Fault input 0V during fault condition
PWMOutput = 0; // Disable motor output if fault occurs.
ENABLE = 0; // Disable H-bridge

if (PWMOutput>0)

P1OVDCON = PWMSTATE_FORWARD; // Set for forward
if (PWMOutput<0)
P1OVDCON = PWMSTATE_REVERSE; // Set for reverse
PWMOutput = -PWMOutput; // Invert PWM signal

if (PWMOutput == 0)


P1DC1 = 3685 - PWMOutput; // Set PWM value



int main(void)
InitPLL(); // Initialize the PLL, wait for lock
InitIO(); // Initialize i/os
InitADC(); // Initialize ADC
InitTimer5(); // Initialize a timer
InitMCPWM(); // Initialize PWM

while (1)

asm("clrwdt"); // Clear watch dog timer
if (IFS1bits.T5IF == 1) // Check control loop timer
IFS1bits.T5IF = 0; // Clear flag for next loop
ENABLE = 1; // Enable H-bridge
ReadAnalog(); // Take analog readings
MotorControl(); // Set PWM drive signal

Disclaimer: The opinions, beliefs, and viewpoints expressed by the various authors and/or forum participants on this website do not necessarily reflect the opinions, beliefs, and viewpoints of Digi-Key Electronics or official policies of Digi-Key Electronics.

About this author

Solutions Cubed

Digi-Key, a world leader in high volume electronic component distribution, has included Solutions Cubed, LLC as a design resource. This allows our company to secure competitive pricing for registered designs belonging to our clients. As a Digi-Key design resource, Solutions Cubed, LLC and Digi-Key work as a team to streamline the design-to-manufacturing phases of product development and work with you to get the best possible solution with pricing as competitive as possible.

Solutions Cubed is an innovative electronic design firm. We have created successful designs for a myriad of industries including mass produced consumer products, deep-sea robotic components, and encrypted decoders for the banking industry. We love meeting new customers and are interested in hearing about your design.

About this publisher

Digi-Key Electronics

Digi-Key Electronics, based in Thief River Falls, Minn., is a global, full-service provider of both prototype/design and production quantities of electronic components, offering more than six million products from over 750 quality name-brand manufacturers at Digi-Key.