Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Old thread has been locked -- no new posts accepted in this thread
???
03/31/07 15:33
Read: times


 
#136325 - Trouble with PCA capture mode
Here's a problem that really has me stumped.

I want to use the capture mode of one of the PCA chanels on a Silicon Labs C8051F120 to measure a time interval that's a few microseconds long. I'm driving the PCA counter with the system clock, which is running at 14.7456 MHz. That gives me a timing resolution of about 68 nanoseconds, which is good enough for what I am doing.

Once I got it all set up, I noticed a bogus result every once in a while. This was originally a part of giant program running on brand new (and possibly buggy) hardware, so my first step was to try to reproduce the problem using a small program running on my trusy SiLabs C8051F120 evaluation board. Often when I try to reduce a problem to its essence, I find the solution in the process. But, alas, not this time. The problem still appears in the small program running on the evaluation board.

Here is the interesting part of the test program, with line numbers added for reference. For the record, I'm using the Archimedes 8051 C compiler version V4.23H/DXT. (I don't think that has anything to do with the problem, but you never know.)
 1 void main() {
 2 
 3     unsigned startTime;
 4     unsigned startTimeLo;
 5     unsigned startTimeHi;
 6     unsigned endTime;
 7     unsigned endTimeLo;
 8     unsigned endTimeHi;
 9     char i;
10 
11     InitializeHardware();
12     while (1) {                         /* Repeat forever */
13         getch();                        /* Wait for an asynchronous event */
14         EA = 0;                         /* No interrupts for a while */
15         CCF0 = 0;                       /* Clear PCA capture flag */
16         startTimeLo = PCA0L;            /* Read PCA counter, LSB */
17         startTimeHi = PCA0H;            /*  first per the data sheet */
18         i = 50; while (--i) ;           /* Spin here for a while */
19         P1.0 = 1;                       /* Assert PCA input line */
20         P1.0 = 1;                       /* Be sure to meet the pulse */
21         P1.0 = 1;                       /*  width requirement of two */
22         P1.0 = 1;                       /*  SYSCLK clock periods */
23         P1.0 = 0;                       /* End the pulse */
24         EA = 1;                         /* Interrupts okay now */
25         if (CCF0) {                     /* Good capture */
26             endTimeLo = PCA0CPL0;       /* Get the capture register */
27             endTimeHi = PCA0CPH0;
28 
29             startTime = startTimeLo + (startTimeHi << 8);
30             endTime   = endTimeLo   + (endTimeHi   << 8);
31             printf("start: %5u (0x%04X), end: %5u (0x%04X), elapsed: %5u\n",
32                 startTime, startTime, endTime, endTime, endTime - startTime);
33 
34             }                           /* End 'good capture' */
35         else {                          /* Bad capture */
36             printf("Bad capture\n");    /* Scream and holler */
37             }                           /* End 'bad capture' */
38         }                               /* End 'repeat forever' */
39     }                                   /* End main() */
When the hardware is initialized at line 11 (more on this later), P0.2 is configured as the PCA channel 0 input pin. I have P0.2 physically connected to P1.0 so that my program can generate pulses on the PCA input line. As I noted before, the PCA channel is configured in rising-edge capture mode, and the PCA clock is driven directly by SYSCLK.

The program repeatedly uses the PCA channel to measure the duration of the loop at line 18. Here's how it works in detail:
  • Immediately before the loop to be measured, lines 15-17 clear the PCA channel's capture flag and grab the start time from the PCA counter. Note that the program reads the low byte of the PCA counter first, as required by the data sheet.
  • Immediately after the loop being measured, lines 19-23 generate a positive pulse on the PCA input pin. As I understand it, this causes the PCA hardware to copy the contents of the PCA counter to the capture registers for reading later. Lines 19-22 are duplicated just to make sure the pulse is wide enough to be detected.
  • If all goes well, the PCA capture flag will have been set at line 25. Lines 26-32 will read the end time from the capture registers, calculate the elapsed time, and report the results.
