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.

MSP430FR2422: MSP430-GCC attribute request

Part Number: MSP430FR2422

Presently gcc allows one to attribute a function as interrupt.

I would like to see an additional modifier tag with the following specification, when added as an attribute:

-Must accompany an "interrupt" tag

-Instead of using the normal RETI to return, use RET

My motivation for this request is to reduce the number of clock cycles spent with interrupts disabled.

When I write an interrupt handler, I access the sensitive bits (such as TA0CCR1) then quickly re-enable interrupts to allow other time sensitive processes to continue.

Then I do whatever needs to be done and RETI from the function.

However, presently if I have an interrupt function, all registers touched in the function are pushed on the stack before I can even access a time sensitive register (such as TA0CCR1)

What I would like to do is split my interrupt handler into 2 functions:

 -an immediate handler (that pushes very few or no registers on the stack) that handles the time sensitive stuff and re-enables interrupts

 -a followup function (tagged with the "interrupt" and the new attribute)  called by the immediate handler (with CALL) that then pushes whatever registers are needed on the stack and returns with RET

I have hacked similar behaviours like this before using asm "br ADDR" instructions, but I think this way would be cleaner.


In the same vein, I would expect that if an interrupt function pushes no arguments on the stack and calls another interrupt function, this would simplify to just a "br" instruction.

  • Sounds like a job for assembly language. Although I suspect that naked could be abused to do what you want.

  • I want to preserve the compiler's automatic register allocation behaviour. So naked does not work here.

  • This code:

    void __attribute__((naked, interrupt(TIMER0_A0_VECTOR))) stub(void)
    {
      tick++;
    }
    
    void __attribute__((interrupt)) Timer0_A0_ISR(void)
    {
      int i;
    
      for(i = 0; i < 10; i++)
        P1OUT ^= 1;
    }
    

    Results in:

    void __attribute__((naked, interrupt(TIMER0_A0_VECTOR))) stub(void)
    {
      tick++;
        4474:       92 53 04 1c     inc     &0x1c04         ;
    
    00004478 <Timer0_A0_ISR>:
    }
    
    void __attribute__((interrupt)) Timer0_A0_ISR(void)
    {
        4478:       0c 15           pushm   #1,     r12     ;16-bit words
    
    0000447a <.LCFI3>:
        447a:       7c 40 0a 00     mov.b   #10,    r12     ;#0x000a
    
    0000447e <.L14>:
      int i;
    
      for(i = 0; i < 10; i++)
        P1OUT ^= 1;
        447e:       d2 e3 02 02     xor.b   #1,     &0x0202 ;r3 As==01
    
    00004482 <.LVL14>:
        4482:       3c 53           add     #-1,    r12     ;r3 As==11
    
    00004484 <.LVL15>:
    
    void __attribute__((interrupt)) Timer0_A0_ISR(void)
    {
      int i;
    
      for(i = 0; i < 10; i++)
        4484:       0c 93           cmp     #0,     r12     ;r3 As==00
        4486:       fb 23           jnz     $-8             ;abs 0x447e
    
    00004488 <.Loc.52.1>:
        P1OUT ^= 1;
    }
        4488:       0c 17           popm    #1,     r12     ;16-bit words
        448a:       00 13           reti 

    Which certainly appears to do what you want.

  • Hi Dave,

    Let me check I understand what you are trying to do:

    • To prevent time-sensitive registers becoming "out-of-date", the "immediate handler" does not save any registers except as explicitly required.
      • I assume this ISR has been written in assembly to prevent GCC saving any of these registers for you?
      • I also assume this ISR doesn't do anything except RETI after calling the "followup function"?
    • The "immediate handler" calls the "followup function" (written in C) which contains the main portion of code in the ISR, and saves whichever registers are modified.

    I understand why this is a problem, but I think having an ISR which can be modified to only partly behave like an ISR is a bit of a work-around and doesn't get at the real issue.

    What if you were somehow able to add a "pre-prologue" section of code to an ISR, which executes before the regular prologue runs and saves the necessary registers? This would also save you having to insert an extra CALL instruction.

    Regards,

  • Prepending a naked interrupt handler in front of the follow up handler probably hits 90% of most of my cases. Pretty neat!

    It doesn't handle the case when the stub must allocate registers which is rarer but still happens.

  • Josef,

      My ISRs are written pretty much in C except in a few cases. Right now I am eating the time delay of pushm before saving these registers.

      You are correct, these handlers never perform any tasks after RETI.

    I really like the idea of pre-prologue and it would definitely work for me in this case!

  • This is a neat trick but potentially dangerous if used with -ffunction-sections. The linker is free to move sections around and will do just that when -mcode-region=either is used.

    There are plenty of GCC optimizations which do reordering, and whilst those operating at the function level appear to all require profile feedback, this isn't behaviour that can be relied on staying the same in the future. Particularly with advancements in LTO.

    However, if the programmer is aware of the risks, this is a nice solution.

  • Ok, sounds good. I need to look into the specifics of this proposed feature more, but we'll aim to get this into one of this year's releases.

    Regards,

  • I did say "abuse". :-)

    You can protect against the linker moving things around quite easily:

    void __attribute__((naked, interrupt(TIMER0_A0_VECTOR))) stub(void)
    {
      tick++;
      __eint();
    
      asm("br &Timer0_A0_ISR\n");
    }
    

    But assembly is still the best way to go. Either for the entire ISR or just this critical bit before jumping into the main section.

**Attention** This is a public forum