LPC2148 FIQ Handler problem

Hello, I’m using FreeRTOS with an LPC2148. I ported the code from the LPC 2106 example. (It works fine) The FIQ interrupt is working fine too, but I need it to launch a function from the ISR, to toggle a pin of the MCU. I have 2 tasks: one that blinks an GREEN LED (just to be sure the system is running), and an ISRHandler which is synchronized with a semaphore. In this case, the ISRHandler turns ON an RED LED. The code I’m using is very similar to the one proposed in the documentation. I’m sure the FIQ interrupt is working fine: With the GREEN LED blinking, if I dont use the ISRHandler, I can turn ON the RED LED in the interrupt when a pin is LOW, and then turn it OFF when the pin returns to HIGH, and the GREEN LED returns to blink. So, the interrupt ends and the blinker task returns to run. BUT, If I enable the ISRHandler task (with xTaskCreate()), the ISRHandler preempts the blinker task after the FIQ interrupt, and apparently doesnt block when the pin is HIGH again, so the GREEN LED doenst blink anymore. I hope my explanation isn’t too confusing. This is the code I’m using: (Ill do a brief summary)

main.h

xSemaphoreHandle xBinarySemaphore;

main.c

int main( void )
{
  // Setup the hardware for use with the Olimex demo board.
  prvSetupHardware();   // Create Binary Semaphore
  vSemaphoreCreateBinary(xBinarySemaphore);   // SETUP FIQ
  PINSEL0 = 0x20000000; // sets p0.14 as EINT1
  VICIntSelect |= 0x00008000;
  VICIntEnable = 0x00008000;   xTaskCreate( vISRHandlerTask, ( signed char * ) “ISRHandler”, 1000, NULL, 3, NULL );
  xTaskCreate( vBlinkTask, (signed char * ) “blinker”, configMINIMAL_STACK_SIZE, NULL, 1, NULL);

  vTaskStartScheduler();   // Should never reach here!
  return 0;
} void FIQ_Handler (void)
{
  // Remove FIQ flag
  EXTINT = 0x2;   **static portBASE_TYPE xHigherPriorityTaskWoken;   xHigherPriorityTaskWoken = pdFALSE;   xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);   if(xHigherPriorityTaskWoken == pdTRUE)
    portYIELD_FROM_ISR();**
}

ISRHandler.c

#include “main.h” #define LED (1 << 20) void vISRHandlerTask(void)
{
  IO1DIR |= (LED); // Initializes P1.16 as output.   for(;;)
  {
    // This task will be blocked until the FIQ gives it the semaphore.
   ** xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);**     IO1SET |= LED;  // turns ON pin 1.16     // When finishing the routine, this task will return to blocked state
    // waiting for another semaphore which will be given again by the FIQ.
  
   /// I tried with giving the semaphore, but the MCU starts with the RED LED ON and doesnt do anything.
    ////xSemaphoreGive(xBinarySemaphore);
  }
}

Blinker.c

#define LED (1 << 19) void vBlinkTask(void)
{
  pwmInit();   pwmFrequency(500);
  pwmDutyCycle(90);   IO1DIR |= LED;   for(;;)
  {
    IO1CLR |= LED;      // just blinks an LED every 100 ticks
    vTaskDelay(50);
    IO1SET |= LED;
    vTaskDelay(50);
  }
}
I’d greatly appreciate any help. Regards,
Carlos

LPC2148 FIQ Handler problem

A couple of comments: 1) Do you have a stack setup for FIQ mode?  Most of the demos provided don’t.  The stacks are normally configured in assembly code from the C start up code, before main() is called. 2) If you are using FIQ then you will have to ensure your portDISABLE_INTERRUPTS() and portENABLE_INTERRUPTS() functions disable/enable both IRQ and FIQ. 3) You are likely to get problems using FreeRTOS API functions from an FIQ handler because FIQ can pre-empt IRQ, and the code does not take that into account (none of the demos use FIQ).  You might be ok if you disable the FIQ interrupt before using any FreeRTOS functions from an IRQ handler, but then that might defeat the object of using FIQ in the first place. Regards.

LPC2148 FIQ Handler problem

Richard, Thank you for your fast response. As you suggested I made a few changes: I increased the FIQ stack size to 400 bytes in startup.s: /* Stack Sizes */
    .set  UND_STACK_SIZE, 0x00000004
    .set  ABT_STACK_SIZE, 0x00000004
    .set  FIQ_STACK_SIZE, 0x00000800
    .set  IRQ_STACK_SIZE, 0X00000400
    .set  SVC_STACK_SIZE, 0x00000400
