This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How can I reenable interrupt inside an isr?

Other Parts Discussed in Thread: TM4C1294NCZAD

HI

I have a question about a TM4C1294NCZAD.

 

I have a timer-interrupt which calls a timer-ISR.

Inside this timer-ISR I want to reenable the timer-interrupt again.

I want to have more timer-interrupts while the processor is still inside the ISR.

So the ISR should called several times from the timer-interrupt before it left.

The timer-interrupt works for a simple interrupt, but not for this nested interrupt.

How I do this?

  • Hello Christoph,

    Once the Timer Interrupt Mask register bit is set then as long as the interrupt source asserts again, it will assert the ISR.

    Also it depends on how the application reads the interrupt status and clears it. If it is an unconditional clear, then the application may lose the interrupt source and thus not fire again.

    If you can post an example of what you are doing and what is not working then it would be more useful.

    Regards
    Amit
  • re-design so you don't have multiple concurrent timer interrupts from the same timer. Seriously, you likely have something wrong.

    Robert
  • Hello Robert,

    Having different sources from the same timer being asserted still should be fine (as an example if the CPU was in a higher priority interrupt the timer may have multiple bits set). Processing them would be the key and that is where "re-design" would be required. Is that a correct interpretation of your post?

    Regards
    Amit
  • Hello Amit


    I can give you a analogous example what I want to do.

    In C2000 processors I have used this structure successfully.

    int main(void)
    {
       g_ui32SysClkFreq = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480),
    			CPU_FREQ_HZ);
    
    	// Initializes Timer0-A
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    	TimerConfigure(TIMER0_BASE, TIMER_CFG_A_PERIODIC);
    	TimerClockSourceSet(TIMER0_BASE, TIMER_CLOCK_SYSTEM);	// 120MHz
    
    	// Configure Timer0-A to interrupt every 250 microseconds):
    	// 120MHz CPU Freq, 250 microsecond Period
    	ui16Period = (1.0 * TGT_GetSystemClockFrequency() * 250e-6) - 1;
    	TimerPrescaleSet(TIMER0_BASE, TIMER_A, 0);
    	TimerLoadSet(TIMER0_BASE, TIMER_A, ui16Period);			
    	TimerControlStall(TIMER0_BASE, TIMER_A, true);			// Freezes counting while the processor is halted by the debugger
    
    	// Enable Timer0-A Interrupts
    	IntEnable(INT_TIMER0A);
    	TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
        
        // Set interrupt priorities
    	IntPrioritySet(INT_TIMER0A, 0);							// Set the Timer0-A to the highest priority
        
        // Enable interrupts
        IntMasterEnable();
        
        // Start Timer0-A
    	TimerEnable(TIMER0_BASE, TIMER_A);
        
        
        while (true)
        {
            // let the interrupt the work do
        }
    }
    
    
    /*-----------------------------------------------------------------------------------------------
     Timer0 interrupt service routine
     -----------------------------------------------------------------------------------------------*/
    interrupt void Timer0IntHandler(void)   // should called every 250us
    {
        static uint16_t counter = 0;
        
        // Clear the timer interrupt
        TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
        
        // increment the counter
        counter++;
            
        // do some work
        SetOutput1High(true);
        delayUs(20);
        SetOutput1High(false);
        
        if (counter == 10)
        {
            // sometimes the work is longer then the timer-period. 
            // In this point it should be possible to fire a new timer-interrupt, 
            // when the processor is still in the timer-isr!
            // Then the work in the isr should be halted! for the new timer-interrupt.
            // This interruption inside the isr doesn't work.
            // The new timer-interrupt is just being triggered again after the actual isr.
            SetOutput2High(true);
            delayUs(300);
            SetOutput2High(false);
        }
    }
    
    
    
        

  • Hi Christoph,

    I imagine CPU_FREQ_HZ is 120000000?

    I don't quite get the TGT_GetSystemClockFrequency you got there. Are you sure this returns the correct frequency?

    Now if you want the same ISR to trigger inside itself, I don't think that is possible at all, nor advisable. I would consider trying to get the ISR as efficient as possible by avoiding any function call in there.
  • Hi Afonso
    As I said, in the C2000 platform I have used this structure very successfully.
    So it is basically possible to fire a interrupt inside his isr (sure in C2000) and for me it was a very helpful structure.

    It would be very pleasant if someone could answer my question.
  • That's part of it Amit, but also consider

    if they are in fact different sources that share an interrupt vector than like UART code you can deal with them in a loop, or conceivably by exiting and re-entering the interrupt. Allowing the interrupt to re-assert itself within the interrupt is asking for trouble, starting with stack overflow.

    If they are the same source then the only comment is Yikes!

    Robert
  • Yikes!, that's asking for problems.

    How do you arrange proper priorities? Surely LIFO isn't really correct?
    How do you handle stack overflow?

    Take a look at Run to completion executives. The one very nice feature of the Cortex processors is the interrupt priority scheme. You can arrange that different tasks run with different hardware priorities. So with the multitude of available timers, you can have multiple timed events at different priorities with very little extra scaffolding. Simple, robust and effective. It would be a lot better on all counts than your current structure.

    Robert
  • Hello Christoph

    C2000 has a different interrupt schemer compared to the NVIC of Cortex M processors. So it would exit the interrupt handler and then re enter if the bit is set and not remain in the interrupt handler.

    Regards
    Amit
  • An amplification of my RTC executive comments.

    There are two common patterns in real-time embedded process

    1. Do nothing in the interrupts
    2. Do everything in the interrupts

    The first is the most common and the easiest to understand. Interrupts are kept as short as possible only doing enough to satisfy the interrupt and moving most processing to the application. Driven by the need for interrupts to respond quickly the goals are

    • to keep latency low
    • do the processing based on priority (many micros have fixed priority schemes and often it only comes into play for simultaneous interrupts)

    This first pattern leads naturally to an RTOS or RTK.

    The second pattern is less common, often used when there is only a single interrupt doing most or all of the work. The non-interrupt code may do nothing or handle some low priority housekeeping. This pattern is the analogue for a run to completion executive. The key attributes of threads/tasks in a run to completion executive are

    • tasks run once, not continuously
    • tasks do not block or wait
    • tasks run in strict priority. A high priority task completes before a low priority task is allowed to run. A low priority task may be pre-empted by a higher priority task.
    • Often all tasks share a common stack
    • As when using interrupts, interprocess communication is somewhat limited (no waiting allowed)

    This fairly obviously not only deals with the 'all work is done in a single task case' but extends to multiple tasks. Indeed it makes it clear how you can use a micro's prioritizable interrupts to achieve a multi-tasking environment.

    So to do a multiple tasks scheduled from a timer interrupt there are several option on the TIVA micros (and most Cortex micros)

    1. Use multiple timers with independent interrupt priorities.
      • Simple
      • Limited expandability, limited by hardware available timers
    2. Use a single timer and some tasks structures and SW interrupt trigger an interrupt for each tasks when it becomes time for it to run
      • More complex
      • Hardware limits the number of distinct priorities
      • Tasks limited by available interrupts to co-opt
      • Multiple tasks can share priorities and basically wait for each other to complete in turn
    3. In the case where a the secondary tasks are dependent on the first task to schedule or wait for it to (partially) complete use a SW interrupt trigger to start the secondary tasks.
    • Basically an extension of option 2
    • Use an RTK
      • Somebodies done the work of developing the kernel
      • A little more overhead than the interrupt based RTC options.

    Robert

  • Thanks for all the help!
    Special thanks to Rober for the detailed answer.