58 lines
2.3 KiB
ReStructuredText
58 lines
2.3 KiB
ReStructuredText
.. _synchrounous_call:
|
|
|
|
Synchronous call within interrupt based device drivers
|
|
######################################################
|
|
|
|
Zephyr provides a set of device drivers for various platforms. As a preemptive
|
|
OS, those are meant to be implemented through an interrupt based mode and not
|
|
a polling mode unless the driven hardware does not provide any interrupt
|
|
enabled mechanism.
|
|
|
|
The higher level calls accessed through devices's specific API, such as i2c.h
|
|
or spi.h, are meant to be, most of the time, synchronous. Thus these calls
|
|
should be blocking.
|
|
|
|
However, and due to the fact Zephyr provides 2 types of executions context on
|
|
a microkernel, drivers need to act accordingly. A nanokernel semaphore cannot
|
|
be used if the context is a task for instance. Thus, include/device.h exposes
|
|
an helper API to handle this case transparently, and no other means should be
|
|
used instead.
|
|
|
|
Usage of synchronous_call_* API
|
|
*******************************
|
|
|
|
1 type and 3 inline functions are exposed to solve this issue.
|
|
|
|
The device_sync_call_t type
|
|
===========================
|
|
|
|
It provides a nanokernel semaphore, always present in both built types:
|
|
nanokernel and microkernel. 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.
|
|
|
|
synchronous_call_init()
|
|
=======================
|
|
|
|
It initializes the device_sync_call_t type: its semaphores and the marker.
|
|
Such function should be used only once in the device driver's instance life
|
|
time. Thus the driver's initialization function is the best place for calling
|
|
it.
|
|
|
|
synchronous_call_wait()
|
|
=======================
|
|
|
|
This functions will block - i.e. will perform a "take wait" - on the relevant
|
|
semaphore. This will make the exposed driver's API function using it a blocking
|
|
function, until the relevant semaphore is released by a give. This is therefore
|
|
used to start a synchronous call, until being signaled for synchronization.
|
|
|
|
synchronous_call_complete()
|
|
===========================
|
|
|
|
This function is used to release the relevant semaphore and thus will unlock
|
|
the blocking function. This is thus being called in the driver's ISR handler
|
|
mostly. This is used to signal the completion of the synchronous call, whatever
|
|
fate would be (error or success).
|