Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] detecting these delays in ISR execution ( "interrupt latency" )

Status
Not open for further replies.

Kittu20

Member level 2
Member level 2
Joined
Oct 18, 2022
Messages
52
Helped
1
Reputation
2
Reaction score
0
Trophy points
6
Activity points
427
Hello everyone,

I'm interested in understanding the potential reasons why processors can experience delays when executing ISR (Interrupt Service Routine) code and how we can determine if the processor is indeed getting delayed during ISR execution. I have written interrupt code for my microcontroller to generate a 1ms timer interrupt. For simplicity, I have removed some unnecessary parts of the code. Here's my simplified code for generating the 1ms timer interrupt for reference.

I have this question because I came across the term "interrupt latency" and I read that due to interrupt latency, processors can experience delays in executing ISR. Can you provide information into the factors that might lead to such delays and suggest methods or tools for monitoring and detecting these delays in ISR execution?

C:
#define _XTAL_FREQ 8000000

// PIC18F45K80 Configuration Bit Settings
// CONFIG1L
#pragma config RETEN = OFF      // VREG Sleep Enable bit (Ultra low-power regulator is Disabled (Controlled by REGSLP bit))
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep)
#pragma config SOSCSEL = HIGH   // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)

// CONFIG1H
#pragma config FOSC = INTIO2    // Oscillator (Internal RC oscillator)
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power Up Timer (Disabled)
#pragma config BOREN = SBORDIS  // Brown Out Detect (Enabled in hardware, SBOREN disabled)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (1.8V)
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1048576  // Watchdog Postscaler (1:1048576)

// CONFIG3H
#pragma config CANMX = PORTB    // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively)
#pragma config MSSPMSK = MSK7   // MSSP address masking (7 Bit address masking mode)
#pragma config MCLRE = ON       // Master Clear Enable (MCLR Enabled, RE3 Disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Overflow Reset (Enabled)
#pragma config BBSIZ = BB2K     // Boot Block Size (2K word Boot Block size)

// CONFIG5L
#pragma config CP0 = OFF        // Code Protect 00800-01FFF (Disabled)
#pragma config CP1 = OFF        // Code Protect 02000-03FFF (Disabled)
#pragma config CP2 = OFF        // Code Protect 04000-05FFF (Disabled)
#pragma config CP3 = OFF        // Code Protect 06000-07FFF (Disabled)

// CONFIG5H
#pragma config CPB = OFF        // Code Protect Boot (Disabled)
#pragma config CPD = OFF        // Data EE Read Protect (Disabled)

// CONFIG6L
#pragma config WRT0 = OFF       // Table Write Protect 00800-01FFF (Disabled)
#pragma config WRT1 = OFF       // Table Write Protect 02000-03FFF (Disabled)
#pragma config WRT2 = OFF       // Table Write Protect 04000-05FFF (Disabled)
#pragma config WRT3 = OFF       // Table Write Protect 06000-07FFF (Disabled)

// CONFIG6H
#pragma config WRTC = OFF       // Config. Write Protect (Disabled)
#pragma config WRTB = OFF       // Table Write Protect Boot (Disabled)
#pragma config WRTD = OFF       // Data EE Write Protect (Disabled)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protect 00800-01FFF (Disabled)
#pragma config EBTR1 = OFF      // Table Read Protect 02000-03FFF (Disabled)
#pragma config EBTR2 = OFF      // Table Read Protect 04000-05FFF (Disabled)
#pragma config EBTR3 = OFF      // Table Read Protect 06000-07FFF (Disabled)

// CONFIG7H
#pragma config EBTRB = OFF      // Table Read Protect Boot (Disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

__bit timeFlag = 0;
//volatile int timeFlag = 0;
volatile unsigned char seconds = 0;


// Calculate Reload_Value for 1ms with a 20 MHz oscillator and prescaler 8
#define Reload_Value 625 // (20,000,000 XTAL / 4 / 8 prescale) = 625

