150 lines
4.3 KiB
ReStructuredText
150 lines
4.3 KiB
ReStructuredText
.. _nanokernel_example:
|
|
|
|
Semaphore, Timer, and Fiber Example
|
|
###################################
|
|
|
|
The following example is intended to provide a basic picture of how Zephyr's
|
|
semaphores, timers, and fibers work. The actual implementations of the
|
|
standard hello_world are much simpler, see
|
|
:file:`ZEPHYR_BASE/samples/hello_world`
|
|
|
|
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(&nanoSemFiber, TICKS_UNLIMITED);
|
|
|
|
/* 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_test (&timer, TICKS_UNLIMITED);
|
|
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_test (&timer, TICKS_UNLIMITED);
|
|
nano_task_sem_give (&nanoSemFiber);
|
|
|
|
/* now wait for fiber to let us have a turn */
|
|
nano_task_sem_take (&nanoSemTask, TICKS_UNLIMITED);
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
task, allowing execution to jump to the fiber.
|
|
nano_fiber_sem_take.
|
|
|
|
#. 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()`. It jumps to the top of the
|
|
while loop.
|