The PSoC family is my go to line of processors for prototyping. It is like having a breadboard full of digital and analog circuits that you can wire up on the fly. I have been doing some stuff with hobby servos lately so I needed to figure out how to do it on the PSoC.
Hobby Servos
Hobby servos set their rotation based on the length or a repeating pulse. The pulse should be 1ms to 2ms long and repeat every 20ms. One end of the rotation is at 1ms and the other is at 2ms.
The PSoC PWM Component
The PWM component is perfect for this job. The PWM component can be setup to have a period and an on time. The period should be 20ms and the on time would be between 1ms and 2ms. The component uses a clock and two counter values. The component will count on every clock pulse. It resets the counters after the period count has been reached and the CMP value determines how long the pulse is logic high.
The PWM output goes to the servo control line. Here is the configuration dialog box for the PWM component. The graph at the top is a good reference for what the output will look like.
The goal is to have a pretty decent resolution to set the 1ms to 2ms pulse. I chose a 2MHz clock. I picked the fastest clock that would still fit within the 16bit (65535) limit of the control. PSoC clocks are derived from system clocks, so you need to pick values easily divided down from them. The IDE helps with creation of these clocks. At 2Mhz the period (repeat rate) should be set to 40,000. The equation is the clock * period(in second) = period counts (2,000,000 counts/sec * 0.02 secs = 40,000 counts).
The CMP Value is how many counts the high pulse should last. The equation is the same. For 1ms the count would be (2,000,000 cnts/sec * 0.001secs = 2,000 counts) and for 2ms the counts would be 4,000. The range is 2,000 to 4,000 (2,000 count resolution). This is better than most hobby servos can do.
The Code
The IDE will generate a bunch of functions, a custom API, for each component used when the application is built. There are two PWM Component functions we need to use for this application .
- PWM_Servo_Start() This will initialize the component and get it running. This is called once at the beginning of the program.
- PWM_Servo_WriteCompare(val) This sets the CMP Value that will be used to set the pulse length.
I also wrote a function the can set the value by degrees.
void setServo(float degrees)
{
unsigned int val;
// convert degrees to compare value
// 2000 to 4000 = 0 to 180
// value is
val = (degrees / 180.0 * 2000.0) + 2000;
PWM_Servo_WriteCompare(val);
}
The Results
Here is a screen shot of my logic analyzer. The output was set for 1/2 rotation. The pulse is 1.51ms and the period is 20.14ms. That is close enough for me. It is likely the clock speed is different between the PSoC and and the analyzer.
Typically you will have to tune the to the actual servos used. Just tweak the endpoint values until you get the rotation you want.