| .. _microkernel_task_irqs: |
| |
| Interrupt Services |
| ################## |
| |
| Concepts |
| ******** |
| |
| The microkernel's :dfn:`task IRQ` objects allow interrupts to be serviced |
| by tasks, rather than only by interrupt service routines (ISRs). These allow |
| a microkernel project to have both task-level device drivers and interrupt-level |
| device drivers. |
| |
| Any number of task IRQs can be defined in a microkernel system. Each task IRQ |
| has a numeric identifier that uniquely identifies it. These identifiers range |
| from 0 to N-1, where N is the total number of task IRQs in the system. |
| |
| A task that wants to service interrupts from a device must first allocate a |
| task IRQ and bind it to the device's interrupt source by specifying the IRQ |
| and interrupt priority level assigned to that device by the system designer. |
| Once a task IRQ has been allocated by a task, it cannot be used by other |
| tasks; this prevents other tasks from interfering with the proper processing |
| of interrupts from that device. |
| |
| When an interrupt is generated by the device, the kernel runs an ISR that |
| masks the interrupt and signals the occurrence of the interrupt to the |
| associated task IRQ. The task can then use the task IRQ to recognize that |
| an interrupt has occurred and take action to service the interrupt. At some |
| point during interrupt servicing, the task must instruct the task IRQ to |
| acknowledge the interrupt; this causes the kernel to unmask the interrupt so |
| that future interrupts can be detected. |
| |
| Purpose |
| ******* |
| |
| Use a task IRQ when the work required to process an interrupt cannot be done |
| in an ISR -- either because it takes a long time, or because it requires the |
| processing routine to block. |
| |
| Usage |
| ***** |
| |
| Configuring Task IRQs |
| ===================== |
| |
| Set the :option:`MAX_NUM_TASK_IRQS` configuration option to specify the number |
| of task IRQs allowed in the project. |
| |
| The default value of zero for this option disables task IRQs. |
| |
| .. note:: |
| Unlike most other microkernel object types, task-level IRQs are defined |
| as a group using a configuration option, rather than as individual |
| public objects in an MDEF or private objects in a source file. |
| |
| |
| Example: Allocating a Task IRQ |
| ============================== |
| |
| This code associates a task IRQ with interrupts generated by a device. |
| Interrupts from that device are then enabled so they can be processed |
| using the task IRQ. |
| |
| .. code-block:: c |
| |
| #define FOO_DEVICE 2 /* device "foo" uses task IRQ object 2 */ |
| #define FOO_IRQ 37 /* device "foo" uses IRQ 37 */ |
| #define FOO_PRIO 3 /* device "foo" uses interrupt priority 3 */ |
| #define FOO_IRQ_FLAGS 0 /* device "foo" IRQ flags. Unused on non-x86 */ |
| |
| if (task_irq_alloc(FOO_DEVICE, FOO_IRQ, FOO_PRIO, FOO_IRQ_FLAGS) == |
| INVALID_VECTOR) { |
| /* The task IRQ or the interrupt source is not available */ |
| printf("Task IRQ allocation failed!"); |
| } |
| |
| Example: Servicing Interrupts using a Task IRQ |
| ============================================== |
| |
| This code allows a task to wait for an interrupt from a device, |
| acknowledge the interrupt, and take the necessary steps to service it. |
| |
| .. code-block:: c |
| |
| task_irq_wait(FOO_DEVICE, TICKS_UNLIMITED); |
| |
| /* Device interrupt is now masked */ |
| /* Do pre-acknowledgement device processing (if any) */ |
| |
| task_irq_ack(FOO_DEVICE); |
| |
| /* Device interrupt is now unmasked */ |
| /* Do post-acknowledgement device processing (if any) */ |
| |
| The steps required to service a device are device-specific. In some cases |
| all processing may need to be completed before the interrupt is acknowledged, |
| while in other cases no processing at all should be done until the interrupt |
| is acknowledged. Some devices may require processing both before and after |
| acknowledgement. |
| |
| |
| APIs |
| **** |
| |
| Task IRQ APIs provided by :file:`microkernel.h` |
| =============================================== |
| |
| :cpp:func:`task_irq_alloc()` |
| Bind a task IRQ to a device and enable interrupts. |
| |
| :cpp:func:`task_irq_ack()` |
| Acknowledge an interrupt and re-enable the interrupt. |
| |
| :c:func:`task_irq_wait()` |
| Wait for an interrupt to occur within a specified time period. |