PIC18F47J13 Capture Mode?

JohnInTX

Joined Jun 26, 2012
4,787
@spinnaker
Keep in mind that when you read the CCP registers, you get two unsigned integers (16 bit). When you subtract them, you get a 2's compliment result but the compiler still treats that result as unsigned. I'm not real sure how XC8 would take casting this to a signed value (it's fussy about such things) but you'll need to do that to be able to complement that arithmetically. HitechC didn't mind.
I'll do some poking around on it..

EDIT2: Disregard. Math is wrong.. Writing C, thinking assembler. Grr,
 
Last edited:

jpanhalt

Joined Jan 18, 2008
11,087
EDIT: Turns out it's pretty simple. Leave the timer values as unsigned, subtract and look at MSbit. If MSbit==1, the result is negative and is the two's complement of the difference. I didn't try any fancy casting to signed values etc.
Not sure that will always work. One of many examples, T2=0xA0FF, T1= 0x01FF. T2-T1 = 0x9F00, which is really positive. Wouldn't looking at STATUS,0 be just as easy and definitive?

That's where the newer instructions help (e.g., my post w/ code). Not sure there is any C-equivalent, but they have been around so long, there must be some use of them.

John
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
The timer overflow sets the timer interrupt flag that can trigger a ISR routine to keep track.

OK so then I just have an interrupt for the timer and increment the count.


I assume the overflow counter would be reset on the second CCP event?
 

JohnInTX

Joined Jun 26, 2012
4,787
Not sure that will always work. One of many examples, T2=0xA0FF, T1= 0x01FF. T2-T1 = 0x9F00, which is really positive. Wouldn't looking at STATUS,0 be just as easy and definitive?

That's where the newer instructions help (e.g., my post w/ code). Not sure there is any C-equivalent, but they have been around so long, there must be some use of them.

John
You couldn't use STATUS,0 since in C you don't know what the intervening instructions are that would change the carry flag. As for 9F00, it's positive for unsigned numbers but its -24832 (dec) in 2's compliment which is what you get after the subtract. I guess I should have said that the max difference is 32767 as the MSbit indicates the sign.

Good catch!
 

nsaspook

Joined Aug 27, 2009
13,315
It's more about understanding binary math on a given device. The C language has a complete implementation of binary math operators. The number format is hardware dependent.
 

jpanhalt

Joined Jan 18, 2008
11,087
Yes, of course, but Timer1 is 16 bits in this case. So, manipulations of its counts could logically be just 16-bit + carry. Multiple overflows are not counted, unless you do as @JohnInTX suggests. Moreover, the TS's test cases do not exceed 16-bits. At 8 MHz, one click is 0.125 us; 65536 clicks is 8.125 ms or about 123 revolutions per second = 7385 rpm. In fact, the TS's examples are about half that.

Now, if they were much lower "rpm", then a simple solution would be to use a slower clock for TMR1. The TS has not told us what degree of precision he needs nor the lowest "rpm" of significance.

I don't object to striving for much greater than 1 part in 2^16 accuracy (<0.002%), but is that needed?
 

nsaspook

Joined Aug 27, 2009
13,315
I think the most of us are holding back at bit on solutions and requirements so the OP can discover answers on his own per his request.
 

JohnInTX

Joined Jun 26, 2012
4,787
Since you're likely to use floats for calculation, I'd do this:
C:
/*
* File:  AACspinnaker.c
* Author: JohnInTX
*
* Created on November 2, 2018, 1:09 PM
*/

// PIC18F47J13 Configuration Bit Settings
// 'C' source line config statements

// CONFIG1L
#pragma config WDTEN = OFF  // Watchdog Timer (Disabled - Controlled by SWDTEN bit)
#pragma config PLLDIV = 1  // 96MHz PLL Prescaler Selection (PLLSEL=0) (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CFGPLLEN = OFF  // PLL Enable Configuration Bit (PLL Disabled)
#pragma config STVREN = ON  // Stack Overflow/Underflow Reset (Enabled)
#pragma config XINST = OFF  // Extended Instruction Set (Disabled)

// CONFIG1H
#pragma config CP0 = OFF  // Code Protect (Program memory is not code-protected)

// CONFIG2L
#pragma config OSC = ECPLL  // Oscillator (EC+PLL (CLKO-RA6))
#pragma config SOSCSEL = HIGH  // T1OSC/SOSC Power Selection Bits (High Power T1OSC/SOSC circuit selected)
#pragma config CLKOEC = ON  // EC Clock Out Enable Bit  (CLKO output enabled on the RA6 pin)
#pragma config FCMEN = ON  // Fail-Safe Clock Monitor (Enabled)
#pragma config IESO = ON  // Internal External Oscillator Switch Over Mode (Enabled)

// CONFIG2H
#pragma config WDTPS = 32768  // Watchdog Postscaler (1:32768)

// CONFIG3L
#pragma config DSWDTOSC = INTOSCREF// DSWDT Clock Select (DSWDT uses INTRC)
#pragma config RTCOSC = T1OSCREF// RTCC Clock Select (RTCC uses T1OSC/T1CKI)
#pragma config DSBOREN = ON  // Deep Sleep BOR (Enabled)
#pragma config DSWDTEN = ON  // Deep Sleep Watchdog Timer (Enabled)
#pragma config DSWDTPS = G2  // Deep Sleep Watchdog Postscaler (1:2,147,483,648 (25.7 days))

// CONFIG3H
#pragma config IOL1WAY = ON  // IOLOCK One-Way Set Enable bit (The IOLOCK bit (PPSCON<0>) can be set once)
#pragma config ADCSEL = BIT10  // ADC 10 or 12 Bit Select (10 - Bit ADC Enabled)
#pragma config PLLSEL = PLL4X  // PLL Selection Bit (Selects 4x PLL)
#pragma config MSSP7B_EN = MSK7 // MSSP address masking (7 Bit address masking mode)

// CONFIG4L
#pragma config WPFP = PAGE_127  // Write/Erase Protect Page Start/End Location (Write Protect Program Flash Page 127)
#pragma config WPCFG = OFF  // Write/Erase Protect Configuration Region  (Configuration Words page not erase/write-protected)

// CONFIG4H
#pragma config WPDIS = OFF  // Write Protect Disable bit (WPFP<6:0>/WPEND region ignored)
#pragma config WPEND = PAGE_WPFP// Write/Erase Protect Region Select bit (valid when WPDIS = 0) (Pages WPFP<6:0> through Configuration Words erase/write protected)
#include <xc.h>

unsigned int first;  // the 16 bit captured values (unsigned int)
unsigned int second;
float Fdiff;

void main(void) {

  first = 0x00c8;  // 200
  second = 0x0064; // 100 NOTE: counted from 200 through 65535->0000 and further to 100
  // almost a full wrap around - total number of COUNTS is 65436

  while(1){  // set breakpoint here, modify values in the Variables debug window
   Fdiff = (float)second-(float)first;  // promote to float and subtract
   if(Fdiff < 0)  // iff negative, add to compensate for wraparound
    Fdiff += 65536.0;

  }// while
}
You could also do it with integers (even 16 bit ones) but managing the wraparound takes some monkey motion.
 

Travm

Joined Aug 16, 2016
363
At first glance I think your seeing the timer overflow. However you should look at your configuration bits closely.

Code:
T1CONbits.TMR1CS = 1
TMR1CS is 2 bits, So I think this should be
Code:
T1CONbits.TMR1CS1 = 0
T1CONbits.TMR1CS0 = 1
Ditto for T1CKPS,
I could be wrong. In the interest of being sure everything is set correctly I prefer to set each register as a full byte, but I think that's just a personal preference. I find it easier to read the data sheets the way they present the registers than doing it bit by bit.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
At first glance I think your seeing the timer overflow. However you should look at your configuration bits closely.

Code:
T1CONbits.TMR1CS = 1
TMR1CS is 2 bits, So I think this should be
Code:
T1CONbits.TMR1CS1 = 0
T1CONbits.TMR1CS0 = 1
Ditto for T1CKPS,
I could be wrong. In the interest of being sure everything is set correctly I prefer to set each register as a full byte, but I think that's just a personal preference. I find it easier to read the data sheets the way they present the registers than doing it bit by bit.

You are wrong. I am not yet using an external clock.
 
Last edited:

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
Alright I figured it out. I was getting thousands of overflows. So I slowed things done.

My clip is running on the 8MHZ internal oscillator.

I chose the Timer1 clock source is the instruction clock (FOSC/4) option T1CONbits.TMR1CS = 0;

I set 8:1 prescaler

Now I am not getting any overflows.

If I am doing my math correctly that is 8,000,000 /4 / 8 or a timer frequency of 250khz or a period of 0.000004 seconds


Now my ticks per rotation is 11307

11307 * 000004 = 0.045228 or 45ms

Which is what I am seeing on my scope.

upload_2018-11-2_23-29-14.png

I assume I did my math correctly?

Thanks for the idea of counting the workflows. That one would have driven me crazy trying to figure out what was going on.
 

jpanhalt

Joined Jan 18, 2008
11,087
Now I am not getting any overflows.
If Timer1 is running continuously, you should still be getting overflows, but not more than one per set of values. At 4 us per tick, it should overflow approximately once every 262 ms. The math still needs to handle the overflow when T1>T2, as has been show to you.

The value you report (45 ms) is well below that so there will be no instances with more than one overflow at that rate. Forty-five milliseconds equates to 22.2 rev/s or 1333 rpm. At a slower speed, say 100 rpm (1.67 rev/s = 600 ms/revolution), your counter will overflow more than once per revolution. When that happens, the math should still give reasonably consistent numbers, but they will be wrong. Failure to detect multiple overflows simply subtracts a constant from the count differences (i.e., T2-T1). Thus, your original data set (post #14) gave reasonable values, but the calculated rpm was much higher than the real rpm.
 

jpanhalt

Joined Jan 18, 2008
11,087
Resetting TMR1 on CCP does not eliminate the problem with slow speeds and overflow of counts.

Can you please tell us what range of speeds you need to measure?
 

Ian Rogers

Joined Dec 12, 2012
1,136
Nothing about that post was related to an external clock
He is referring to the TMR1CS bit... This is the external / internal clock select bit.... He doesn't need this switched on...

I think you were referring to the pre-scaler bits and not the clock select (CS) bit! Just a misunderstanding!
 
Top