Part One in this two-article series focuses on the hardware setup and on using a pulse-width-modulated signal to control a servo.

Supporting Information

 

Required Hardware/Software

 

Another PWM Application

If you look through the articles listed under “Supporting Information,” you will notice that I recently covered quite a bit of information on using a pulse-width-modulated signal (with the help of a low-pass filter) as an inexpensive digital-to-analog converter. In the process of exploring this topic I demonstrated how to generate PWM signals with the SAM4S Xplained Pro development platform. With all this PWM business fresh in our minds, I think it makes sense to look at another standard application for PWM signals: servo control.

As you probably know, the term “servo” (short for servomotor) usually refers to a PWM-controlled rotary actuator that uses feedback to precisely control the angular position of its output shaft. The pulse width of the control signal corresponds to an angular position, and the motor automatically rotates its shaft to the proper position based on the current pulse width; it’s a simple and effective arrangement. Typical “hobby” servos adopt a standard control scheme in which a 1 ms pulse corresponds to the extreme-left position, 1.5 ms corresponds to center, and 2 ms corresponds to extreme right. (You will soon see, though, that these values are “guidelines”; some adjustments may be needed.)

 

Servo Specs—Or Lack Thereof

The servo I will be using for this project is the TowerPro SG92R. Digi-Key’s product page for the SG92R points you to a “datasheet” that must be one of the most uninformative technical documents I have ever read. It is a grand total of two pages, the first consisting entirely of a photograph. The only piece of solid information is that the servo can rotate 180°. It also mentions the standard pulse-width-to-position relationship, which (at least for my servo) proved to be highly inaccurate. No current or voltage specs, no torque, no dead band width, no recommendations for PWM frequency, and, worst of all, no pinout. The datasheet does say quite a bit about using the servo in conjunction with Arduino hardware—information which for me is thoroughly useless, as I do not own and have never used any Arduino product.

Fortunately for you, I’ll provide the necessary information, so you can skip the datasheet. The nominal supply voltage is 5 V, and I can confirm that 5 V works because that’s what I am using. One website claims that the acceptable range is 3 V to 7.2 V. I can also confirm that you can successfully drive the control signal with 3.3 V logic, even when the supply voltage is 5 V. I didn’t measure the current, but the servo works fine with a 5 V, 1 A wall-mount transformer. The topic of servo-control PWM frequency is a bit complicated, so I’ll bypass the details; suffice it to say that a good choice is somewhere in the 40 to 60 Hz range. We will use 50 Hz in this project. Finally, here is the pinout:

 

 

Motor Power

So the servo needs 5 V. We have 5 V available from the SAM4S Xplained Pro; why bother with the wall-mount transformer? Well, the fact is that motors in general are not kind to power supplies. The SAM4S board’s 5 V supply comes from the USB connection, and it’s not a great idea to risk damaging the USB port by asking it to supply power for a motor. With a small servo like this one, you might get away with it, but I need all my USB ports, so in this situation I will choose safe over possibly sorry. Fortunately, it is quite convenient to bring in external power, especially if you are using the PROTO1 extension board. The SAM4S board can be powered by the “DEBUG” USB connector, the “SAM4S” USB connector, or an external supply. Even better, it automatically detects which voltages are present and powers the board accordingly. If more than one voltage is present, it chooses the power source based on the following priority scheme: External power is used whenever it is present; if external power is not provided and both USB connections have bus power available, the board uses “DEBUG” USB power; “SAM4S” USB power is used only when the other two sources are not active.

So all we need to do is connect the leads of the wall-mount transformer to the connector near the top-right corner of the PROTO1 board, as follows:

 

A spring blade inside the connector terminals clamps down on the wire when you insert it. This works fine as long as your wire is sufficiently rigid; if it’s not, coat it with a little bit of solder. The SAM4S board will automatically use this external power whenever it is available. To power the servo, just solder a jumper to one of the through-holes in the external power bus (labeled “EP5V0”) and plug the other end of the jumper into the servo connector’s red-wire terminal.

 

Signal and Ground

There’s not much to say about the rest of the hardware setup. One of the pins on the PROTO1 header is labeled “PWM+”; jumper this to the servo connector’s orange-wire terminal. Add a jumper for ground, and you’re good to go.

 

 

Firmware

You will need to add three Atmel Software Framework (ASF) modules to your new project—one for the PWM interface, one for USB communication, and one for the ASF delay functions:

 

 

Note that we are using the “CDC” version of the USB module. This stands for “communications device class,” which is a generic class that can be used in any situation where basic serial communication is required. The ASF’s CDC module makes it surprisingly easy to establish a virtual COM port connection with the PC, and a virtual COM port connection is just what we need—a straightforward interface that allows us to communicate with the PC using a standard terminal program or any other program that includes serial port functionality. We’ll cover the USB portion of this project in the next article.

Here is the code we will use to confirm that we can properly control the servo.

 

                    #include <asf.h>

#define PWM0H_SERVO IOPORT_CREATE_PIN(PIOA, 23)