Note (lines 14 and 24) that I have disabled interrupts during the actual measurement, so that the duration of the loop should be exactly the same every single time. Here is some typical output from the program:
start: 32693 (0x7FB5), end: 33483 (0x82CB), elapsed:   790
start: 61353 (0xEFA9), end: 62143 (0xF2BF), elapsed:   790
start: 14150 (0x3746), end: 14940 (0x3A5C), elapsed:   790
start: 47605 (0xB9F5), end: 48395 (0xBD0B), elapsed:   790
start: 12190 (0x2F9E), end: 12980 (0x32B4), elapsed:   790
start: 45301 (0xB0F5), end: 46091 (0xB40B), elapsed:   790
start:   235 (0x00EB), end:  1025 (0x0401), elapsed:   790
start: 16146 (0x3F12), end: 16936 (0x4228), elapsed:   790
start: 10560 (0x2940), end: 11350 (0x2C56), elapsed:   790
start: 42193 (0xA4D1), end: 42983 (0xA7E7), elapsed:   790
SYSCLK on the eval board runs at 22.1184 MHz, so PCA counter iteration represents about 45 nanoseconds. 790 times that is about 38 microseconds, which is reasonable for the loop at line 18.

So far so good.

The problem is that every once in a while, the measured time is low by exactly 256 counts, like this:
start: 14591 (0x38FF), end: 15125 (0x3B15), elapsed:   534
This only happens when the low byte of the start time is 0xFF, and it always happens when the low byte of the start time is 0xFF. Based on that observation, it seems to me that the program is not reading the PCA counter correctly at lines 16-17, but I don't see why.

On the "real" system where I first saw this problem (different hardware, different but similar code, slightly slower SYSCLK), the result is low by exactly 256 counts whenever the low byte of the start time is in the range 0xF9 through 0xFF, inclusive. How's that for weird?

For completeness, here's the interesting part of the test program's hardware init routine:
/*  ---------------------------------------------------------------------------
    Configure the C8051F120 I/O

    Here's how we're using the I/O ports.  (I) and (O) indicate inputs and
    outputs.

    P0.0 (O) - UART 0 TxD
    P0.1 (I) - UART 0 RxD
    P0.2 (I) - PCA Channel 0 - looped back from P1.0
  
    P1.0 (O) - Output connected to PCA input
    P1.6 (O) - LED on evaluation board
      ------------------------------------------------------------------------ */

    SFRPAGE = CONFIG_PAGE;                      /* Address xbar registers */

    XBR0 = 0x04 |                               /* Enable UART 0 RxD and TxD */
           0x08;                                /* Enable CEX0 */
    XBR2 = 0x40;                                /* Enable the crossbar */

    P0MDOUT = 0x01;                             /* Set up push-pull outputs */
    P1MDOUT = 0x41;

/*  ---------------------------------------------------------------------------
    Configure the PCA.  See Section 24 of the data sheet for complete info
    ------------------------------------------------------------------------ */

    SFRPAGE = PCA0_PAGE;                        /* PCA configuration page */
    PCA0MD = 0x08;                              /* PCA clock = SYSCLK */
    PCA0CN = 0x40;                              /* Enable the PCA counter */

    PCA0CPM0 = 0x20;                            /* Put PCA Module 0 in rising-
                                                    edge capture mode */
Of course there's more stuff to set up the UART, timers, etc. If you want to see the whole program, it's here.

Has anybody had problems like this with the PCA? Can anybody see where I've done something stupid? I'm stuck.

Thanks,

-- Russ


List of 6 messages in thread
TopicAuthorDate
Trouble with PCA capture mode            01/01/70 00:00      
   I recall something similar being discussed            01/01/70 00:00      
      Erik, is this the thread?            01/01/70 00:00      
         I guess so see quote below            01/01/70 00:00      
   Problem solved            01/01/70 00:00      
      gald to point you there            01/01/70 00:00      

Back to Subject List