The Scientist and Engineer's Guide to Digital Signal Processing508
1. Obtain a sample with the ADC; generate an interrupt
2. Detect and manage the interrupt
3. Move the sample into the input signal's circular buffer
4. Update the pointer for the input signal's circular buffer
5. Zero the accumulator
6. Control the loop through each of the coefficients
7. Fetch the coefficient from the coefficient's circular buffer
8. Update the pointer for the coefficient's circular buffer
9. Fetch the sample from the input signal's circular buffer
10. Update the pointer for the input signal's circular buffer
11. Multiply the coefficient by the sample
12. Add the product to the accumulator
13. Move the output sample (accumulator) to a holding buffer
14. Move the output sample from the holding buffer to the DAC
TABLE 28-1
FIR filter steps.
array (e.g., 20048), or a variable that holds its length (e.g., 8). Third, the step
size of the memory addressing must be specified. In Fig. 28-3 the step size is
one, for example: address 20043 contains one sample, address 20044 contains
the next sample, and so on. This is frequently not the case. For instance, the
addressing may refer to bytes, and each sample may require two or four bytes
to hold its value. In these cases, the step size would need to be two or four,
respectively.
These three values define the size and configuration of the circular buffer, and
will not change during the program operation. The fourth value, the pointer to
the most recent sample, must be modified as each new sample is acquired. In
other words, there must be program logic that controls how this fourth value is
updated based on the value of the first three values. While this logic is quite
simple, it must be very fast. This is the whole point of this discussion; DSPs
should be optimized at managing circular buffers to achieve the highest
possible execution speed.
As an aside, circular buffering is also useful in off-line processing. Consider
a program where both the input and the output signals are completely contained
in memory. Circular buffering isn't needed for a convolution calculation,
because every sample can be immediately accessed. However, many algorithms
are implemented in stages, with an intermediate signal being created between
each stage. For instance, a recursive filter carried out as a series of biquads
operates in this way. The brute force method is to store the entire length of
each intermediate signal in memory. Circular buffering provides another
option: store only those intermediate samples needed for the calculation at
hand. This reduces the required amount of memory, at the expense of a more
complicated algorithm. The important idea is that circular buffers are useful
for off-line processing, but critical for real-time applications.
Now we can look at the steps needed to implement an FIR filter using circular
buffers for both the input signal and the coefficients. This list may seem trivial
and overexamined- it's not! The efficient handling of these individual tasks is
what separates a DSP from a traditional microprocessor. For each new sample,
all the following steps need to be taken: