< SCHEMATIC 1. The electronic playground is contained
within U1, the Xilinx XC2C64A. U2 is a 1 MHz clock source
that can be divided by 10 and 100 with the movement of
a jumper. The LEDs and switches are here because the
XC2C64A is part of a XC2C64A development board design.
reload the servo control pulse counter value. We can follow
the easier coding path by selecting a servo control pulse
window time that lies on a power of two boundary. The
power of two timing method allows the servo control
pulse counter to run continuously and reset itself without
intervention.
Ultimately, we want the servo control pulse counter to
roll over to zero and restart the servo control pulse width
timing period automatically. The closest power of two
boundary value that meets our 16 ms servo control pulse
window timing limitation is 0x4000. Thus, we will assign a
bit pattern that will allow our servo control pulse counter to
count from 0x0000 to 0x3FFF and roll over to 0x0000. Our
selection of 0x4000 as the servo control pulse window
count provides a 16.384 ms control pulse window. If we
find that we need more time to service more servos, we
could multiply our servo control pulse window time by two
and use 0x8000 as our servo control pulse count value.
Counting from 0x0000 to 0x7FFF would yield a 32.768 ms
servo control pulse window.
From what I have read, 40 ms is the typical minimum
servo control pulse window used by RF-based hobby servo
systems and is mandated by the FCC (Federal
Communications Commission) to limit interference. We can
service a bunch of hobby servos in a 40 ms window. Let’s
go with the 32.768 ms servo control pulse window for
now. If necessary, we can always scale the pulse window
time back to 16.384 ms with the flip of a bit. Here’s the
32.768 ms servo control pulse window bit pattern:
32,768 µs = 0x8000 µs = 0b1000000000000000 µs
We will count from 0x0000 to 0x7FFF and roll over.
If that doesn’t compute, remember that we clock on zero
and the zero clock counts as one clock pulse. So, we’ll need
15 bits — not 16 bits — for our 32.768 ms servo control
pulse counter.
Transposing the Servo Math
The idea is to plant the servo position pulse (1 ms to
2 ms) at the beginning of the 32.768 ms servo control
pulse window. Let’s begin by putting some code together
that will center the servo rotor:
module rcservo(
input clk_1mhz,
output reg pwm_out
);
Verilog is module based. Our rcservo Verilog module
The CPLD Servo Driver
has an input and an output. The output is registered,
which means it has the ability to emulate a flip-flop.
A registered Verilog component also has the means
of holding a value just as a D flip-flop can on its
complementary Q and outputs. The input signal — which
has defaulted to a Verilog type of wire — is derived from
our LTC6900 1 MHz clock output. Verilog wires cannot hold
values and can only be driven by an external force such as
a register or the output of a gate. Basically, a Verilog wire
is just like the copper wire you use to connect electronic
components.
Next, let’s associate our pulse width numeric values
with some human-readable names using the Verilog
keyword parameter. Verilog parameters are equivalent to
C constants:
parameter
parameter
minpulsewidth = 1000;
servo_vector = 500;
All of our Verilog parameter values are in microsecond
units. The minpulsewidth Verilog parameter should be
obvious as to its use. The Verilog parameter servo_vector
represents the relative position of the servo rotor. We must
always have a minimum servo position pulse width of 1 ms.
So, adding 500 µs (0.5 ms) to the minimum servo position
pulse width with the servo_vector value of 500 will give us
the 1.5 ms centering pulse we are looking for.
We calculated that we would need a total of 15 bits to
implement our 32.768 ms servo control pulse window.
Here’s the Verilog instantiation of our 15-bit servo control
pulse register, which we will call window_32ms:
reg
[14:0] window_32ms;
If you lay down a “1” for every bit position in the
window_32ms register (bits 14 through 0), you’ll end up
with 0x7FFF hexadecimal, or 0b111111111111111 binary.
When the window_32ms register contains 0x7FFF and is
incremented, it will roll over to zero. So far, so good.
We’ve served up the potatoes. Now, let’s bring the meat
to the table:
always @(posedge clk_1mhz)
begin
window_32ms <= window_32ms + 1;
pwm_out <= (window_32ms <
(servo_vector + minpulsewidth));
end
endmodule
The Verilog always @(posedge clk_1mhz) statement
does exactly what it says. Every time the positive edge of
the LTC6900-provided 1 MHz clock occurs, everything
between the begin and end block delimiters is executed.
The Verilog endmodule keyword signals the end of the
rcservo module.
The always @(posedge clk_1mhz) block statement is
SERVO 08.2008 39