PIC16 XC8 CCP Capture module issues? - Page 1
Forum section: electronics / general

author: nexus
author_rank: Regular Contributor
timestamp: February 07, 2021, 03:30:27 am
content: Hi all,Almost ready to call my first pic project done... its been a long road and lots of lessions learned. I've been developing on the second rev of a custom 16F1788 board I made.Last issue I'm running into is an issue using one of the CCP modules to Capture. Since this project is for a fan controller, I have PWM going out to the fan on CCP1 and the fan tachometer signal on CCP2. I've got the PWM on CCP1 working no problem. I'm just struggling to get CCP2 to capture the tachometer period so I can calculate RPM and display it.I've read and reread the datasheet as well as found some helpful examples.One such example I've referenced heavily is page 16 of this:http://ww1.microchip.com/downloads/en/Appnotes/00003381A.pdfAccording to the datasheet, CCP modules use Timer1 (16 bits) in capture and compare modes. I believe I'm setting up the CCP2 and TMR1 registers correctly for my intentions:Code:Tach_Initialize() {//CCP modules use TMR1 as timebase in both capture and compare modesTMR1CS1 = 0; //Timer 1 clock source is instruction clock (Fosc/4)TMR1CS0 = 0;T1CONbits.nT1SYNC = 1; //T1CKPS1 = 1; //Timer 1 prescale value is 1:4T1CKPS0 = 0;TMR1ON = 1; // Timer1 always onTMR1GE = 0;//CCP2 configCCP2M3 = 0; //Capture on rising edge of CCP2 input (RB3)CCP2M2 = 1;CCP2M1 = 0;CCP2M0 = 1;CCPR2H = 0x00; //initialize CCP2 high and low registers to zeroCCPR2L = 0x00;CCP2IF = 0; // Clear CCP2 interrupt request bitCCP2IE = 1; // Enable CCP2 peripheral interrupt}I also initialize RB3 as follows:Code:TRISB = (1<<3); //set RB3 as inputAPFCON1 = (1<<0); //set bit 0 (RB3) as CCP2 in alternate pin register 1The rest of my configs for general setup are as follows:Code:// CONFIG1#pragma config FOSC = INTOSC // INTOSC oscillator#pragma config PLLEN = ON //PLL ON#pragma config WDTE = OFF // WDT disabled#pragma config PWRTE = OFF // Power-up Timer disabled#pragma config MCLRE = OFF // MCLR/VPP pin function is MCLR#pragma config CP = OFF // Code protection is disabled#pragma config CPD = OFF // Data Memory Code Protection disabled#pragma config BOREN = OFF // Brown-out Reset disabled#pragma config CLKOUTEN = OFF // Clock Out disabled.#pragma config IESO = OFF // Internal/External Switchover disabled#pragma config FCMEN = OFF // Fail-Safe Clock Monitor is disabled// CONFIG2#pragma config WRT = OFF // Flash Memory Self-Write Protection off#pragma config PLLEN = ON // PLL Enable (4x PLL enabled)#pragma config STVREN = OFF // Stack Overflow /Underflow reset disabled#pragma config BORV = LO // Brown-out Reset Voltage Selection#pragma config LVP = OFF // Low-Voltage Programming disbledfinally, I have an ISR which runs a few things, including the display update and a rotary encoder scan, into which ive also added the fan tachometer routine I mimicked from that microchip resource:Code:void __interrupt() display_encoder (void) {if(INTCONbits.T0IF && INTCONbits.T0IE) {// if timer flag is set & interrupt enabledTMR0 -= 250;//display routine...//encoder routine...//fan tachometerccp2val =(CCPR2H <<8)^CCPR2L;//or// ccp2val = CCPR2L;// ccp2val|= CCPR2H*256U;prevCapt1 = currentCapt1;currentCapt1 = ccp2val;if(currentCapt1 > prevCapt1) {fan1_tmr_val = currentCapt1 - prevCapt1; // Find tach period}else // Timer1 rolled over{fan1_tmr_val=(0xFFFF-prevCapt1)+currentCapt1;}fan1_spd = timer_const / fan1_tmr_val;CCP2IF = 0; //clear CCP2 interrupt flagT0IF = 0; // clear timer0 interrupt flag}}however, even following the example closely and double and triple checking the datasheet to make sure CCP2 and TMR1 are configured correctly, I can't get any sensible numbers to display in correlation the fan speed. I have my scope hooked up across the tachometer input (RB3) which is an open collector that pulls low twice per fan rev. The square wave is perfectly fine, so I know signal is getting to RB3.For reference, at low fan speeds the frequency is around 70hz (14.4ms period) and around 50% is 267hz or a 3.7ms period. Even though I'm using the TIMER_CONST in the example, I should at least get a value on my display even if it is totally incorrect. So far, nothing shows up when I try to display fan1_spd (I've verified that my display routine works with other numeric values).Not sure where I'm making a mistake?

author: nexus
author_rank: Regular Contributor
timestamp: February 07, 2021, 06:20:31 am
content: A few more hours of suffering and I found a well enough documented example that worked:https://www.microchip.com/forums/m837075.aspxHope that link is helpful for others as well. I will be making the project open source soon! Schematic and some test setup pics attached.