MQX kernel ISR vs MQX managed ISR

Document created by Daniel Chen Employee on Oct 17, 2017
Version 1Show Document
  • View in full screen mode

Interrupts can be handled by MQX (MQX managed ISR) or bypassing MQX (MQX kernel ISR). If you want that MQX handled all the ISR process, you can use MQX managed ISR.  By this ISR,  MQX catches all hardware interrupts in the range that the BSP defined and saves the context of the active task. For most interrupts, MQX calls the ISR that is stored in the interrupt vector table at the location identified by its interrupt vector number. The disadvantage with this is the interrupt latency is longer and depends completely on MQX.

 

Hardware vector table for all MQX managed isrs points to MQX kernel function _int_kernel_isr()). This function invokes user isr by jumping into instruction pointed by "isr_ptr" , as the below graph shows.

 

 

A task can install an MQX managed ISR interrupt using:

 

 _int_install_isr(interrupt_vector_number,isr_ptr,isr_data_ptr)

_bsp_int_init(Vector, Pri, Subpri, TRUE);

 

Vector – number of non-core vector (for example, 37 for LLWU, defined in IRQInterruptIndex in the MCU header file)

Pri – priority of the interrupt source. Allowed values: MQX_HARDWARE_INTERRUPT_LEVEL_MAX, MQX_HARDWARE_INTERRUPT_LEVEL_MAX + 1, …, 7, where 7 is the lowest application interrupt priority level.

Subpri – zero on Kinetis.

Enable – TRUE to enable the interrupt vector source in NVIC.

 

 At this level of interrupt, you can call MQX services.

 

The other option is MQX kernel ISR. Some real-time applications need special event handling to occur outside the scope of MQX. The need might arise that the latency in servicing an interrupt be less than the MQX interrupt latency. If this is the case, an application can use _int_install_kernel_isr() to bypass MQX and let the interrupt be serviced immediately. You will have the very same Performance as if you were running bare metal.

 

A kernel ISR must save the registers that it needs and must service the hardware interrupt. When the kernel ISR is finished; it must restore the registers and perform a return-from-interrupt instruction. Even though the compiler handles this for you.

 

In this case, you can't use MQX services.  However, you can put data in global area, which a task can access. The disadvantage on this is shared data problem and you can impact the kernel if the restoring stack fails.

 

If you need faster MQX kernel ISR, you can install Kernel ISR with :

_int_install_kernel_isr(vector_num, isr_ptr)

 _bsp_int_init(Vector, Pri, Subpri, TRUE);

 

Vector – number of non-core vector (for example, 79 for FTM1, defined in IRQInterruptIndex in the MCU header file)

Pri – priority of the interrupt source. Allowed values: 0 for highest priority kernel isr, 1, ..,MQX_HARDWARE_INTERRUPT_LEVEL_MAX-1 for lowest priority kernel isr.

Subpri – zero on Kinetis.

Enable – TRUE to enable the interrupt vector source in NVIC.

 

And very important, to install a HW interrupt handler, you need the HW interrupt table in RAM, so your user_config.h has to define MQX_ROM_VECTORS to 0.

 

Next is a demo to show how to use mqx kernel ISR, you can download it for more details.

 

static void GPIO_Init(void);

static void IRQ_Init (void);

void PortA_ISR(void);

void PortE_ISR(void);

              

TASK_TEMPLATE_STRUCT MQX_template_list[] =

{

/*  Task number, Entry point, Stack, Pri, String, Auto? */

   {MAIN_TASK,   Main_task,   1500,  9,   "main", MQX_AUTO_START_TASK},

   {0,           0,           0,     0,   0,      0,                 }

};

 

char SW=0;

 

 

/*TASK*-----------------------------------------------------

*

* Task Name    : Main_task

* Comments     :

*    This task prints " Hello World "

*

*END*-----------------------------------------------------*/

 

void Main_task(uint_32 initial_data)

{

   int counter=0;

               printf("\n Hello World \n");

  

   GPIO_Init();

  

   IRQ_Init();

  

   while(1){

                  if(SW==1){

                                 SW=0;

                                 printf("IRQ A was generated\n");

                  }

                  if(SW==2){

                                 SW=0;

                                 printf("IRQ E was generated\n\r");

                  }

                  printf("Waiting for IRQ... %d\n\r", counter);

                  counter++;

                  _time_delay(1000);

   }

  

   _mqx_exit(0);

}

 

static void GPIO_Init(void){

              

               SIM_SCGC5 = (0|SIM_SCGC5_PORTA_MASK|SIM_SCGC5_PORTE_MASK); /* Enable clock for PORTA */

              

               PORTA_PCR19 |= (0|PORT_PCR_MUX(1)|PORT_PCR_IRQC(0xA));//|PORT_PCR_PE_MASK;//|PORT_PCR_PS_MASK;

               PORTE_PCR26 |= (0|PORT_PCR_MUX(1)|PORT_PCR_IRQC(0xA))|PORT_PCR_PE_MASK|PORT_PCR_PS_MASK;

}

 

static void IRQ_Init (void){

               uint32_t result;

                                 

               /* install the interrupt routine */

               _int_install_kernel_isr (103, PortA_ISR);

               _int_install_kernel_isr (107, PortE_ISR);

                             

               result = _cortex_int_init(107, 2, TRUE);

               result = _cortex_int_init(103, 3, TRUE);

              

}

 

void PortA_ISR(void){

               SW=1;

               PORTA_ISFR=0xFFFFFFFF;  //Clear Port A ISR flags

}

 

void PortE_ISR(void){

               SW=2;

               PORTE_ISFR=0xFFFFFFFF;  //Clear Port E ISR flags

}

Outcomes