CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

CCP Module, Max edge capture rate, and interrupt latency

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
apakSeO



Joined: 07 Dec 2016
Posts: 60
Location: Northeast USA

View user's profile Send private message

CCP Module, Max edge capture rate, and interrupt latency
PostPosted: Fri May 31, 2019 11:26 am     Reply with quote

PIC16F1779
CCS v5.081

Goal: I'm trying to capture both rising and falling edges of a 56kHz signal in one of this PICs CCP modules; specifically, CCP8. This input signal has a frequency of 56kHz maximum; thus the minimum time between rising/falling edges is 1/2*56kHz = 8.93us

I wish to capture every rising/falling edge into a 16-bit circular buffer, for later processing in the main loop.

I find that running at 16MHz clock, I am struggling with (a) the interrupt latency and (b) the amount of time to service the ISR. It is pretty disheartening to find out that a measly 56kHz square wave cannot be measured by this uC running at 16MHz. Can anything be done in my code to speed either of these operations?

Here is example code:
Code:

#include <16F1779.h>
#device PIC16F1779
#device ICD=TRUE                                             
#device ADC=10
#use delay(INTERNAL=16MHZ, CLOCK=16MHZ)
#fuses INTRC_IO
#fuses NOWDT           
#fuses NOPROTECT
#fuses DEBUG
#fuses CLKOUT
#fuses NOBROWNOUT
#fuses NOPUT

#include <stdint.h>

volatile uint16_t  edges[16]        = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
volatile uint8_t  edges_idx         = 0;

void main(void)
{
    // Set B0 as an input
    set_tris_b(0b00000001);
    port_b_pullups(0b00000000);
   
    set_tris_c(0b00000000);
    port_c_pullups(0b00000000);
   
    // Configure CCP8 pin to CCP function
    #pin_select CCP8 = PIN_B0
 
    setup_ccp8(CCP_CAPTURE_EE|CCP_CAPTRUE_INPUT_CCP_PIN);

    // Setup timer1 ( 16-bit ) as the CCP time base.
    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);             // "T1_INTERNAL" --> T1CON:CS is "00" --> T1 Clock is Instruction Clock, Fosc/4
                                                        // "T1_FOSC"     --> T1CON:CS is "01" --> T1 Clock is System Clock, Fosc
    set_timer1(0);   

    // Enable the CCP8 interrupt
    enable_interrupts(INT_CCP8);
   
    // Enable interrupts globally
    enable_interrupts(GLOBAL);
   
    while(1)   
    {
     
    }//while(1)
       
}//void main())

#int_ccp8
void ccp8_capture_isr(void)
{   
    output_high(PIN_C7);
   
    edges[edges_idx] = get_capture(8);
    if( edges_idx < 15 )   edges_idx++;
    else                   edges_idx = 0;
   
    output_low(PIN_C7);
   
}



Now, a few screen shots to illlustrate what is happening:



( In the above scope capture, ignore the momentary spike; my signal generator is acting wonky today. )

YELLOW is input signal, a 56kHz, 50% duty cycle square wave.
BLUE is the PIN_C7 toggling high/low inside the ISR, for a rough timing estimate.

So you see the first spike, the ISR triggers ( let's ignore this spurious noise for sake of this convo )
Then you see the 1st real rising edge, then the ISR enters a whopping 10.2us later.



We spend about 7.2us inside the ISR.

The combination of ISR entrance latency + the time to service the ISR overflows into the next edge time, be it rising or falling.

Is there anything obvious I am doing in my code above that is increasing the time to enter the ISR, or to service it? Could there be another way of approaching this task in order to capture all the rising/falling edges?

Thanks for any help you may provide ahead of time Smile
Ttelmah



Joined: 11 Mar 2010
Posts: 19549

View user's profile Send private message

PostPosted: Fri May 31, 2019 11:39 am     Reply with quote

Look at using #INT_GLOBAL instead of the standard handling.

Example here (on a timer):
<http://www.ccsinfo.com/forum/viewtopic.php?t=49614&highlight=int+global>

Key is that your code will have to save every register that is used in
your handler code.

The standard interrupt handler save all registers used, and then checks
which interrupt has triggered. With a single interrupt this check is not
needed, and your code only needs to save registers it does use.

Result you can probably halve the latency.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri May 31, 2019 1:21 pm     Reply with quote

If your code does nothing else, or if you are willing to dedicate the
processor to only capturing for a short time, you could just
poll the CCP interrupt flag. Don't use an isr.
Ttelmah



Joined: 11 Mar 2010
Posts: 19549

View user's profile Send private message

PostPosted: Fri May 31, 2019 1:31 pm     Reply with quote

Very true.

It is important to remember that you can always just 'poll' an interrupt
(if (interrupt_active(INT_XXX))) and this is far faster than calling any
form of interupt handler.
With both #INT_GLOBAL or polling, remeber you have to clear the
interrupt.
apakSeO



Joined: 07 Dec 2016
Posts: 60
Location: Northeast USA

View user's profile Send private message

PostPosted: Wed Jun 05, 2019 11:26 am     Reply with quote

Thanks Guys,

Yes you're right; luckily in this application, I can poll endlessly in a tight loop with no impact to the main program while waiting for the first edge to come in.

Thanks for the suggestion. I can see this tool of ISR flag polling being useful in many circumstances in the future ....
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group