2015-08-11 21:42:45 +08:00
|
|
|
.. _microkernel_task_irqs:
|
|
|
|
|
|
|
|
Interrupt Services
|
|
|
|
##################
|
|
|
|
|
|
|
|
Concepts
|
|
|
|
********
|
|
|
|
|
2016-03-16 23:28:46 +08:00
|
|
|
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
|
2015-08-11 21:42:45 +08:00
|
|
|
of interrupts from that device.
|
|
|
|
|
2016-03-16 23:28:46 +08:00
|
|
|
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.
|
2015-08-11 21:42:45 +08:00
|
|
|
|
|
|
|
Purpose
|
|
|
|
*******
|
|
|
|
|
2016-03-16 23:28:46 +08:00
|
|
|
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.
|
2015-08-11 21:42:45 +08:00
|
|
|
|
|
|
|
Usage
|
|
|
|
*****
|
|
|
|
|
|
|
|
Configuring Task IRQs
|
|
|
|
=====================
|
|
|
|
|
2016-03-16 23:28:46 +08:00
|
|
|
Set the :option:`MAX_NUM_TASK_IRQS` configuration option to specify the number
|
|
|
|
of task IRQs allowed in the project.
|
2015-08-11 21:42:45 +08:00
|
|
|
|
|
|
|
The default value of zero for this option disables task IRQs.
|
|
|
|
|
|
|
|
.. note::
|
2015-08-19 04:15:10 +08:00
|
|
|
Unlike most other microkernel object types, task-level IRQs are defined
|
|
|
|
as a group using a configuration option, rather than as individual
|
2015-09-11 13:12:02 +08:00
|
|
|
public objects in an MDEF or private objects in a source file.
|
2015-08-11 21:42:45 +08:00
|
|
|
|
2016-03-16 23:28:46 +08:00
|
|
|
|
2015-08-11 21:42:45 +08:00
|
|
|
Example: Allocating a Task IRQ
|
|
|
|
==============================
|
|
|
|
|
|
|
|
This code associates a task IRQ with interrupts generated by a device.
|
2016-03-16 23:28:46 +08:00
|
|
|
Interrupts from that device are then enabled so they can be processed
|
|
|
|
using the task IRQ.
|
2015-08-11 21:42:45 +08:00
|
|
|
|
|
|
|
.. 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 */
|
2015-11-03 07:18:02 +08:00
|
|
|
#define FOO_IRQ_FLAGS 0 /* device "foo" IRQ flags. Unused on non-x86 */
|
2015-08-11 21:42:45 +08:00
|
|
|
|
2015-11-03 07:18:02 +08:00
|
|
|
if (task_irq_alloc(FOO_DEVICE, FOO_IRQ, FOO_PRIO, FOO_IRQ_FLAGS) ==
|
|
|
|
INVALID_VECTOR) {
|
2015-08-11 21:42:45 +08:00
|
|
|
/* 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
|
|
|
|
|
2015-12-08 04:06:07 +08:00
|
|
|
task_irq_wait(FOO_DEVICE, TICKS_UNLIMITED);
|
2015-08-11 21:42:45 +08:00
|
|
|
|
|
|
|
/* 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) */
|
|
|
|
|
2016-03-16 23:28:46 +08:00
|
|
|
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.
|
2015-08-11 21:42:45 +08:00
|
|
|
|
|
|
|
|
|
|
|
APIs
|
|
|
|
****
|
|
|
|
|
2016-03-16 23:28:46 +08:00
|
|
|
Task IRQ APIs provided by :file:`microkernel.h`
|
|
|
|
===============================================
|
2015-08-11 21:42:45 +08:00
|
|
|
|
2015-10-08 04:55:39 +08:00
|
|
|
:cpp:func:`task_irq_alloc()`
|
2016-03-16 23:28:46 +08:00
|
|
|
Bind a task IRQ to a device and enable interrupts.
|
2015-10-08 04:55:39 +08:00
|
|
|
|
|
|
|
:cpp:func:`task_irq_ack()`
|
2016-03-16 23:28:46 +08:00
|
|
|
Acknowledge an interrupt and re-enable the interrupt.
|
2015-10-08 04:55:39 +08:00
|
|
|
|
2015-12-08 04:06:07 +08:00
|
|
|
:c:func:`task_irq_wait()`
|
2016-03-16 23:28:46 +08:00
|
|
|
Wait for an interrupt to occur within a specified time period.
|