6.2 Frequency Division

Because the rotational speed of a stepper motor is proportional to the frequency of cycling through the stepping bit patterns, it becomes important to control this stepping frequency precisely.

The most intuitive method is simply to change the overflow value of a timer. This approach works to an extent, but it is not well suited for precise frequency control. The problem is because $f = \frac{1}{p}$, in which $f$ is frequency, and $p$ is period. In our case, $p$ is always quantized by the divider of the timer clock.

Most stepper motors can step at 500Hz. This translates to a period of exactly 2ms. But how about 499Hz? It translates to a period of about 2.004ms. It may seem to make sense to set up the timer so we can control its period at 0.004ms intervals. But this is not true. At 333Hz, the period is 3.333ms, which is not a multiple of 0.004ms!

Using the period of a timer to directly control stepper also has other disadvantages. For example, a differentially driven robot will need two timers to control its two motors. As we will discuss later, acceleration control also needs its own frequency control. Does this mean that we need to use two more timers to control acceleration and deceleration? Soon, we are left with no timer to provide the basic monotonic tick for time keeping and other periodic logic.

This is why we need a different scheme for generating a variety of frequencies. We will use one single timer to do this.

The basic idea is that we begin with a timer overflow period that is much shorter than the shortest stepping period. In our example, let's assume that a stepper steps at a maximum speed of 500 steps per second. In this case, we can assume a 5kHz timer interrupt frequency for relatively smooth stepping.

But 5kHz is not divisible by 499Hz, is it? You are correct! With a 5kHz base frequency, the 499Hz stepping will be slightly uneven. This is what happens in one second:

The period is $(49\times 9+48)\times 2 + 10\times 2.2=1000$ in milliseconds. Is this terrible? Not really. Since the variance of the long versus short steps is only off by 10%, most stepper motors will work fine.

This pattern is generated using the following code:


\begin{lstlisting}{}
sum += step_freq;
if (sum > base_freq
{
sum -= base_freq;
perform_step();
}
\end{lstlisting}

In this code, step_freq is the stepping frequency (499Hz), whereas base_freq is the base frequency (5000Hz).

Intuitively, this code should work. As step_freq increases, it takes fewer iterations to overflow sum. To generate a 499Hz frequency (for stepping), this code should be executed at 5kHz (5000 times per second).

To make this logic cleaner, one can always make use of structures. The following code makes this frequency division logic flexible:


\begin{lstlisting}{}
struct FreqDiv
{
unsigned int freq;
unsigned int sum;
vo...
...base_freq;
if (pfd->cb_func) pfd->cb_func(pfd->cb_param);
}
}
\end{lstlisting}

The only tricky part in this code are the use of the cb_func and cb_param. cb_func is a ``call back'' function whenever there is an overflow. cb_param is just a pointer to something that is passed to the callback function. This way, the call back function can have its own very complex structure for storing parameters and non-volatile state information.

Also, note that base_freq is not specific to the structure. This is because typically, all mechanisms that rely on frequency division can rely on the same timer, hence having the same base frequency.

Copyright © 2006-02-15 by Tak Auyeung