I am programming on an embedded microcontroller (TMS320F28069) a 32-bit floating point MCU. I was going over some of the example projects, and one of them implements a simple FIR filter on ADC sampled data.
Let's say the ADC buffer has 10 elements. And let's say the filter has length 3 (FILTER_LEN=3
). The filter implementation is pretty straightforward, it starts at the end of the delay chain and moves its way to the beginning.
float32 ssfir(float32 *x, float32 *a, Uint16 n)
{
Uint16 i; // general purpose
float32 y; // result
float32 *xold; // delay line pointer
/*** Setup the pointers ***/
a = a + (n-1); // a points to last coefficient
x = x + (n-1); // x points to last buffer element
xold = x; // xold points to last buffer element
/*** Last tap has no delay line update ***/
y = (*a--)*(*x--);
/*** Do the other taps from end to beginning ***/
for(i=0; i<n-1; i++)
{
y = y + (*a--)*(*x); // filter tap
*xold-- = *x--; // delay line update
}
/*** Finish up ***/
return(y);
}
Now, here is how the ADC circular buffer is implemented.
//---------------------------------------------------------------------
interrupt void ADCINT1_ISR(void) // PIE1.1 @ 0x000D40 ADCINT1
{
static float32 *AdcBufPtr = AdcBuf; // Pointer to ADC data buffer
static float32 *AdcBufFilteredPtr = AdcBufFiltered; // Pointer to ADC filtered data buffer
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Must acknowledge the PIE group
//--- Manage the ADC registers
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // Clear ADCINT1 flag
//--- Read the ADC result:
*AdcBufPtr = ADC_FS_VOLTAGE*(float32)AdcResult.ADCRESULT0;
//--- Call the filter function
xDelay[0] = *AdcBufPtr++; // Add the new entry to the delay chain
*AdcBufFilteredPtr++ = ssfir(xDelay, coeffs, FILTER_LEN);
//--- Brute-force the circular buffer
if( AdcBufPtr == (AdcBuf + ADC_BUF_LEN) )
{
AdcBufPtr = AdcBuf; // Rewind the pointer to the beginning
AdcBufFilteredPtr = AdcBufFiltered; // Rewind the pointer to the beginning
}
}
xDelay
is a float32 array of length FILTER_LEN
initialized with 0s and coeffs
is a float32 array of length FILTER_LEN
initialized with the filter coefficients.
My question is, what is going on here:
//--- Call the filter function
xDelay[0] = *AdcBufPtr++; // Add the new entry to the delay chain
*AdcBufFilteredPtr++ = ssfir(xDelay, coeffs, FILTER_LEN);
How do values ever get stored in xDelay[1]
or xDelay[2]
?
Their implementation seems to work fine, but I'm not following how old data gets pushed back in the xDelay array.
in the ssfir() function the following line shuffles the elements in the xDelay array
*xold-- = *x--; // delay line update
the line is in the for loop so the [1] element is copied to the [2] then the [0] element is copied to the [1] since the x and xold pointers decrement in spite of the for loop counting up