This page is available in: en

HOWTO: Define your own Interrupt Handler

Written by: Mohit Sindhwani, Viometrix

In this brief ‘how-to’ article, we look at the method to be used for defining your own interrupt handler in the T-Kernel environment.

Background

In many embedded systems, interrupts are used to interface with the real world. When an event happens, the peripheral responsible for dealing with it raises an interrupt to the CPU. The CPU then stops doing what it’s doing, saves some of its essential context and attends to the interrupt. The routine that deals with the interrupt is called the interrupt handler (or interrupt service routine) and is supposed to quickly do interrupt-related processing. After this is completed, the CPU restores the context of the previously running program and execution continues as though nothing happened. The specifics of how to install and use interrupt handlers is usually dependent on the CPU and/ or the RTOS. Here, we look at how you can create and use your own interrupt handler in the T-Kernel environment.

Essential Reading: The main reference for this is actually Section 4.8 – Interrupt Management Function of the T-Kernel specification. Refer to that section for the necessary details.

Coding the Interrupt Handler

The T-Kernel allows developers to create two types of interrupt handlers: handlers written in assembly or handlers written in a high-level language. This article focuses primarily on high-level language handlers. Details for assembly language handlers is available in the T-Kernel specification.

The C function prototype for a high-level T-Kernel ISR is shown below:

EXPORT void tk_serial_isr (UINT dintno);

Typically, an interrupt handler should do the following:

  1. Read/ write data from/ to the peripheral: This is the main task that needs to be done to respond to the interrupt.
  2. Remove the interrupt request: In devices such as the UART, a read interrupt request is automatically removed when you read from the device. However, in some devices such as timers, it is necessary to write to a special flag that clears the interrupt request.
  3. Inform the application that the interrupt occurred: In many cases, you will need to communicate to the running application that the event has happened. Typically, this is done by issuing a system call. To see the system calls that are possible from the ISR, check Section 3.2.2 of the T-Kernel specification.
  4. Return from the exception: Finally, you need to return from the service handler. In the case of the high-level interrupt handler, you only need to issue a return; just as in a normal function. The T-Kernel handles the rest for you.

void tk_my_isr(UINT dintno)
{
    /*
     * Perform hardware-related work
     *
     * This is where you should put code for reading or writing to the
     * specific peripheral.  This part depends on your device
     */

     /* Sample: */
     c = ReadDatafromSerialDevice();

    /*
     * Remove the Interrupt Request
     *
     * If the hardware requires a specific method for removing the
     * interrupt request, you should deal with it.  Devices like
     * UART usually de-assert the interrupt when you read the data
     * but devices like timer require a special write request to
     * de-assert the interrupt.
     */

    /* Inform the application that the interrupt happened */

    /* Sample: */
    tk_sig_sem(sem_id, 1);

    return;
}

Registering/ Defining your Interrupt Handler

Once you have written the function for the interrupt handler, you need to register it with the T-Kernel so that it is called when the interrupt happens the next time. You register an interrupt handler by calling tk_def_int.

The C language interface for tk_def_int is as shown below:

ER ercd = tk_def_int (UINT dintno, T_DINT *pk_dint ) ;

The first parameter dintno is the interrupt number. Usually, this is the interrupt vector number – the specific meaning of this number is implementation dependent and can be found in the Implementation Specifications that came with your T-Kernel port.

Other than this, all you need to do is fill out the details of the T_DINT structure to include the following information:

  • The type of handler: high level or assembly (specified using TA_HLANG or TA_ASM respectively)
  • The address of the handler function

The TA_HLNG specifies that the interrupt handler being registered is a high-level language interrupt handler. The T-Kernel will do the necessary part to save the context, etc. before this function is called and will automatically restore the context after execution of the handler is completed.

The code for defining the interrupt handler is shown below. You need to call tk_def_int and pass it the interrupt number and the address of the T_DINT structure.


{
    T_DINT int_pkt;
    ER ercd;
    int_pkt.intatr = TA_HLNG;
    int_pkt.inthdr = tk_my_isr;
    ercd = tk_def_int (SERIAL_RX_ISR, &int_pkt);
}

That’s all there is to it! Once this is done, the T-Kernel will now call your specific function when the interrupt occurs.

If you want to remove the definition that you have made, you need to call tk_def_int and pass it the interrupt number (usually the interrupt vector number) and NULL as the address of the T_DINT structure.