blob: cb8518866f5acafc90ada9316c7666a0a939f54e [file] [log] [blame]
.. _synchronous_call:
Synchronous Calls
*****************
Zephyr provides a set of device drivers for multiple platforms. Each driver
should support an interrupt-based implementation, rather than polling, unless
the specific hardware does not provide any interrupt.
High-level calls accessed through devices's specific API, such as i2c.h
or spi.h, are usually intended as synchronous. Thus, these calls should be
blocking.
Due to the fact that Zephyr provides two types of execution contexts (task
and fiber) on a microkernel, drivers need to act accordingly. For example, a
nanokernel semaphore cannot be used when the context is a task, so the
:file:`include/device.h` exposes a helper API to handle this case transparently;
no other means ought to be used instead.
Zephyr API exposes 1 type and 3 inline functions to solve this issue.
``device_sync_call_t``
This type provides a nanokernel semaphore, always present in both nanokernel
and microkernel use cases. It is meant to be used within a fiber context.
Then, and only on a microkernel type, it will provide a kernel semaphore
meant to be used within a task context. A boolean marker is used to remember
the caller's context when running a microkernel.
:cpp:func:`device_sync_call_init()`
This function initializes the ``device_sync_call_t`` type semaphores and the
marker. This function should be used only once in the device driver's instance
lifetime. Thus, the driver's initialization function is the best place for
calling it.
:cpp:func:`device_sync_call_wait()`
This function will block - that is, it will perform a "take wait" - on the
relevant semaphore. The exposed driver's API function can then be used as a
blocking function until the relevant semaphore is released by a ``give``.
This is therefore used to start a synchronous call, and waits until being
signaled for synchronization.
:cpp:func:`device_sync_call_complete()`
This function releases the relevant semaphore and thus will unlock the blocking
function. Most frequently will it be called in the driver's ISR handler. It is
used to signal the completion of the synchronous call (error or success).