To workaround this problem, a new method of measuring the period(s) was developed. PIC input capture logic was used to capture timer values at the rising edge of the AUX signal. Since 16-bit values are captured, two input capture units were used. IC2 and IC1 were used to capture the 32-bit timer value composed of TMR5 and TMR4.

To eliminate the effects of jitter during the time allocated, the initial frequency count was used to determine the number of periods, "n", to measure over before returning a period count.

This routine was used when it provided a finer resolution then existing bpFreq_count() routine:

- Code: Select all
`unsigned long bpPeriod_count(unsigned int n){`

static unsigned int i;

static unsigned long j, k, l, m, d, s;

IFS0bits.IC2IF=0; // clear input capture interrupt flag

IFS0bits.IC1IF=0; // clear input capture interrupt flag

// configure IC1 to RP20 (AUX)

RPINR7bits.IC2R=AUXPIN_RPIN;

RPINR7bits.IC1R=AUXPIN_RPIN;

//timer 4 internal, measures interval

TMR5HLD=0x00;

TMR4=0x00;

T4CON=0b1000; //.T32=1, bit 3

//start timer4

T4CONbits.TON=1;

// unimplemented: [15:14]=0b00,

// ICSIDL: [13]=0b0, input capture module continues to operate in CPU idle mode

// ICTSEL[2:0]: [12:10]=0b010=TMR4, 0b011=TMR5 (unimplemented for 16-bit capture)

// unimplemented: [9:8]=0b00

// ICTMR: [7]=0b0=TMR3, 0b1=TMR2 (unimplemented for 32-bit capture)

// ICI[1:0]: [6:5]=0b00, 1 capture per interrupt

// ICOV,ICBNE: [4:3]=0b00, read-only buffer overflow and not empty

// ICM[2:0]: [2:0]=0b011, capture every rising edge

IC2CON1=0x0C03; // fails with ICM 0 or 3 (0 always read from IC2BUF)

IC1CON1=0x0803;

// unimplemented: [15:9]=0b0000000

// IC32: [8]=0b0

// ICTRIG: [7]=0b0, synchronize with SYNCSEL specified source

// TRIGSTAT: [6]=0b0, cleared by SW, holds timer in reset when low, trigger chosen by syncsel sets bit and releases timer from reset.

// unimplemented: [5]=0b0

// SYNCSEL[4:0]: [4:0]=0b10100, selects trigger/synchronization source to be IC1.

IC2CON2=0x0014;

IC1CON2=0x0014;

// read input capture bits n times

while(IC1CON1bits.ICBNE) // clear buffer

j = IC1BUF;

while(IC2CON1bits.ICBNE) // clear buffer

k = IC2BUF;

while(!IC1CON1bits.ICBNE); // wait for ICBNE

k = IC1BUF;

m = IC2BUF;

for(i=s=0; i<n; i++) {

while(!IC1CON1bits.ICBNE); // wait for ICBNE

j = IC1BUF;

l = IC2BUF;

d = ((l-m)<<16) + (j-k);

s = s + d;

m = l;

k = j;

}

// turn off input capture modules, reset control to POR state

IC1CON1=0;

IC1CON2=0;

T4CONbits.TON=0;

return s/n;

}

To determine the finer resolution, a comparison was done between the frequency resolution provided by bpFreq_count(), which counts AUX signal edges over a 1 second interval, and the frequency resolution provided by the new routine, bpPeriod_count(), which captures 16MHz timer values each AUX signal edge.

Since we count frequency over a 1 second interval:

Frequency = f

where "f" is the frequency measurement count by the existing method.

And how fine this resolution is can be calculated over an increment as:

(f - (f-1))/f

or simply the expected 1/f.

Since the period is measured with a 16MHz clocked timer:

Frequency = 16e6/p

Where "p" is the period count of a captured 16MHz timer.

And how fine this resolution is can be calculated over an increment as:

(16e6/(p-1) - 16e6/p) / 16e6/(p-1)

which reduces to 1 - (p-1)/p.

The crossing point where 1-bit of frequency resolution provided by a period count is equivalent to 1-bit of

frequency resolution provided by a frequency count is given by the equation:

1 - (p-1)/p = 1/f

Noting f = Frequency = 16e6/p, we can determine the crossing point count by solving:

1 - (p-1)/p = p/16e6

which reduces to p=4000

Therefore, frequency measurement resolution can be improved using the new period measurement routine for p>4000.

For p slightly greater the 4000, it makes sense to output an additional fractional decimal digit. An equation very similar to the

above can be used to determine when it makes sense to output yet another fractional decimal digit, i.e. when p is greater then

the crossing point where an increment of period count resolution is 1/10 of an increment of frequency resolution:

1 - (p-1)/p = 0.1*p/16e6

which reduces to p=4*10^(7/2) or p=1.264911e4

For our measurements, recall that recalculating using a period count to improve the measurement resolution was roughly limited to 1 second (p=16e6), limited by the initial frequency count>=1. For period counts less the 16e6, Additional equations were solved for decimal digit crossing points resulting in the following table:

- Code: Select all
`| Frequency Resolution | Period Count (p) | Frequency |`

|----------------------+------------------------+-----------|

| 1 | 4*10^(6/2) =4000 | 4000 |

| .1 | 4*10^(7/2) =1.264911e4 | 1264.911 |

| .01 | 4*10^(8/2) =4e4 | 400 |

| .001 | 4*10^(9/2) =1.264911e5 | 126.4911 |

| .0001 | 4*10^(10/2)=4e5 | 40 |

| .00001 | 4*10^(11/2)=1.264911e6 | 12.64911 |

| .000001 | 4*10^(12/2)=4e6 | 4 |

| .0000001 | 4*10^(13/2)=1.264911e7 | 1.264911 |

Experimentally it was determined, that it didn't make sense to output resolutions less then 1e-5 due to oscillator accuracy;

although, the commented code was retained should a more accurate timer clock source be used.