void initializeTimer1() {
    // Configure Timer1 in 8-bit mode with a prescaler of 8
    T1CON = 0b00110000; // mode 0x08 interrupt, CCP1 pin hi on ==

    // Configure CCP module
    // CCP1CON = 0b00001011; // 0x0B
    CCP1CON = 0b00001000; // 0x08
  
    // Load the high and low bytes of Reload_Value into CCPR1
    CCPR1 = Reload_Value;
   // CCPR1H = (Reload_Value >> 8); // Load high byte of Reload_Value
   // CCPR1L = (Reload_Value & 0xFF); // Load low byte of Reload_Value

    // Clear Timer1 registers
    TMR1H = 0;
    TMR1L = 0;

    // Clear Timer1 interrupt flag
  //  TMR1IF = 0;
    // Clear CCP1 interrupt flag
    CCP1IF = 0;
  
    // Start Timer1 and CCP module
    TMR1ON = 1;
    CCP1IE = 1; // Enable CCP1 interrupt
}

void main() {
    // Initialize Timer1
    initializeTimer1();

    // Initialize INTCON register
    INTCON = 0; // Clear INTCON register
  
    // Enable global and peripheral interrupts
    INTCONbits.PEIE = 1; // Peripheral Interrupt Enable
    INTCONbits.GIE = 1;  // Global Interrupt Enable

    while (1) {
        // Check if the timeFlag is set (1ms interval)
        if (timeFlag) {
            // Increment seconds
            seconds++;

          
            // Reset the timeFlag to indicate that the 1ms interval has been processed
            timeFlag = 0;
        }
    }
}

void __interrupt() ISR() {
    if (CCP1IF){     
               // Clear the CCP1 interrupt flag
        CCP1IF = 0;
                // advance COMPARE value
        CCPR1 += Reload_Value;
      
        timeFlag = 1;    // Notify main routine
    }
}
 

Solution
Hi,

how to detect the latency:
* read out the counter value in the ISR and subtract CCPR1 value.

Reasons for the latency:
* finishing the currently running command
* Interrupt is maked out (single interrupt or globally) maybe to perform an "atomic process"
* other ISR is currently running that prevents another ISR to be executed
* maybe other reasons

However, latency usually is small unless your code creates them. In this case: optimize your code.
And usually small latencies don´t cause a problem. The timing from executing one ISR to the next ISR may be jittery, but does not add up.
This means if your 1ms uncertainty is +/-2us, then the expectable timing for 1000 x ISR should still be 1000ms +/- 2us.
I see you add an offset to the...
Hi,

how to detect the latency:
* read out the counter value in the ISR and subtract CCPR1 value.

Reasons for the latency:
* finishing the currently running command
* Interrupt is maked out (single interrupt or globally) maybe to perform an "atomic process"
* other ISR is currently running that prevents another ISR to be executed
* maybe other reasons

However, latency usually is small unless your code creates them. In this case: optimize your code.
And usually small latencies don´t cause a problem. The timing from executing one ISR to the next ISR may be jittery, but does not add up.
This means if your 1ms uncertainty is +/-2us, then the expectable timing for 1000 x ISR should still be 1000ms +/- 2us.
I see you add an offset to the CCPR1 value. This is the correct software way. But if possible I´d use a hardware solution. Many microcontroller have an option to automatically relaod the value for the next event.

Klaus
 
Solution
The snippet do not evince any reason to add any kind of latency other than the above assignment themselves, let's agree, negligible. Since you said that had removed unrelated code to the issue, it is possible that there was blocked instructions there, such as flag check ( while... ), callback built-in functions, etc.
 
Stack push one primary reason for latency. Good practice is to minimize f()
calls inside an ISR. which can cause a lot of stack push. Also using pointers
excellent method of minimizing latency.

ISR priority setting in IDE.....

Google "interrupt latency embedded pdf", lots more info.


Regards, Dana.
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top