Difference between revisions of "Zephyr device driver paradigm"
m (→^ Overview) |
m (Add section "References".) |
||
Line 23: | Line 23: | ||
* https://docs.zephyrproject.org/latest/reference/peripherals/sensor.html#group__sensor__interface_1gafbf65226a227e9f8824908bc38e336f5 | * https://docs.zephyrproject.org/latest/reference/peripherals/sensor.html#group__sensor__interface_1gafbf65226a227e9f8824908bc38e336f5 | ||
+ | |||
|- | |- | ||
| style="background:#f0f0f0; valign=top; padding:10px;" | <font color="#ffffff"></font> <!-- vertical spacing row --> | | style="background:#f0f0f0; valign=top; padding:10px;" | <font color="#ffffff"></font> <!-- vertical spacing row --> | ||
Line 406: | Line 407: | ||
59 #include <syscalls/sensor_channel_get_mrsh.c> | 59 #include <syscalls/sensor_channel_get_mrsh.c> | ||
</pre> | </pre> | ||
+ | |||
+ | |- | ||
+ | | style="background:#f0f0f0; valign=top; padding:10px;" | <font color="#ffffff"></font> <!-- vertical spacing row --> | ||
+ | | style="background:#f0f0f0; width:100%; padding:10px;" | | ||
+ | |- | ||
+ | | style="background:#e6ffcc; valign=top; padding:10px;" | <font color="#ffffff"></font><!-- #e6ffcc is light green --> | ||
+ | | style="background:#f0f0f0; width:100%; padding:10px;" | | ||
+ | |||
+ | == [[#top|^]] References == | ||
+ | |||
+ | * https://blog.golioth.io/adding-an-out-of-tree-sensor-driver-to-zephyr/ | ||
|} | |} |
Revision as of 22:55, 3 October 2022
. . . Color annotations here . . .
Contents
^ OverviewThis page began as a holding place for notes from a specific search early on during Zephyr out-of-tree driver development. Search is for the definition of routines with names ending in `_sensor_fetch`, `sensor_get` and related. A good starting point to understand Zephyr device driver model is at: Turns out these routines are defined by the given project team's developers, and Zephyr Project itself provides only the API definition and its rules. A complex arrangement of macros and some other programmatic features of Zephyr RTOS connect calling code with routines which have these standardized names. This is why it was not possible to track down specific routine definitions in the Zephyr sources on Github, but rather only in the build-time artifacts of compiled sample apps and personal Zephyr based apps. This page's section should be marked red, per 2021 Q4 local schema to identify page sections well formed, or under active development, or needing review. Original overview summary:
| |
^ Zephyr Triggers as Interrupt HandlersZephyr RTOS 2.6.0 documentation on `triggers`, mechanism for interrupt service routines: Following code example is copied from Zephyr 2.6.0 documentation, here for easier reference:
The following example contains a trigger fired whenever temperature crosses the 26 degree Celsius threshold. It also samples the temperature every second. A real application would ideally disable periodic sampling in the interest of saving power. Since the application has direct access to the kernel config symbols, no trigger is registered when triggering was disabled by the driver’s configuration. #define UCEL_PER_CEL 1000000 #define UCEL_PER_MCEL 1000 #define TEMP_INITIAL_CEL 25 #define TEMP_WINDOW_HALF_UCEL 500000 static const char *now_str(void) { static char buf[16]; /* ...HH:MM:SS.MMM */ uint32_t now = k_uptime_get_32(); unsigned int ms = now % MSEC_PER_SEC; unsigned int s; unsigned int min; unsigned int h; now /= MSEC_PER_SEC; s = now % 60U; now /= 60U; min = now % 60U; now /= 60U; h = now; snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u", h, min, s, ms); return buf; } #ifdef CONFIG_MCP9808_TRIGGER static struct sensor_trigger trig; static int set_window(const struct device *dev, const struct sensor_value *temp) { const int temp_ucel = temp->val1 * UCEL_PER_CEL + temp->val2; const int low_ucel = temp_ucel - TEMP_WINDOW_HALF_UCEL; const int high_ucel = temp_ucel + TEMP_WINDOW_HALF_UCEL; struct sensor_value val = { .val1 = low_ucel / UCEL_PER_CEL, .val2 = low_ucel % UCEL_PER_CEL, }; int rc = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP, SENSOR_ATTR_LOWER_THRESH, &val); if (rc == 0) { val.val1 = high_ucel / UCEL_PER_CEL, val.val2 = high_ucel % UCEL_PER_CEL, rc = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP, SENSOR_ATTR_UPPER_THRESH, &val); } if (rc == 0) { printf("Alert on temp outside [%d, %d] milli-Celsius\n", low_ucel / UCEL_PER_MCEL, high_ucel / UCEL_PER_MCEL); } return rc; } static inline int set_window_ucel(const struct device *dev, int temp_ucel) { struct sensor_value val = { .val1 = temp_ucel / UCEL_PER_CEL, .val2 = temp_ucel % UCEL_PER_CEL, }; return set_window(dev, &val); } static void trigger_handler(const struct device *dev, struct sensor_trigger *trig) { struct sensor_value temp; static size_t cnt; int rc; ++cnt; rc = sensor_sample_fetch(dev); if (rc != 0) { printf("sensor_sample_fetch error: %d\n", rc); return; } rc = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp); if (rc != 0) { printf("sensor_channel_get error: %d\n", rc); return; } printf("trigger fired %u, temp %g deg C\n", cnt, sensor_value_to_double(&temp)); set_window(dev, &temp); } #endif void main(void) { const struct device *dev = DEVICE_DT_GET_ANY(microchip_mcp9808); int rc; if (dev == NULL) { printf("Device not found.\n"); return; } if (!device_is_ready(dev)) { printf("Device %s is not ready.\n", dev->name); return; } #ifdef CONFIG_MCP9808_TRIGGER rc = set_window_ucel(dev, TEMP_INITIAL_CEL * UCEL_PER_CEL); if (rc == 0) { trig.type = SENSOR_TRIG_THRESHOLD; trig.chan = SENSOR_CHAN_AMBIENT_TEMP; rc = sensor_trigger_set(dev, &trig, trigger_handler); } if (rc != 0) { printf("Trigger set failed: %d\n", rc); return; } printk("Trigger set got %d\n", rc); #endif while (1) { struct sensor_value temp; rc = sensor_sample_fetch(dev); if (rc != 0) { printf("sensor_sample_fetch error: %d\n", rc); break; } rc = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp); if (rc != 0) { printf("sensor_channel_get error: %d\n", rc); break; } printf("%s: %g C\n", now_str(), sensor_value_to_double(&temp)); k_sleep(K_SECONDS(2)); } }
| |
^ sensor_sample_fetch_channel instancesIn Zephyr 2.6.0, Zephyr RTOS device driver API function ted@localhost:~/projects/zephyr-based/z3-aqw-demo/air-quality-wing-zephyr-demo$ ls basic ble bootloader golioth img Makefile modules README.md tools west.yml zephyr ted@localhost:~/projects/zephyr-based/z3-aqw-demo/air-quality-wing-zephyr-demo$ grep -nr sensor_sample_fetch_chan ./* ./zephyr/drivers/sensor/sensor_handlers.c:41:static inline int z_vrfy_sensor_sample_fetch_chan(const struct device *dev, ./zephyr/drivers/sensor/sensor_handlers.c:45: return z_impl_sensor_sample_fetch_chan((const struct device *)dev, ./zephyr/drivers/sensor/sensor_handlers.c:48:#include <syscalls/sensor_sample_fetch_chan_mrsh.c> ./zephyr/include/drivers/sensor.h:535:__syscall int sensor_sample_fetch_chan(const struct device *dev, ./zephyr/include/drivers/sensor.h:538:static inline int z_impl_sensor_sample_fetch_chan(const struct device *dev, ./zephyr/include/drivers/sensor.h:553: * @ref sensor_sample_fetch_chan. It is guaranteed that two subsequent ./zephyr/include/drivers/sensor.h:555: * value, if @ref sensor_sample_fetch or @ref sensor_sample_fetch_chan ./zephyr/tests/drivers/sensor/generic/src/main.c:115: zassert_equal(sensor_sample_fetch_chan(dev, chan_elements[0].chan), ./zephyr/tests/drivers/sensor/sbs_gauge/src/test_sbs_gauge.c:25: zassert_true(sensor_sample_fetch_chan(dev, channel) < 0, "Sample fetch failed"); ./zephyr/tests/drivers/sensor/sbs_gauge/src/test_sbs_gauge.c:33: zassert_true(sensor_sample_fetch_chan(dev, channel) == -ENOTSUP, "Invalid function"); ./zephyr/samples/shields/x_nucleo_iks01a2/sensorhub/src/main.c:19: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); ./zephyr/samples/shields/x_nucleo_iks01a2/standard/src/main.c:19: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); ./zephyr/samples/shields/x_nucleo_iks01a3/sensorhub/src/main.c:19: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/shields/x_nucleo_iks01a3/sensorhub/src/main.c:32: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/shields/x_nucleo_iks01a3/sensorhub/src/main.c:39: sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); ./zephyr/samples/shields/x_nucleo_iks01a3/sensorhub/src/main.c:46: sensor_sample_fetch_chan(dev, SENSOR_CHAN_DIE_TEMP); ./zephyr/samples/shields/x_nucleo_iks01a3/standard/src/main.c:19: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); ./zephyr/samples/shields/x_nucleo_iks01a3/standard/src/main.c:30: sensor_sample_fetch_chan(dev, SENSOR_CHAN_PRESS); ./zephyr/samples/shields/x_nucleo_iks01a3/standard/src/main.c:51: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/shields/x_nucleo_iks01a3/standard/src/main.c:64: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/shields/x_nucleo_iks01a3/standard/src/main.c:71: sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); ./zephyr/samples/shields/x_nucleo_iks01a3/standard/src/main.c:78: sensor_sample_fetch_chan(dev, SENSOR_CHAN_DIE_TEMP); ./zephyr/samples/shields/x_nucleo_iks01a1/src/main.c:19: sensor_sample_fetch_chan(dev, trig->chan); ./zephyr/samples/shields/x_nucleo_iks02a1/sensorhub/src/main.c:19: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/shields/x_nucleo_iks02a1/sensorhub/src/main.c:32: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/shields/x_nucleo_iks02a1/sensorhub/src/main.c:39: sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); ./zephyr/samples/shields/x_nucleo_iks02a1/sensorhub/src/main.c:46: sensor_sample_fetch_chan(dev, SENSOR_CHAN_DIE_TEMP); ./zephyr/samples/shields/x_nucleo_iks02a1/standard/src/main.c:19: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/shields/x_nucleo_iks02a1/standard/src/main.c:30: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); ./zephyr/samples/shields/x_nucleo_iks02a1/standard/src/main.c:42: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/shields/x_nucleo_iks02a1/standard/src/main.c:49: sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:48: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:60: sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:73: sensor_sample_fetch_chan(dev, SENSOR_CHAN_MAGN_XYZ); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:87: sensor_sample_fetch_chan(dev, SENSOR_CHAN_PRESS); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:90: sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:311: sensor_sample_fetch_chan(accel_dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:321: sensor_sample_fetch_chan(accel_dev, SENSOR_CHAN_GYRO_XYZ); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:331: sensor_sample_fetch_chan(accel_dev, SENSOR_CHAN_MAGN_XYZ); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:342: sensor_sample_fetch_chan(accel_dev, SENSOR_CHAN_PRESS); ./zephyr/samples/boards/96b_argonkey/sensors/src/main.c:345: sensor_sample_fetch_chan(accel_dev, SENSOR_CHAN_AMBIENT_TEMP); ./zephyr/samples/boards/sensortile_box/src/main.c:29: sensor_sample_fetch_chan(dev, SENSOR_CHAN_PRESS); ./zephyr/samples/boards/sensortile_box/src/main.c:40: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/boards/sensortile_box/src/main.c:53: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/boards/sensortile_box/src/main.c:60: sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); ./zephyr/samples/boards/sensortile_box/src/main.c:67: sensor_sample_fetch_chan(dev, SENSOR_CHAN_DIE_TEMP); ./zephyr/samples/boards/sensortile_box/src/main.c:88: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/sensor/lsm6dso/src/main.c:34: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/sensor/lsm6dso/src/main.c:43: sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); ./zephyr/samples/sensor/max6675/src/main.c:34: ret = sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP); ./zephyr/samples/sensor/lsm6dsl/src/main.c:44: sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); ./zephyr/samples/sensor/lsm6dsl/src/main.c:50: sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); ./zephyr/samples/sensor/lsm6dsl/src/main.c:57: sensor_sample_fetch_chan(dev, SENSOR_CHAN_MAGN_XYZ); ./zephyr/samples/sensor/lsm6dsl/src/main.c:65: sensor_sample_fetch_chan(dev, SENSOR_CHAN_PRESS); ./zephyr/samples/sensor/lsm6dsl/src/main.c:68: sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP); ./zephyr/samples/sensor/max44009/src/main.c:33: if (sensor_sample_fetch_chan(dev, SENSOR_CHAN_LIGHT) != 0) { ./zephyr/samples/sensor/bq274xx/src/main.c:35: status = sensor_sample_fetch_chan(dev, ./zephyr/samples/sensor/bq274xx/src/main.c:51: status = sensor_sample_fetch_chan(dev, ./zephyr/samples/sensor/bq274xx/src/main.c:67: status = sensor_sample_fetch_chan(dev, ./zephyr/samples/sensor/bq274xx/src/main.c:84: status = sensor_sample_fetch_chan(dev, ./zephyr/samples/sensor/bq274xx/src/main.c:102: status = sensor_sample_fetch_chan(dev, ./zephyr/samples/sensor/bq274xx/src/main.c:119: status = sensor_sample_fetch_chan(dev, ./zephyr/samples/sensor/bq274xx/src/main.c:136: status = sensor_sample_fetch_chan(dev, ./zephyr/samples/sensor/bq274xx/src/main.c:152: status = sensor_sample_fetch_chan(dev, ./zephyr/samples/sensor/bq274xx/src/main.c:170: status = sensor_sample_fetch_chan(dev, ./zephyr/samples/sensor/bq274xx/src/main.c:189: status = sensor_sample_fetch_chan(dev, SENSOR_CHAN_GAUGE_TEMP); ted@localhost:~/projects/zephyr-based/z3-aqw-demo/air-quality-wing-zephyr-demo$
The 'build' directory by the way is, by default named 'build' when projects are compiled via `west`. When compiling via Segger Nordic version 5.60 the build directory of a project defaults to a naming scheme of 'build_[board_name]'. Thus when building a project in Segger for two or more targeted boards or hardware systems, at that point there will be two or more build directories containing build artifacts for those boards. | |
^ Definition of z_mrsh_sensor_sample_fetch_channel"./z4-sandbox-kionix-work/kionix-driver-demo/build/zephyr/include/generated/syscalls/sensor_sample_fetch_chan_mrsh.c" 27L, 901C 1,1 All 1 /* auto-generated by gen_syscalls.py, don't edit */ 2 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) 3 #pragma GCC diagnostic push 4 #endif 5 #ifdef __GNUC__ 6 #pragma GCC diagnostic ignored "-Wstrict-aliasing" 7 #endif 8 #include <syscalls/sensor.h> 9 10 extern int z_vrfy_sensor_sample_fetch_chan(const struct device * dev, enum sensor_channel type); 11 uintptr_t z_mrsh_sensor_sample_fetch_chan(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, 12 uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, void *ssf) 13 { 14 _current->syscall_frame = ssf; 15 (void) arg2; /* unused */ 16 (void) arg3; /* unused */ 17 (void) arg4; /* unused */ 18 (void) arg5; /* unused */ 19 int ret = z_vrfy_sensor_sample_fetch_chan(*(const struct device **)&arg0, *(enum sensor_channel*)&arg1) 20 ; 21 _current->syscall_frame = NULL; 22 return (uintptr_t) ret; 23 } 24 25 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) 26 #pragma GCC diagnostic pop 27 #endif | |
^ Further Search for z_vrfy_sensor_sample_fetch_chan()ted@localhost:~/projects/zephyr-based$ grep -nr z_vrfy_sensor_sample_fetch_chan ./* ./z3-aqw-demo/air-quality-wing-zephyr-demo/zephyr/drivers/sensor/sensor_handlers.c:41:static inline int z_vrfy_sensor_sample_fetch_chan(const struct device *dev, ./z4-sandbox-kionix-work/kionix-driver-demo/build/mcuboot/zephyr/include/generated/syscalls/sensor_sample_fetch_chan_mrsh.c:10:extern int z_vrfy_sensor_sample_fetch_chan(const struct device * dev, enum sensor_channel type); ./z4-sandbox-kionix-work/kionix-driver-demo/build/mcuboot/zephyr/include/generated/syscalls/sensor_sample_fetch_chan_mrsh.c:19: int ret = z_vrfy_sensor_sample_fetch_chan(*(const struct device **)&arg0, *(enum sensor_channel*)&arg1) ./z4-sandbox-kionix-work/kionix-driver-demo/build/zephyr/include/generated/syscalls/sensor_sample_fetch_chan_mrsh.c:10:extern int z_vrfy_sensor_sample_fetch_chan(const struct device * dev, enum sensor_channel type); ./z4-sandbox-kionix-work/kionix-driver-demo/build/zephyr/include/generated/syscalls/sensor_sample_fetch_chan_mrsh.c:19: int ret = z_vrfy_sensor_sample_fetch_chan(*(const struct device **)&arg0, *(enum sensor_channel*)&arg1) ./z4-sandbox-kionix-work/zephyr/drivers/sensor/sensor_handlers.c:41:static inline int z_vrfy_sensor_sample_fetch_chan(const struct device *dev, ted@localhost:~/projects/zephyr-based$ | |
^ 4 - File Which Defines z_vrfy_sensor_attr_set And Uses Macro Z_OOPS1 /* 2 * Copyright (c) 2017 Intel Corporation 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #include <drivers/sensor.h> 8 #include <syscall_handler.h> 9 10 static inline int z_vrfy_sensor_attr_set(const struct device *dev, 11 enum sensor_channel chan, 12 enum sensor_attribute attr, 13 const struct sensor_value *val) 14 { 15 Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, attr_set)); 16 Z_OOPS(Z_SYSCALL_MEMORY_READ(val, sizeof(struct sensor_value))); 17 return z_impl_sensor_attr_set((const struct device *)dev, chan, attr, 18 (const struct sensor_value *)val); 19 } 20 #include <syscalls/sensor_attr_set_mrsh.c> 21 22 static inline int z_vrfy_sensor_attr_get(const struct device *dev, 23 enum sensor_channel chan, 24 enum sensor_attribute attr, 25 struct sensor_value *val) 26 { 27 Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, attr_get)); 28 Z_OOPS(Z_SYSCALL_MEMORY_WRITE(val, sizeof(struct sensor_value))); 29 return z_impl_sensor_attr_get((const struct device *)dev, chan, attr, 30 (struct sensor_value *)val); 31 } 32 #include <syscalls/sensor_attr_get_mrsh.c> 33 34 static inline int z_vrfy_sensor_sample_fetch(const struct device *dev) 35 { 36 Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, sample_fetch)); 37 return z_impl_sensor_sample_fetch((const struct device *)dev); 38 } 39 #include <syscalls/sensor_sample_fetch_mrsh.c> 40 41 static inline int z_vrfy_sensor_sample_fetch_chan(const struct device *dev, 42 enum sensor_channel type) 43 { 44 Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, sample_fetch)); 45 return z_impl_sensor_sample_fetch_chan((const struct device *)dev, 46 type); 47 } 48 #include <syscalls/sensor_sample_fetch_chan_mrsh.c> 49 50 static inline int z_vrfy_sensor_channel_get(const struct device *dev, 51 enum sensor_channel chan, 52 struct sensor_value *val) 53 { 54 Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, channel_get)); 55 Z_OOPS(Z_SYSCALL_MEMORY_WRITE(val, sizeof(struct sensor_value))); 56 return z_impl_sensor_channel_get((const struct device *)dev, chan, 57 (struct sensor_value *)val); 58 } 59 #include <syscalls/sensor_channel_get_mrsh.c> | |
^ References |