1
\$\begingroup\$

I'm using the PIC18F46k22 mcu and I'm using two function in my high priority interrupt routine:

#pragma code
#pragma code My_HiPrio_Int=0x0008   
#pragma code
#pragma interrupt chk_isr

#pragma code
void My_HiPrio_Int(void)
{
    _asm
        GOTO chk_isr
    _endasm
}

void chk_isr(void)      /*Serial Interrupt*/
{   
    INTCONbits.GIE = 0;

    if(INTCONbits.TMR0IF==1)   //Timer routine
        Timer0_ISR();

    if(PIR1bits.RC1IF)     //RS485 receiver 
        RC_ISR();

    INTCONbits.GIE = 1;


}


void Timer0_ISR(void)
{
    nTick0++;

    if(pSet == 0) nTickSetPress++;
    else nTickSetPress = 0;

    if(pPlus == 0) nTickPlusPress++;
    else nTickPlusPress = 0;

    if(pMinus == 0) nTickMinusPress++;
    else nTickMinusPress = 0;

    if(pShift == 0) nTickShfPress++;
    else nTickShfPress = 0;

    if(pCountPlus == 0) nTickCount++;
    else nTickCount = 0;

    if(pReset == 0) nTickResetPress++;
    else nTickResetPress = 0;

    if(bCdlyStart == 1) nCdlyCount++;
    if(nCdlyCount >= nTickCdly) bCdlyStart = 0;

    if(bDisplayTime == 1) nDisplayTimeCount++;

    if(bBlinkDigitFast == 1) nTickBlinkFast++;

    TMR0H = TMR0HValue;
    TMR0L = TMR0LValue;
    INTCONbits.TMR0IF = 0;
}


void RC_ISR(void)       
{
    rxbuf485 = RCREG1;

    if (rxbuf485 == 0)
    {
        return;
    }

    if (rxbuf485 == TOKEN)
    {
        b485RxToken = 1;
        return;
    }

    if (b485RxComplete) return;

    if (!b485SOH)
    {
        if (rxbuf485 != SOH) return;
        b485SOH = 1;
        n485RxDataPos = 0;
        b485RxComplete = 0;
        memset (RS485RXDATA, 0, sizeof(RS485RXDATA));
        return;
    }   
    else if (rxbuf485 == EOT)
    {
        b485SOH = 0;
        b485RxComplete = 1;
        return;
    }
    if (n485RxDataPos == 50) 
        n485RxDataPos = 50;

    if (n485RxDataPos>=RS485RXSIZE) 
        n485RxDataPos--;

    RS485RXDATA[n485RxDataPos++] = rxbuf485;
    return;

}

void Timer0Init(void)
{
    T0CON = 0x07;
    TMR0H = TMR0HValue;
    TMR0L = TMR0LValue;
    T0CONbits.TMR0ON = 1;
    INTCONbits.TMR0IE = 1;
    nTick0 = 0; 
    nTickSetPress = 0;
    nTickResetPress = 0;
    nTickCdly = 0; 
    nTickBlinkFast = 0;
}

void RS485Init(void)
{
    TRISCbits.TRISC7=1;     // RX
    TRISCbits.TRISC6=0;     // TX

    TXSTA1 = 0x00;          
    RCSTA1 = 0x90;      
    SPBRG1 = 30;            
    BAUDCON1 = 0x00;    
    PIE1bits.RC1IE = 1;      
    TRISCbits.TRISC3 = 0;
    p485 = 0;               

    memset (RS485RXDATA, 0, sizeof(RS485RXDATA));   
}

Can two routine be done in a high priority interrupt? Will there be any problem in long term? This is because I'm trying to find out why my device always hang after running a few days...

\$\endgroup\$
  • 2
    \$\begingroup\$ Have you considered declaring your 2 functions as inline? This would avoid having these as real function calls in the compiled code. Also, the idea of using a function like memset inside an ISR doesn't seem like agood idea to me ... I couldn't really give you a good reason though - seems like there might be lots of unnecessary stack usage by all of the function parameter values. \$\endgroup\$ – brhans Oct 14 '14 at 1:47
  • \$\begingroup\$ Adding more to @brhans comment, I can see there is some unncessary code in those "ISR" functions. Also, you don't need a return at the end of function, you can save an instruction there. I don't think calling two functions in ISR making it unresponsive but there could be some another reason for that! \$\endgroup\$ – Swanand Oct 20 '14 at 9:22
  • \$\begingroup\$ Note also that with the C18, calling another function from the interrupt routine may add such an overhead that it fails badly. Check e.g. xargs.com/pic/c-faq.html#isrfunc In had the issue even with a short subroutine call (in C) on mplabx with xc8. So this is yet another reason to inline the calls, here again for the interruption to return as fast as possible. \$\endgroup\$ – MoonCactus Feb 22 '15 at 16:09
1
\$\begingroup\$

There is much silliness here:

  1. Your interrupt routine is just jumping into another routine instead of executing directly. You may need to do something like that if you are also using low priority interrupts, but this doesn't seem to be the case.

  2. What's with setting GIE to 0 in the interrupt routine? You need to actually read the datasheet.

  3. Even worse, you are setting GIE to 1 near the end of the second interrupt routine. I could try to explain why you shouldn't do that, but you need to read the datasheet anyway, so you can discover for yourself why this is a dumb idea.

  4. By being too clever by a half, as the British like to say, you have defeated the compiler's means of properly turning on interrupts again at the end of the interrupt service routine. Put another way, you are no longer running a RETFIE instruction.

  5. This whole thing could have been done much more easily in assembler, and then maybe you'd see how the interrupt code is messed up the way it is now. Unlike on large systems with many levels of abstraction, on small resource limited systems using a compiler doesn't alleviate the need to actually understand what is happening at the machine instruction level.

  6. Messing with machine details like interrupts absolutely requires reading the datasheet.

\$\endgroup\$
0
\$\begingroup\$

There's no trouble in calling functions within ISRs, neither assigning high priority to multiple peripherals as long as it doesn't create a conflict while servicing them. There are a couple of things to have in mind though, such as latency and the order in which you service them. Calling functions within ISRs add extra cycles when the context switch is performed (in and out), but its something that might not affect your application at all if weighed in. As for the order, consider writing up top the if(flag){} chain the higher priority or critical services, they will be checked first. There's something odd in your code and that might the the reason why your MCU hangs, after you call RC_ISR(); you are not clearing the PIR1bits.RC1IF flag. You are exiting the high priority ISR with a flag that will force a reentry.

\$\endgroup\$
  • \$\begingroup\$ There's no trouble in calling functions within ISRs There might be problems if the function in question is also called outside the interrupt and if the compiler doesn't support reentrant functions \$\endgroup\$ – m.Alin Oct 31 '14 at 14:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.