I've been playing with my bpv4 recently and I noticed while measuring frequency results were unexpected.
I addressed one of the problems observed as a printing error with bpWlongdecf(). Please see
http://dangerousprototypes.com/track/view.php?id=66
The other problem appeared to be a resolution issue. As an example, while measuring a 2Hz frequency, the measurement was often 1Hz. So I decided to take a stab at improving frequency measurements. I decided to use the prescaler only when necessary. I also decided to measure the period and divide for low frequencies.
I updated AUXpin.c bpFreq() with:
- Code: Select all
void bpFreq(void){
//static unsigned int j,k;
long l;
if(AUXmode==AUX_PWM){
//bpWline(OUMSG_AUX_FREQ_PWM);
BPMSG1037;
return;
}
//bpWstring(OUMSG_AUX_FREQCOUNT);
BPMSG1038;
//setup timer
T4CON=0; //make sure the counters are off
T2CON=0;
//timer 2 external
AUXPIN_DIR=1;//aux input
RPINR3bits.T2CKR=AUXPIN_RPIN; //assign T2 clock input to aux input
// should be good on bpv4
T2CON=0b111010; //(TCKPS1|TCKPS0|T32|TCS); prescale to 256
// counter only seems to be good til around 6.7MHz,
// use 4.2MHz (nearest power of 2 without exceeding 6.7MHz) for reliable reading
l=bpFreq_count();// all measurements within 26bits (<67MHz)
if(l>0x3fff){//if >4.2MHz prescaler required
l*=256;//adjust for prescaler
}else{// get a more accurate reading without prescaler
//bpWline("Autorange");f
BPMSG1245;
T2CON=0b001010; //(TCKPS1|TCKPS0|T32|TCS); prescale to 0
l=bpFreq_count();
}
if(l>0x3ff){//if it's less than 1KHz, get a more accurate reading by measuring period
bpWlongdecf(l); // this function uses comma's to seperate thousands.
}else{// counting tics is inferior to measuring period for low frequencies
BPMSG1245;
l=bpLFreq_count();
if(l<0) BPMSG1244; // " UNKNOWN ERROR", no timeout but not count either.
else if(l==0) bpWline("Frequencies < 1Hz not supported");
else{
bpWlongdecf(l/100);
UART1TX('.');
l = l % 100;
if (l < 10) UART1TX('0');
bpWdec(l);
}
}
if(l>0) bpWstring(" Hz");
bpWBR;
//return clock input to other pin
RPINR3bits.T2CKR=0b11111; //assign T2 clock input to nothing
T4CON=0; //make sure the counters are off
T2CON=0;
}
which uses a new function bpLFreq_count():
- Code: Select all
long bpLFreq_count(void){
static unsigned int j;
static long l;
//timer 4 internal, measures interval
TMR5HLD=0x00;
TMR4=0x00;
T4CON=0b1000; //.T32=1, bit 3
//one second of counting time
PR5=0xf4;//most significant word
PR4=0x2400;//least significant word
IFS1bits.T5IF=0;//clear interrupt flag
//timeout on timer4 (timer 5 interrupt) while looking for rising edge
j=IOPOR & AUX;
//start timer4
T4CONbits.TON=1;
// timeout on interrupt
while(IFS1bits.T5IF==0) {
// break on rising edge
if((IOPOR & AUX) && !j) break;
j=IOPOR & AUX;
};
//stop timer4
T4CONbits.TON=0;
// rising edge never found, no support for <1Hz
if(IFS1bits.T5IF) return 0;
//timer 4 internal, measures interval
TMR5HLD=0x00;
TMR4=0x00;
T4CON=0b1000; //.T32=1, bit 3
IFS1bits.T5IF=0;//clear interrupt flag
//timeout on timer4 (timer 5 interrupt) while looking for rising edge
j=IOPOR & AUX;
//start timer4
T4CONbits.TON=1;
// timeout on interrupt
while(IFS1bits.T5IF==0) {
// break on rising edge
if((IOPOR & AUX) && !j) break;
j=IOPOR & AUX;
};
//stop timer4
T4CONbits.TON=0;
// rising edge never found, no support for <1Hz
if(IFS1bits.T5IF) return 0;
//spit out 32bit value
j=TMR4;
l=TMR5HLD;
l=(l<<16)+j;
// convert to 1/100 of a Hz
if(l) return(0x00f42400*100/l);
// error, no timeout interrupt but count still 0.
return -1;
}
This code seemed to work good for the two high end ranges; however, for the low frequency range (when bpLFreq_count was called) Gremlins went to work.
For an unknown reason this function returned a frequency of f/N where N can be 1 to 4. When N=1the results are exactly what I expect.
Does anyone have any idea what might be going on?
Do I have "special" hardware? Could someone repeat this and confirm the results I see?
Thanx.



