Doc: Change the Nanokernel Objects to the Nanokernel Services section.
Moves the Nanokernel Object documentation to a new Nanokernel Services section within the Kernel Primer. Labels, cross-references, figures, headings and filenames were updated to reflect the new structure. Change-Id: I04f97e712d78cd211a8ed1315f86895a51affa01 Signed-off-by: Rodrigo Caballero <rodrigo.caballero.abraham@intel.com>
This commit is contained in:
parent
4d8b60adca
commit
f81ee6efdd
8 changed files with 404 additions and 375 deletions
28
doc/kernel/nanokernel/nanokernel.rst
Normal file
28
doc/kernel/nanokernel/nanokernel.rst
Normal file
|
@ -0,0 +1,28 @@
|
|||
.. _nanokernel:
|
||||
|
||||
Nanokernel Services
|
||||
###################
|
||||
|
||||
Section Scope
|
||||
*************
|
||||
|
||||
This section provides an overview of the most important nanokernel
|
||||
services. The information contained here is an aid to better understand
|
||||
how the kernel operates at the nanokernel level.
|
||||
|
||||
Document Format
|
||||
***************
|
||||
|
||||
Each service is broken off to its own section, containing a definition, a
|
||||
functional description, the service initialization syntax, and a table
|
||||
of APIs with the context which may call them. Please refer to the API documentation for further
|
||||
details regarding the functionality of each service.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
nanokernel_fibers
|
||||
nanokernel_timers
|
||||
nanokernel_signaling
|
||||
nanokernel_data
|
||||
nanokernel_interrupts
|
100
doc/kernel/nanokernel/nanokernel_data.rst
Normal file
100
doc/kernel/nanokernel/nanokernel_data.rst
Normal file
|
@ -0,0 +1,100 @@
|
|||
.. _nanokernel_data:
|
||||
|
||||
Data Passing Services
|
||||
#####################
|
||||
|
||||
This section contains the information about all data passing services available in the nanokernel.
|
||||
|
||||
Nanokernel FIFO
|
||||
***************
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
|
||||
The FIFO object is defined in :file:`kernel/nanokernel/nano_fifo.c`.
|
||||
This is a linked list of memory that allows the caller to store data of
|
||||
any size. The data is stored in first-in-first-out order.
|
||||
|
||||
Function
|
||||
========
|
||||
|
||||
|
||||
Multiple processes can wait on the same FIFO object. Data is passed to
|
||||
the first fiber that waited on the FIFO, and then to the background
|
||||
task if no fibers are waiting. Through this mechanism the FIFO object
|
||||
can synchronize or communicate between more than two contexts through
|
||||
its API. Any ISR, fiber, or task can attempt to get data from a FIFO
|
||||
without waiting on the data to be stored.
|
||||
|
||||
.. note::
|
||||
|
||||
The FIFO object reserves the first WORD in each stored memory
|
||||
block as a link pointer to the next item. The size of the WORD
|
||||
depends on the platform and can be 16 bit, 32 bit, etc.
|
||||
|
||||
Application Program Interfaces
|
||||
==============================
|
||||
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| Context | Interfaces |
|
||||
+================================+================================================================+
|
||||
| **Initialization** | :c:func:`nano_fifo_init()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Interrupt Service Routines** | :c:func:`nano_isr_fifo_get()`, :c:func:`nano_isr_fifo_put()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Fibers** | :c:func:`nano_fiber_fifo_get()`, |
|
||||
| | :c:func:`nano_fiber_fifo_get_wait()`, |
|
||||
| | :c:func:`nano_fiber_fifo_put()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Tasks** | :c:func:`nano_task_fifo_get()`, |
|
||||
| | :c:func:`nano_task_fifo_get_wait()`, |
|
||||
| | :c:func:`nano_task_fifo_put()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
|
||||
Nanokernel LIFO Object
|
||||
**********************
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
The LIFO is defined in :file:`kernel/nanokernel/nano_lifo.c`. It
|
||||
consists of a linked list of memory blocks that uses the first word in
|
||||
each block as a next pointer. The data is stored in last-in-first-out
|
||||
order.
|
||||
|
||||
Function
|
||||
========
|
||||
|
||||
When a message is added to the LIFO, the data is stored at the head of
|
||||
the list. Messages taken off the LIFO object are taken from the head.
|
||||
|
||||
The LIFO object requires the first 32-bit word to be empty in order to
|
||||
maintain the linked list.
|
||||
|
||||
The LIFO object does not store information about the size of the
|
||||
messages.
|
||||
|
||||
The LIFO object remembers one waiting context. When a second context
|
||||
starts waiting for data from the same LIFO object, the first context
|
||||
remains waiting and never reaches the runnable state.
|
||||
|
||||
Application Program Interfaces
|
||||
==============================
|
||||
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| Context | Interfaces |
|
||||
+================================+================================================================+
|
||||
| **Initialization** | :c:func:`nano_lifo_init()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Interrupt Service Routines** | :c:func:`nano_isr_lifo_get()`, |
|
||||
| | :c:func:`nano_isr_lifo_put()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Fibers** | :c:func:`nano_fiber_lifo_get()`, |
|
||||
| | :c:func:`nano_fiber_lifo_get_wait()`, |
|
||||
| | :c:func:`nano_fiber_lifo_put()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Tasks** | :c:func:`nano_task_lifo_get()`, |
|
||||
| | :c:func:`nano_task_lifo_get_wait()`, |
|
||||
| | :c:func:`nano_task_lifo_put()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
147
doc/kernel/nanokernel/nanokernel_example.rst
Normal file
147
doc/kernel/nanokernel/nanokernel_example.rst
Normal file
|
@ -0,0 +1,147 @@
|
|||
.. _nanokernel_example:
|
||||
|
||||
Semaphore, Timer, and Fiber Example
|
||||
###################################
|
||||
|
||||
The following example is pulled from the file:
|
||||
:file:`samples/microkernel/apps/hello_world/src/hello.c`.
|
||||
|
||||
Example Code
|
||||
************
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <nanokernel.h>
|
||||
|
||||
#include <nanokernel/cpu.h>
|
||||
|
||||
/* specify delay between greetings (in ms); compute equivalent in ticks */
|
||||
|
||||
#define SLEEPTIME
|
||||
|
||||
#define SLEEPTICKS (SLEEPTIME * CONFIG_TICKFREQ / 1000)
|
||||
|
||||
#define STACKSIZE 2000
|
||||
|
||||
char fiberStack[STACKSIZE];
|
||||
|
||||
struct nano_sem nanoSemTask;
|
||||
|
||||
struct nano_sem nanoSemFiber;
|
||||
|
||||
void fiberEntry (void)
|
||||
|
||||
{
|
||||
struct nano_timer timer;
|
||||
uint32_t data[2] = {0, 0};
|
||||
|
||||
nano_sem_init (&nanoSemFiber);
|
||||
nano_timer_init (&timer, data);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* wait for task to let us have a turn */
|
||||
nano_fiber_sem_take_wait (&nanoSemFiber);
|
||||
|
||||
/* say "hello" */
|
||||
PRINT ("%s: Hello World!\n", __FUNCTION__);
|
||||
|
||||
/* wait a while, then let task have a turn */
|
||||
nano_fiber_timer_start (&timer, SLEEPTICKS);
|
||||
nano_fiber_timer_wait (&timer);
|
||||
nano_fiber_sem_give (&nanoSemTask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void main (void)
|
||||
|
||||
{
|
||||
struct nano_timer timer;
|
||||
uint32_t data[2] = {0, 0};
|
||||
|
||||
task_fiber_start (&fiberStack[0], STACKSIZE,
|
||||
(nano_fiber_entry_t) fiberEntry, 0, 0, 7, 0);
|
||||
|
||||
nano_sem_init (&nanoSemTask);
|
||||
nano_timer_init (&timer, data);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* say "hello" */
|
||||
PRINT ("%s: Hello World!\n", __FUNCTION__);
|
||||
|
||||
/* wait a while, then let fiber have a turn */
|
||||
nano_task_timer_start (&timer, SLEEPTICKS);
|
||||
nano_task_timer_wait (&timer);
|
||||
nano_task_sem_give (&nanoSemFiber);
|
||||
|
||||
/* now wait for fiber to let us have a turn */
|
||||
nano_task_sem_take_wait (&nanoSemTask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Step-by-Step Description
|
||||
************************
|
||||
|
||||
A quick breakdown of the major objects in use by this sample includes:
|
||||
|
||||
- One fiber, executing in the :c:func:`fiberEntry()` routine.
|
||||
|
||||
- The background task, executing in the :c:func:`main()` routine.
|
||||
|
||||
- Two semaphores (*nanoSemTask*, *nanoSemFiber*),
|
||||
|
||||
- Two timers:
|
||||
|
||||
+ One local to the fiber (timer)
|
||||
|
||||
+ One local to background task (timer)
|
||||
|
||||
First, the background task starts executing main(). The background task
|
||||
calls task_fiber_start initializing and starting the fiber. Since a
|
||||
fiber is available to be run, the background task is pre-empted and the
|
||||
fiber begins running.
|
||||
|
||||
Execution jumps to fiberEntry. nanoSemFiber and the fiber-local timer
|
||||
before dropping into the while loop, where it takes and waits on
|
||||
nanoSemFiber. task_fiber_start.
|
||||
|
||||
The background task initializes nanoSemTask and the task-local timer.
|
||||
|
||||
The following steps repeat endlessly:
|
||||
|
||||
#. The background task execution begins at the top of the main while
|
||||
loop and prints, “main: Hello World!”
|
||||
|
||||
#. The background task then starts a timer for SLEEPTICKS in the
|
||||
future, and waits for that timer to expire.
|
||||
|
||||
|
||||
#. Once the timer expires, it signals the fiber by giving the
|
||||
nanoSemFiber semaphore, which in turn marks the fiber as runnable.
|
||||
|
||||
#. The fiber, now marked as runnable, pre-empts the background
|
||||
process, allowing execution to jump to the fiber.
|
||||
nano_fiber_sem_take_wait.
|
||||
|
||||
#. The fiber then prints, “fiberEntry: Hello World!” It starts a time
|
||||
for SLEEPTICKS in the future and waits for that timer to expire. The
|
||||
fiber is marked as not runnable, and execution jumps to the
|
||||
background task.
|
||||
|
||||
#. The background task then takes and waits on the nanoSemTask
|
||||
semaphore.
|
||||
|
||||
#. Once the timer expires, the fiber signals the background task by
|
||||
giving the nanoSemFiber semaphore. The background task is marked as
|
||||
runnable, but code execution continues in the fiber, since fibers
|
||||
take priority over the background task. The fiber execution
|
||||
continues to the top of the while loop, where it takes and waits on
|
||||
nanoSemFiber. The fiber is marked as not runnable, and the
|
||||
background task is scheduled.
|
||||
|
||||
#. The background task execution picks up after the call to
|
||||
:c:func:`nano_task_sem_take_wait()`. It jumps to the top of the
|
||||
while loop.
|
|
@ -1,7 +1,7 @@
|
|||
.. _fibers:
|
||||
.. _fiber_services:
|
||||
|
||||
Fibers
|
||||
######
|
||||
Fiber Services
|
||||
##############
|
||||
|
||||
A fiber is an execution thread and a lightweight alternative to a task. It can
|
||||
use nanokernel objects but not microkernel objects. A runnable fiber will
|
||||
|
@ -41,7 +41,7 @@ and starts a fiber from another fiber, while
|
|||
:c:func:`task_fiber_start()` does so from a task. Both APIs use the
|
||||
parameters *parameter1* and *parameter2* as *arg1* and *arg2* given to
|
||||
the fiber . The full documentation on these APIs can be found in the
|
||||
:ref:`code`.
|
||||
:ref:`in-code_apis`.
|
||||
|
||||
When :c:func:`task_fiber_start()`is called from a task, the new fiber
|
||||
will be immediately ready to run. The background task immediately stops
|
||||
|
@ -91,8 +91,8 @@ unacceptable delay in the scheduling of other fibers, it should yield
|
|||
by placing a :c:func:`fiber_yield()` call within the loop of a
|
||||
computational cannot call :c:func:`fiber_yield()`.
|
||||
|
||||
Scheduling Fibers
|
||||
*****************
|
||||
Fiber Scheduling Model
|
||||
######################
|
||||
|
||||
The fibers in the Zephyr Kernel are priority-scheduled. When several fibers
|
||||
are ready to run, they run in the order of their priority. When more
|
||||
|
@ -115,7 +115,7 @@ for responding to an external event:
|
|||
|
||||
|
||||
Moving Computation Processing to a Task
|
||||
=======================================
|
||||
***************************************
|
||||
|
||||
Move the processing to a task to minimize the amount of computation that
|
||||
is performed at the fiber level. This reduces the scheduling delay for
|
||||
|
@ -124,14 +124,14 @@ handles the external event runnable.
|
|||
|
||||
|
||||
Moving Code to Handle External Event to ISR
|
||||
===========================================
|
||||
*******************************************
|
||||
|
||||
Move the code to handle the external event into an ISR. The ISR is
|
||||
executed immediately after the event is recognized, without waiting for
|
||||
the other fibers in the queue to be unscheduled.
|
||||
|
||||
Adding Yielding Points to Fibers
|
||||
================================
|
||||
********************************
|
||||
|
||||
Add yielding points to fibers with :c:func:`fiber_yield()`. This service
|
||||
un-schedules a fiber and places it at the end of the ready fiber list
|
|
@ -1,11 +1,10 @@
|
|||
Interrupt Service Routines
|
||||
##########################
|
||||
Interrupt Services
|
||||
##################
|
||||
|
||||
========
|
||||
Concepts
|
||||
========
|
||||
********
|
||||
|
||||
Interrupt Service Routines (ISRs) are execution threads
|
||||
:abbr:`ISRs (Interrupt Service Routines)` are execution threads
|
||||
that run in response to a hardware or software interrupt.
|
||||
They are used to preempt the execution of the
|
||||
task or fiber running at the time of the interrupt,
|
||||
|
@ -21,7 +20,7 @@ Each ISR has the following properties:
|
|||
* The address of the function that is invoked to handle the interrupt.
|
||||
* The argument value that is passed to that function.
|
||||
|
||||
An Interrupt Descriptor Table (IDT) is used to associate a given interrupt
|
||||
An :abbr:`IDT (Interrupt Descriptor Table)` is used to associate a given interrupt
|
||||
source with a given ISR.
|
||||
Only a single ISR can be associated with a specific IRQ at any given time.
|
||||
An ISR can be incorporated into the IDT when the Zephyr project is built
|
||||
|
@ -33,13 +32,13 @@ allowing a single function to service a device that generates
|
|||
multiple types of interrupts or to service multiple devices
|
||||
(usually of the same type). The argument value passed to an ISR's function
|
||||
can be used to allow the function to determine which interrupt has been
|
||||
signalled.
|
||||
signaled.
|
||||
|
||||
The Zephyr kernel provides a default ISR for all unused IDT entries. This ISR
|
||||
generates a fatal system error if an unexpected interrupt is signalled.
|
||||
generates a fatal system error if an unexpected interrupt is signaled.
|
||||
|
||||
The kernel supports interrupt nesting. This allows an ISR to be preempted
|
||||
in mid-execution if a higher priority interrupt is signalled. The lower
|
||||
in mid-execution if a higher priority interrupt is signaled. The lower
|
||||
priority ISR resumes execution once the higher priority ISR has completed
|
||||
its processing.
|
||||
|
||||
|
@ -50,10 +49,8 @@ be applied when it is already in effect. The collective lock must be
|
|||
unlocked an equal number of times before interrupts are again processed
|
||||
by the kernel.
|
||||
|
||||
|
||||
=======
|
||||
Purpose
|
||||
=======
|
||||
*******
|
||||
|
||||
Use an ISR to perform interrupt processing that requires a very rapid
|
||||
response, and which can be done quickly and without blocking.
|
||||
|
@ -64,13 +61,8 @@ response, and which can be done quickly and without blocking.
|
|||
should be handed off to a fiber or task. See `Offloading ISR Work`_ for
|
||||
a description of various techniques that can be used in a Zephyr project.
|
||||
|
||||
|
||||
=====
|
||||
Usage
|
||||
=====
|
||||
|
||||
Installing an ISR
|
||||
=================
|
||||
*****************
|
||||
|
||||
Use one of the following procedures to install an ISR:
|
||||
|
||||
|
@ -79,7 +71,7 @@ Use one of the following procedures to install an ISR:
|
|||
|
||||
|
||||
Installing a Static ISR
|
||||
***********************
|
||||
=======================
|
||||
|
||||
Use a static ISR to register an interrupt handler when the interrupt
|
||||
parameters are known during the build time and the device is always
|
||||
|
@ -127,7 +119,7 @@ For x86 platforms only, you must also create an interrupt stub as follows:
|
|||
|
||||
|
||||
Installing a Dynamic ISR
|
||||
************************
|
||||
========================
|
||||
|
||||
Use a dynamic ISR to register an interrupt handler when the interrupt
|
||||
parameters can be found out only at runtime, or when a device is not always
|
||||
|
@ -174,7 +166,7 @@ This is an example of a dynamic interrupt for x86:
|
|||
|
||||
|
||||
Working with Interrupts
|
||||
=======================
|
||||
***********************
|
||||
|
||||
Use the following:
|
||||
|
||||
|
@ -183,7 +175,7 @@ Use the following:
|
|||
|
||||
|
||||
Offloading ISR Work
|
||||
*******************
|
||||
===================
|
||||
|
||||
Interrupt service routines should generally be kept short
|
||||
to ensure predictable system operation.
|
||||
|
@ -200,17 +192,17 @@ to a fiber or task.
|
|||
The :c:func:`nano_isr_XXX()` APIs should be used to notify the helper fiber
|
||||
(or task) that work is available for it.
|
||||
|
||||
See :ref:`fibers`.
|
||||
See :ref:`fiber_services`.
|
||||
|
||||
2. An ISR can signal the microkernel server fiber to do interrupt-related
|
||||
work by sending an event that has an associated event handler.
|
||||
|
||||
See :ref:`events`.
|
||||
See :ref:`microkernel_events`.
|
||||
|
||||
3. An ISR can signal a helper task to do interrupt-related work
|
||||
by sending an event that the helper task detects.
|
||||
|
||||
See :ref:`events`.
|
||||
See :ref:`microkernel_events`.
|
||||
|
||||
4. An ISR can signal a helper task to do interrupt-related work.
|
||||
by giving a semaphore that the helper task takes.
|
||||
|
@ -220,7 +212,7 @@ to a fiber or task.
|
|||
5. A kernel-supplied ISR can signal a helper task to do interrupt-related work
|
||||
using a task IRQ that the helper task allocates.
|
||||
|
||||
See :ref:`task_IRQs`.
|
||||
See :ref:`microkernel_task_irqs`.
|
||||
|
||||
When an ISR offloads work to a fiber there is typically a single
|
||||
context switch to that fiber when the ISR completes.
|
||||
|
@ -239,7 +231,7 @@ that are scheduled to run.
|
|||
|
||||
|
||||
IDT Security
|
||||
************
|
||||
============
|
||||
|
||||
Ideally, the IDT memory area should be protected against accidental
|
||||
modification, in the same way that text and read-only data areas
|
||||
|
@ -251,9 +243,9 @@ therefore *not* protected. This is true even for systems using
|
|||
reside in read-only memory (such as flash memory or ROM).
|
||||
|
||||
|
||||
========
|
||||
ISR APIs
|
||||
========
|
||||
|
||||
APIs
|
||||
****
|
||||
|
||||
This table lists interrupt-related Application Program Interfaces.
|
||||
|
||||
|
@ -272,9 +264,9 @@ This table lists interrupt-related Application Program Interfaces.
|
|||
| :c:func:`irq_unlock()` | Removes lock on interrupts from all sources. |
|
||||
+-------------------------+-------------------------------------------------+
|
||||
|
||||
==========
|
||||
ISR Macros
|
||||
==========
|
||||
|
||||
Macros
|
||||
******
|
||||
|
||||
This table lists the macros used to install a static ISR.
|
||||
|
||||
|
@ -285,5 +277,4 @@ This table lists the macros used to install a static ISR.
|
|||
+----------------------------------+-----------------------------------------+
|
||||
| :c:macro:`IRQ_CONFIG( )` | Registers a static ISR with the |
|
||||
| | interrupt controller. |
|
||||
+----------------------------------+-----------------------------------------+
|
||||
|
||||
+----------------------------------+-----------------------------------------+
|
51
doc/kernel/nanokernel/nanokernel_signaling.rst
Normal file
51
doc/kernel/nanokernel/nanokernel_signaling.rst
Normal file
|
@ -0,0 +1,51 @@
|
|||
.. _nanokernel_signaling:
|
||||
|
||||
Signaling Services
|
||||
##################
|
||||
|
||||
Nanokernel Semaphore
|
||||
********************
|
||||
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
The nanokernel semaphore is defined in
|
||||
:file:`kernel/nanokernel/nano_sema.c` and implements a counting
|
||||
semaphore that sends signals from one fiber to another.
|
||||
|
||||
Function
|
||||
========
|
||||
|
||||
Nanokernel semaphore objects can be used from an ISR, a fiber, or the
|
||||
background task. Interrupt handlers can use the nanokernel’s semaphore
|
||||
object to reschedule a fiber waiting for the interrupt.
|
||||
|
||||
Only one context can wait on a semaphore at a time. The semaphore starts
|
||||
with a count of 0 and remains that way if no context is pending on it.
|
||||
Each 'give' operation increments the count by 1. Following multiple
|
||||
'give' operations, the same number of 'take' operations can be
|
||||
performed without the calling context having to wait on the semaphore.
|
||||
Thus after n 'give' operations a semaphore can 'take' n times without
|
||||
pending. If a second context waits for the same semaphore object, the
|
||||
first context is lost and never wakes up.
|
||||
|
||||
Application Program Interfaces
|
||||
==============================
|
||||
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| Context | Interfaces |
|
||||
+================================+================================================================+
|
||||
| **Initialization** | :c:func:`nano_sem_init()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Interrupt Service Routines** | :c:func:`nano_isr_sem_give()`, |
|
||||
| | :c:func:`nano_isr_sem_take()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Fibers** | :c:func:`nano_fiber_sem_give()`, |
|
||||
| | :c:func:`nano_fiber_sem_take()`, |
|
||||
| | :c:func:`nano_fiber_sem_take_wait()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Tasks** | :c:func:`nano_task_sem_give()`, |
|
||||
| | :c:func:`nano_task_sem_take()`, |
|
||||
| | :c:func:`nano_task_sem_take_wait()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
43
doc/kernel/nanokernel/nanokernel_timers.rst
Normal file
43
doc/kernel/nanokernel/nanokernel_timers.rst
Normal file
|
@ -0,0 +1,43 @@
|
|||
.. _nanokernel_timers:
|
||||
|
||||
Timer Services
|
||||
##############
|
||||
|
||||
Definition
|
||||
**********
|
||||
|
||||
The timer objects is defined in :file:`kernel/nanokernel/nano_timer.c`
|
||||
and implements digital counters that either increment or decrement at a
|
||||
fixed frequency. Timers can be called from a task or fiber context.
|
||||
|
||||
Function
|
||||
********
|
||||
|
||||
Only a fiber or task context can call timers. Timers can only be used in
|
||||
a nanokernel if it is not part of a microkernel. Timers are optional in
|
||||
nanokernel-only systems. The nanokernel timers are simple. The
|
||||
:c:func:`nano_node_tick_delta()` routine is not reentrant and should
|
||||
only be called from a single context, unless it is certain other
|
||||
contexts are not using the elapsed timer.
|
||||
|
||||
|
||||
APIs
|
||||
****
|
||||
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| Context | Interface |
|
||||
+================================+================================================================+
|
||||
| **Initialization** | :c:func:`nano_timer_init()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Interrupt Service Routines** | |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Fibers** | :c:func:`nano_fiber_timer_test()`, |
|
||||
| | :c:func:`nano_fiber_timer_wait()`, |
|
||||
| | :c:func:`nano_fiber_timer_start()`, |
|
||||
| | :c:func:`nano_fiber_timer_stop()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
||||
| **Tasks** | :c:func:`nano_task_timer_test()`, |
|
||||
| | :c:func:`nano_task_timer_wait()`, |
|
||||
| | :c:func:`nano_task_timer_start()`, |
|
||||
| | :c:func:`nano_task_timer_stop()` |
|
||||
+--------------------------------+----------------------------------------------------------------+
|
|
@ -1,331 +0,0 @@
|
|||
.. _nanokernelObjects:
|
||||
|
||||
Nanokernel Objects
|
||||
##################
|
||||
|
||||
Section Scope
|
||||
*************
|
||||
|
||||
This section provides an overview of the most important nanokernel
|
||||
objects. The information contained here is an aid to better understand
|
||||
how the Zephyr Kernel operates at the nanokernel level.
|
||||
|
||||
Document Format
|
||||
***************
|
||||
|
||||
|
||||
Each object is broken off to its own section, containing a definition, a
|
||||
functional description, the object initialization syntax, and a table
|
||||
of Application Program Interfaces (APIs) with the context which may
|
||||
call them. Please refer to the API documentation for further details
|
||||
regarding each object’s functionality.
|
||||
|
||||
Nanokernel FIFO
|
||||
***************
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
|
||||
The FIFO object is defined in :file:`kernel/nanokernel/nano_fifo.c`.
|
||||
This is a linked list of memory that allows the caller to store data of
|
||||
any size. The data is stored in first-in-first-out order.
|
||||
|
||||
Function
|
||||
========
|
||||
|
||||
|
||||
Multiple processes can wait on the same FIFO object. Data is passed to
|
||||
the first fiber that waited on the FIFO, and then to the background
|
||||
task if no fibers are waiting. Through this mechanism the FIFO object
|
||||
can synchronize or communicate between more than two contexts through
|
||||
its API. Any ISR, fiber, or task can attempt to get data from a FIFO
|
||||
without waiting on the data to be stored.
|
||||
|
||||
.. note::
|
||||
|
||||
The FIFO object reserves the first WORD in each stored memory
|
||||
block as a link pointer to the next item. The size of the WORD
|
||||
depends on the platform and can be 16 bit, 32 bit, etc.
|
||||
|
||||
Application Program Interfaces
|
||||
==============================
|
||||
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Context** | **Interfaces** |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Initialization** | :c:func:`nano_fifo_init()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Interrupt Service Routines** | :c:func:`nano_isr_fifo_get()`, :c:func:`nano_isr_fifo_put()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Fibers** | :c:func:`nano_fiber_fifo_get()`, :c:func:`nano_fiber_fifo_get_wait()`, :c:func:`nano_fiber_fifo_put()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Tasks** | :c:func:`nano_task_fifo_get()`, :c:func:`nano_task_fifo_get_wait()`, :c:func:`nano_task_fifo_put()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Nanokernel LIFO Object
|
||||
**********************
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
The LIFO is defined in :file:`kernel/nanokernel/nano_lifo.c`. It
|
||||
consists of a linked list of memory blocks that uses the first word in
|
||||
each block as a next pointer. The data is stored in last-in-first-out
|
||||
order.
|
||||
|
||||
Function
|
||||
========
|
||||
|
||||
When a message is added to the LIFO, the data is stored at the head of
|
||||
the list. Messages taken off the LIFO object are taken from the head.
|
||||
|
||||
The LIFO object requires the first 32-bit word to be empty in order to
|
||||
maintain the linked list.
|
||||
|
||||
The LIFO object does not store information about the size of the
|
||||
messages.
|
||||
|
||||
The LIFO object remembers one waiting context. When a second context
|
||||
starts waiting for data from the same LIFO object, the first context
|
||||
remains waiting and never reaches the runnable state.
|
||||
|
||||
Application Program Interfaces
|
||||
==============================
|
||||
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Context** | **Interfaces** |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Initialization** | :c:func:`nano_lifo_init()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Interrupt Service Routines** | :c:func:`nano_isr_lifo_get()`, :c:func:`nano_isr_lifo_put()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Fibers** | :c:func:`nano_fiber_lifo_get()`, :c:func:`nano_fiber_lifo_get_wait()`, :c:func:`nano_fiber_lifo_put()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Tasks** | :c:func:`nano_task_lifo_get()`, :c:func:`nano_task_lifo_get_wait()`, :c:func:`nano_task_lifo_put()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Nanokernel Semaphore
|
||||
********************
|
||||
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
The nanokernel semaphore is defined in
|
||||
:file:`kernel/nanokernel/nano_sema.c` and implements a counting
|
||||
semaphore that sends signals from one fiber to another.
|
||||
|
||||
Function
|
||||
========
|
||||
|
||||
Nanokernel semaphore objects can be used from an ISR, a fiber, or the
|
||||
background task. Interrupt handlers can use the nanokernel’s semaphore
|
||||
object to reschedule a fiber waiting for the interrupt.
|
||||
|
||||
Only one context can wait on a semaphore at a time. The semaphore starts
|
||||
with a count of 0 and remains that way if no context is pending on it.
|
||||
Each 'give' operation increments the count by 1. Following multiple
|
||||
'give' operations, the same number of 'take' operations can be
|
||||
performed without the calling context having to wait on the semaphore.
|
||||
Thus after n 'give' operations a semaphore can 'take' n times without
|
||||
pending. If a second context waits for the same semaphore object, the
|
||||
first context is lost and never wakes up.
|
||||
|
||||
Application Program Interfaces
|
||||
==============================
|
||||
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| Context | Interfaces |
|
||||
+================================+========================================================================================================+
|
||||
| **Initialization** | :c:func:`nano_sem_init()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Interrupt Service Routines** | :c:func:`nano_isr_sem_give()`, :c:func:`nano_isr_sem_take()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Fibers** | :c:func:`nano_fiber_sem_give()`, :c:func:`nano_fiber_sem_take()`, :c:func:`nano_fiber_sem_take_wait()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| **Tasks** | :c:func:`nano_task_sem_give()`, :c:func:`nano_task_sem_take()`, :c:func:`nano_task_sem_take_wait()` |
|
||||
+--------------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Timer Objects
|
||||
*************
|
||||
|
||||
Definition
|
||||
==========
|
||||
|
||||
The timer objects is defined in :file:`kernel/nanokernel/nano_timer.c`
|
||||
and implements digital counters that either increment or decrement at a
|
||||
fixed frequency. Timers can be called from a task or fiber context.
|
||||
|
||||
Function
|
||||
========
|
||||
|
||||
Only a fiber or task context can call timers. Timers can only be used in
|
||||
a nanokernel if it is not part of a microkernel. Timers are optional in
|
||||
nanokernel-only systems. The nanokernel timers are simple. The
|
||||
:c:func:`nano_node_tick_delta()` routine is not reentrant and should
|
||||
only be called from a single context, unless it is certain other
|
||||
contexts are not using the elapsed timer.
|
||||
|
||||
|
||||
Application Program Interfaces
|
||||
==============================
|
||||
|
||||
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| **Context** | **Interface** |
|
||||
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| **Initialization** | :c:func:`nano_timer_init()` |
|
||||
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| **Interrupt Service Routines** | |
|
||||
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| **Fibers** | :c:func:`nano_fiber_timer_test()`, :c:func:`nano_fiber_timer_wait()`, :c:func:`nano_fiber_timer_start()`, :c:func:`nano_fiber_timer_stop()` |
|
||||
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| **Tasks** | :c:func:`nano_task_timer_test()`, :c:func:`nano_task_timer_wait()`, :c:func:`nano_task_timer_start()`, :c:func:`nano_task_timer_stop()` |
|
||||
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Semaphore, Timer, and Fiber Example
|
||||
***********************************
|
||||
|
||||
|
||||
The following example is pulled from the file:
|
||||
:file:`samples/microkernel/apps/hello_world/src/hello.c`.
|
||||
|
||||
Example Code
|
||||
============
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <nanokernel.h>
|
||||
|
||||
#include <nanokernel/cpu.h>
|
||||
|
||||
/* specify delay between greetings (in ms); compute equivalent in ticks */
|
||||
|
||||
#define SLEEPTIME
|
||||
|
||||
#define SLEEPTICKS (SLEEPTIME * CONFIG_TICKFREQ / 1000)
|
||||
|
||||
#define STACKSIZE 2000
|
||||
|
||||
char fiberStack[STACKSIZE];
|
||||
|
||||
struct nano_sem nanoSemTask;
|
||||
|
||||
struct nano_sem nanoSemFiber;
|
||||
|
||||
void fiberEntry (void)
|
||||
|
||||
{
|
||||
struct nano_timer timer;
|
||||
uint32_t data[2] = {0, 0};
|
||||
|
||||
nano_sem_init (&nanoSemFiber);
|
||||
nano_timer_init (&timer, data);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* wait for task to let us have a turn */
|
||||
nano_fiber_sem_take_wait (&nanoSemFiber);
|
||||
|
||||
/* say "hello" */
|
||||
PRINT ("%s: Hello World!\n", __FUNCTION__);
|
||||
|
||||
/* wait a while, then let task have a turn */
|
||||
nano_fiber_timer_start (&timer, SLEEPTICKS);
|
||||
nano_fiber_timer_wait (&timer);
|
||||
nano_fiber_sem_give (&nanoSemTask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void main (void)
|
||||
|
||||
{
|
||||
struct nano_timer timer;
|
||||
uint32_t data[2] = {0, 0};
|
||||
|
||||
task_fiber_start (&fiberStack[0], STACKSIZE,
|
||||
(nano_fiber_entry_t) fiberEntry, 0, 0, 7, 0);
|
||||
|
||||
nano_sem_init (&nanoSemTask);
|
||||
nano_timer_init (&timer, data);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* say "hello" */
|
||||
PRINT ("%s: Hello World!\n", __FUNCTION__);
|
||||
|
||||
/* wait a while, then let fiber have a turn */
|
||||
nano_task_timer_start (&timer, SLEEPTICKS);
|
||||
nano_task_timer_wait (&timer);
|
||||
nano_task_sem_give (&nanoSemFiber);
|
||||
|
||||
/* now wait for fiber to let us have a turn */
|
||||
nano_task_sem_take_wait (&nanoSemTask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Step-by-Step Description
|
||||
========================
|
||||
|
||||
A quick breakdown of the major objects in use by this sample includes:
|
||||
|
||||
- One fiber, executing in the :c:func:`fiberEntry()` routine.
|
||||
|
||||
- The background task, executing in the :c:func:`main()` routine.
|
||||
|
||||
- Two semaphores (*nanoSemTask*, *nanoSemFiber*),
|
||||
|
||||
- Two timers:
|
||||
|
||||
+ One local to the fiber (timer)
|
||||
|
||||
+ One local to background task (timer)
|
||||
|
||||
First, the background task starts executing main(). The background task
|
||||
calls task_fiber_start initializing and starting the fiber. Since a
|
||||
fiber is available to be run, the background task is pre-empted and the
|
||||
fiber begins running.
|
||||
|
||||
Execution jumps to fiberEntry. nanoSemFiber and the fiber-local timer
|
||||
before dropping into the while loop, where it takes and waits on
|
||||
nanoSemFiber. task_fiber_start.
|
||||
|
||||
The background task initializes nanoSemTask and the task-local timer.
|
||||
|
||||
The following steps repeat endlessly:
|
||||
|
||||
#. The background task execution begins at the top of the main while
|
||||
loop and prints, “main: Hello World!”
|
||||
|
||||
#. The background task then starts a timer for SLEEPTICKS in the
|
||||
future, and waits for that timer to expire.
|
||||
|
||||
|
||||
#. Once the timer expires, it signals the fiber by giving the
|
||||
nanoSemFiber semaphore, which in turn marks the fiber as runnable.
|
||||
|
||||
#. The fiber, now marked as runnable, pre-empts the background
|
||||
process, allowing execution to jump to the fiber.
|
||||
nano_fiber_sem_take_wait.
|
||||
|
||||
#. The fiber then prints, “fiberEntry: Hello World!” It starts a time
|
||||
for SLEEPTICKS in the future and waits for that timer to expire. The
|
||||
fiber is marked as not runnable, and execution jumps to the
|
||||
background task.
|
||||
|
||||
#. The background task then takes and waits on the nanoSemTask
|
||||
semaphore.
|
||||
|
||||
#. Once the timer expires, the fiber signals the background task by
|
||||
giving the nanoSemFiber semaphore. The background task is marked as
|
||||
runnable, but code execution continues in the fiber, since fibers
|
||||
take priority over the background task. The fiber execution
|
||||
continues to the top of the while loop, where it takes and waits on
|
||||
nanoSemFiber. The fiber is marked as not runnable, and the
|
||||
background task is scheduled.
|
||||
|
||||
#. The background task execution picks up after the call to
|
||||
:c:func:`nano_task_sem_take_wait()`. It jumps to the top of the
|
||||
while loop.
|
Loading…
Add table
Add a link
Reference in a new issue