Difference between revisions of "Zephyr drivers"
m (Add section q Trigger a.k.a. Interrupt Support q) |
m (Add missed formatting) |
||
| (9 intermediate revisions by the same user not shown) | |||
| Line 45: | Line 45: | ||
== [[#top|^]] Bosch BMI323 Driver Example == | == [[#top|^]] Bosch BMI323 Driver Example == | ||
| − | The Bosch BMI323 accelerometer magnetometer combined sensor has a driver in Zephyr 4.3.0. | + | The Bosch BMI323 accelerometer magnetometer combined sensor has a driver in Zephyr 4.3.0. The driver has just a few source files with nearly all driver functions defined in bmi323.c. The driver follows Zephyr's sensor model, and entails a notion of "set" and "get" functions for sensor attributes. In this context attributes are most often sensor configuration registers. To configure the sensor for particular operating modes is to "set its attributes" in Zephyr sensor model terminology. This driver also implements "get" and "fetch" functions for Zephyr supported sensor "channels". Each channel maps to a type of reading the sensor can take, for example x-axis acceleration, y-axis magnetometer reading, die temperature and similar. |
| − | The structure is defined starting at about line 384, bmi323.c:384 | + | === [[#top|^]] Attribute Setters === |
| + | |||
| + | This driver implements its sensor attribute setter function in bmi323.c in two places. The first place is a sensor API struct which the driver declares. This API struct organizes the public API function of the driver. These APIs implement and honor each a function signature that's type defined in Zephyr's sensor.h header file. | ||
| + | |||
| + | The structure is defined starting at about line 384, bmi323.c:384. Technically the reference to the attribute setter function is not part of this function's definition, but the reference is needed for the driver to function in Zephyr's "sensor model". | ||
| + | |||
| + | To "set an attribute" equates to writing one or more registers of the given sensor. This assumes of course a sensor with a digital interface. | ||
| + | |||
| + | <i>Excerpt 101 - BMI323 device API definition</i> | ||
<pre> | <pre> | ||
| Line 135: | Line 143: | ||
</pre> | </pre> | ||
| − | == [[#top|^]] Mutex Use in BMI323 Driver == | + | === [[#top|^]] Mutex Use in BMI323 Driver === |
| − | BMI323 driver code locks a mutex in the | + | BMI323 driver code locks a mutex in seven of the driver routines of bmi323.c. It's not yet clear why these particular routines are mutex protected but if any of them may be called by interrupt driven code, or two or more threads of execution then this mutual exclusion protection will be critical to avoiding race conditions: |
1. line 384: static int bosch_bmi323_driver_api_attr_set(...) | 1. line 384: static int bosch_bmi323_driver_api_attr_set(...) | ||
| Line 153: | Line 161: | ||
7. line 1241: static int bosch_bmi323_pm_action(...) | 7. line 1241: static int bosch_bmi323_pm_action(...) | ||
| − | == [[#top|^]] BMI323 Driver Routines == | + | === [[#top|^]] BMI323 Driver Routines === |
| + | |||
| + | All BMI323 driver functions appear to be statically qualified. A simple text search over bmi323.c gives the list of these functions in the next code excerpt. Some annotations are added in columns left of the functions to highlight (1) driver functions related to interrupt support and (2) functions which are mutex protected. | ||
| + | |||
| + | <i>Excerpt 102 - BMI323 driver functions</i> | ||
<pre> | <pre> | ||
| − | 59:static int bosch_bmi323_bus_init(const struct device *dev) | + | 59:static int bosch_bmi323_bus_init(const struct device *dev) |
| − | 68:static int bosch_bmi323_bus_read_words(const struct device *dev, uint8_t offset, uint16_t *words, | + | 68:static int bosch_bmi323_bus_read_words(const struct device *dev, uint8_t offset, uint16_t *words, |
| − | 78:static int bosch_bmi323_bus_write_words(const struct device *dev, uint8_t offset, uint16_t *words, | + | 78:static int bosch_bmi323_bus_write_words(const struct device *dev, uint8_t offset, uint16_t *words, |
| − | 88:static int32_t bosch_bmi323_lsb_from_fullscale(int64_t fullscale) | + | 88:static int32_t bosch_bmi323_lsb_from_fullscale(int64_t fullscale) |
| − | 94:static int64_t bosch_bmi323_value_to_micro(int16_t value, int32_t lsb) | + | 94:static int64_t bosch_bmi323_value_to_micro(int16_t value, int32_t lsb) |
| − | 100:static void bosch_bmi323_value_to_sensor_value(struct sensor_value *result, int16_t value, | + | 100:static void bosch_bmi323_value_to_sensor_value(struct sensor_value *result, int16_t value, |
| − | 111:static bool bosch_bmi323_value_is_valid(int16_t value) | + | 111:static bool bosch_bmi323_value_is_valid(int16_t value) |
| − | 116:static int bosch_bmi323_validate_chip_id(const struct device *dev) | + | 116:static int bosch_bmi323_validate_chip_id(const struct device *dev) |
| − | 134:static int bosch_bmi323_soft_reset(const struct device *dev) | + | 134:static int bosch_bmi323_soft_reset(const struct device *dev) |
| − | 152:static int bosch_bmi323_enable_feature_engine(const struct device *dev) | + | 152:static int bosch_bmi323_enable_feature_engine(const struct device *dev) |
| − | 178:static int bosch_bmi323_driver_api_set_acc_odr(const struct device *dev, | + | 178:static int bosch_bmi323_driver_api_set_acc_odr(const struct device *dev, |
| − | 226:static int bosch_bmi323_driver_api_set_acc_full_scale(const struct device *dev, | + | 226:static int bosch_bmi323_driver_api_set_acc_full_scale(const struct device *dev, |
| − | 257:static int bosch_bmi323_driver_api_set_acc_feature_mask(const struct device *dev, | + | 257:static int bosch_bmi323_driver_api_set_acc_feature_mask(const struct device *dev, |
| − | 280:static int bosch_bmi323_driver_api_set_gyro_odr(const struct device *dev, | + | 280:static int bosch_bmi323_driver_api_set_gyro_odr(const struct device *dev, |
| − | 328:static int bosch_bmi323_driver_api_set_gyro_full_scale(const struct device *dev, | + | 328:static int bosch_bmi323_driver_api_set_gyro_full_scale(const struct device *dev, |
| − | 361:static int bosch_bmi323_driver_api_set_gyro_feature_mask(const struct device *dev, | + | 361:static int bosch_bmi323_driver_api_set_gyro_feature_mask(const struct device *dev, |
| − | 384:static int bosch_bmi323_driver_api_attr_set(const struct device *dev, enum sensor_channel chan, | + | [mtx] 384:static int bosch_bmi323_driver_api_attr_set(const struct device *dev, enum sensor_channel chan, |
| − | 455:static int bosch_bmi323_driver_api_get_acc_odr(const struct device *dev, struct sensor_value *val) | + | 455:static int bosch_bmi323_driver_api_get_acc_odr(const struct device *dev, struct sensor_value *val) |
| − | 530:static int bosch_bmi323_driver_api_get_acc_full_scale(const struct device *dev, | + | 530:static int bosch_bmi323_driver_api_get_acc_full_scale(const struct device *dev, |
| − | 566:static int bosch_bmi323_driver_api_get_acc_feature_mask(const struct device *dev, | + | 566:static int bosch_bmi323_driver_api_get_acc_feature_mask(const struct device *dev, |
| − | 589:static int bosch_bmi323_driver_api_get_gyro_odr(const struct device *dev, struct sensor_value *val) | + | 589:static int bosch_bmi323_driver_api_get_gyro_odr(const struct device *dev, struct sensor_value *val) |
| − | 664:static int bosch_bmi323_driver_api_get_gyro_full_scale(const struct device *dev, | + | 664:static int bosch_bmi323_driver_api_get_gyro_full_scale(const struct device *dev, |
| − | 704:static int bosch_bmi323_driver_api_get_gyro_feature_mask(const struct device *dev, | + | 704:static int bosch_bmi323_driver_api_get_gyro_feature_mask(const struct device *dev, |
| − | 727:static int bosch_bmi323_driver_api_attr_get(const struct device *dev, enum sensor_channel chan, | + | [mtx] 727:static int bosch_bmi323_driver_api_attr_get(const struct device *dev, enum sensor_channel chan, |
| − | 796:static int bosch_bmi323_driver_api_trigger_set_acc_drdy(const struct device *dev) | + | [irq] 796:static int bosch_bmi323_driver_api_trigger_set_acc_drdy(const struct device *dev) |
| − | 806:static int bosch_bmi323_driver_api_trigger_set_acc_motion(const struct device *dev) | + | [irq] 806:static int bosch_bmi323_driver_api_trigger_set_acc_motion(const struct device *dev) |
| − | 843:static int bosch_bmi323_driver_api_trigger_set(const struct device *dev, | + | [irq] [mtx] 843:static int bosch_bmi323_driver_api_trigger_set(const struct device *dev, |
| − | 883:static int bosch_bmi323_driver_api_fetch_acc_samples(const struct device *dev) | + | 883:static int bosch_bmi323_driver_api_fetch_acc_samples(const struct device *dev) |
| − | 925:static int bosch_bmi323_driver_api_fetch_gyro_samples(const struct device *dev) | + | 925:static int bosch_bmi323_driver_api_fetch_gyro_samples(const struct device *dev) |
| − | 968:static int bosch_bmi323_driver_api_fetch_temperature(const struct device *dev) | + | 968:static int bosch_bmi323_driver_api_fetch_temperature(const struct device *dev) |
| − | 996:static int bosch_bmi323_driver_api_sample_fetch(const struct device *dev, enum sensor_channel chan) | + | [mtx] 996:static int bosch_bmi323_driver_api_sample_fetch(const struct device *dev, enum sensor_channel chan) |
| − | 1047:static int bosch_bmi323_driver_api_channel_get(const struct device *dev, enum sensor_channel chan, | + | [mtx] 1047:static int bosch_bmi323_driver_api_channel_get(const struct device *dev, enum sensor_channel chan, |
| − | 1100:static DEVICE_API(sensor, bosch_bmi323_api) = { | + | 1100:static DEVICE_API(sensor, bosch_bmi323_api) = { |
| − | 1108:static void bosch_bmi323_irq_callback(const struct device *dev) | + | [irq] 1108:static void bosch_bmi323_irq_callback(const struct device *dev) |
| − | 1115:static int bosch_bmi323_init_irq(const struct device *dev) | + | [irq] 1115:static int bosch_bmi323_init_irq(const struct device *dev) |
| − | 1139:static int bosch_bmi323_init_int1(const struct device *dev) | + | [irq] 1139:static int bosch_bmi323_init_int1(const struct device *dev) |
| − | 1150:static void bosch_bmi323_irq_callback_handler(struct k_work *item) | + | [irq] [mtx] 1150:static void bosch_bmi323_irq_callback_handler(struct k_work *item) |
| − | 1164:static int bosch_bmi323_pm_resume(const struct device *dev) | + | 1164:static int bosch_bmi323_pm_resume(const struct device *dev) |
| − | 1225:static int bosch_bmi323_pm_suspend(const struct device *dev) | + | 1225:static int bosch_bmi323_pm_suspend(const struct device *dev) |
| − | 1241:static int bosch_bmi323_pm_action(const struct device *dev, enum pm_device_action action) | + | [mtx] 1241:static int bosch_bmi323_pm_action(const struct device *dev, enum pm_device_action action) |
| − | 1271:static int bosch_bmi323_init(const struct device *dev) | + | 1271:static int bosch_bmi323_init(const struct device *dev) |
| − | 1318: static struct bosch_bmi323_data bosch_bmi323_data_##inst; \ | + | 1318: static struct bosch_bmi323_data bosch_bmi323_data_##inst; \ |
| − | 1322: static void bosch_bmi323_irq_callback##inst(const struct device *dev, \ | + | [irq] 1322: static void bosch_bmi323_irq_callback##inst(const struct device *dev, \ |
| − | 1328: static const struct bosch_bmi323_config bosch_bmi323_config_##inst = { \ | + | 1328: static const struct bosch_bmi323_config bosch_bmi323_config_##inst = { \ |
</pre> | </pre> | ||
| − | == [[#top|^]] Sensor Bus API and Sensor Bus == | + | === [[#top|^]] Sensor Bus API and Sensor Bus === |
| + | |||
| + | The BMI323 sensor provides I2C and SPI digital interfaces. These are in fact the only ways to the talk with this sensor. This is common however for MEMs type accelerometers. There are code comments in the driver to the effect that I2C is not yet supported but will be added. | ||
| + | |||
| + | One strange feature is that the driver bus read() and write() functions implement 16-bit words rather than bytes, even though both I2C and SPI generally use bytes as their granular unit of data. | ||
<pre> | <pre> | ||
| Line 224: | Line 240: | ||
</pre> | </pre> | ||
| − | == [[#top|^]] Trigger a.k.a. Interrupt Support == | + | === [[#top|^]] Trigger a.k.a. Interrupt Support === |
| + | |||
| + | BMI323 sensor driver provides interrupt handling and support through the following code constructs. The first routine calls helper functions to write config registers. This and the two helper functions are set up functions. They are not interrupt service handlers nor routines submitted as work at the detection of an interrupt. | ||
| + | |||
| + | * https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/sensor/bosch/bmi323/bmi323.c#L843 | ||
| + | |||
| + | <pre> | ||
| + | 843 static int bosch_bmi323_driver_api_trigger_set(const struct device *dev, | ||
| + | 844 const struct sensor_trigger *trig, | ||
| + | 845 sensor_trigger_handler_t handler) | ||
| + | 846 { | ||
| + | 847 struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; | ||
| + | 848 int ret = -ENODEV; | ||
| + | 849 | ||
| + | 850 k_mutex_lock(&data->lock, K_FOREVER); | ||
| + | 851 | ||
| + | 852 data->trigger = trig; | ||
| + | 853 data->trigger_handler = handler; | ||
| + | 854 | ||
| + | 855 switch (trig->chan) { | ||
| + | 856 case SENSOR_CHAN_ACCEL_XYZ: | ||
| + | 857 switch (trig->type) { | ||
| + | 858 case SENSOR_TRIG_DATA_READY: | ||
| + | 859 ret = bosch_bmi323_driver_api_trigger_set_acc_drdy(dev); | ||
| + | 860 | ||
| + | 861 break; | ||
| + | 862 | ||
| + | 863 case SENSOR_TRIG_MOTION: | ||
| + | 864 ret = bosch_bmi323_driver_api_trigger_set_acc_motion(dev); | ||
| + | 865 | ||
| + | 866 break; | ||
| + | 867 | ||
| + | 868 default: | ||
| + | 869 break; | ||
| + | 870 } | ||
| + | 871 | ||
| + | 872 break; | ||
| + | 873 | ||
| + | 874 default: | ||
| + | 875 break; | ||
| + | 876 } | ||
| + | 877 | ||
| + | 878 k_mutex_unlock(&data->lock); | ||
| + | 879 | ||
| + | 880 return ret; | ||
| + | 881 } | ||
| + | </pre> | ||
| + | |||
| + | The following code excerpts are a structure to organize the BMI323 sensor driver API, following by the driver's callback function. The callback function is, maybe no here but in a general sense called shortly or as soon as possible after a sensor interrupt such as "data ready", "motion detected" occurs. The callback is executed according to the relative priority of the thread in which it runs, among threads in the given application. | ||
| + | |||
| + | There is some indirection to unwrap in order for the program to "reach" the address of the callback. In routine `bosch_bmi323_irq_callback()` the callback handler, a routine, exists in *dev->data->callback_work. There seems to be a pattern where Zephyr driver functions declare a local pointer to the `data` member of the passed device structure. | ||
| + | |||
| + | * https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/sensor/bosch/bmi323/bmi323.c#L1100 | ||
| + | |||
| + | <pre> | ||
| + | 1100 static DEVICE_API(sensor, bosch_bmi323_api) = { | ||
| + | 1101 .attr_set = bosch_bmi323_driver_api_attr_set, | ||
| + | 1102 .attr_get = bosch_bmi323_driver_api_attr_get, | ||
| + | 1103 .trigger_set = bosch_bmi323_driver_api_trigger_set, | ||
| + | 1104 .sample_fetch = bosch_bmi323_driver_api_sample_fetch, | ||
| + | 1105 .channel_get = bosch_bmi323_driver_api_channel_get, | ||
| + | 1106 }; | ||
| + | 1107 | ||
| + | 1108 static void bosch_bmi323_irq_callback(const struct device *dev) | ||
| + | 1109 { | ||
| + | 1110 struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; | ||
| + | 1111 | ||
| + | 1112 k_work_submit(&data->callback_work); | ||
| + | 1113 } | ||
| + | </pre> | ||
| + | |||
| + | |||
| + | * https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/sensor/bosch/bmi323/bmi323.c#L1115 | ||
| + | |||
| + | <pre> | ||
| + | 1115 static int bosch_bmi323_init_irq(const struct device *dev) | ||
| + | 1116 { | ||
| + | 1117 struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; | ||
| + | 1118 struct bosch_bmi323_config *config = (struct bosch_bmi323_config *)dev->config; | ||
| + | 1119 int ret; | ||
| + | 1120 | ||
| + | 1121 ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); | ||
| + | 1122 | ||
| + | 1123 if (ret < 0) { | ||
| + | 1124 return ret; | ||
| + | 1125 } | ||
| + | 1126 | ||
| + | 1127 gpio_init_callback(&data->gpio_callback, config->int_gpio_callback, | ||
| + | 1128 BIT(config->int_gpio.pin)); | ||
| + | 1129 | ||
| + | 1130 ret = gpio_add_callback(config->int_gpio.port, &data->gpio_callback); | ||
| + | 1131 | ||
| + | 1132 if (ret < 0) { | ||
| + | 1133 return ret; | ||
| + | 1134 } | ||
| + | 1135 | ||
| + | 1136 return gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE); | ||
| + | 1137 } | ||
| + | </pre> | ||
| + | |||
| + | * https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/sensor/bosch/bmi323/bmi323.c#L1139 | ||
| + | |||
| + | <pre> | ||
| + | 1139 static int bosch_bmi323_init_int1(const struct device *dev) | ||
| + | 1140 { | ||
| + | 1141 uint16_t buf; | ||
| + | 1142 | ||
| + | 1143 buf = IMU_BOSCH_BMI323_REG_VALUE(IO_INT_CTRL, INT1_LVL, ACT_HIGH) | | ||
| + | 1144 IMU_BOSCH_BMI323_REG_VALUE(IO_INT_CTRL, INT1_OD, PUSH_PULL) | | ||
| + | 1145 IMU_BOSCH_BMI323_REG_VALUE(IO_INT_CTRL, INT1_OUTPUT_EN, EN); | ||
| + | 1146 | ||
| + | 1147 return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_IO_INT_CTRL, &buf, 1); | ||
| + | 1148 } | ||
| + | </pre> | ||
| − | |||
* https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/sensor/bosch/bmi323/bmi323.c#L1150 | * https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/sensor/bosch/bmi323/bmi323.c#L1150 | ||
Latest revision as of 04:46, 26 February 2026
Keywords: sensor interrupts : sensor triggers : Zephyr triggers : sensor interrupt support
OVERVIEW
This page a stash point to hold Zephyr driver notes. Zephyr RTOS project includes a range of types of drivers. First type referenced by this page will be Zephyr's sensor drivers.
^ Zephyr Sensor Model
Zephyr 4.3.0 device driver documentation:
Zephyr 4.3.0 sensor model:
"Sensor attribute get" function prototype. This prototype reveals Zephyr's enumerations for sensor yyy . . .
Zephyr's sensor model plays a big role in the design of sensor drivers for this RTOS. Zephyr's [... sensor.h] header defines many things. Two important enums from this header file are:
_ Sensor channel enum _
_ Sensor attribute enum _
Sensor channels generally correspond to readings of a quantity in specific units, like degrees centigrade and acceleration in the x-axis. Sensor attributes generally corrrespond to configuration settings for a sensor, where these settings modify the way in which readings are taken and reported.
For a Zephyr driver to support configuration of a sensor's attributes, it must implement a function of the form:
sensor_attr_set()
int sensor_attr_set(const struct device* dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value* val)
. . . whose typedef is at https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/drivers/sensor.h#L431.
^ Bosch BMI323 Driver Example
The Bosch BMI323 accelerometer magnetometer combined sensor has a driver in Zephyr 4.3.0. The driver has just a few source files with nearly all driver functions defined in bmi323.c. The driver follows Zephyr's sensor model, and entails a notion of "set" and "get" functions for sensor attributes. In this context attributes are most often sensor configuration registers. To configure the sensor for particular operating modes is to "set its attributes" in Zephyr sensor model terminology. This driver also implements "get" and "fetch" functions for Zephyr supported sensor "channels". Each channel maps to a type of reading the sensor can take, for example x-axis acceleration, y-axis magnetometer reading, die temperature and similar.
^ Attribute Setters
This driver implements its sensor attribute setter function in bmi323.c in two places. The first place is a sensor API struct which the driver declares. This API struct organizes the public API function of the driver. These APIs implement and honor each a function signature that's type defined in Zephyr's sensor.h header file.
The structure is defined starting at about line 384, bmi323.c:384. Technically the reference to the attribute setter function is not part of this function's definition, but the reference is needed for the driver to function in Zephyr's "sensor model".
To "set an attribute" equates to writing one or more registers of the given sensor. This assumes of course a sensor with a digital interface.
Excerpt 101 - BMI323 device API definition
static DEVICE_API(sensor, bosch_bmi323_api) = {
.attr_set = bosch_bmi323_driver_api_attr_set, <-- attribute setter
.attr_get = bosch_bmi323_driver_api_attr_get,
.trigger_set = bosch_bmi323_driver_api_trigger_set,
.sample_fetch = bosch_bmi323_driver_api_sample_fetch,
.channel_get = bosch_bmi323_driver_api_channel_get,
};
The attribute setter function is defined at about line 1101, bmi323.c:1101:
static int bosch_bmi323_driver_api_attr_set(const struct device *dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data;
int ret;
k_mutex_lock(&data->lock, K_FOREVER);
switch (chan) {
case SENSOR_CHAN_ACCEL_XYZ:
switch (attr) {
case SENSOR_ATTR_SAMPLING_FREQUENCY:
ret = bosch_bmi323_driver_api_set_acc_odr(dev, val);
break;
case SENSOR_ATTR_FULL_SCALE:
ret = bosch_bmi323_driver_api_set_acc_full_scale(dev, val);
break;
case SENSOR_ATTR_FEATURE_MASK:
ret = bosch_bmi323_driver_api_set_acc_feature_mask(dev, val);
break;
default:
ret = -ENODEV;
break;
}
break;
case SENSOR_CHAN_GYRO_XYZ:
switch (attr) {
case SENSOR_ATTR_SAMPLING_FREQUENCY:
ret = bosch_bmi323_driver_api_set_gyro_odr(dev, val);
break;
case SENSOR_ATTR_FULL_SCALE:
ret = bosch_bmi323_driver_api_set_gyro_full_scale(dev, val);
break;
case SENSOR_ATTR_FEATURE_MASK:
ret = bosch_bmi323_driver_api_set_gyro_feature_mask(dev, val);
break;
default:
ret = -ENODEV;
break;
}
break;
default:
ret = -ENODEV;
break;
}
k_mutex_unlock(&data->lock);
return ret;
}
^ Mutex Use in BMI323 Driver
BMI323 driver code locks a mutex in seven of the driver routines of bmi323.c. It's not yet clear why these particular routines are mutex protected but if any of them may be called by interrupt driven code, or two or more threads of execution then this mutual exclusion protection will be critical to avoiding race conditions:
1. line 384: static int bosch_bmi323_driver_api_attr_set(...)
2. line 727: static int bosch_bmi323_driver_api_attr_get(...)
3. line 843: static int bosch_bmi323_driver_api_trigger_set(...)
4. line 996: static int bosch_bmi323_driver_api_sample_fetch(const struct device *dev, enum sensor_channel chan)
5. line 1047: static int bosch_bmi323_driver_api_channel_get(...)
6. line 1150: static void bosch_bmi323_irq_callback_handler(...)
7. line 1241: static int bosch_bmi323_pm_action(...)
^ BMI323 Driver Routines
All BMI323 driver functions appear to be statically qualified. A simple text search over bmi323.c gives the list of these functions in the next code excerpt. Some annotations are added in columns left of the functions to highlight (1) driver functions related to interrupt support and (2) functions which are mutex protected.
Excerpt 102 - BMI323 driver functions
59:static int bosch_bmi323_bus_init(const struct device *dev)
68:static int bosch_bmi323_bus_read_words(const struct device *dev, uint8_t offset, uint16_t *words,
78:static int bosch_bmi323_bus_write_words(const struct device *dev, uint8_t offset, uint16_t *words,
88:static int32_t bosch_bmi323_lsb_from_fullscale(int64_t fullscale)
94:static int64_t bosch_bmi323_value_to_micro(int16_t value, int32_t lsb)
100:static void bosch_bmi323_value_to_sensor_value(struct sensor_value *result, int16_t value,
111:static bool bosch_bmi323_value_is_valid(int16_t value)
116:static int bosch_bmi323_validate_chip_id(const struct device *dev)
134:static int bosch_bmi323_soft_reset(const struct device *dev)
152:static int bosch_bmi323_enable_feature_engine(const struct device *dev)
178:static int bosch_bmi323_driver_api_set_acc_odr(const struct device *dev,
226:static int bosch_bmi323_driver_api_set_acc_full_scale(const struct device *dev,
257:static int bosch_bmi323_driver_api_set_acc_feature_mask(const struct device *dev,
280:static int bosch_bmi323_driver_api_set_gyro_odr(const struct device *dev,
328:static int bosch_bmi323_driver_api_set_gyro_full_scale(const struct device *dev,
361:static int bosch_bmi323_driver_api_set_gyro_feature_mask(const struct device *dev,
[mtx] 384:static int bosch_bmi323_driver_api_attr_set(const struct device *dev, enum sensor_channel chan,
455:static int bosch_bmi323_driver_api_get_acc_odr(const struct device *dev, struct sensor_value *val)
530:static int bosch_bmi323_driver_api_get_acc_full_scale(const struct device *dev,
566:static int bosch_bmi323_driver_api_get_acc_feature_mask(const struct device *dev,
589:static int bosch_bmi323_driver_api_get_gyro_odr(const struct device *dev, struct sensor_value *val)
664:static int bosch_bmi323_driver_api_get_gyro_full_scale(const struct device *dev,
704:static int bosch_bmi323_driver_api_get_gyro_feature_mask(const struct device *dev,
[mtx] 727:static int bosch_bmi323_driver_api_attr_get(const struct device *dev, enum sensor_channel chan,
[irq] 796:static int bosch_bmi323_driver_api_trigger_set_acc_drdy(const struct device *dev)
[irq] 806:static int bosch_bmi323_driver_api_trigger_set_acc_motion(const struct device *dev)
[irq] [mtx] 843:static int bosch_bmi323_driver_api_trigger_set(const struct device *dev,
883:static int bosch_bmi323_driver_api_fetch_acc_samples(const struct device *dev)
925:static int bosch_bmi323_driver_api_fetch_gyro_samples(const struct device *dev)
968:static int bosch_bmi323_driver_api_fetch_temperature(const struct device *dev)
[mtx] 996:static int bosch_bmi323_driver_api_sample_fetch(const struct device *dev, enum sensor_channel chan)
[mtx] 1047:static int bosch_bmi323_driver_api_channel_get(const struct device *dev, enum sensor_channel chan,
1100:static DEVICE_API(sensor, bosch_bmi323_api) = {
[irq] 1108:static void bosch_bmi323_irq_callback(const struct device *dev)
[irq] 1115:static int bosch_bmi323_init_irq(const struct device *dev)
[irq] 1139:static int bosch_bmi323_init_int1(const struct device *dev)
[irq] [mtx] 1150:static void bosch_bmi323_irq_callback_handler(struct k_work *item)
1164:static int bosch_bmi323_pm_resume(const struct device *dev)
1225:static int bosch_bmi323_pm_suspend(const struct device *dev)
[mtx] 1241:static int bosch_bmi323_pm_action(const struct device *dev, enum pm_device_action action)
1271:static int bosch_bmi323_init(const struct device *dev)
1318: static struct bosch_bmi323_data bosch_bmi323_data_##inst; \
[irq] 1322: static void bosch_bmi323_irq_callback##inst(const struct device *dev, \
1328: static const struct bosch_bmi323_config bosch_bmi323_config_##inst = { \
^ Sensor Bus API and Sensor Bus
The BMI323 sensor provides I2C and SPI digital interfaces. These are in fact the only ways to the talk with this sensor. This is common however for MEMs type accelerometers. There are code comments in the driver to the effect that I2C is not yet supported but will be added.
One strange feature is that the driver bus read() and write() functions implement 16-bit words rather than bytes, even though both I2C and SPI generally use bytes as their granular unit of data.
178 struct bosch_bmi323_bus_api {
179 /* Read up to multiple words from the BMI323 */
180 int (*read_words)(const void *context, uint8_t offset, uint16_t *words,
181 uint16_t words_count);
182
183 /* Write up to multiple words to the BLI323 */
184 int (*write_words)(const void *context, uint8_t offset, uint16_t *words,
185 uint16_t words_count);
186
187 /* Initialize the bus */
188 int (*init)(const void *context);
189 };
190
191 struct bosch_bmi323_bus {
192 const void *context;
193 const struct bosch_bmi323_bus_api *api;
194 };
^ Trigger a.k.a. Interrupt Support
BMI323 sensor driver provides interrupt handling and support through the following code constructs. The first routine calls helper functions to write config registers. This and the two helper functions are set up functions. They are not interrupt service handlers nor routines submitted as work at the detection of an interrupt.
843 static int bosch_bmi323_driver_api_trigger_set(const struct device *dev,
844 const struct sensor_trigger *trig,
845 sensor_trigger_handler_t handler)
846 {
847 struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data;
848 int ret = -ENODEV;
849
850 k_mutex_lock(&data->lock, K_FOREVER);
851
852 data->trigger = trig;
853 data->trigger_handler = handler;
854
855 switch (trig->chan) {
856 case SENSOR_CHAN_ACCEL_XYZ:
857 switch (trig->type) {
858 case SENSOR_TRIG_DATA_READY:
859 ret = bosch_bmi323_driver_api_trigger_set_acc_drdy(dev);
860
861 break;
862
863 case SENSOR_TRIG_MOTION:
864 ret = bosch_bmi323_driver_api_trigger_set_acc_motion(dev);
865
866 break;
867
868 default:
869 break;
870 }
871
872 break;
873
874 default:
875 break;
876 }
877
878 k_mutex_unlock(&data->lock);
879
880 return ret;
881 }
The following code excerpts are a structure to organize the BMI323 sensor driver API, following by the driver's callback function. The callback function is, maybe no here but in a general sense called shortly or as soon as possible after a sensor interrupt such as "data ready", "motion detected" occurs. The callback is executed according to the relative priority of the thread in which it runs, among threads in the given application.
There is some indirection to unwrap in order for the program to "reach" the address of the callback. In routine `bosch_bmi323_irq_callback()` the callback handler, a routine, exists in *dev->data->callback_work. There seems to be a pattern where Zephyr driver functions declare a local pointer to the `data` member of the passed device structure.
1100 static DEVICE_API(sensor, bosch_bmi323_api) = {
1101 .attr_set = bosch_bmi323_driver_api_attr_set,
1102 .attr_get = bosch_bmi323_driver_api_attr_get,
1103 .trigger_set = bosch_bmi323_driver_api_trigger_set,
1104 .sample_fetch = bosch_bmi323_driver_api_sample_fetch,
1105 .channel_get = bosch_bmi323_driver_api_channel_get,
1106 };
1107
1108 static void bosch_bmi323_irq_callback(const struct device *dev)
1109 {
1110 struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data;
1111
1112 k_work_submit(&data->callback_work);
1113 }
1115 static int bosch_bmi323_init_irq(const struct device *dev)
1116 {
1117 struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data;
1118 struct bosch_bmi323_config *config = (struct bosch_bmi323_config *)dev->config;
1119 int ret;
1120
1121 ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT);
1122
1123 if (ret < 0) {
1124 return ret;
1125 }
1126
1127 gpio_init_callback(&data->gpio_callback, config->int_gpio_callback,
1128 BIT(config->int_gpio.pin));
1129
1130 ret = gpio_add_callback(config->int_gpio.port, &data->gpio_callback);
1131
1132 if (ret < 0) {
1133 return ret;
1134 }
1135
1136 return gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE);
1137 }
1139 static int bosch_bmi323_init_int1(const struct device *dev)
1140 {
1141 uint16_t buf;
1142
1143 buf = IMU_BOSCH_BMI323_REG_VALUE(IO_INT_CTRL, INT1_LVL, ACT_HIGH) |
1144 IMU_BOSCH_BMI323_REG_VALUE(IO_INT_CTRL, INT1_OD, PUSH_PULL) |
1145 IMU_BOSCH_BMI323_REG_VALUE(IO_INT_CTRL, INT1_OUTPUT_EN, EN);
1146
1147 return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_IO_INT_CTRL, &buf, 1);
1148 }
1150 static void bosch_bmi323_irq_callback_handler(struct k_work *item)
1151 {
1152 struct bosch_bmi323_data *data =
1153 CONTAINER_OF(item, struct bosch_bmi323_data, callback_work);
1154
1155 k_mutex_lock(&data->lock, K_FOREVER);
1156
1157 if (data->trigger_handler != NULL) {
1158 data->trigger_handler(data->dev, data->trigger);
1159 }
1160
1161 k_mutex_unlock(&data->lock);
1162 }
^ References
1. https://github.com/zephyrproject-rtos/zephyr/issues/30133