Skip to main content

Topics

This section allows you to view all Topics made by this member. Note that you can only see Topics made in areas you currently have access to.

Topics - mrmr

1
Bus Pirate Support / Frequency Resolution (pun intended)
Despite double sampling in firmware, an earlier attempt to improve frequency resolution by measuring the period(s) proved to intermittently fail for frequencies above 775Hz. More frequent failures occurred at 2 KHz especially when a high jitter sourced clock signal (DLL generated) was used. During failure either a timer timeout failed to set the interrupt flag or the reading IFS1bits.T5IF failed. This resulted in a long pause during frequency measurement, requiring the timer to loop, before code execution continued.

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]
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]
| 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.
2
Bus Pirate Support / Improving Frequency Measurement Resolution & Gremlins
Hi All,

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://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]
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]
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.

( ! ) Fatal error: Uncaught exception 'Elk_Exception' with message 'Please try again. If you come back to this error screen, report the error to an administrator.' in /var/www/dangerousprototypes/forum/sources/database/Db-mysql.class.php on line 696
( ! ) Elk_Exception: Please try again. If you come back to this error screen, report the error to an administrator. in /var/www/dangerousprototypes/forum/sources/database/Db-mysql.class.php on line 696
Call Stack
#TimeMemoryFunctionLocation
10.01202314592session_write_close ( )...(null):0
20.01222446184ElkArte\sources\subs\SessionHandler\DatabaseHandler->write( )...(null):0
30.01232446960Database_MySQL->query( ).../DatabaseHandler.php:119
40.05712585696Database_MySQL->error( ).../Db-mysql.class.php:273