interrupt on arm9

Pavel Pisa ppisa4lists at
Fri Oct 26 14:13:45 UTC 2007

Hello All,

I typically use constructs described bellow to connect interrupt
in the driver like RTEMS code on ARM920T based PiMX1 board.
The example is for SPI interface which events are processed by driver
worker thread.


static rtems_isr spi_mx1_isr(rtems_irq_hdl_param data);
static int spi_mx1_ctrl_fnc(struct spi_ifc *ifc, int ctrl, void *p);

/* Some structure describing concrete hardware driver instance context */
typedef struct spi_mx1_ifc {
    spi_ifc_t spi_ifc;
    rtems_id  task;
    volatile struct mx1_cspi_regs *cspi_regs;
    rtems_irq_connect_data *irq_data;
    int gpio_port;
  } spi_mx1_ifc_t;

/* Structure used for interrupt registration, defined by RTEMS. */
rtems_irq_connect_data spi1_mx1_isr_data = {
    .name       = BSP_INT_SPI1,     /* SPI1 interrupt vector number */
    .hdl        = spi_mx1_isr,      /* SPI interrupt service routine */
    .on         = drvsup_mx1_isr_on,
    .off        = drvsup_mx1_isr_off,
    .isOn       = drvsup_mx1_isr_is_on,
   #if 0
    .irqLevel   = 3,    /* unused for ARM */
    .irqTrigger = 0     /* unused for ARM */

/* MX1 SPI driver instance 1 */
spi_mx1_ifc_t spi1_mx1_ifc = {
    .spi_ifc = {            /* Common/target HW independent SPI driver context */
    .task=(rtems_id)0,      /* Worker thread/task ID to allow send events from ISR */
    .cspi_regs=&_reg_CSPI1, /* Pointer to SPI1 controller registers base */
    .irq_data=&spi1_mx1_isr_data, /* Pointer to the RTEMS IRQ connect data */
    .gpio_port=1            /* SPI driver instance number */

/* Interrupt service routine */
static rtems_isr
spi_mx1_isr(rtems_irq_hdl_param data)
  spi_mx1_ifc_t *mx1_ifc = &spi1_mx1_ifc;
  /* The context can be passed through "data" parameter for 4.6.99+ RTEMS versions */

  mx1_ifc->cspi_regs->INT &= ~MX1_CSPI_INT_ENABLE_m;

  rtems_event_send(mx1_ifc->task, SPI_EVENT_ISR);

/* Function called from driver worker thread to wait for IRQ */
static inline rtems_status_code
spi_mx1_wait_irq(spi_ifc_t *ifc)
  rtems_status_code status;
  rtems_event_set   events;
  rtems_interval    ticks;

  ticks = SPI_ISR_TIMEOUT;

  status=rtems_event_receive(SPI_EVENT_ISR ,
                               RTEMS_EVENT_ANY|RTEMS_WAIT, ticks, &events);

  if (status != RTEMS_SUCCESSFUL){
    DEB_LOG("spi_mx1_wait_irq: rtems_event_receive %s\n",rtems_status_text(stat
  return status;

/* Part of SPI driver initialization sequence */

  status=rtems_task_create (rtems_build_name('S','P','I','0'+(mx1_ifc->gpio_por
          /*priority*/ SPI_MX1_KWT_PRIORITY,
          /*stacksize*/ RTEMS_MINIMUM_STACK_SIZE+4096,
  if (status != RTEMS_SUCCESSFUL){
    printf("spi_mx1_init: rtems_task_create %s\n",rtems_status_text(status));
    return status;

  /* Install the interrupt handler */
  if (!BSP_install_rtems_irq_handler(mx1_ifc->irq_data)){
    printf("spi_mx1_init: BSP_install_rtems_irq_handler failed\n");

This utilizes relatively low level RTEMS code, but I think,
that it is OK for "drivers". It requires some support routines
listed bellow. These are our target (M9328 MX1) specific.
It would be better, if RTEMS can assign some default routines
for given IRQ controller if the fields "on", "off" or "isOn"
are not assigned.

/* Enables spi_mx1 interrupts. */
drvsup_mx1_isr_on(const rtems_irq_connect_data *isr_data)
        /* Enable interrupts */
        MC9328MXL_AITC_INTENNUM = isr_data->name;


/* Disables spi_mx1 interrupts */
drvsup_mx1_isr_off(const rtems_irq_connect_data *isr_data)
        /* disable all various TX/RX interrupts */
        MC9328MXL_AITC_INTDISNUM = isr_data->name;


/* Tests to see if spi_mx1 interrupts are enabled, and returns non-0 if so.
 * If interrupt is not enabled, returns 0.
drvsup_mx1_isr_is_on(const rtems_irq_connect_data *isr_data)
                return MC9328MXL_AITC_INTENABLEL & (1 << ((isr_data->name)&0x1f
                return MC9328MXL_AITC_INTENABLEH & (1 << ((isr_data->name - 32)

The newer RTEMS versions (4.6.99+) allows to pass "data" parameter
to ISR routine. Then generic code to register interrupt handler (with
same syntax same as is used in Linux kernel) can be implemented for
ARMxxx as listed bellow. Again, it would be great, if it is implemented
as generic RTEMS service. It could help people to alternate between
Linux and RTEMS development as well, because Linux folks are used
for this usage and it contains parameters required for multi instance

/* Set new interrupt handler simple and clear way.
drvsup_request_irq(rtems_irq_number irq_num, rtems_irq_hdl irq_handler,
                        unsigned options, char *name, rtems_irq_hdl_param data)
        rtems_irq_connect_data *irq_connect_data;

                return -1;

                return -1;

        memset(irq_connect_data, 0, sizeof(rtems_irq_connect_data));

        irq_connect_data->name  = irq_num;
        irq_connect_data->hdl   = irq_handler;
        irq_connect_data->handle= data;
        irq_connect_data->on    = drvsup_mx1_isr_on;
        irq_connect_data->off   = drvsup_mx1_isr_off;
        irq_connect_data->isOn  = drvsup_mx1_isr_is_on;
        #if 0
        irq_connect_data->irqLevel   = 3;       /* unused for ARM */
        irq_connect_data->irqTrigger = 0;       /* unused for ARM */

        if (!BSP_install_rtems_irq_handler(irq_connect_data)){
                return -1;

        return 0;

If you have interrest in the code, I can send more full driver examples.
Generalization and definition of rtems_request_irq() according to above
example would be nice to have as well.

Best wishes

                Pavel Pisa

More information about the users mailing list