??? 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:
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: 790SYSCLK 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: 534This 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 |
Topic | Author | Date |
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 |