Hi again folks! In this tutorial we go through interfacing and control of servo motors with ARM7 LPC2148 microcontroller. In my previous tutorial I had explained PWM in ARM7 LPC2148, now its time use PWM block and control servos. RC servos, as the name suggests, are used in RC airplanes, cars and even robots like hexapods, robotic arms, etc. These servos typically accept a PWM signal having a period of 20ms (i.e. a frequency of 50Hz). The commonly used RC servos have a total rotation swing of around 180 degrees(-90 to +90). 0 degree position is called “neutral” which is at the center of the total rotation swing, and hence also called the center position.
- A pulse width of 500µs or 0.5ms is the minimum pulse width which positions the servo’s output shaft at -90 degrees.
- A pulse width of 1500µs or 1.5ms positions the servo at 0 degree.
- Finally a pulse width of 2500µs or 2.5ms is the maximum pulse width which positions the servo at +90 degrees.
With this information, lets proceed with generating a PWM signal to control servo motors using LPC2148.
Configuring LPC2148 PWM to generate Servo PWM signal
Defining the PWM resolution
Since the PWM pulses vary from 500µs to 2500µs, a resolution of 1µs is more than sufficient. Hence we will configure the PWM block for 1µs resolution and with a period of 20ms(20000µs). Make sure you go through the “PWM Prescaler (PWMPR) Calculations” explained in my LPC2148 PWM tutorial previously. As mentioned previously in that tutorial, the basic formula for working the value of PR given resolution is:
Since we need resolution is µs scale, we can scale the equation and rewrite it as follows:
Now, to get the value of PR for 1µs Resolution, given we know and have already set PCLK, can be done as follows:
Hence,
Finally, since we will be using CCLK=PCLK=60Mhz, we get PR as follows:
Visit my tutorial on LPC2148 PLL and Clock setup for more on how to setup CCLK and PCLK.
Setting up PWM block for 20ms period with output
Now, assuming both CCLK and PCLK are configured to run at 60Mhz, PWM Block can be configured to control RC Servo as follows:
- Select the PWMx function on the respective IO pin.
- Set PWMPR = 59 to get a resolution of 1us. PWMTC increments every 59+1 Clock cycles @ 60mhz.
- Set PWMMCR = 0x1 (bit0 = 1) to Reset PWMTC on PWMMR0 (and , 0x8= interrupt when PWMMR1 matches PWMTC i.e after PWMMR1 reaches the value assigned to it)
- Set PWMMR0 = 20000 which sets the period to 20ms for all PWM outputs.
- Set PWMMR1 to default PWM pulse time. We will use 1500µs i.e. neutral position.
- Set the corresponding bits in PWMLER to update the values in match registers.
- Set the corresponding bits PWMPCR to enable PWMx Output.
Example to configure & initialize PWM with PWM1 Output:
PINSEL0 |= (1<<1); //set Bits [1:0] = 10 to select PWM1 for P0.0
PWMPR = 59; //PWMTC increments every 59+1 Clock cycles @ 60mhz to yield a resolution of 1us
PWMMCR = 0x1; //Reset PWMTC on PWMMR0 Match which defines the PWM period
PWMMR0 = 20000; //PWM period of 20ms
PWMMR1 = 1500; //Default Pulse time. Brings servo in neutral position
PWMLER = (1<<0) | (1<<1); //Enable Match 1 & Match 2 Latch to update new values
PWMPCR = (1<<9); //Enable PWM1 Output
PWMTCR = (1<<1); //Reset PWM Counter
PWMTCR = (1<<0) | (1<<3); //IMP! - Enable Counter and PWM
Updating new PWM/Pulse values:
Once PWM1 output is enabled we need to only update PWM match register 1 i.e. PWMMR1 (& PWMLER) with new values to control our servo's position. For updating new Match values to any of the Match register, the corresponding bit in the Latch Enable Register (PWMLER) must be set to 1. After New values are updated the Latch Enable Bit in PWMLER is again reset. Hence, for every update we must set the corresponding bit in PWMLER to 1. This update will happen at the beginning of next PWM period. For more please read the register explanation given in LPC2148 PWM tutorial previously.
Example for updating PWMMR1:
while(1) //main control loop
{
//...
//..
PWMMR1 = 900;
PWMLER |= (1<<1); //Bit[1] corresponds to PWMMR1 Latch
/*new value will be updated at the beginning of next Period*/
//..
}
ARM7 LPC2148 Servo Interfacing examples
Example 1: Simple Servo Control using LPC214x
Example 1: Simple Servo Control using LPC214x
In this example we will repeatedly set the servo position to +45, 0, -45 degrees which roughly corresponds to 1ms, 1.5ms and 2ms pulse widths for most RC servos. Here, we will use a delay of 2 seconds between each position. Schematic and Color coding for various servo plugs is also given in the diagram below. Please confirm the color coding of your servo plug before you proceed with any connections.
Source Code:
/*(C) Umang Gajera - www.ocfreaks.com
LPC2148 Servo Interfacing Tutorial - Example 1
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/
#include <lpc214x.h>
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header
int main(void)
{
initClocks(); //Set PCLK = CCLK = 60Mhz
initTimer0(); //For delay functions
PINSEL0 |= (1<<1); //set Bits [1:0] = 10 to select PWM1 for P0.0
PWMPR = 59; //PWMTC increments every 59+1 Clock cycles @ 60mhz to yield a resolution of 1us
PWMMCR = 0x1; //Reset PWMTC on PWMMR0 Match which defines the PWM period
PWMMR0 = 20000; //PWM period of 20ms
PWMMR1 = 1500; //Default Pulse time. Brings servo in neutral position
PWMLER = (1<<0) | (1<<1); //Enable Match 1 & Match 2 Latch to update new values
PWMPCR = (1<<9); //Enable PWM1 Output
PWMTCR = (1<<1); //Reset PWM Counter
PWMTCR = (1<<0) | (1<<3); //IMP! - Enable Counter and PWM
delayMS(2000); //Initial delay
while(1)
{
PWMMR1 = 1000; //1ms Pulse
PWMLER |= (1<<1); //Set MR1 Latch
delayMS(2000); //2 Secs Delay
PWMMR1 = 1500; //1.5ms Pulse
PWMLER |= (1<<1);
delayMS(2000);
PWMMR1 = 2000; //2ms Pulse
PWMLER |= (1<<1);
delayMS(2000);
PWMMR1 = 1500; //1.5ms Pulse
PWMLER |= (1<<1);
delayMS(2000);
}
//return 0; //This won't execute normally
}
Project Download:
Example 2: Sweep/Interpolate Servo between two positions with LPC214x
In this example we will sweep the servo between +45 & -45 degrees. The servo shaft will rotate at constant speed between the two defined locations. Here, we have to play with two parameters which define how smooth and fast will the servo move. These are: the delay between two steps and the step increment. In our case we will use a step increment of 20µs and an inter-step delay of 1 period i.e. 20ms. The wiring is same as shown for example 1.
Source Code:
/*(C) Umang Gajera - www.ocfreaks.com
LPC2148 Servo Interfacing Tutorial - Example 1
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/
#include <lpc214x.h>
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header
int main(void)
{
initClocks(); //Set PCLK = CCLK = 60Mhz
initTimer0(); //For delay functions
PINSEL0 |= (1<<1); //set Bits [1:0] = 10 to select PWM1 for P0.0
PWMPR = 59; //PWMTC increments every 59+1 Clock cycles @ 60mhz to yield a resolution of 1us
PWMMCR = 0x1; //Reset PWMTC on PWMMR0 Match which defines the PWM perioed
PWMMR0 = 20000; //PWM period of 20ms
PWMMR1 = 1000; //Default(starting) Pulse time for sweep.
PWMLER = (1<<0) | (1<<1); //Enable Match 1 & Match 2 Latch to update new values
PWMPCR = (1<<9); //Enable PWM1 Output
PWMTCR = (1<<1); //Reset PWM Counter
PWMTCR = (1<<0) | (1<<3); //IMP! - Enable Counter and PWM
delayMS(1000); //Initial delay
int step = 20; //In us
int stepDelay = 20; //In ms
int pulse=1000;
while(1)
{
while(pulse<2000)
{
PWMMR1 = pulse;
PWMLER |= (1<<1);
delayMS(stepDelay);
pulse = pulse + step;
}
while(pulse>1000)
{
PWMMR1 = pulse;
PWMLER |= (1<<1);
delayMS(stepDelay);
pulse = pulse - step;
}
}
//return 0; //This won't execute normally
}
Project Download: