FIQ help needed

jorick23 wrote on Thursday, June 21, 2007:

Processor:  STM750 (ARM7)
Compiler:   IAR

I’m programming firmware for a stepper motor.  Currently, the time between steps is controlled by a timer that sends a pulse to the stepper motor every time it expires.  An IRQ interrupt allows the timer to be reloaded and other things to be done every step.

The problem is that when FreeRTOS switches tasks, it disables interrupts for as long as 28 microseconds.  This causes the motor interrupt to be delayed sometimes until interrupts are reenabled.  This interrupt MUST NOT be delayed for any length of time!

I thought that the answer to this problem would be to set up the timer to trigger a fast interrupt (FIQ), since they have a higher priority than IRQs.  So I tried setting up Timer 2 to generate an FIQ.  But when I run the program, the FIQ is always active because the FIQ Pending bit won’t clear (interrupt signal always on?).  An oscilloscope shows no activity on the GPIO line defined as the output from the timer.

Can anyone tell me how to simply set up a timer to generate an FIQ?  I can’t find any documentation anywhere on this subject, and ST’s documentation doesn’t tell an ARM newbie like me what to do.

Thanks!

rtel wrote on Friday, June 22, 2007:

For ST microcontroller specific settings I would suggest posting a question on the ST forum (somewhere on mcu.st.com).

As a FreeRTOS.org note, I have successfully used the FIQ to run high priority interrupts in the manner you describe.  Note however that you may need to change the definitions of vPortEnterCritical() and vPortExitCritical().  In the ST750/IAR port these use the intrinsics __diable_interrupt() and __enable_interrupt(), and I’m not sure if these disable/enable both IRQ and FIQ, or just IRQ.  In your case you want only the IRQ to be disabled.  Note also that FIQ interrupts cannot use FreeRTOS.org API functions with such a setup.

Regards.

jorick23 wrote on Friday, June 22, 2007:

I can help you with this one.  __disable_interrupt() disables both FIQ and IRQ interrupts.  Here’s the disassembled code for the IAR functions called by the intrinsic (comments are my own).  Note that there are two entry points in the disable function, one for Thumb mode and one for ARM mode, but for some reason there’s no Thumb mode entry for the enable function.

Disable interrupts:

??DiI_t:                         ; This function is in Thumb mode
        bx      pc               ; Jump to the ARM function
        nop                      ; Alignment instruction
??DiI_a:                         ; This function is in ARM mode
        mrs     r12, cpsr        ; Get the status flags
        orr     r12, r12, #0xC0  ; Disable both IRQ and FIQ
        msr     cpsr_c, r12      ; Store the updated status flags
        mrs     r12, cpsr        ; Get the updated status flags again
        ands    r12, r12, #0xC0  ; Were the flags set okay?
        beq     ??DiI_a          ; No, go back and try again
        bx      lr               ; Return to caller

Enable interrupts:

??EiI_a:                         ; This function is in ARM mode
        mrs     r12, cpsr        ; Get the status flags
        bic     r12, r12, #0xC0  ; Enable both IRQ and FIQ
        msr     cpsr_c, r12      ; Store the updated status flags
        mrs     r12, cpsr        ; Get the updated status flags again
        ands    r12, r12, #0xC0  ; Were the flags cleared okay?
        bne     ??EiI_a          ; No, go back and try again
        bx      lr               ; Return to caller

In order to keep from disabling FIQ, the two 0xC0’s needs to be changed to 0x80.

I added custom assembler functions with the same names that affect only the IRQ.  Using the same names causes my function to be used instead of IAR’s, so I don’t have to change any FreeRTOS code.

frankandersen wrote on Tuesday, July 10, 2007:

Hi Ricky,

Where did you put the Enable and Disable functions, in my attempt the intrinsic functions are still called.

Best regards, Frank Andersen

jorick23 wrote on Wednesday, July 11, 2007:

I put them at the end of the assembler file containing the interrupt vectors.  Make sure the names are exactly ??DiI_t and ??EnI_t for the Thumb mode entry points, and ??DiI_a and ??EnI_a for the ARM mode.  Also, make sure you declare those labels public so that the linker will use them instead of the library versions.