in main (just to be sure), i added: int main( void )
{
** portENABLE_INTERRUPTS();**

Also, in portmacro.h the codes seems to be correctly handling the activation/deactivation of FIQ and IRQ: #define portDISABLE_INTERRUPTS()
__asm volatile (
“STMDB SP!, {R0} nt” /* Push R0. */
“MRS R0, CPSR nt” /* Get CPSR. */
**”ORR R0, R0, #0xC0 nt” /* Disable IRQ, FIQ. */ **
“MSR CPSR, R0 nt” /* Write back modified value. */
“LDMIA SP!, {R0} ” ) /* Pop R0. */ #define portENABLE_INTERRUPTS()
__asm volatile (
“STMDB SP!, {R0} nt” /* Push R0. */
“MRS R0, CPSR nt” /* Get CPSR. */
**”BIC R0, R0, #0xC0 nt” /* Enable IRQ, FIQ. */ **
“MSR CPSR, R0 nt” /* Write back modified value. */
“LDMIA SP!, {R0}
Also I added to the ISRHandler: void vISRHandlerTask(void)
{
  IO1DIR |= (LED); // Initializes P1.16 as output.   for(;;)
  {
// This task will be blocked until the FIQ gives it the semaphore.
    xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);     portDISABLE_INTERRUPTS();     IO1SET |= LED;     // When finishing the routine, this task will return to blocked state
    // waiting for another semaphore which will be given again by the FIQ.
    //xSemaphoreGive(xBinarySemaphore);    ** portENABLE_INTERRUPTS();**
  }
} As you said on number 3:
_You are likely to get problems using FreeRTOS API functions from an FIQ handler because FIQ can pre-empt IRQ, and the code does not take that into account (none of the demos use FIQ). _ If I understand, you mean, the FIQ can preempt the IRQ? But I only have a FIQ. there are not other interrupts. You might be ok if you disable the FIQ interrupt before using any FreeRTOS functions from an IRQ handler, but then that might defeat the object of using FIQ in the first place. I think this too is applicable when having FIQ and IRQ interrupts? Or am I wrong? I can add now, that, with this code if I remove the call to xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken); in the FIQ routine, the LED returns to blink, so that seems to be the trouble. I’m using the FIQ because its the fastest one only, but if you tell me that the IRQ will work, then I could give it a try. (Or any other workaround :D) Thank you for your support!!
Carlos

LPC2148 FIQ Handler problem

Sorry, This doesnt work either. void vISRHandlerTask(void)
{
  IO1DIR |= (LED); // Initializes P1.16 as output.   for(;;)
  {
portDISABLE_INTERRUPTS(); // This task will be blocked until the FIQ gives it the semaphore.
    xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);     IO1SET |= LED;     // When finishing the routine, this task will return to blocked state
    // waiting for another semaphore which will be given again by the FIQ.
    //xSemaphoreGive(xBinarySemaphore);     portENABLE_INTERRUPTS();
  }
} Carlos

LPC2148 FIQ Handler problem

No one? Any help please? I just need to interrupt the MCU with an external interrupt, and then do some processing with a task, periodically…

LPC2148 FIQ Handler problem

Hi Carlos, I don’t know anything about this specific MCU so I did a quick read of the user manual. From your code above, I do not see where you are configuring the EXT interrupt mode and polarity. These registers apparently default to 0 which means level sensitive active low. I suspect  when you change the state of the external pin to low, the interrupt fires as expected. You clear the interrupt flag but at this point the input is still low so as soon as the interrupt exits, it will fire again. You end up doing nothing more than servicing the interrupt. I’ve done this sort of thing. You could make the input edge triggered (falling or rising). Hope this helps
travfrog

LPC2148 FIQ Handler problem

Dear all, The problem is solved! travfrog thank you too for your help: The EXT is set to level sensitive by default as you said, so I was triggering the interrupt by moving a wire from VCC/GND. Now I’ve set it to edge sensitive so I can trigger it with a PWM. Here’s what I dit  to make the **FIQ[/b work (thanks to mikaeleiman from lpc2000 yahoo group)
main.c: void FIQ_Handler (void) __attribute__ ((interrupt(”FIQ”))) __attribute((naked)); void FIQ_Handler (void)
{
  portSAVE_CONTEXT();   actualFIQHandler();   EXTINT = 0x2;   portRESTORE_CONTEXT();
}
actualFIQHandler.c void actualFIQHandler(void) __attribute__((noinline));
void actualFIQHandler(void)
{
  static signed portBASE_TYPE xHigherPriorityTaskWoken;   xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);   if ( xHigherPriorityTaskWoken )
  {
    // switch context to newly awoken task
    portYIELD_FROM_ISR();
  }
}
and finally ISRHandler.c void vISRHandlerTask(void)
{
  IO1DIR |= (LED); // Initializes P1.16 as output.   int flag=0;   for(;;)
  {
portDISABLE_INTERRUPTS(); // This task will be blocked until the FIQ gives it the semaphore.
    xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);     if(flag==1)
    {
    IO1SET |= LED;
    flag=0;
    }
    else
    {
    IO1CLR |= LED;
    flag=1;
    }     // When finishing the routine, this task will return to blocked state
    // waiting for another semaphore which will be given again by the FIQ.     portENABLE_INTERRUPTS();
  }
} I defined the interrupt as edge sensitive, and its working okay now. Thank you for your support!
Carlos**