| .. _microkernel_task_irqs: |
| |
| Interrupt Services |
| ################## |
| |
| Concepts |
| ******** |
| |
| The microkernel's task IRQ objects allow interrupts to be serviced |
| by tasks, rather than interrupt service routines (ISRs). |
| This allows a microkernel project to have task-level device drivers, |
| in addition to 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 utilized 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 then 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. |
| |
| When a task no longer needs a task IRQ it should free the task IRQ. |
| This disables the interrupt associated with the task IRQ |
| and makes the task IRQ available for re-allocation. |
| |
| |
| 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 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 */ |
| |
| if (task_irq_alloc(FOO_DEVICE, FOO_IRQ, FOO_PRIO) == 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_test_wait(FOO_DEVICE); |
| |
| /* 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. |
| |
| |
| Example: Freeing a Task IRQ |
| =========================== |
| |
| This code allows a task to disassociate a task IRQ |
| from interrupts generated by its associated device. |
| Interrupts from that device are no longer enabled. |
| |
| .. code-block:: c |
| |
| task_irq_free(FOO_DEVICE); |
| |
| |
| |
| APIs |
| **** |
| |
| The following task IRQ APIs are provided by :file:`microkernel.h`: |
| |
| +----------------------------------------+-----------------------------------+ |
| | Call | Description | |
| +========================================+===================================+ |
| | :cpp:func:`task_irq_alloc()` | Binds a task IRQ to a device | |
| | | and enables interrupts. | |
| +----------------------------------------+-----------------------------------+ |
| | :cpp:func:`task_irq_ack()` | Acknowledges an interrupt and | |
| | | re-enables the interrupt. | |
| +----------------------------------------+-----------------------------------+ |
| | :cpp:func:`task_irq_free()` | Unbinds a task IRQ from a device | |
| | | and disables interrupts. | |
| +----------------------------------------+-----------------------------------+ |
| | :c:func:`task_irq_test()` | Tests to determine if an | |
| | | interrupt has occurred. | |
| +----------------------------------------+-----------------------------------+ |
| | :c:func:`task_irq_test_wait()` | Waits for an interrupt to occur. | |
| +----------------------------------------+-----------------------------------+ |
| | :c:func:`task_irq_test_wait_timeout()` | Waits for an interrupt to occur | |
| | | within a specified time period. | |
| +----------------------------------------+-----------------------------------+ |
| |