frankandersen wrote on Thursday, July 12, 2007:

Hi Ricky,

I get two errors:

Error[403]: Illegal register, ‘PC’ is not allowed here C:\FreeRTOSV431\FreeRTOS\Demo\ARM7_LPC2378_STK_IAR\SrcIAR\cstartup.s79 154

??DiI_t: ; This function is in Thumb mode
          bx pc ; Jump to the ARM function this is the error
          nop ; Alignment instruction

Then I tried to replace the bx pc with nop, then the following error came.

Error[e27]: Entry "??DiI_a" in module ?RESET ( C:\FreeRTOSV431\FreeRTOS\Demo\ARM7_LPC2378_STK_IAR\Flash_Debug\Obj\cstartup.r79 ) redefined in module ?DiI_t ( C:\Program Files\

Where did you find the assembler code for the functions?

Best regards, Frank Andersen

jorick23 wrote on Thursday, July 12, 2007:

I used the IAR j-link debugger to step through the code.  The original code set the interrupt disable bits and then looped back to check if they were still set.  I got rid of the loop in my version.

Perhaps you can try an end run around the compiler by using “bx r15”?  If that doesn’t work, try
________ldr_____r0, =??DiI_t
________bx______r0

As for error e27, it appears that you may be including the library file endisint.s79 in your project.  If you do that you’ll get the “redefined” error.  You can only replace functions that appear in libraries, so you’ll need to remove the file from your project list and just use the C runtime library (either Normal or Full, go to Options -> C/C++ Compiler -> Library Configuration to set it).

Here’s the exact code I have for the IAR EWARM assembler version 4.41:

________rseg____CODE:CODE(2)
________code16

??DiI_t:
________bx______pc______________________// Switch to arm mode
________nop_____________________________// Alignment instruction

________code32

??DiI_a:
________mrs_____r0, cpsr________________// Get the status flags
________orr_____r0, r0, #0x80___________// Disable IRQ interrupts
________msr_____cpsr_c, r0______________// Store the updated status flags
________bx______lr______________________// Return

________code16

??EnI_t:
________bx______pc______________________// Switch to arm mode
________nop_____________________________// Alignment instruction

________code32

??EnI_a:
________mrs_____r0, cpsr________________// Get the status flags
________bic_____r0, r0, #0x80___________// Enable IRQ interrupts
________msr_____cpsr_c, r0______________// Store the updated status flags
________bx______lr______________________// Return

frankandersen wrote on Friday, July 13, 2007:

Hi Ricky,

Thank you very much, I was not aware of the RSEG and CODExx things.

Do you know how to the functions __enable_interrupt and __disable_interrupt is defined, I would like to make two functions for enabling and disabling the FIQ interrupt. I have made a duplicate of the ??DiI_t, ??DiI_a, ??EnI_t and ??EnI_a and change the #0x80 to #0x40.

I would like to have two functions __enable_fiq and __disable_fiq

But depending on if the ARM is running thumb or arm, I need to call:

??DiF_t
??DiF_a

Does I need to check T bit in CPSR and then branch to the t or a function?

Regarding the loop that checks if the I or F bit is set, I have seen and app not from NXP that states that it is neccesary to check if the bit is set. But IAR does not do that.

Best regards, Frank Andersen

jorick23 wrote on Friday, July 13, 2007:

If you’re calling the functions from C, you could write the routines in ARM mode only and let the compiler worry about generating the proper code for the call.  Just make sure you use the __arm keyword in the C function prototypes so that the compiler can generate the correct code.

__arm void __disable_fiq (void);
__arm void __enable_fiq (void);

You don’t have to worry about using the ??DiF_t naming convention since there’s no library version of that function.

If you’re calling them from assembler, write the routines in Thumb and ARM mode just like I did and then use the bl instruction to branch to the proper label depending on the mode you’re in.  You don’t need to check the T bit because you’ll already know which mode you’re in by whether the code is written in Thumb or ARM instructions.

There may be some processors that need you to check if the bit is set.  But I’m using the STR750 and STR912 processors which don’t need the check so I left it out.  IAR included it just in case one of the processors that required the check was being used.