#define PWM_CLOCKSOURCE_FREQ 1000000
#define PWM_FREQ 50
#define PWM_PERIOD_TICKS PWM_CLOCKSOURCE_FREQ/PWM_FREQ
#define PULSE_WIDTH_FULL_LEFT_TICKS 1000
#define PULSE_WIDTH_CENTER_TICKS 1500
#define PULSE_WIDTH_FULL_RIGHT_TICKS 2000

pwm_channel_t PWM0_config;

int main (void)
{
	//clock configuration and initialization
	sysclk_init();
	
	/*Disable the watchdog timer and configure/initialize
	port pins connected to various components incorporated 
	into the SAM4S Xplained development platform, e.g., the 
	NAND flash, the OLED interface, the LEDs, the SW0 pushbutton.*/  
	board_init();
	
	//connect peripheral B to pin A23
	pio_configure_pin(PWM0H_SERVO, PIO_TYPE_PIO_PERIPH_B);

	//enable the peripheral clock for the PWM hardware
	pmc_enable_periph_clk(ID_PWM);

	//disable the PWM channel until it is properly configured
	pwm_channel_disable(PWM, PWM_CHANNEL_0);

	//PWM clock configuration
	pwm_clock_t PWM_clock_config = 
	{
		.ul_clka = PWM_CLOCKSOURCE_FREQ,
		.ul_clkb = 0,
		.ul_mck = sysclk_get_cpu_hz()
	};
	
	//apply the clock configuration
	pwm_init(PWM, &PWM_clock_config);
	
	//select channel 0
	PWM0_config.channel = PWM_CHANNEL_0;
	//select clock A
	PWM0_config.ul_prescaler = PWM_CMR_CPRE_CLKA;
	//active state is logic high
	PWM0_config.polarity = PWM_HIGH;
	//left-aligned mode
	PWM0_config.alignment = PWM_ALIGN_LEFT;
	
	PWM0_config.ul_period = PWM_PERIOD_TICKS;
	PWM0_config.ul_duty = PULSE_WIDTH_CENTER_TICKS;
	
	//apply the channel configuration
	pwm_channel_init(PWM, &PWM0_config);
		
	//configuration is complete, so enable the channel
	pwm_channel_enable(PWM, PWM_CHANNEL_0);
	
	while(1)
	{
		delay_ms(1000);
		
		pwm_channel_update_duty(PWM, &PWM0_config, PULSE_WIDTH_FULL_LEFT_TICKS);
				
		delay_ms(1000);
				
		pwm_channel_update_duty(PWM, &PWM0_config, PULSE_WIDTH_FULL_RIGHT_TICKS);
				
		delay_ms(1000);
		
		pwm_channel_update_duty(PWM, &PWM0_config, PULSE_WIDTH_CENTER_TICKS);
	}
}
                  

The comments and descriptive identifiers should allow you to understand what is going on in the code. However, if you’re confused about something related to the PWM functionality or the port-pin configuration, refer to Pulse-Width Modulation with the SAM4S Xplained Pro for more information.

The PWM timing configuration is governed by the six preprocessor definitions near the beginning of the code:

 

                    #define PWM_CLOCKSOURCE_FREQ 1000000
#define PWM_FREQ 50
#define PWM_PERIOD_TICKS PWM_CLOCKSOURCE_FREQ/PWM_FREQ
#define PULSE_WIDTH_FULL_LEFT_TICKS 1000
#define PULSE_WIDTH_CENTER_TICKS 1500
#define PULSE_WIDTH_FULL_RIGHT_TICKS 2000
                  

The clock driving the PWM hardware is set to 1 MHz. The PWM period and pulse width are defined in units of clock ticks, so whatever values we load into the period and pulse-width registers correspond to durations in microseconds. The values shown above correspond to the nominal pulse widths for extreme-left, center, and extreme-right shaft positions: 1000 clock ticks for 1 ms, 1500 clock ticks for 1.5 ms, and 2000 clock ticks for 2 ms. The infinite while loop at the end of the main() function cycles through these three positions, with successive updates to the pulse-width register separated by a one-second delay. The following video shows the results:

 


As you can see, the rotational range of the shaft is nowhere near 180°; it looks more like 90°. With a little trial and error I found that the following values produce the expected 180° rotation:

 

                    #define PULSE_WIDTH_FULL_LEFT_TICKS 480
#define PULSE_WIDTH_CENTER_TICKS 1440
#define PULSE_WIDTH_FULL_RIGHT_TICKS 2350
                  


You can use the following link to download the source and project files:

 

  Source and Project Files  


Conclusion

We’ve set up our hardware and implemented some basic servo-control firmware. We’ve also established the pulse widths that actually move the shaft to extreme left, center, and extreme right. In the next article we’ll incorporate USB functionality so that we can control the servo from a PC.

 

Next Article in Series:

 

Comments

1 Comment


  • mjaa 2016-05-05

    Thank you for a well written and useful article.  Being a senior (read old) embedded engineer, I cut my teeth on these conrol applications using mainly Mororola 68XX series microprocessors and peripheral ICs in the mid 70’s. I can still remember thinking we had witnessed a quantum leap in embedded architecture when the local Motorola rep strung (literally) a pre-production MC6801 microcontroller chip across the lab with 2 wires one direction (+5V, GND) and 3 wires the other direction to a teletype. Power was applied and the teletype came to life with the monitor program. That was my first experience with a full computer on a single IC.