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.

Compiler/TMS320F28377D: Cannot read IFR register in C code

Part Number: TMS320F28377D

Tool/software: TI C/C++ Compiler

I have an application where I want to test the interrupt flags in the IFR register while the interrupt is not enabled (e.g. IER.x == 0 or INTM == 1). 

The IFR register is declared in F2837xD_device.h as "extern __cregister volatile unsigned int IFR". The CPU supports reading the IFR register into the accumulator using the stack as follows:

PUSH IFR

POP @AL

The compiler SHOULD therefore able to read the IFR into a variable for testing in my application.

BUT the following code fails to build:

if (IFR & M_INT14) doSomething();

with the error message:

>>> Illegal use of control register

Please can you advise me on how to read the IFR register within C code.

I realise I could write an assembly function that performs the read through the stack, but this is not acceptable as this code is called very often.

  • Hi,

     I think IFR read/write is limited and  is done inside the CPU via special opcodes to perform an AND and OR.

    Please refer to thread here with similar question

    https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/57522

  • Hi Santosh,

    The question you have linked is indeed the same as mine, but I do not agree with the answer provided by TI.

    There are instructions within the C28x to read the IFR (PUSH IFR), and I do not see a valid reason the compiler disallows the reading of a readable register.

    As stated in my original question, I am not attempting to perform a read-modify-write on the IFR. I agree that would be dangerous. Instead, I am trying to emulate the interrupt handling without going through an actual ISR.

    I expect the following code to compile:

    EmulateInterrupt14() {

        if (IFR & 0x2000) {

            HandleInterrupt14();

            IFR &= ~0x2000;

        }

    }

    I expect the above code to compile to the following instructions (or something similar):

    _EmulateInterrupt14:

            PUSH IFR

            POP AL

            TBIT AL, 13

            B $C$L1, NTC

            LCR _HandleInterrupt14

            AND IFR, 0xDFFF

    $C$L1:

            LRETR

    Please can you explain why the compiler throws an error on a read of IFR rather than emit the "PUSH IFR, POP AL" instructions?

  • IainRist said:
    explain why the compiler throws an error on a read of IFR rather than emit the "PUSH IFR, POP AL" instructions?

    Because an interrupt might come in between those two instructions.  When that occurs, the value in AL is wrong.

    Thanks and regards,

    -George

  • Hi George,

    I am confused why reading the IFR is considered so dangerous as to be disallowed by the compiler, especially because what I am trying to achieve is typical polling behaviour.

    Yes I understand the value might be out-of-date as soon as I read it, but that is the same as any status register of a peripheral that can update asynchronous to CPU execution. What makes the IFR register special?

    Please could you explain the reasoning behind this choice?

    Currently I am having to call an assembly function to push the IFR onto the stack and pop off the stack into AL to return, wasting cycles in the function call and return and the Flash prefetch.

  • The IFR register in the CPU has limited access.  The only opcodes that access it are AND, OR, PUSH or POP.  This is per the architecture.  These opcodes are specifically for IFR - they are not the generic AND/OR/PUSH/POP opcodes. The modification of IFR is done within the CPU itself as mentioned previously, to protect from lost interrupts or invalid interrupts getting serviced. 

    The instruction set is documented in http://www.ti.com/lit/spru430

  • Iain,

    I'd like to understand a bit more about your end goal.   You mention the following:

    IainRist said:

    As stated in my original question, I am not attempting to perform a read-modify-write on the IFR. I agree that would be dangerous. Instead, I am trying to emulate the interrupt handling without going through an actual ISR.

    I expect the following code to compile:

    EmulateInterrupt14() {

        if (IFR & 0x2000) {

            HandleInterrupt14();

            IFR &= ~0x2000;

        }

    }

    Can you help me understand the goal of emulating the ISR vs going through the full interrupt path? 

  • Hi Lori,

    I am running a statistical profiler where a CPU timer 2 is used to trigger a sample of execution state. CPU timer 2's interrupt goes directly into the CPU, not via the PIE.

    I want my statistical profiler to work within interrupt context in addition to task context, but I do not want to take the hit of either nested interrupt context switches or the profiler affecting my timing-sensitive operations within an interrupt; an interrupt can be delayed, but the work within it cannot be interrupted once started. As such I only want to check if the timer has expired at certain points of the ISR.

    I have since found that the timer peripheral does set a flag on counter overflow, TCR.TIF, so I can manage that flag to achieve my ends.

    The question still remains why is the IFR register treated differently to every other status register in the system, in that I can set and clear bits, using the |= and &=~ operators, but I cannot read the value even though the assembly instructions are available to do so? But this is now more of an academic question as I have found a workaround.

    Thanks,

    Iain

  • Thank you for the follow-up, Iain.

    I agree there are a lot of status registers on the device.  These are, for the most part, are part of a register that is memory mapped and we can't control how the end user manipulates them.  It can cause a lot of havoc depending on what is done.

    For the IFR - I can only really attribute it to history. Being part of the CPU, has been there.. "forever".  Even before C28x it was the same in the C27x.   The compiler's behavior around it has been this way forever.  I don't recall other cases like yours where using a small assembly routine wasn't an option. Making it a little more difficult to modify lowers one option for havoc. 

    I'm glad you found another option for your case. 

    Best Regards

    Lori