Difference between revisions of "Iis2dh"

From Wiki at Neela Nurseries
Jump to: navigation, search
m
m (^ STMicro Forum)
 
(54 intermediate revisions by the same user not shown)
Line 1: Line 1:
Notes on . . .
 
  
*  https://community.st.com/s/question/0D50X00009XkdfV/understanding-acceleration-data-from-iis2dh
+
 
 +
__TOC__
 +
 
 +
== [[#top|^]] Overview ==
 +
 
 +
Notes on STMicro IIS22DH high frequency MEMS accelerometer, and drivers for IIS2DH and LIS2DH sensors in Nordic Semi sdk-nrf 1.6.1.  A promising top-level starting point to understand STMicro's significant code contribution to the drivers of these and related sensors is here:
 +
 
 +
*  https://github.com/STMicroelectronics/STMems_Standard_C_drivers
 +
 
 +
Some promising more specific STMicro projects on Github:
 +
*  https://github.com/STMicroelectronics/iis2dh
 +
*  https://github.com/STMicroelectronics/STMems_Standard_C_drivers/tree/master/iis2dh_STdC/examples
 +
*  https://github.com/STMicroelectronics/STMems_Standard_C_drivers/blob/master/iis2dh_STdC/examples/iis2dh_read_data_polling.c
 +
 
 +
A non-Zephyr forum post with configuration steps outlined (not obvious how these would all be achieved in Zephyr context):
 +
 
 +
*  https://community.st.com/s/question/0D50X00009XkdfV/understanding-acceleration-data-from-iis2dh <i>(Excerpt from this post copied to section below . . .)</i>
 +
 
 +
 
 +
Symbols in the polling code example from STMicroelectronic/iis2dh repo are defined in a sub-part of sdk-nrf modules/hal/ project space:
 +
<pre>
 +
guest@ubuntu-vm:~/embedded/z3-on-var/modules/hal/st$ grep -nr IIS2DH_2g ./*
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.h:742:  IIS2DH_2g  = 0,
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:636:    case IIS2DH_2g:
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:637:      *val = IIS2DH_2g;
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:649:      *val = IIS2DH_2g;
 +
 
 +
guest@ubuntu-vm:~/embedded/z3-on-var/modules/hal/st$ grep -nr IIS2DH_ODR_1Hz ./*
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.h:707:  IIS2DH_ODR_1Hz                        = 0x01,
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:402:    case IIS2DH_ODR_1Hz:
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:403:      *val = IIS2DH_ODR_1Hz;
 +
 
 +
guest@ubuntu-vm:~/embedded/z3-on-var/modules/hal/st$ grep -nr IIS2DH_TEMP_ENABLE ./*
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.h:692:  IIS2DH_TEMP_ENABLE  = 3,
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:285:    case IIS2DH_TEMP_ENABLE:
 +
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:286:      *val = IIS2DH_TEMP_ENABLE;
 +
guest@ubuntu-vm:~/embedded/z3-on-var/modules/hal/st$ grep -nr PROPERTY_ENABLE ./*
 +
</pre>
 +
 
 +
And really the above project is pulled in to Nordic's sdk-nrf.  Looks to be at a slightly older, or at least different version, but driver header and sources at https://github.com/STMicroelectronics/iis2dh are the same as in the STMicro hal code in Nordic sdk-nrf v1.6.1.
 +
 
 +
<!-- comment -->
 +
 
 +
== [[#top|^]] IIS2DH Control Registers As C Structures ==
 +
 
 +
An excerpt from Nordic sdk-nrf <code>modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.h</code>:
 +
 
 +
<pre>
 +
#define IIS2DH_CTRL_REG4            0x23U
 +
typedef struct {
 +
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
 +
  uint8_t sim              : 1;
 +
  uint8_t st                : 2;
 +
  uint8_t hr                : 1;
 +
  uint8_t fs                : 2;
 +
  uint8_t ble              : 1;
 +
  uint8_t bdu              : 1;
 +
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
 +
  uint8_t bdu              : 1;
 +
  uint8_t ble              : 1;
 +
  uint8_t fs                : 2;
 +
  uint8_t hr                : 1;
 +
  uint8_t st                : 2;
 +
  uint8_t sim              : 1;
 +
#endif /* DRV_BYTE_ORDER */
 +
} iis2dh_ctrl_reg4_t;
 +
</pre>
 +
 
 +
<!-- comment -->
 +
 
 +
== [[#top|^]] Possible Zephyr Driver Routines for IIS2DH ==
 +
 
 +
Following routines are not obvious nor mentioned anywhere in Zephyr Project documentation found so far, nor are they hinted at by any trace of analogous routines in the build artifacts of [https://github.com/zephyrproject-rtos/zephyr/tree/main/samples/sensor/lis2dh Zephyr lis2dh sample app].  But may we use these following routines in app level code we want to have talking with STMicro's IIS2DH sensor? . . .
 +
 
 +
<pre></pre>
 +
  1 guest@vm:~/projects/zephyr-based/project-stage-1$ grep -nr stmdev_ctx_t ./*
 +
  2 Binary file ./build/zephyr/zephyr.elf matches
 +
  3 Binary file ./build/zephyr/zephyr_prebuilt.elf matches
 +
  4 ./build/zephyr/zephyr.lst:55935:<font color="red">int32_t iis2dh_read_reg(</font>stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
 +
  5 ./build/zephyr/zephyr.lst:55953:<font color="maroon">int32_t iis2dh_write_reg(</font>stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
 +
  6 ./build/zephyr/zephyr.lst:55973:int32_t iis2dh_operating_mode_set(stmdev_ctx_t *ctx, iis2dh_op_md_t val)
 +
  7 ./build/zephyr/zephyr.lst:56065:int32_t iis2dh_data_rate_set(stmdev_ctx_t *ctx, iis2dh_odr_t val)
 +
  8 ./build/zephyr/zephyr.lst:56107:int32_t iis2dh_full_scale_set(stmdev_ctx_t *ctx, iis2dh_fs_t val)
 +
  9 ./build/zephyr/zephyr.lst:56149:int32_t iis2dh_block_data_update_set(stmdev_ctx_t *ctx, uint8_t val)
 +
10 ./build/zephyr/zephyr.lst:56191:int32_t iis2dh_acceleration_raw_get(stmdev_ctx_t *ctx, int16_t *val)
 +
11 ./build/zephyr/zephyr.lst:56231:int32_t iis2dh_device_id_get(stmdev_ctx_t *ctx, uint8_t *buff)
 +
12 Binary file ./build/zephyr/CMakeFiles/zephyr.dir/home/ted/projects/zephyr-based/modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c.obj matches
 +
13 Binary file ./build/zephyr/libzephyr.a matches
 +
14 Binary file ./build/zephyr/drivers/sensor/iis2dh/CMakeFiles/drivers__sensor__iis2dh.dir/iis2dh_trigger.c.obj matches
 +
15 Binary file ./build/zephyr/drivers/sensor/iis2dh/CMakeFiles/drivers__sensor__iis2dh.dir/iis2dh_i2c.c.obj matches
 +
16 Binary file ./build/zephyr/drivers/sensor/iis2dh/CMakeFiles/drivers__sensor__iis2dh.dir/iis2dh.c.obj matches
 +
17 Binary file ./build/zephyr/drivers/sensor/iis2dh/libdrivers__sensor__iis2dh.a matches
 +
18 guest@vm:~/projects/zephyr-based/project-stage-1$
 +
<pre></pre>
 +
 
 +
Looks like there are actually many more IIS2DH API routines available in the modules/hal source file from STMicro:
 +
 
 +
<pre>
 +
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver$ grep -nr stmdev_ctx_t ./*.c
 +
49:int32_t iis2dh_read_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
 +
67:int32_t iis2dh_write_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
 +
182:int32_t iis2dh_temp_status_reg_get(stmdev_ctx_t *ctx, uint8_t *buff)
 +
196:int32_t iis2dh_temp_data_ready_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
215:int32_t iis2dh_temp_data_ovr_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
234:int32_t iis2dh_temperature_raw_get(stmdev_ctx_t *ctx, int16_t *val)
 +
253:int32_t iis2dh_temperature_meas_set(stmdev_ctx_t *ctx, iis2dh_temp_en_t val)
 +
275:int32_t iis2dh_temperature_meas_get(stmdev_ctx_t *ctx, iis2dh_temp_en_t *val)
 +
304:int32_t iis2dh_operating_mode_set(stmdev_ctx_t *ctx, iis2dh_op_md_t val)
 +
343:int32_t iis2dh_operating_mode_get(stmdev_ctx_t *ctx, iis2dh_op_md_t *val)
 +
371:int32_t iis2dh_data_rate_set(stmdev_ctx_t *ctx, iis2dh_odr_t val)
 +
392:int32_t iis2dh_data_rate_get(stmdev_ctx_t *ctx, iis2dh_odr_t *val)
 +
445:int32_t iis2dh_high_pass_on_outputs_set(stmdev_ctx_t *ctx, uint8_t val)
 +
467:int32_t iis2dh_high_pass_on_outputs_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
492:int32_t iis2dh_high_pass_bandwidth_set(stmdev_ctx_t *ctx, iis2dh_hpcf_t val)
 +
519:int32_t iis2dh_high_pass_bandwidth_get(stmdev_ctx_t *ctx, iis2dh_hpcf_t *val)
 +
553:int32_t iis2dh_high_pass_mode_set(stmdev_ctx_t *ctx, iis2dh_hpm_t val)
 +
574:int32_t iis2dh_high_pass_mode_get(stmdev_ctx_t *ctx, iis2dh_hpm_t *val)
 +
608:int32_t iis2dh_full_scale_set(stmdev_ctx_t *ctx, iis2dh_fs_t val)
 +
629:int32_t iis2dh_full_scale_get(stmdev_ctx_t *ctx, iis2dh_fs_t *val)
 +
663:int32_t iis2dh_block_data_update_set(stmdev_ctx_t *ctx, uint8_t val)
 +
684:int32_t iis2dh_block_data_update_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
704:int32_t iis2dh_filter_reference_set(stmdev_ctx_t *ctx, uint8_t *buff)
 +
720:int32_t iis2dh_filter_reference_get(stmdev_ctx_t *ctx, uint8_t *buff)
 +
734:int32_t iis2dh_xl_data_ready_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
752:int32_t iis2dh_xl_data_ovr_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
770:int32_t iis2dh_acceleration_raw_get(stmdev_ctx_t *ctx, int16_t *val)
 +
804:int32_t iis2dh_device_id_get(stmdev_ctx_t *ctx, uint8_t *buff)
 +
818:int32_t iis2dh_self_test_set(stmdev_ctx_t *ctx, iis2dh_st_t val)
 +
839:int32_t iis2dh_self_test_get(stmdev_ctx_t *ctx, iis2dh_st_t *val)
 +
870:int32_t iis2dh_data_format_set(stmdev_ctx_t *ctx, iis2dh_ble_t val)
 +
891:int32_t iis2dh_data_format_get(stmdev_ctx_t *ctx, iis2dh_ble_t *val)
 +
919:int32_t iis2dh_boot_set(stmdev_ctx_t *ctx, uint8_t val)
 +
940:int32_t iis2dh_boot_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
959:int32_t iis2dh_int_occurrencies_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
974:int32_t iis2dh_status_get(stmdev_ctx_t *ctx, iis2dh_status_reg_t *val)
 +
1001:int32_t iis2dh_int1_gen_conf_set(stmdev_ctx_t *ctx, iis2dh_int1_cfg_t *val)
 +
1016:int32_t iis2dh_int1_gen_conf_get(stmdev_ctx_t *ctx, iis2dh_int1_cfg_t *val)
 +
1031:int32_t iis2dh_int1_gen_source_get(stmdev_ctx_t *ctx, iis2dh_int1_src_t *val)
 +
1047:int32_t iis2dh_int1_gen_threshold_set(stmdev_ctx_t *ctx, uint8_t val)
 +
1070:int32_t iis2dh_int1_gen_threshold_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1090:int32_t iis2dh_int1_gen_duration_set(stmdev_ctx_t *ctx, uint8_t val)
 +
1114:int32_t iis2dh_int1_gen_duration_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1147:int32_t iis2dh_int2_gen_conf_set(stmdev_ctx_t *ctx, iis2dh_int2_cfg_t *val)
 +
1162:int32_t iis2dh_int2_gen_conf_get(stmdev_ctx_t *ctx, iis2dh_int2_cfg_t *val)
 +
1176:int32_t iis2dh_int2_gen_source_get(stmdev_ctx_t *ctx, iis2dh_int2_src_t *val)
 +
1192:int32_t iis2dh_int2_gen_threshold_set(stmdev_ctx_t *ctx, uint8_t val)
 +
1215:int32_t iis2dh_int2_gen_threshold_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1235:int32_t iis2dh_int2_gen_duration_set(stmdev_ctx_t *ctx, uint8_t val)
 +
1259:int32_t iis2dh_int2_gen_duration_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1291:int32_t iis2dh_high_pass_int_conf_set(stmdev_ctx_t *ctx, iis2dh_hp_t val)
 +
1312:int32_t iis2dh_high_pass_int_conf_get(stmdev_ctx_t *ctx, iis2dh_hp_t *val)
 +
1358:int32_t iis2dh_pin_int1_config_set(stmdev_ctx_t *ctx, iis2dh_ctrl_reg3_t *val)
 +
1373:int32_t iis2dh_pin_int1_config_get(stmdev_ctx_t *ctx, iis2dh_ctrl_reg3_t *val)
 +
1389:int32_t iis2dh_int2_pin_detect_4d_set(stmdev_ctx_t *ctx, uint8_t val)
 +
1411:int32_t iis2dh_int2_pin_detect_4d_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1432:int32_t iis2dh_int2_pin_notification_mode_set(stmdev_ctx_t *ctx,
 +
1456:int32_t iis2dh_int2_pin_notification_mode_get(stmdev_ctx_t *ctx,
 +
1486:int32_t iis2dh_int1_pin_detect_4d_set(stmdev_ctx_t *ctx, uint8_t val)
 +
1508:int32_t iis2dh_int1_pin_detect_4d_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1528:int32_t iis2dh_int1_pin_notification_mode_set(stmdev_ctx_t *ctx,
 +
1551:int32_t iis2dh_int1_pin_notification_mode_get(stmdev_ctx_t *ctx,
 +
1580:int32_t iis2dh_pin_int2_config_set(stmdev_ctx_t *ctx, iis2dh_ctrl_reg6_t *val)
 +
1595:int32_t iis2dh_pin_int2_config_get(stmdev_ctx_t *ctx, iis2dh_ctrl_reg6_t *val)
 +
1622:int32_t iis2dh_fifo_set(stmdev_ctx_t *ctx, uint8_t val)
 +
1643:int32_t iis2dh_fifo_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1662:int32_t iis2dh_fifo_watermark_set(stmdev_ctx_t *ctx, uint8_t val)
 +
1685:int32_t iis2dh_fifo_watermark_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1705:int32_t iis2dh_fifo_trigger_event_set(stmdev_ctx_t *ctx, iis2dh_tr_t val)
 +
1728:int32_t iis2dh_fifo_trigger_event_get(stmdev_ctx_t *ctx, iis2dh_tr_t *val)
 +
1757:int32_t iis2dh_fifo_mode_set(stmdev_ctx_t *ctx, iis2dh_fm_t val)
 +
1780:int32_t iis2dh_fifo_mode_get(stmdev_ctx_t *ctx, iis2dh_fm_t *val)
 +
1815:int32_t iis2dh_fifo_status_get(stmdev_ctx_t *ctx, iis2dh_fifo_src_reg_t *val)
 +
1829:int32_t iis2dh_fifo_data_level_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1847:int32_t iis2dh_fifo_empty_flag_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1865:int32_t iis2dh_fifo_ovr_flag_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1883:int32_t iis2dh_fifo_fth_flag_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
1914:int32_t iis2dh_tap_conf_set(stmdev_ctx_t *ctx, iis2dh_click_cfg_t *val)
 +
1929:int32_t iis2dh_tap_conf_get(stmdev_ctx_t *ctx, iis2dh_click_cfg_t *val)
 +
1943:int32_t iis2dh_tap_source_get(stmdev_ctx_t *ctx, iis2dh_click_src_t *val)
 +
1958:int32_t iis2dh_tap_threshold_set(stmdev_ctx_t *ctx, uint8_t val)
 +
1980:int32_t iis2dh_tap_threshold_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
2001:int32_t iis2dh_shock_dur_set(stmdev_ctx_t *ctx, uint8_t val)
 +
2024:int32_t iis2dh_shock_dur_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
2046:int32_t iis2dh_quiet_dur_set(stmdev_ctx_t *ctx, uint8_t val)
 +
2071:int32_t iis2dh_quiet_dur_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
2093:int32_t iis2dh_double_tap_timeout_set(stmdev_ctx_t *ctx, uint8_t val)
 +
2117:int32_t iis2dh_double_tap_timeout_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
2151:int32_t iis2dh_act_threshold_set(stmdev_ctx_t *ctx, uint8_t val)
 +
2174:int32_t iis2dh_act_threshold_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
2194:int32_t iis2dh_act_timeout_set(stmdev_ctx_t *ctx, uint8_t val)
 +
2216:int32_t iis2dh_act_timeout_get(stmdev_ctx_t *ctx, uint8_t *val)
 +
2248:int32_t iis2dh_spi_mode_set(stmdev_ctx_t *ctx, iis2dh_sim_t val)
 +
2269:int32_t iis2dh_spi_mode_get(stmdev_ctx_t *ctx, iis2dh_sim_t *val)
 +
 
 +
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver$
 +
</pre>
 +
<!-- comment -->
 +
 
 +
== [[#top|^]] Zephyr RTOS Tie-In To STMicro IIS2DH Driver API ==
 +
 
 +
File `$ENV{ZEPHYR_BASE}/drivers/sensor/iis2dh/iis2dh.c` end with:ii2
 +
 
 +
<pre>
 +
312 struct iis2dh_data iis2dh_data;
 +
313
 +
314 DEVICE_DT_INST_DEFINE(0, iis2dh_init, NULL,
 +
315              &iis2dh_data, &iis2dh_cfg, POST_KERNEL,
 +
316              CONFIG_SENSOR_INIT_PRIORITY, &iis2dh_driver_api);
 +
</pre>
 +
 
 +
...Somewhere data member `&iis2dh_data` gets assigned a value.  This data member in turn is referenced when the above driver API routines are called.  For example in routine `iis2dh_sample_fetch()` there is reference to an stmdev_ctx_t structure that's assigned to the device handle's "data" member:
 +
 
 +
203 static int iis2dh_sample_fetch(const struct device *dev,
 +
204                                enum sensor_channel chan)
 +
205 {
 +
206        struct iis2dh_data <font color="green">*iis2dh = dev->data</font>;
 +
207        int16_t buf[3];
 +
208
 +
209        /* fetch raw data sample */
 +
210        if (iis2dh_acceleration_raw_get(<font color="green">iis2dh->ctx</font>, buf) < 0) {
 +
211                LOG_DBG("Failed to fetch raw data sample");
 +
212                return -EIO;
 +
213        }
 +
214
 +
215        iis2dh->acc[0] = sys_le16_to_cpu(buf[0]);
 +
216        iis2dh->acc[1] = sys_le16_to_cpu(buf[1]);
 +
217        iis2dh->acc[2] = sys_le16_to_cpu(buf[2]);
 +
218
 +
219        return 0;
 +
220 }
 +
 
 +
The structure `iis2dh_data` is defined in corresponding header file `iis2dh.h` as:
 +
 
 +
<pre>
 +
59 /* sensor data */
 +
60 struct iis2dh_data {
 +
61        const struct device *bus;
 +
62        int16_t acc[3];
 +
63        uint32_t gain;
 +
64
 +
65        stmdev_ctx_t *ctx;
 +
66 #ifdef CONFIG_IIS2DH_TRIGGER
 +
67        const struct device *dev;
 +
68        const struct device *gpio;
 +
69        uint8_t gpio_pin;
 +
70        struct gpio_callback gpio_cb;
 +
71        sensor_trigger_handler_t drdy_handler;
 +
72 #if defined(CONFIG_IIS2DH_TRIGGER_OWN_THREAD)
 +
73        K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_IIS2DH_THREAD_STACK_SIZE);
 +
74        struct k_thread thread;
 +
75        struct k_sem gpio_sem;
 +
76 #elif defined(CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD)
 +
77        struct k_work work;
 +
78 #endif /* CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD */
 +
79 #endif /* CONFIG_IIS2DH_TRIGGER */
 +
80 #if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
 +
81        struct spi_cs_control cs_ctrl;
 +
82 #endif
 +
83 };
 +
</pre>
 +
 
 +
Structure <code>stmdev_ctx_t</code> is defined:
 +
 
 +
<pre>
 +
110 typedef int32_t (*stmdev_write_ptr)(void *, uint8_t, uint8_t*, uint16_t);
 +
111 typedef int32_t (*stmdev_read_ptr) (void *, uint8_t, uint8_t*, uint16_t);
 +
112
 +
113 typedef struct {
 +
114  /** Component mandatory fields **/
 +
115  stmdev_write_ptr  write_reg;
 +
116  stmdev_read_ptr  read_reg;
 +
117  /** Customizable optional pointer **/
 +
118  void *handle;
 +
119 } stmdev_ctx_t;
 +
</pre>
 +
 
 +
<!-- comment -->
 +
 
 +
== [[#top|^]] Assignment To ctx Structure ==
 +
 
 +
So question, where is *ctx assigned a value?  Ah, *ctx is assigned a value in the zephyr/drivers/sensor/iis2dh/iis2dh_i2c.c file.  This value is a data structure which entails two C function pointers.  Code excerpt here:
 +
 
 +
<pre>
 +
19 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
 +
20
 +
21 static uint16_t iis2dh_i2c_slave_addr = DT_INST_REG_ADDR(0);
 +
22
 +
23 LOG_MODULE_DECLARE(IIS2DH, CONFIG_SENSOR_LOG_LEVEL);
 +
24
 +
25 static int iis2dh_i2c_read(struct iis2dh_data *data, uint8_t reg_addr,
 +
26                            uint8_t *value, uint16_t len)
 +
27 {
 +
28        return i2c_burst_read(data->bus, iis2dh_i2c_slave_addr,
 +
29                              reg_addr | 0x80, value, len);
 +
30 }
 +
31
 +
32 static int iis2dh_i2c_write(struct iis2dh_data *data, uint8_t reg_addr,
 +
33                            uint8_t *value, uint16_t len)
 +
34 {
 +
35        return i2c_burst_write(data->bus, iis2dh_i2c_slave_addr,
 +
36                                reg_addr | 0x80, value, len);
 +
37 }
 +
38
 +
39 stmdev_ctx_t iis2dh_i2c_ctx = {
 +
40        .read_reg = (stmdev_read_ptr) iis2dh_i2c_read,
 +
41        .write_reg = (stmdev_write_ptr) iis2dh_i2c_write,
 +
42 };
 +
43
 +
44 int iis2dh_i2c_init(const struct device *dev)
 +
45 {
 +
46        struct iis2dh_data *data = dev->data;
 +
47
 +
48        data->ctx = &iis2dh_i2c_ctx;
 +
49        data->ctx->handle = data;
 +
50
 +
51        return 0;
 +
52 }
 +
53 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
 +
</pre>
 +
 
 +
=== [[#top|^]] edit point ===
 +
 
 +
{| style="cellpadding=30px;"
 +
|-
 +
| style="vertical-align:top; padding:10px; width:50%;" |
 +
Routine `int i2c_burst_read()` is a Zephyr in-tree driver routine.  In possibly erroneous C syntax the assignment from the Zephyr device structure handle on down is:
 +
 
 +
  dev->data->ctx->.read_reg = (stmdev_read_ptr) iis2dh_i2c_read
 +
              ^^^
 +
              :
 +
  Valid when *data is typecast as `struct iis2dh_data`.
 +
 
 +
Routine `iis2dh_i2c_read` calls `i2c_burst_read()`, which in turn calls `i2c_write_read()`, which in turn calls 'i2c_transfer()', which would seem to be the final routine call in this call stack but in fact is a pointer to a project's given processor specific I2C peripheral:
 +
 
 +
<pre>
 +
346 __syscall int i2c_transfer(const struct device *dev,
 +
347                            struct i2c_msg *msgs, uint8_t num_msgs,
 +
348                            uint16_t addr);
 +
349
 +
350 static inline int z_impl_i2c_transfer(const struct device *dev,
 +
351                                      struct i2c_msg *msgs, uint8_t num_msgs,
 +
352                                      uint16_t addr)
 +
353 {
 +
354        const struct i2c_driver_api *api =
 +
355                (const struct i2c_driver_api *)dev->api;
 +
356
 +
357        return api->transfer(dev, msgs, num_msgs, addr);
 +
358 }
 +
</pre>
 +
 
 +
 
 +
| style="valign:top; padding:10px;" |
 +
<i>Excerpt from zephyr/include/drivers/i2c.h:</i>
 +
<pre>
 +
607 static inline int i2c_burst_read(const struct device *dev,
 +
608                                  uint16_t dev_addr,
 +
609                                  uint8_t start_addr,
 +
610                                  uint8_t *buf,
 +
611                                  uint32_t num_bytes)
 +
612 {
 +
613        return i2c_write_read(dev, dev_addr,
 +
614                              &start_addr, sizeof(start_addr),
 +
615                              buf, num_bytes);
 +
616 }
 +
</pre>
 +
 
 +
<pre>
 +
572 static inline int i2c_write_read(const struct device *dev, uint16_t addr,
 +
573                                  const void *write_buf, size_t num_write,
 +
574                                  void *read_buf, size_t num_read)
 +
575 {
 +
576        struct i2c_msg msg[2];
 +
577
 +
578        msg[0].buf = (uint8_t *)write_buf;
 +
579        msg[0].len = num_write;
 +
580        msg[0].flags = I2C_MSG_WRITE;
 +
581
 +
582        msg[1].buf = (uint8_t *)read_buf;
 +
583        msg[1].len = num_read;
 +
584        msg[1].flags = I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP;
 +
585
 +
586        return i2c_transfer(dev, msg, 2, addr);
 +
587 }
 +
</pre>
 +
 
 +
<pre>
 +
346 __syscall int i2c_transfer(const struct device *dev,
 +
347                            struct i2c_msg *msgs, uint8_t num_msgs,
 +
348                            uint16_t addr);
 +
349
 +
350 static inline int z_impl_i2c_transfer(const struct device *dev,
 +
351                                      struct i2c_msg *msgs, uint8_t num_msgs,
 +
352                                      uint16_t addr)
 +
353 {
 +
354        const struct i2c_driver_api *api =
 +
355                (const struct i2c_driver_api *)dev->api;
 +
356
 +
357        return api->transfer(dev, msgs, num_msgs, addr);
 +
358 }
 +
</pre>
 +
|}
 +
 
 +
<!-- comment -->
 +
 
 +
== [[#top|^]]  Why Does iis2dh_device_id_get Return 3 When No Device Connected? ==
 +
 
 +
Following routine in STMicro's driver API code base returns ASCII "3", decimal 51 even when no device connected.  This is the ID value spec'd in the IIS2DH datasheet.  How is this value getting returned?  The routine in question is here:
 +
 
 +
<pre>
 +
796 /**
 +
797  * @brief  DeviceWhoamI .[get]
 +
798  *
 +
799  * @param  ctx      read / write interface definitions
 +
800  * @param  buff    buffer that stores data read
 +
801  * @retval          interface status (MANDATORY: return 0 -> no Error)
 +
802  *
 +
803  */
 +
804 int32_t iis2dh_device_id_get(stmdev_ctx_t *ctx, uint8_t *buff)
 +
805 {
 +
806  int32_t ret;
 +
807  ret = iis2dh_read_reg(ctx, IIS2DH_WHO_AM_I, buff, 1);
 +
808  return ret;
 +
809 }
 +
</pre>
 +
 
 +
From comment block it looks like the value 3 in our situation is an error value coming from routine `iis2dh_read_reg()`.  This routine is defined:
 +
 
 +
<pre>
 +
  39 /**
 +
  40  * @brief  Read generic device register
 +
  41  *
 +
  42  * @param  ctx  read / write interface definitions(ptr)
 +
  43  * @param  reg  register to read
 +
  44  * @param  data  pointer to buffer that store the data read(ptr)
 +
  45  * @param  len  number of consecutive register to read
 +
  46  * @retval          interface status (MANDATORY: return 0 -> no Error)
 +
  47  *
 +
  48  */
 +
  49 int32_t iis2dh_read_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
 +
  50                        uint16_t len)
 +
  51 {
 +
  52  int32_t ret;
 +
  53  ret = ctx->read_reg(ctx->handle, reg, data, len);
 +
  54  return ret;
 +
  55 }
 +
</pre>
 +
 
 +
Ok this begs the question then where and how are the ctx function pointers assigned to point to functions?  We were working to answer this question yesterday, and it is something of a repeat of a key question we faced when building the out-of-tree driver for Kionix sensor . . .
 +
 
 +
<!-- comment -->
 +
 
 +
== [[#top|^]] Configuration Post from ST Micro Forum ==
  
 
<i>Excerpt on accelerator configurations from this developer:</i>
 
<i>Excerpt on accelerator configurations from this developer:</i>
Line 7: Line 457:
 
Edited by ST Community July 21, 2018 at 5:26 PM
 
Edited by ST Community July 21, 2018 at 5:26 PM
 
Posted on January 02, 2017 at 16:21
 
Posted on January 02, 2017 at 16:21
 
 
  
 
   
 
   
Line 583: Line 1,031:
 
  -->
 
  -->
  
 +
<!-- comment -->
 +
 +
== * ==
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] LIS2DH Data Structure ==
 +
 +
LIS2DH data structure, comparable to IIS2DH data structure but no `ctx` element:
 +
 +
{|
 +
|-
 +
| style="vertical-align:top; padding:10px; width:50%;" |
 +
 +
LIS2DH data structure definition:
 +
<pre>
 +
220 struct lis2dh_data {
 +
221        const struct device *bus;
 +
222        const struct lis2dh_transfer_function *hw_tf;
 +
223
 +
224        union lis2dh_sample sample;
 +
225        /* current scaling factor, in micro m/s^2 / lsb */
 +
226        uint32_t scale;
 +
227
 +
228 #ifdef CONFIG_LIS2DH_TRIGGER
 +
229        const struct device *dev;
 +
230        const struct device *gpio_int1;
 +
231        const struct device *gpio_int2;
 +
232        struct gpio_callback gpio_int1_cb;
 +
233        struct gpio_callback gpio_int2_cb;
 +
234
 +
235        sensor_trigger_handler_t handler_drdy;
 +
236        sensor_trigger_handler_t handler_anymotion;
 +
237        atomic_t trig_flags;
 +
238        enum sensor_channel chan_drdy;
 +
239
 +
240 #if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD)
 +
241        K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DH_THREAD_STACK_SIZE);
 +
242        struct k_thread thread;
 +
243        struct k_sem gpio_sem;
 +
244 #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD)
 +
245        struct k_work work;
 +
246 #endif
 +
247
 +
248 #endif /* CONFIG_LIS2DH_TRIGGER */
 +
249
 +
250 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
 +
251        struct spi_cs_control cs_ctrl;
 +
252 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
 +
253 };
 +
</pre>
 +
 +
| style="vertical-align:top; padding:10px; width:50%;" |
 +
LIS2DH 'transfer function' structure definition:
 +
<pre>
 +
207 struct lis2dh_transfer_function {
 +
208        int (*read_data)(const struct device *dev, uint8_t reg_addr,
 +
209                          uint8_t *value, uint8_t len);
 +
210        int (*write_data)(const struct device *dev, uint8_t reg_addr,
 +
211                          uint8_t *value, uint8_t len);
 +
212        int (*read_reg)(const struct device *dev, uint8_t reg_addr,
 +
213                        uint8_t *value);
 +
214        int (*write_reg)(const struct device *dev, uint8_t reg_addr,
 +
215                          uint8_t value);
 +
216        int (*update_reg)(const struct device *dev, uint8_t reg_addr,
 +
217                          uint8_t mask, uint8_t value);
 +
218 };
 +
</pre>
 +
 +
LIS2DH 'transfer function' structure assignment, in file ./drivers/sensor/lis2ds12/lis2ds12_i2c.c:72:
 +
<pre>
 +
68 int lis2ds12_i2c_init(const struct device *dev)
 +
69 {
 +
70        struct lis2ds12_data *data = dev->data;
 +
71
 +
72        data->hw_tf = &lis2ds12_i2c_transfer_fn;
 +
73
 +
74        return 0;
 +
75 }
 +
76 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
 +
</pre>
 +
 +
This transfer function is a structure of five function pointers:
 +
<pre>
 +
60 static const struct lis2ds12_transfer_function lis2ds12_i2c_transfer_fn = {
 +
61        .read_data = lis2ds12_i2c_read_data,
 +
62        .write_data = lis2ds12_i2c_write_data,
 +
63        .read_reg  = lis2ds12_i2c_read_reg,
 +
64        .write_reg  = lis2ds12_i2c_write_reg,
 +
65        .update_reg = lis2ds12_i2c_update_reg,
 +
66 };
 +
67
 +
</pre>
 +
 +
These functions are defines nearby just above, first two for examples are:
 +
<pre>
 +
17 #include "lis2ds12.h"
 +
18
 +
19 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
 +
20
 +
21 static uint16_t lis2ds12_i2c_slave_addr = DT_INST_REG_ADDR(0);
 +
22
 +
23 LOG_MODULE_DECLARE(LIS2DS12, CONFIG_SENSOR_LOG_LEVEL);
 +
24
 +
25 static int lis2ds12_i2c_read_data(struct lis2ds12_data *data, uint8_t reg_addr,
 +
26                                  uint8_t *value, uint8_t len)
 +
27 {
 +
28        return i2c_burst_read(data->comm_master, lis2ds12_i2c_slave_addr,
 +
29                              reg_addr, value, len);
 +
30 }
 +
31
 +
32 static int lis2ds12_i2c_write_data(struct lis2ds12_data *data, uint8_t reg_addr,
 +
33                                  uint8_t *value, uint8_t len)
 +
34 {
 +
35        return i2c_burst_write(data->comm_master, lis2ds12_i2c_slave_addr,
 +
36                                reg_addr, value, len);
 +
37 }
 +
</pre>
 +
|}
 +
 +
 +
 +
 +
 +
== [[#top|^]] LIS2DH Sample Fetch Routine ==
 +
 +
What is going on in this LIS2DH API routine by STMicro, especially at line 107?
 +
 +
<pre>
 +
81 static int lis2dh_sample_fetch(const struct device *dev,
 +
82                                enum sensor_channel chan)
 +
83 {
 +
84        struct lis2dh_data *lis2dh = dev->data;
 +
85        size_t i;
 +
86        int status;
 +
87
 +
88        __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL ||
 +
89                        chan == SENSOR_CHAN_ACCEL_XYZ);
 +
90
 +
91        /*
 +
92          * since status and all accel data register addresses are consecutive,
 +
93          * a burst read can be used to read all the samples
 +
94          */
 +
95        status = lis2dh->hw_tf->read_data(dev, LIS2DH_REG_STATUS,
 +
96                                          lis2dh->sample.raw,
 +
97                                          sizeof(lis2dh->sample.raw));
 +
98        if (status < 0) {
 +
99                LOG_WRN("Could not read accel axis data");
 +
100                return status;
 +
101        }
 +
102
 +
103        for (i = 116 static inline void iis2dh_channel_get_acc(const struct device *dev,
 +
117                                          enum sensor_channel chan,
 +
118                                          struct sensor_value *val)
 +
119 {
 +
120        int i;
 +
121        uint8_t ofs_start, ofs_stop;
 +
122        struct iis2dh_data *iis2dh = dev->data;
 +
123        struct sensor_value *pval = val;
 +
124
 +
125        switch (chan) {
 +
126        case SENSOR_CHAN_ACCEL_X:
 +
127                ofs_start = ofs_stop = 0U;
 +
128                break;
 +
129        case SENSOR_CHAN_ACCEL_Y:
 +
130                ofs_start = ofs_stop = 1U;
 +
131                break;
 +
132        case SENSOR_CHAN_ACCEL_Z:
 +
133                ofs_start = ofs_stop = 2U;
 +
134                break;
 +
135        default:
 +
136                ofs_start = 0U; ofs_stop = 2U;
 +
137                break;
 +
138        }
 +
139
 +
140        for (i = ofs_start; i <= ofs_stop ; i++) {
 +
141                iis2dh_convert(pval++, iis2dh->acc[i], iis2dh->gain);
 +
142        }
 +
143 }
 +
144
 +
145 static int iis2dh_channel_get(const struct device *dev,
 +
146                              enum sensor_channel chan,
 +
147                              struct sensor_value *val)
 +
148 {
 +
149        switch (chan) {
 +
150        case SENSOR_CHAN_ACCEL_X:
 +
151        case SENSOR_CHAN_ACCEL_Y:
 +
152        case SENSOR_CHAN_ACCEL_Z:
 +
153        case SENSOR_CHAN_ACCEL_XYZ:
 +
154                iis2dh_channel_get_acc(dev, chan, val);
 +
155                return 0;
 +
156        default:
 +
157                LOG_DBG("Channel not supported");
 +
158                break;
 +
159        }
 +
160
 +
161        return -ENOTSUP;
 +
162 }
 +
0; i < (3 * sizeof(int16_t)); i += sizeof(int16_t)) {
 +
104                int16_t *sample =
 +
105                        (int16_t *)&lis2dh->sample.raw[1 + i];
 +
106
 +
107                *sample = sys_le16_to_cpu(*sample);
 +
108        }
 +
109
 +
110        if (lis2dh->sample.status & LIS2DH_STATUS_DRDY_MASK) {
 +
111                return 0;
 +
112        }
 +
113
 +
114        return -ENODATA;
 +
115 }
 +
</pre>
 +
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] LIS2DH Sample Get Routine Supports Writing Multiple sensor_type Data ==
 +
 +
From [ww]/zephyr/drivers/sensor/iis2dh/iis2dh.c, note the use of `pval` and C's unary increment operator to handle returning X, Y and Z triplet readings to calling code:
 +
 +
<pre>
 +
116 static inline void iis2dh_channel_get_acc(const struct device *dev,
 +
117                                          enum sensor_channel chan,
 +
118                                          struct sensor_value *val)
 +
119 {
 +
120        int i;
 +
121        uint8_t ofs_start, ofs_stop;
 +
122        struct iis2dh_data *iis2dh = dev->data;
 +
123        struct sensor_value *pval = val;
 +
124
 +
125        switch (chan) {
 +
126        case SENSOR_CHAN_ACCEL_X:
 +
127                ofs_start = ofs_stop = 0U;
 +
128      <!-- comment -->          break;
 +
129        case SENSOR_CHAN_ACCEL_Y:
 +
130                ofs_start = ofs_stop = 1U;
 +
131                break;
 +
132        case SENSOR_CHAN_ACCEL_Z:
 +
133                ofs_start = ofs_stop = 2U;
 +
134                break;
 +
135        default:
 +
136                ofs_start = 0U; ofs_stop = 2U;
 +
137                break;
 +
138        }
 +
139
 +
140        for (i = ofs_start; i <= ofs_stop ; i++) {
 +
141                iis2dh_convert(pval++, iis2dh->acc[i], iis2dh->gain);
 +
142        }
 +
143 }
 +
144
 +
145 static int iis2dh_channel_get(const struct device *dev,
 +
146                              enum sensor_channel chan,
 +
147                              struct sensor_value *val)
 +
148 {
 +
149        switch (chan) {
 +
150        case SENSOR_CHAN_ACCEL_X:
 +
151        case SENSOR_CHAN_ACCEL_Y:
 +
152        case SENSOR_CHAN_ACCEL_Z:
 +
153        case SENSOR_CHAN_ACCEL_XYZ:
 +
154                iis2dh_channel_get_acc(dev, chan, val);
 +
155                return 0;
 +
156        default:
 +
157                LOG_DBG("Channel not supported");
 +
158                break;
 +
159        }
 +
160
 +
161        return -ENOTSUP;
 +
162 }
 +
</pre>
 +
 +
<!-- comment -->
 +
 +
 +
== [[#top|^]] ENOTSUP Definition - return value of -134 ==
 +
 +
<pre>
 +
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$ grep -nr ENOTSUP ./* | grep define | grep ENOTSUP
 +
./drivers/flash/jesd216.h:326: * @retval -ENOTSUP if the erase type index is undefined.
 +
./include/usb/bos.h:67:#define usb_handle_bos(x, y, z) -ENOTSUP
 +
./lib/libc/minimal/include/errno.h:115:#define ENOTSUP 134        /**< Unsupported value */
 +
./subsys/net/ip/net_shell.c:3973:#define ping_ipv6(...) -ENOTSUP
 +
./subsys/net/ip/net_shell.c:4082:#define ping_ipv4(...) -ENOTSUP
 +
./subsys/usb/os_desc.h:34:#define usb_handle_os_desc(x, y, z) -ENOTSUP
 +
./subsys/usb/os_desc.h:35:#define usb_handle_os_desc_feature(x, y, z) -ENOTSUP
 +
./tests/kernel/fpu_sharing/float_disable/src/k_float_disable.c:39:#define K_FLOAT_DISABLE_SYSCALL_RETVAL -ENOTSUP
 +
 +
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$
 +
</pre>
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] iis2dh_attr_set() calls iis2dh_config() ==
 +
 +
<pre>
 +
164 static int iis2dh_config(const struct device *dev, enum sensor_channel chan,
 +
165                          enum sensor_attribute attr,
 +
166                          const struct sensor_value *val)
 +
167 {
 +
168        switch (attr) {
 +
169 #if (CONFIG_IIS2DH_RANGE == 0)
 +
170        case SENSOR_ATTR_FULL_SCALE:
 +
171                return iis2dh_set_range(dev, sensor_ms2_to_g(val));
 +
172 #endif
 +
173 #if (CONFIG_IIS2DH_ODR == 0)
 +
174        case SENSOR_ATTR_SAMPLING_FREQUENCY:
 +
175                return iis2dh_set_odr(dev, val->val1);
 +
176 #endif
 +
177        default:
 +
178                LOG_DBG("Acc attribute not supported");
 +
179                break;
 +
180        }
 +
181
 +
182        return -ENOTSUP;
 +
183 }
 +
184
 +
185 static int iis2dh_attr_set(const struct device *dev, enum sensor_channel chan,
 +
186                            enum sensor_attribute attr,
 +
187                            const struct sensor_value *val)
 +
188 {
 +
189        switch (chan) {
 +
190        case SENSOR_CHAN_ACCEL_X:
 +
191        case SENSOR_CHAN_ACCEL_Y:
 +
192        case SENSOR_CHAN_ACCEL_Z:
 +
193        case SENSOR_CHAN_ACCEL_XYZ:
 +
194                return iis2dh_config(dev, chan, attr, val);
 +
195        default:
 +
196                LOG_DBG("Attr not supported on %d channel", chan);
 +
197                break;
 +
198        }
 +
199
 +
200        return -ENOTSUP;
 +
201 }
 +
</pre>
 +
 +
In turn this routine gets called when setting ODR at run time:
 +
 +
<pre>
 +
86 #if (CONFIG_IIS2DH_ODR == 0)
 +
87 /**
 +
88  * iis2dh_set_odr - set new sampling frequency
 +
89  * @dev: Pointer to instance of struct device (I2C or SPI)
 +
90  * @odr: Output data rate
 +
91  */
 +
92 static int iis2dh_set_odr(const struct device *dev, uint16_t odr)
 +
93 {
 +
94        struct iis2dh_data *iis2dh = dev->data;
 +
95        const struct iis2dh_device_config *cfg = dev->config;
 +
96        iis2dh_odr_t val;
 +
97
 +
98        val = IIS2DH_ODR_TO_REG_HR(cfg->pm, odr);
 +
99
 +
100        return iis2dh_data_rate_set(iis2dh->ctx, val);
 +
101 }
 +
102 #endif
 +
</pre>
 +
 +
And in turn this routine:
 +
 +
<pre>
 +
363 /**
 +
364  * @brief  Output data rate selection.[set]
 +
365  *
 +
366  * @param  ctx      read / write interface definitions
 +
367  * @param  val      change the values of odr in reg CTRL_REG1
 +
368  * @retval          interface status (MANDATORY: return 0 -> no Error)
 +
369  *
 +
370  */
 +
371 int32_t iis2dh_data_rate_set(stmdev_ctx_t *ctx, iis2dh_odr_t val)
 +
372 {
 +
373  iis2dh_ctrl_reg1_t ctrl_reg1;
 +
374  int32_t ret;
 +
375
 +
376  ret = iis2dh_read_reg(ctx, IIS2DH_CTRL_REG1, (uint8_t*)&ctrl_reg1, 1);
 +
377  if (ret == 0) {
 +
378    ctrl_reg1.odr = (uint8_t)val;
 +
379    ret = iis2dh_write_reg(ctx, IIS2DH_CTRL_REG1, (uint8_t*)&ctrl_reg1, 1);
 +
380  }
 +
381  return ret;
 +
382 }
 +
</pre>
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] edit point ==
 +
 +
Text searched in STMicro's IIS2DH mid-level driver directory, containing iis2dh.[ch]:
 +
 +
<pre>
 +
2032  grep -n _set *.c
 +
2033  grep -n _get *.c
 +
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver$
 +
</pre>
 +
 +
<!-- comment -->
 +
 +
== * ==
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] LIS2DH Driver Output at Boot Time ==
 +
 +
Some output from Kionix driver demo, interesting early message, earlier even than Zephyr RTOS banner message:
 +
 +
<pre>
 +
[00:00:00.408,569] <inf> lis2dh: bus=I2C_1 fs=2, odr=0x4 lp_en=0x0 scale=9576
 +
*** Booting Zephyr OS build v2.6.0-rc1-ncs1  ***
 +
+++ Kionix Driver Demo version 0p2 +++
 +
- SUCCESS - found Kionix accelerometer and device is ready
 +
- DEV - starting comparative LIS2DH test thread . . .zzz -  - zzz
 +
Success finding lis2dh device,
 +
Call to device_is_ready() says LIS2DH sensor is ready,
 +
Device name found to be 'LIS2DH'
 +
lis2dh task at loop iteration 0x00000000
 +
Failed to set odr: -134
 +
Sampling at 1 Hz (asuuming so as sensor_attr_set returns 0 status - success
 +
sampling at 1 Hz, per call to sensor_attr_get(),
 +
#0 @ 1519 ms: x -0.306432 , y -0.383040 , z -9.614304
 +
fetched and got acceleration readings 0, 4294660864
 +
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
lis2dh task at loop iteration 0x00000001
 +
Failed to set odr: -134
 +
Sampling at 1 Hz (asuuming so as sensor_attr_set returns 0 status - success
 +
sampling at 1 Hz, per call to sensor_attr_get(),
 +
#1 @ 4525 ms: x -0.421344 , y -0.229824 , z -9.614304
 +
fetched and got acceleration readings 0, 4294545952
 +
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
lis2dh task at loop iteration 0x00000002
 +
Failed to set odr: -134
 +
Sampling at 1 Hz (asuuming so as sensor_attr_set returns 0 status - success
 +
sampling at 1 Hz, per call to sensor_attr_get(),
 +
#2 @ 7530 ms: x -0.268128 , y -0.268128 , z -9.576000
 +
fetched and got acceleration readings 0, 4294699168
 +
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
lis2dh task at loop iteration 0x00000003
 +
Failed to set odr: -134
 +
Sampling at 1 Hz (asuuming so as sensor_attr_set returns 0 status - success
 +
sampling at 1 Hz, per call to sensor_attr_get(),
 +
#3 @ 10536 ms: x -0.344736 , y -0.344736 , z -9.652608
 +
fetched and got acceleration readings 0, 4294622560
 +
 +
zzz -  - zzz
 +
  .
 +
  .
 +
  .
 +
</pre>
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] IIS2DH Test App Output with SDA Disconnected ==
 +
 +
<pre>
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
zzz -  - zzz
 +
iis2dh task at loop iteration 0x0000001F
 +
[00:03:08.955,505] <err> i2c_nrfx_twim: Error 0x0BAE0001 occurred for message 0
 +
sensor who-am-i check returns '3',
 +
[00:03:08.957,489] <err> i2c_nrfx_twim: Error 0x0BAE0001 occurred for message 0
 +
Failed to set odr: -5
 +
Sampling at 5 Hz (assuming so as sensor_attr_set returns 0 status - success
 +
sampling at Output Data Rate (ODR) setting 5,
 +
- DEV004 - requesting sensor fetch of all available readings...
 +
[00:03:08.961,853] <err> i2c_nrfx_twim: Error 0x0BAE0001 occurred for message 0
 +
ERROR: Update failed: -5
 +
- DEV004 - fetching readings again...
 +
[00:03:08.984,313] <err> i2c_nrfx_twim: Error 0x0BAE0001 occurred for message 0
 +
- DEV004 - getting X axis reading only...
 +
fetched and got acceleration readings 0, 0
 +
</pre>
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] Read Of ACCEL_X_L Plus Six Advances Readings One Byte Only ==
 +
 +
<pre>
 +
222 - IIS2DH FIFO source register holds 223, buffered reading count is 31,
 +
data from 31 readings:
 +
2B 00  2D 00  FE 00 
 +
00 2D  00 FE  00 26 
 +
2D 00  FE 00  26 00 
 +
00 FE  00 26  00 31 
 +
FE 00  26 00  31 00 
 +
00 26  00 31  00 FF    <-- mark
 +
26 00  31 00  FF 00 
 +
00 31  00 FF  00 20 
 +
31 00  FF 00  20 00 
 +
00 FF  00 20  00 37 
 +
FF 00  20 00  37 00 
 +
00 20  00 37  00 00    <-- mark
 +
20 00  37 00  00 00 
 +
00 37  00 00  00 1A 
 +
37 00  00 00  1A 00 
 +
00 00  00 1A  00 3A 
 +
00 00  1A 00  3A 00 
 +
00 1A  00 3A  00 00    <-- mark
 +
1A 00  3A 00  00 00 
 +
00 3A  00 00  00 15 
 +
3A 00  00 00  15 00 
 +
00 00  00 15  00 3A 
 +
00 00  15 00  3A 00 
 +
00 15  00 3A  00 00    <-- mark
 +
15 00  3A 00  00 00 
 +
00 3A  00 00  00 0F 
 +
3A 00  00 00  0F 00 
 +
00 00  00 0F  00 3C 
 +
00 00  0F 00  3C 00 
 +
00 0F  00 3C  00 00    <-- mark
 +
0F 00  3C 00  00 00 
 +
 +
333 -
 +
Clearing any interrupts we read from CTRL_REG3:  0
 +
</pre>
  
 +
<!-- comment -->
 +
 +
== * ==
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] STMicro Forum ==
 +
STMicro forum posts regarding IIS2DH configuration, IIS2DH commands:
 +
 +
*  https://community.st.com/s/global-search/iis2dh
 +
 +
*  https://community.st.com/s/question/0D50X00009XkZNASA3/iis2dh-interrupt-generation-and-tech-details
 +
 +
Excerpt:
 +
<pre>
 +
Miroslav BATEK (Employee)
 +
Edited by ST Community July 21, 2018 at 5:47 PM
 +
Posted on November 11, 2016 at 12:24
 +
 +
 +
 +
 +
 +
 +
1) Your setting of INT1_CFG register to (0011 1111b) doesn’t make sense. Basically you want trigger the interrupt if the acceleration value is lower or higher than threshold in any axis, this is always true. If the interrupt is not latched, the value is valid for one period of your ODR settings. If it is latched the value is set until you read the INT1_SRC register.
 +
 +
 +
 +
 +
 +
 +
2) If you set AOI, 6D = 00. The OR condition is used between the other bits settings.
 +
 +
 +
 +
If you set AOI, 6D = 10. The AND condition is used between the other bits settings.
 +
 +
 +
 +
If you want use 6D detection you can set AOI, 6D bits 01 or 11. Other bits in the INT1_CFG register are ignored.
 +
 +
 +
 +
Maybe an example will help:
 +
 +
 +
 +
INT1_CFG = 00101010b … if acceleration value in X axis OR in Y axis OR in Z axis will be higher than INT1_THS for time defined in INT1_DURATION register the interrupt will be triggered.
 +
 +
INT1_CFG = 10010101b … if acceleration value in X axis AND in Y axis AND in Z axis will be lower than INT1_THS for time defined in INT1_DURATION register the interrupt will be triggered.
 +
 +
3)
 +
 +
 +
 +
You don’t have to worry about this sentence. You don’t have to reboot the accelerometer. It is just saying you can’t configure these register during the start-up of the accelerometer. I suppose there is already small delay after power-up so this is not an issue.
 +
 +
 +
 +
 +
4) By execution “Reboot memory content� command default values from internal non-volatile memory are loaded to working registers. By this you can reset the register settings to default values.
 +
 +
 +
 +
 +
5) For High pass filter setting please refer to AN3308 for LIS3DH. The settings is very similar to IIS2DH.
 +
 +
Best regards
 +
 +
 +
 +
Miroslav
 +
 +
Selected as BestSelected as Best
 +
 +
</pre>
 +
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] validate_enabled_instances.c ==
 +
 +
 +
[1]+  Stopped                vi /home/ted/projects/zephyr-based/z4-sandbox-kionix-work/zephyr/soc/arm/nordic_nrf/validate_enabled_instances.c
 +
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/hardware-Stage1-firmware-aws-iot-stand-alone/boards$
 +
 +
<pre>
 +
20 /*
 +
21  * In most Nordic SoCs, SPI and TWI peripherals with the same instance number
 +
22  * share certain resources and therefore cannot be used at the same time (in
 +
23  * nRF53 and nRF91 Series this limitation concerns UART peripherals as well).
 +
24  *
 +
25  * In some SoCs, like nRF52810, there are only single instances of
 +
26  * these peripherals and they are arranged in a different way, so this
 +
27  * limitation does not apply.
 +
28  *
 +
29  * The build assertions below check if conflicting peripheral instances are not
 +
30  * enabled simultaneously.
 +
31  */
 +
32
 +
33 #define CHECK(idx) \
 +
34        !(I2C_ENABLED(idx) && SPI_ENABLED(idx)) && \
 +
35        !(I2C_ENABLED(idx) && UART_ENABLED(idx)) && \
 +
36        !(SPI_ENABLED(idx) && UART_ENABLED(idx))
 +
37
 +
38 #define MSG(idx) \
 +
39        "Only one of the following peripherals can be enabled: " \
 +
40        "SPI"#idx", SPIM"#idx", SPIS"#idx", TWI"#idx", TWIM"#idx", TWIS"#idx \
 +
41        IF_ENABLED(CONFIG_SOC_SERIES_NRF53X, (", UARTE"#idx)) \
 +
42        IF_ENABLED(CONFIG_SOC_SERIES_NRF91X, (", UARTE"#idx)) \
 +
43        ". Check nodes with status \"okay\" in zephyr.dts."
 +
44
 +
45 #if (!IS_ENABLED(CONFIG_SOC_NRF52810) &&        \
 +
46        !IS_ENABLED(CONFIG_SOC_NRF52805) &&    \
 +
47        !IS_ENABLED(CONFIG_SOC_NRF52811))
 +
48 BUILD_ASSERT(CHECK(0), MSG(0));
 +
49 #endif
 +
50 BUILD_ASSERT(CHECK(1), MSG(1));
 +
51 BUILD_ASSERT(CHECK(2), MSG(2));
 +
52 BUILD_ASSERT(CHECK(3), MSG(3));
 +
53
 +
54 #if IS_ENABLED(CONFIG_SOC_NRF52811)
 +
</pre>
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] edit point ==
 +
 +
<!-- comment -->
 +
 +
== [[#top|^]] edit point ==
 +
 +
 +
<!-- comment -->
 +
 +
 +
 +
<!-- comment -->
  
 
<!-- EOF -->
 
<!-- EOF -->

Latest revision as of 17:00, 11 August 2022


^ Overview

Notes on STMicro IIS22DH high frequency MEMS accelerometer, and drivers for IIS2DH and LIS2DH sensors in Nordic Semi sdk-nrf 1.6.1. A promising top-level starting point to understand STMicro's significant code contribution to the drivers of these and related sensors is here:

Some promising more specific STMicro projects on Github:

A non-Zephyr forum post with configuration steps outlined (not obvious how these would all be achieved in Zephyr context):


Symbols in the polling code example from STMicroelectronic/iis2dh repo are defined in a sub-part of sdk-nrf modules/hal/ project space:

guest@ubuntu-vm:~/embedded/z3-on-var/modules/hal/st$ grep -nr IIS2DH_2g ./*
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.h:742:  IIS2DH_2g   = 0,
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:636:    case IIS2DH_2g:
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:637:      *val = IIS2DH_2g;
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:649:      *val = IIS2DH_2g;

guest@ubuntu-vm:~/embedded/z3-on-var/modules/hal/st$ grep -nr IIS2DH_ODR_1Hz ./*
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.h:707:  IIS2DH_ODR_1Hz                         = 0x01,
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:402:    case IIS2DH_ODR_1Hz:
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:403:      *val = IIS2DH_ODR_1Hz;

guest@ubuntu-vm:~/embedded/z3-on-var/modules/hal/st$ grep -nr IIS2DH_TEMP_ENABLE ./*
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.h:692:  IIS2DH_TEMP_ENABLE   = 3,
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:285:    case IIS2DH_TEMP_ENABLE:
./sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c:286:      *val = IIS2DH_TEMP_ENABLE;
guest@ubuntu-vm:~/embedded/z3-on-var/modules/hal/st$ grep -nr PROPERTY_ENABLE ./*

And really the above project is pulled in to Nordic's sdk-nrf. Looks to be at a slightly older, or at least different version, but driver header and sources at https://github.com/STMicroelectronics/iis2dh are the same as in the STMicro hal code in Nordic sdk-nrf v1.6.1.


^ IIS2DH Control Registers As C Structures

An excerpt from Nordic sdk-nrf modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.h:

#define IIS2DH_CTRL_REG4             0x23U
typedef struct {
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
  uint8_t sim               : 1;
  uint8_t st                : 2;
  uint8_t hr                : 1;
  uint8_t fs                : 2;
  uint8_t ble               : 1;
  uint8_t bdu               : 1;
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
  uint8_t bdu               : 1;
  uint8_t ble               : 1;
  uint8_t fs                : 2;
  uint8_t hr                : 1;
  uint8_t st                : 2;
  uint8_t sim               : 1;
#endif /* DRV_BYTE_ORDER */
} iis2dh_ctrl_reg4_t;


^ Possible Zephyr Driver Routines for IIS2DH

Following routines are not obvious nor mentioned anywhere in Zephyr Project documentation found so far, nor are they hinted at by any trace of analogous routines in the build artifacts of Zephyr lis2dh sample app. But may we use these following routines in app level code we want to have talking with STMicro's IIS2DH sensor? . . .


 1 guest@vm:~/projects/zephyr-based/project-stage-1$ grep -nr stmdev_ctx_t ./*
 2 Binary file ./build/zephyr/zephyr.elf matches
 3 Binary file ./build/zephyr/zephyr_prebuilt.elf matches
 4 ./build/zephyr/zephyr.lst:55935:int32_t iis2dh_read_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
 5 ./build/zephyr/zephyr.lst:55953:int32_t iis2dh_write_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
 6 ./build/zephyr/zephyr.lst:55973:int32_t iis2dh_operating_mode_set(stmdev_ctx_t *ctx, iis2dh_op_md_t val)
 7 ./build/zephyr/zephyr.lst:56065:int32_t iis2dh_data_rate_set(stmdev_ctx_t *ctx, iis2dh_odr_t val)
 8 ./build/zephyr/zephyr.lst:56107:int32_t iis2dh_full_scale_set(stmdev_ctx_t *ctx, iis2dh_fs_t val)
 9 ./build/zephyr/zephyr.lst:56149:int32_t iis2dh_block_data_update_set(stmdev_ctx_t *ctx, uint8_t val)
10 ./build/zephyr/zephyr.lst:56191:int32_t iis2dh_acceleration_raw_get(stmdev_ctx_t *ctx, int16_t *val)
11 ./build/zephyr/zephyr.lst:56231:int32_t iis2dh_device_id_get(stmdev_ctx_t *ctx, uint8_t *buff)
12 Binary file ./build/zephyr/CMakeFiles/zephyr.dir/home/ted/projects/zephyr-based/modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver/iis2dh_reg.c.obj matches
13 Binary file ./build/zephyr/libzephyr.a matches
14 Binary file ./build/zephyr/drivers/sensor/iis2dh/CMakeFiles/drivers__sensor__iis2dh.dir/iis2dh_trigger.c.obj matches
15 Binary file ./build/zephyr/drivers/sensor/iis2dh/CMakeFiles/drivers__sensor__iis2dh.dir/iis2dh_i2c.c.obj matches
16 Binary file ./build/zephyr/drivers/sensor/iis2dh/CMakeFiles/drivers__sensor__iis2dh.dir/iis2dh.c.obj matches
17 Binary file ./build/zephyr/drivers/sensor/iis2dh/libdrivers__sensor__iis2dh.a matches
18 guest@vm:~/projects/zephyr-based/project-stage-1$

Looks like there are actually many more IIS2DH API routines available in the modules/hal source file from STMicro:

ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver$ grep -nr stmdev_ctx_t ./*.c
49:int32_t iis2dh_read_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
67:int32_t iis2dh_write_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
182:int32_t iis2dh_temp_status_reg_get(stmdev_ctx_t *ctx, uint8_t *buff)
196:int32_t iis2dh_temp_data_ready_get(stmdev_ctx_t *ctx, uint8_t *val)
215:int32_t iis2dh_temp_data_ovr_get(stmdev_ctx_t *ctx, uint8_t *val)
234:int32_t iis2dh_temperature_raw_get(stmdev_ctx_t *ctx, int16_t *val)
253:int32_t iis2dh_temperature_meas_set(stmdev_ctx_t *ctx, iis2dh_temp_en_t val)
275:int32_t iis2dh_temperature_meas_get(stmdev_ctx_t *ctx, iis2dh_temp_en_t *val)
304:int32_t iis2dh_operating_mode_set(stmdev_ctx_t *ctx, iis2dh_op_md_t val)
343:int32_t iis2dh_operating_mode_get(stmdev_ctx_t *ctx, iis2dh_op_md_t *val)
371:int32_t iis2dh_data_rate_set(stmdev_ctx_t *ctx, iis2dh_odr_t val)
392:int32_t iis2dh_data_rate_get(stmdev_ctx_t *ctx, iis2dh_odr_t *val)
445:int32_t iis2dh_high_pass_on_outputs_set(stmdev_ctx_t *ctx, uint8_t val)
467:int32_t iis2dh_high_pass_on_outputs_get(stmdev_ctx_t *ctx, uint8_t *val)
492:int32_t iis2dh_high_pass_bandwidth_set(stmdev_ctx_t *ctx, iis2dh_hpcf_t val)
519:int32_t iis2dh_high_pass_bandwidth_get(stmdev_ctx_t *ctx, iis2dh_hpcf_t *val)
553:int32_t iis2dh_high_pass_mode_set(stmdev_ctx_t *ctx, iis2dh_hpm_t val)
574:int32_t iis2dh_high_pass_mode_get(stmdev_ctx_t *ctx, iis2dh_hpm_t *val)
608:int32_t iis2dh_full_scale_set(stmdev_ctx_t *ctx, iis2dh_fs_t val)
629:int32_t iis2dh_full_scale_get(stmdev_ctx_t *ctx, iis2dh_fs_t *val)
663:int32_t iis2dh_block_data_update_set(stmdev_ctx_t *ctx, uint8_t val)
684:int32_t iis2dh_block_data_update_get(stmdev_ctx_t *ctx, uint8_t *val)
704:int32_t iis2dh_filter_reference_set(stmdev_ctx_t *ctx, uint8_t *buff)
720:int32_t iis2dh_filter_reference_get(stmdev_ctx_t *ctx, uint8_t *buff)
734:int32_t iis2dh_xl_data_ready_get(stmdev_ctx_t *ctx, uint8_t *val)
752:int32_t iis2dh_xl_data_ovr_get(stmdev_ctx_t *ctx, uint8_t *val)
770:int32_t iis2dh_acceleration_raw_get(stmdev_ctx_t *ctx, int16_t *val)
804:int32_t iis2dh_device_id_get(stmdev_ctx_t *ctx, uint8_t *buff)
818:int32_t iis2dh_self_test_set(stmdev_ctx_t *ctx, iis2dh_st_t val)
839:int32_t iis2dh_self_test_get(stmdev_ctx_t *ctx, iis2dh_st_t *val)
870:int32_t iis2dh_data_format_set(stmdev_ctx_t *ctx, iis2dh_ble_t val)
891:int32_t iis2dh_data_format_get(stmdev_ctx_t *ctx, iis2dh_ble_t *val)
919:int32_t iis2dh_boot_set(stmdev_ctx_t *ctx, uint8_t val)
940:int32_t iis2dh_boot_get(stmdev_ctx_t *ctx, uint8_t *val)
959:int32_t iis2dh_int_occurrencies_get(stmdev_ctx_t *ctx, uint8_t *val)
974:int32_t iis2dh_status_get(stmdev_ctx_t *ctx, iis2dh_status_reg_t *val)
1001:int32_t iis2dh_int1_gen_conf_set(stmdev_ctx_t *ctx, iis2dh_int1_cfg_t *val)
1016:int32_t iis2dh_int1_gen_conf_get(stmdev_ctx_t *ctx, iis2dh_int1_cfg_t *val)
1031:int32_t iis2dh_int1_gen_source_get(stmdev_ctx_t *ctx, iis2dh_int1_src_t *val)
1047:int32_t iis2dh_int1_gen_threshold_set(stmdev_ctx_t *ctx, uint8_t val)
1070:int32_t iis2dh_int1_gen_threshold_get(stmdev_ctx_t *ctx, uint8_t *val)
1090:int32_t iis2dh_int1_gen_duration_set(stmdev_ctx_t *ctx, uint8_t val)
1114:int32_t iis2dh_int1_gen_duration_get(stmdev_ctx_t *ctx, uint8_t *val)
1147:int32_t iis2dh_int2_gen_conf_set(stmdev_ctx_t *ctx, iis2dh_int2_cfg_t *val)
1162:int32_t iis2dh_int2_gen_conf_get(stmdev_ctx_t *ctx, iis2dh_int2_cfg_t *val)
1176:int32_t iis2dh_int2_gen_source_get(stmdev_ctx_t *ctx, iis2dh_int2_src_t *val)
1192:int32_t iis2dh_int2_gen_threshold_set(stmdev_ctx_t *ctx, uint8_t val)
1215:int32_t iis2dh_int2_gen_threshold_get(stmdev_ctx_t *ctx, uint8_t *val)
1235:int32_t iis2dh_int2_gen_duration_set(stmdev_ctx_t *ctx, uint8_t val)
1259:int32_t iis2dh_int2_gen_duration_get(stmdev_ctx_t *ctx, uint8_t *val)
1291:int32_t iis2dh_high_pass_int_conf_set(stmdev_ctx_t *ctx, iis2dh_hp_t val)
1312:int32_t iis2dh_high_pass_int_conf_get(stmdev_ctx_t *ctx, iis2dh_hp_t *val)
1358:int32_t iis2dh_pin_int1_config_set(stmdev_ctx_t *ctx, iis2dh_ctrl_reg3_t *val)
1373:int32_t iis2dh_pin_int1_config_get(stmdev_ctx_t *ctx, iis2dh_ctrl_reg3_t *val)
1389:int32_t iis2dh_int2_pin_detect_4d_set(stmdev_ctx_t *ctx, uint8_t val)
1411:int32_t iis2dh_int2_pin_detect_4d_get(stmdev_ctx_t *ctx, uint8_t *val)
1432:int32_t iis2dh_int2_pin_notification_mode_set(stmdev_ctx_t *ctx,
1456:int32_t iis2dh_int2_pin_notification_mode_get(stmdev_ctx_t *ctx,
1486:int32_t iis2dh_int1_pin_detect_4d_set(stmdev_ctx_t *ctx, uint8_t val)
1508:int32_t iis2dh_int1_pin_detect_4d_get(stmdev_ctx_t *ctx, uint8_t *val)
1528:int32_t iis2dh_int1_pin_notification_mode_set(stmdev_ctx_t *ctx,
1551:int32_t iis2dh_int1_pin_notification_mode_get(stmdev_ctx_t *ctx,
1580:int32_t iis2dh_pin_int2_config_set(stmdev_ctx_t *ctx, iis2dh_ctrl_reg6_t *val)
1595:int32_t iis2dh_pin_int2_config_get(stmdev_ctx_t *ctx, iis2dh_ctrl_reg6_t *val)
1622:int32_t iis2dh_fifo_set(stmdev_ctx_t *ctx, uint8_t val)
1643:int32_t iis2dh_fifo_get(stmdev_ctx_t *ctx, uint8_t *val)
1662:int32_t iis2dh_fifo_watermark_set(stmdev_ctx_t *ctx, uint8_t val)
1685:int32_t iis2dh_fifo_watermark_get(stmdev_ctx_t *ctx, uint8_t *val)
1705:int32_t iis2dh_fifo_trigger_event_set(stmdev_ctx_t *ctx, iis2dh_tr_t val)
1728:int32_t iis2dh_fifo_trigger_event_get(stmdev_ctx_t *ctx, iis2dh_tr_t *val)
1757:int32_t iis2dh_fifo_mode_set(stmdev_ctx_t *ctx, iis2dh_fm_t val)
1780:int32_t iis2dh_fifo_mode_get(stmdev_ctx_t *ctx, iis2dh_fm_t *val)
1815:int32_t iis2dh_fifo_status_get(stmdev_ctx_t *ctx, iis2dh_fifo_src_reg_t *val)
1829:int32_t iis2dh_fifo_data_level_get(stmdev_ctx_t *ctx, uint8_t *val)
1847:int32_t iis2dh_fifo_empty_flag_get(stmdev_ctx_t *ctx, uint8_t *val)
1865:int32_t iis2dh_fifo_ovr_flag_get(stmdev_ctx_t *ctx, uint8_t *val)
1883:int32_t iis2dh_fifo_fth_flag_get(stmdev_ctx_t *ctx, uint8_t *val)
1914:int32_t iis2dh_tap_conf_set(stmdev_ctx_t *ctx, iis2dh_click_cfg_t *val)
1929:int32_t iis2dh_tap_conf_get(stmdev_ctx_t *ctx, iis2dh_click_cfg_t *val)
1943:int32_t iis2dh_tap_source_get(stmdev_ctx_t *ctx, iis2dh_click_src_t *val)
1958:int32_t iis2dh_tap_threshold_set(stmdev_ctx_t *ctx, uint8_t val)
1980:int32_t iis2dh_tap_threshold_get(stmdev_ctx_t *ctx, uint8_t *val)
2001:int32_t iis2dh_shock_dur_set(stmdev_ctx_t *ctx, uint8_t val)
2024:int32_t iis2dh_shock_dur_get(stmdev_ctx_t *ctx, uint8_t *val)
2046:int32_t iis2dh_quiet_dur_set(stmdev_ctx_t *ctx, uint8_t val)
2071:int32_t iis2dh_quiet_dur_get(stmdev_ctx_t *ctx, uint8_t *val)
2093:int32_t iis2dh_double_tap_timeout_set(stmdev_ctx_t *ctx, uint8_t val)
2117:int32_t iis2dh_double_tap_timeout_get(stmdev_ctx_t *ctx, uint8_t *val)
2151:int32_t iis2dh_act_threshold_set(stmdev_ctx_t *ctx, uint8_t val)
2174:int32_t iis2dh_act_threshold_get(stmdev_ctx_t *ctx, uint8_t *val)
2194:int32_t iis2dh_act_timeout_set(stmdev_ctx_t *ctx, uint8_t val)
2216:int32_t iis2dh_act_timeout_get(stmdev_ctx_t *ctx, uint8_t *val)
2248:int32_t iis2dh_spi_mode_set(stmdev_ctx_t *ctx, iis2dh_sim_t val)
2269:int32_t iis2dh_spi_mode_get(stmdev_ctx_t *ctx, iis2dh_sim_t *val)

ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver$ 

^ Zephyr RTOS Tie-In To STMicro IIS2DH Driver API

File `$ENV{ZEPHYR_BASE}/drivers/sensor/iis2dh/iis2dh.c` end with:ii2

312 struct iis2dh_data iis2dh_data;
313
314 DEVICE_DT_INST_DEFINE(0, iis2dh_init, NULL,
315              &iis2dh_data, &iis2dh_cfg, POST_KERNEL,
316              CONFIG_SENSOR_INIT_PRIORITY, &iis2dh_driver_api);

...Somewhere data member `&iis2dh_data` gets assigned a value. This data member in turn is referenced when the above driver API routines are called. For example in routine `iis2dh_sample_fetch()` there is reference to an stmdev_ctx_t structure that's assigned to the device handle's "data" member:

203 static int iis2dh_sample_fetch(const struct device *dev,
204                                enum sensor_channel chan)
205 {
206         struct iis2dh_data *iis2dh = dev->data;
207         int16_t buf[3];
208
209         /* fetch raw data sample */
210         if (iis2dh_acceleration_raw_get(iis2dh->ctx, buf) < 0) {
211                 LOG_DBG("Failed to fetch raw data sample");
212                 return -EIO;
213         }
214
215         iis2dh->acc[0] = sys_le16_to_cpu(buf[0]);
216         iis2dh->acc[1] = sys_le16_to_cpu(buf[1]);
217         iis2dh->acc[2] = sys_le16_to_cpu(buf[2]);
218
219         return 0;
220 }

The structure `iis2dh_data` is defined in corresponding header file `iis2dh.h` as:

 59 /* sensor data */
 60 struct iis2dh_data {
 61         const struct device *bus;
 62         int16_t acc[3];
 63         uint32_t gain;
 64
 65         stmdev_ctx_t *ctx;
 66 #ifdef CONFIG_IIS2DH_TRIGGER
 67         const struct device *dev;
 68         const struct device *gpio;
 69         uint8_t gpio_pin;
 70         struct gpio_callback gpio_cb;
 71         sensor_trigger_handler_t drdy_handler;
 72 #if defined(CONFIG_IIS2DH_TRIGGER_OWN_THREAD)
 73         K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_IIS2DH_THREAD_STACK_SIZE);
 74         struct k_thread thread;
 75         struct k_sem gpio_sem;
 76 #elif defined(CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD)
 77         struct k_work work;
 78 #endif /* CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD */
 79 #endif /* CONFIG_IIS2DH_TRIGGER */
 80 #if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
 81         struct spi_cs_control cs_ctrl;
 82 #endif
 83 };

Structure stmdev_ctx_t is defined:

110 typedef int32_t (*stmdev_write_ptr)(void *, uint8_t, uint8_t*, uint16_t);
111 typedef int32_t (*stmdev_read_ptr) (void *, uint8_t, uint8_t*, uint16_t);
112 
113 typedef struct {
114   /** Component mandatory fields **/
115   stmdev_write_ptr  write_reg;
116   stmdev_read_ptr   read_reg;
117   /** Customizable optional pointer **/
118   void *handle;
119 } stmdev_ctx_t;


^ Assignment To ctx Structure

So question, where is *ctx assigned a value? Ah, *ctx is assigned a value in the zephyr/drivers/sensor/iis2dh/iis2dh_i2c.c file. This value is a data structure which entails two C function pointers. Code excerpt here:

 19 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
 20
 21 static uint16_t iis2dh_i2c_slave_addr = DT_INST_REG_ADDR(0);
 22
 23 LOG_MODULE_DECLARE(IIS2DH, CONFIG_SENSOR_LOG_LEVEL);
 24
 25 static int iis2dh_i2c_read(struct iis2dh_data *data, uint8_t reg_addr,
 26                            uint8_t *value, uint16_t len)
 27 {
 28         return i2c_burst_read(data->bus, iis2dh_i2c_slave_addr,
 29                               reg_addr | 0x80, value, len);
 30 }
 31
 32 static int iis2dh_i2c_write(struct iis2dh_data *data, uint8_t reg_addr,
 33                             uint8_t *value, uint16_t len)
 34 {
 35         return i2c_burst_write(data->bus, iis2dh_i2c_slave_addr,
 36                                reg_addr | 0x80, value, len);
 37 }
 38
 39 stmdev_ctx_t iis2dh_i2c_ctx = {
 40         .read_reg = (stmdev_read_ptr) iis2dh_i2c_read,
 41         .write_reg = (stmdev_write_ptr) iis2dh_i2c_write,
 42 };
 43
 44 int iis2dh_i2c_init(const struct device *dev)
 45 {
 46         struct iis2dh_data *data = dev->data;
 47
 48         data->ctx = &iis2dh_i2c_ctx;
 49         data->ctx->handle = data;
 50
 51         return 0;
 52 }
 53 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */

^ edit point

Routine `int i2c_burst_read()` is a Zephyr in-tree driver routine. In possibly erroneous C syntax the assignment from the Zephyr device structure handle on down is:

  dev->data->ctx->.read_reg = (stmdev_read_ptr) iis2dh_i2c_read
             ^^^
              :
  Valid when *data is typecast as `struct iis2dh_data`.

Routine `iis2dh_i2c_read` calls `i2c_burst_read()`, which in turn calls `i2c_write_read()`, which in turn calls 'i2c_transfer()', which would seem to be the final routine call in this call stack but in fact is a pointer to a project's given processor specific I2C peripheral:

346 __syscall int i2c_transfer(const struct device *dev,
347                            struct i2c_msg *msgs, uint8_t num_msgs,
348                            uint16_t addr);
349 
350 static inline int z_impl_i2c_transfer(const struct device *dev,
351                                       struct i2c_msg *msgs, uint8_t num_msgs,
352                                       uint16_t addr)
353 {
354         const struct i2c_driver_api *api =
355                 (const struct i2c_driver_api *)dev->api;
356 
357         return api->transfer(dev, msgs, num_msgs, addr);
358 }


Excerpt from zephyr/include/drivers/i2c.h:

607 static inline int i2c_burst_read(const struct device *dev,
608                                  uint16_t dev_addr,
609                                  uint8_t start_addr,
610                                  uint8_t *buf,
611                                  uint32_t num_bytes)
612 {
613         return i2c_write_read(dev, dev_addr,
614                               &start_addr, sizeof(start_addr),
615                               buf, num_bytes);
616 }
572 static inline int i2c_write_read(const struct device *dev, uint16_t addr,
573                                  const void *write_buf, size_t num_write,
574                                  void *read_buf, size_t num_read)
575 {
576         struct i2c_msg msg[2];
577 
578         msg[0].buf = (uint8_t *)write_buf;
579         msg[0].len = num_write;
580         msg[0].flags = I2C_MSG_WRITE;
581 
582         msg[1].buf = (uint8_t *)read_buf;
583         msg[1].len = num_read;
584         msg[1].flags = I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP;
585 
586         return i2c_transfer(dev, msg, 2, addr);
587 }
346 __syscall int i2c_transfer(const struct device *dev,
347                            struct i2c_msg *msgs, uint8_t num_msgs,
348                            uint16_t addr);
349 
350 static inline int z_impl_i2c_transfer(const struct device *dev,
351                                       struct i2c_msg *msgs, uint8_t num_msgs,
352                                       uint16_t addr)
353 {
354         const struct i2c_driver_api *api =
355                 (const struct i2c_driver_api *)dev->api;
356 
357         return api->transfer(dev, msgs, num_msgs, addr);
358 }


^ Why Does iis2dh_device_id_get Return 3 When No Device Connected?

Following routine in STMicro's driver API code base returns ASCII "3", decimal 51 even when no device connected. This is the ID value spec'd in the IIS2DH datasheet. How is this value getting returned? The routine in question is here:

 796 /**
 797   * @brief  DeviceWhoamI .[get]
 798   *
 799   * @param  ctx      read / write interface definitions
 800   * @param  buff     buffer that stores data read
 801   * @retval          interface status (MANDATORY: return 0 -> no Error)
 802   *
 803   */
 804 int32_t iis2dh_device_id_get(stmdev_ctx_t *ctx, uint8_t *buff)
 805 {
 806   int32_t ret;
 807   ret = iis2dh_read_reg(ctx, IIS2DH_WHO_AM_I, buff, 1);
 808   return ret;
 809 }

From comment block it looks like the value 3 in our situation is an error value coming from routine `iis2dh_read_reg()`. This routine is defined:

  39 /**
  40   * @brief  Read generic device register
  41   *
  42   * @param  ctx   read / write interface definitions(ptr)
  43   * @param  reg   register to read
  44   * @param  data  pointer to buffer that store the data read(ptr)
  45   * @param  len   number of consecutive register to read
  46   * @retval          interface status (MANDATORY: return 0 -> no Error)
  47   *
  48   */
  49 int32_t iis2dh_read_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data,
  50                         uint16_t len)
  51 {
  52   int32_t ret;
  53   ret = ctx->read_reg(ctx->handle, reg, data, len);
  54   return ret;
  55 }

Ok this begs the question then where and how are the ctx function pointers assigned to point to functions? We were working to answer this question yesterday, and it is something of a repeat of a key question we faced when building the out-of-tree driver for Kionix sensor . . .


^ Configuration Post from ST Micro Forum

Excerpt on accelerator configurations from this developer: mhackney (Community Member) Edited by ST Community July 21, 2018 at 5:26 PM Posted on January 02, 2017 at 16:21


Ok, I overlooked the data sheet that Low Power mode is 8-bit data output. But that still does not explain why the data is not left aligned?

Also, here is my complete configuration to sanity check:

// setup CTRL_REG1


accelerometer_write(CTRL_REG1, 0b10011100); // ODR 5.376kHz in LPMode [7-4] Low power enable [3] Z enable [2]

// setup CTRL_REG2


accelerometer_write(CTRL_REG2, 0b00110001); //

// setup CTRL_REG3


accelerometer_write(CTRL_REG3, 0b01000000); // AOI (And Or Interrupt) on INT1 en [6]

// setup CTRL_REG6


accelerometer_write(CTRL_REG6, 0b00000000); //

// setup CTRL_REG4


accelerometer_write(CTRL_REG4, 0b00110000); // Full-scale selection 16G [5-4]

// setup CTRL_REG5


accelerometer_write(CTRL_REG5, 0b01001010); // FIFO enable [6] Latch INT1 [3]

// setup INT1_CFG


accelerometer_write(INT1_CFG, 0b00100000); // ZHIE enabled [5]

// setup INT1_THS


accelerometer_write(INT1_THS, Z_PROBE_SENSITIVITY); // 40

// setup INT1_DURATION


accelerometer_write(INT1_DURATION, 0);




*

^ LIS2DH Data Structure

LIS2DH data structure, comparable to IIS2DH data structure but no `ctx` element:

LIS2DH data structure definition:

220 struct lis2dh_data {
221         const struct device *bus;
222         const struct lis2dh_transfer_function *hw_tf;
223 
224         union lis2dh_sample sample;
225         /* current scaling factor, in micro m/s^2 / lsb */
226         uint32_t scale;
227 
228 #ifdef CONFIG_LIS2DH_TRIGGER
229         const struct device *dev;
230         const struct device *gpio_int1;
231         const struct device *gpio_int2;
232         struct gpio_callback gpio_int1_cb;
233         struct gpio_callback gpio_int2_cb;
234 
235         sensor_trigger_handler_t handler_drdy;
236         sensor_trigger_handler_t handler_anymotion;
237         atomic_t trig_flags;
238         enum sensor_channel chan_drdy;
239 
240 #if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD)
241         K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DH_THREAD_STACK_SIZE);
242         struct k_thread thread;
243         struct k_sem gpio_sem;
244 #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD)
245         struct k_work work;
246 #endif
247 
248 #endif /* CONFIG_LIS2DH_TRIGGER */
249 
250 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
251         struct spi_cs_control cs_ctrl;
252 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
253 };

LIS2DH 'transfer function' structure definition:

207 struct lis2dh_transfer_function {
208         int (*read_data)(const struct device *dev, uint8_t reg_addr,
209                          uint8_t *value, uint8_t len);
210         int (*write_data)(const struct device *dev, uint8_t reg_addr,
211                           uint8_t *value, uint8_t len);
212         int (*read_reg)(const struct device *dev, uint8_t reg_addr,
213                         uint8_t *value);
214         int (*write_reg)(const struct device *dev, uint8_t reg_addr,
215                          uint8_t value);
216         int (*update_reg)(const struct device *dev, uint8_t reg_addr,
217                           uint8_t mask, uint8_t value);
218 };

LIS2DH 'transfer function' structure assignment, in file ./drivers/sensor/lis2ds12/lis2ds12_i2c.c:72:

 68 int lis2ds12_i2c_init(const struct device *dev)
 69 {
 70         struct lis2ds12_data *data = dev->data;
 71 
 72         data->hw_tf = &lis2ds12_i2c_transfer_fn;
 73 
 74         return 0;
 75 }
 76 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */

This transfer function is a structure of five function pointers:

 60 static const struct lis2ds12_transfer_function lis2ds12_i2c_transfer_fn = {
 61         .read_data = lis2ds12_i2c_read_data,
 62         .write_data = lis2ds12_i2c_write_data,
 63         .read_reg  = lis2ds12_i2c_read_reg,
 64         .write_reg  = lis2ds12_i2c_write_reg,
 65         .update_reg = lis2ds12_i2c_update_reg,
 66 };
 67 

These functions are defines nearby just above, first two for examples are:

17 #include "lis2ds12.h"
 18 
 19 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
 20 
 21 static uint16_t lis2ds12_i2c_slave_addr = DT_INST_REG_ADDR(0);
 22 
 23 LOG_MODULE_DECLARE(LIS2DS12, CONFIG_SENSOR_LOG_LEVEL);
 24 
 25 static int lis2ds12_i2c_read_data(struct lis2ds12_data *data, uint8_t reg_addr,
 26                                  uint8_t *value, uint8_t len)
 27 {
 28         return i2c_burst_read(data->comm_master, lis2ds12_i2c_slave_addr,
 29                               reg_addr, value, len);
 30 }
 31 
 32 static int lis2ds12_i2c_write_data(struct lis2ds12_data *data, uint8_t reg_addr,
 33                                   uint8_t *value, uint8_t len)
 34 {
 35         return i2c_burst_write(data->comm_master, lis2ds12_i2c_slave_addr,
 36                                reg_addr, value, len);
 37 }



^ LIS2DH Sample Fetch Routine

What is going on in this LIS2DH API routine by STMicro, especially at line 107?

 81 static int lis2dh_sample_fetch(const struct device *dev,
 82                                enum sensor_channel chan)
 83 {
 84         struct lis2dh_data *lis2dh = dev->data;
 85         size_t i;
 86         int status;
 87 
 88         __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL ||
 89                         chan == SENSOR_CHAN_ACCEL_XYZ);
 90 
 91         /*
 92          * since status and all accel data register addresses are consecutive,
 93          * a burst read can be used to read all the samples
 94          */
 95         status = lis2dh->hw_tf->read_data(dev, LIS2DH_REG_STATUS,
 96                                           lis2dh->sample.raw,
 97                                           sizeof(lis2dh->sample.raw));
 98         if (status < 0) {
 99                 LOG_WRN("Could not read accel axis data");
100                 return status;
101         }
102 
103         for (i = 116 static inline void iis2dh_channel_get_acc(const struct device *dev,
117                                           enum sensor_channel chan,
118                                           struct sensor_value *val)
119 {
120         int i;
121         uint8_t ofs_start, ofs_stop;
122         struct iis2dh_data *iis2dh = dev->data;
123         struct sensor_value *pval = val;
124 
125         switch (chan) {
126         case SENSOR_CHAN_ACCEL_X:
127                 ofs_start = ofs_stop = 0U;
128                 break;
129         case SENSOR_CHAN_ACCEL_Y:
130                 ofs_start = ofs_stop = 1U;
131                 break;
132         case SENSOR_CHAN_ACCEL_Z:
133                 ofs_start = ofs_stop = 2U;
134                 break;
135         default:
136                 ofs_start = 0U; ofs_stop = 2U;
137                 break;
138         }
139 
140         for (i = ofs_start; i <= ofs_stop ; i++) {
141                 iis2dh_convert(pval++, iis2dh->acc[i], iis2dh->gain);
142         }
143 }
144 
145 static int iis2dh_channel_get(const struct device *dev,
146                               enum sensor_channel chan,
147                               struct sensor_value *val)
148 {
149         switch (chan) {
150         case SENSOR_CHAN_ACCEL_X:
151         case SENSOR_CHAN_ACCEL_Y:
152         case SENSOR_CHAN_ACCEL_Z:
153         case SENSOR_CHAN_ACCEL_XYZ:
154                 iis2dh_channel_get_acc(dev, chan, val);
155                 return 0;
156         default:
157                 LOG_DBG("Channel not supported");
158                 break;
159         }
160 
161         return -ENOTSUP;
162 }
0; i < (3 * sizeof(int16_t)); i += sizeof(int16_t)) {
104                 int16_t *sample =
105                         (int16_t *)&lis2dh->sample.raw[1 + i];
106 
107                 *sample = sys_le16_to_cpu(*sample);
108         }
109 
110         if (lis2dh->sample.status & LIS2DH_STATUS_DRDY_MASK) {
111                 return 0;
112         }
113 
114         return -ENODATA;
115 }


^ LIS2DH Sample Get Routine Supports Writing Multiple sensor_type Data

From [ww]/zephyr/drivers/sensor/iis2dh/iis2dh.c, note the use of `pval` and C's unary increment operator to handle returning X, Y and Z triplet readings to calling code:

116 static inline void iis2dh_channel_get_acc(const struct device *dev,
117                                           enum sensor_channel chan,
118                                           struct sensor_value *val)
119 {
120         int i;
121         uint8_t ofs_start, ofs_stop;
122         struct iis2dh_data *iis2dh = dev->data;
123         struct sensor_value *pval = val;
124 
125         switch (chan) {
126         case SENSOR_CHAN_ACCEL_X:
127                 ofs_start = ofs_stop = 0U;
128       <!-- comment -->          break;
129         case SENSOR_CHAN_ACCEL_Y:
130                 ofs_start = ofs_stop = 1U;
131                 break;
132         case SENSOR_CHAN_ACCEL_Z:
133                 ofs_start = ofs_stop = 2U;
134                 break;
135         default:
136                 ofs_start = 0U; ofs_stop = 2U;
137                 break;
138         }
139 
140         for (i = ofs_start; i <= ofs_stop ; i++) {
141                 iis2dh_convert(pval++, iis2dh->acc[i], iis2dh->gain);
142         }
143 }
144 
145 static int iis2dh_channel_get(const struct device *dev,
146                               enum sensor_channel chan,
147                               struct sensor_value *val)
148 {
149         switch (chan) {
150         case SENSOR_CHAN_ACCEL_X:
151         case SENSOR_CHAN_ACCEL_Y:
152         case SENSOR_CHAN_ACCEL_Z:
153         case SENSOR_CHAN_ACCEL_XYZ:
154                 iis2dh_channel_get_acc(dev, chan, val);
155                 return 0;
156         default:
157                 LOG_DBG("Channel not supported");
158                 break;
159         }
160 
161         return -ENOTSUP;
162 }


^ ENOTSUP Definition - return value of -134

ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$ grep -nr ENOTSUP ./* | grep define | grep ENOTSUP
./drivers/flash/jesd216.h:326: * @retval -ENOTSUP if the erase type index is undefined.
./include/usb/bos.h:67:#define usb_handle_bos(x, y, z)		-ENOTSUP
./lib/libc/minimal/include/errno.h:115:#define ENOTSUP 134         /**< Unsupported value */
./subsys/net/ip/net_shell.c:3973:#define ping_ipv6(...) -ENOTSUP
./subsys/net/ip/net_shell.c:4082:#define ping_ipv4(...) -ENOTSUP
./subsys/usb/os_desc.h:34:#define usb_handle_os_desc(x, y, z)		-ENOTSUP
./subsys/usb/os_desc.h:35:#define usb_handle_os_desc_feature(x, y, z)	-ENOTSUP
./tests/kernel/fpu_sharing/float_disable/src/k_float_disable.c:39:#define K_FLOAT_DISABLE_SYSCALL_RETVAL -ENOTSUP

ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$


^ iis2dh_attr_set() calls iis2dh_config()

164 static int iis2dh_config(const struct device *dev, enum sensor_channel chan,
165                          enum sensor_attribute attr,
166                          const struct sensor_value *val)
167 {
168         switch (attr) {
169 #if (CONFIG_IIS2DH_RANGE == 0)
170         case SENSOR_ATTR_FULL_SCALE:
171                 return iis2dh_set_range(dev, sensor_ms2_to_g(val));
172 #endif
173 #if (CONFIG_IIS2DH_ODR == 0)
174         case SENSOR_ATTR_SAMPLING_FREQUENCY:
175                 return iis2dh_set_odr(dev, val->val1);
176 #endif
177         default:
178                 LOG_DBG("Acc attribute not supported");
179                 break;
180         }
181 
182         return -ENOTSUP;
183 }
184 
185 static int iis2dh_attr_set(const struct device *dev, enum sensor_channel chan,
186                            enum sensor_attribute attr,
187                            const struct sensor_value *val)
188 {
189         switch (chan) {
190         case SENSOR_CHAN_ACCEL_X:
191         case SENSOR_CHAN_ACCEL_Y:
192         case SENSOR_CHAN_ACCEL_Z:
193         case SENSOR_CHAN_ACCEL_XYZ:
194                 return iis2dh_config(dev, chan, attr, val);
195         default:
196                 LOG_DBG("Attr not supported on %d channel", chan);
197                 break;
198         }
199 
200         return -ENOTSUP;
201 }

In turn this routine gets called when setting ODR at run time:

 86 #if (CONFIG_IIS2DH_ODR == 0)
 87 /**
 88  * iis2dh_set_odr - set new sampling frequency
 89  * @dev: Pointer to instance of struct device (I2C or SPI)
 90  * @odr: Output data rate
 91  */
 92 static int iis2dh_set_odr(const struct device *dev, uint16_t odr)
 93 {
 94         struct iis2dh_data *iis2dh = dev->data;
 95         const struct iis2dh_device_config *cfg = dev->config;
 96         iis2dh_odr_t val;
 97 
 98         val = IIS2DH_ODR_TO_REG_HR(cfg->pm, odr);
 99 
100         return iis2dh_data_rate_set(iis2dh->ctx, val);
101 }
102 #endif

And in turn this routine:

363 /**
 364   * @brief  Output data rate selection.[set]
 365   *
 366   * @param  ctx      read / write interface definitions
 367   * @param  val      change the values of odr in reg CTRL_REG1
 368   * @retval          interface status (MANDATORY: return 0 -> no Error)
 369   *
 370   */
 371 int32_t iis2dh_data_rate_set(stmdev_ctx_t *ctx, iis2dh_odr_t val)
 372 {
 373   iis2dh_ctrl_reg1_t ctrl_reg1;
 374   int32_t ret;
 375 
 376   ret = iis2dh_read_reg(ctx, IIS2DH_CTRL_REG1, (uint8_t*)&ctrl_reg1, 1);
 377   if (ret == 0) {
 378     ctrl_reg1.odr = (uint8_t)val;
 379     ret = iis2dh_write_reg(ctx, IIS2DH_CTRL_REG1, (uint8_t*)&ctrl_reg1, 1);
 380   }
 381   return ret;
 382 }


^ edit point

Text searched in STMicro's IIS2DH mid-level driver directory, containing iis2dh.[ch]:

 2032  grep -n _set *.c
 2033  grep -n _get *.c
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/modules/hal/st/sensor/stmemsc/iis2dh_STdC/driver$


*

^ LIS2DH Driver Output at Boot Time

Some output from Kionix driver demo, interesting early message, earlier even than Zephyr RTOS banner message:

[00:00:00.408,569] <inf> lis2dh: bus=I2C_1 fs=2, odr=0x4 lp_en=0x0 scale=9576
*** Booting Zephyr OS build v2.6.0-rc1-ncs1  ***
+++ Kionix Driver Demo version 0p2 +++
- SUCCESS - found Kionix accelerometer and device is ready
- DEV - starting comparative LIS2DH test thread . . .zzz -  - zzz
Success finding lis2dh device,
Call to device_is_ready() says LIS2DH sensor is ready,
Device name found to be 'LIS2DH'
lis2dh task at loop iteration 0x00000000
Failed to set odr: -134
Sampling at 1 Hz (asuuming so as sensor_attr_set returns 0 status - success
sampling at 1 Hz, per call to sensor_attr_get(),
#0 @ 1519 ms: x -0.306432 , y -0.383040 , z -9.614304
fetched and got acceleration readings 0, 4294660864

zzz -  - zzz
zzz -  - zzz
zzz -  - zzz
lis2dh task at loop iteration 0x00000001
Failed to set odr: -134
Sampling at 1 Hz (asuuming so as sensor_attr_set returns 0 status - success
sampling at 1 Hz, per call to sensor_attr_get(),
#1 @ 4525 ms: x -0.421344 , y -0.229824 , z -9.614304
fetched and got acceleration readings 0, 4294545952

zzz -  - zzz
zzz -  - zzz
zzz -  - zzz
lis2dh task at loop iteration 0x00000002
Failed to set odr: -134
Sampling at 1 Hz (asuuming so as sensor_attr_set returns 0 status - success
sampling at 1 Hz, per call to sensor_attr_get(),
#2 @ 7530 ms: x -0.268128 , y -0.268128 , z -9.576000
fetched and got acceleration readings 0, 4294699168

zzz -  - zzz
zzz -  - zzz
zzz -  - zzz
lis2dh task at loop iteration 0x00000003
Failed to set odr: -134
Sampling at 1 Hz (asuuming so as sensor_attr_set returns 0 status - success
sampling at 1 Hz, per call to sensor_attr_get(),
#3 @ 10536 ms: x -0.344736 , y -0.344736 , z -9.652608
fetched and got acceleration readings 0, 4294622560

zzz -  - zzz
   .
   .
   .


^ IIS2DH Test App Output with SDA Disconnected

zzz -  - zzz
zzz -  - zzz
zzz -  - zzz
zzz -  - zzz
zzz -  - zzz
zzz -  - zzz
iis2dh task at loop iteration 0x0000001F
[00:03:08.955,505] <err> i2c_nrfx_twim: Error 0x0BAE0001 occurred for message 0
sensor who-am-i check returns '3',
[00:03:08.957,489] <err> i2c_nrfx_twim: Error 0x0BAE0001 occurred for message 0
Failed to set odr: -5
Sampling at 5 Hz (assuming so as sensor_attr_set returns 0 status - success
sampling at Output Data Rate (ODR) setting 5,
- DEV004 - requesting sensor fetch of all available readings...
[00:03:08.961,853] <err> i2c_nrfx_twim: Error 0x0BAE0001 occurred for message 0
ERROR: Update failed: -5
- DEV004 - fetching readings again...
[00:03:08.984,313] <err> i2c_nrfx_twim: Error 0x0BAE0001 occurred for message 0
- DEV004 - getting X axis reading only...
fetched and got acceleration readings 0, 0


^ Read Of ACCEL_X_L Plus Six Advances Readings One Byte Only

222 - IIS2DH FIFO source register holds 223, buffered reading count is 31,
data from 31 readings:
 2B 00  2D 00  FE 00  
 00 2D  00 FE  00 26  
 2D 00  FE 00  26 00  
 00 FE  00 26  00 31  
 FE 00  26 00  31 00  
 00 26  00 31  00 FF     <-- mark
 26 00  31 00  FF 00  
 00 31  00 FF  00 20  
 31 00  FF 00  20 00  
 00 FF  00 20  00 37  
 FF 00  20 00  37 00  
 00 20  00 37  00 00     <-- mark
 20 00  37 00  00 00  
 00 37  00 00  00 1A  
 37 00  00 00  1A 00  
 00 00  00 1A  00 3A  
 00 00  1A 00  3A 00  
 00 1A  00 3A  00 00     <-- mark
 1A 00  3A 00  00 00  
 00 3A  00 00  00 15  
 3A 00  00 00  15 00  
 00 00  00 15  00 3A  
 00 00  15 00  3A 00  
 00 15  00 3A  00 00     <-- mark
 15 00  3A 00  00 00  
 00 3A  00 00  00 0F  
 3A 00  00 00  0F 00  
 00 00  00 0F  00 3C  
 00 00  0F 00  3C 00  
 00 0F  00 3C  00 00     <-- mark
 0F 00  3C 00  00 00  

333 - 
Clearing any interrupts we read from CTRL_REG3:  0


*

^ STMicro Forum

STMicro forum posts regarding IIS2DH configuration, IIS2DH commands:

Excerpt:

Miroslav BATEK (Employee)
Edited by ST Community July 21, 2018 at 5:47 PM
Posted on November 11, 2016 at 12:24

 

 

 
1) Your setting of INT1_CFG register to (0011 1111b) doesn’t make sense. Basically you want trigger the interrupt if the acceleration value is lower or higher than threshold in any axis, this is always true. If the interrupt is not latched, the value is valid for one period of your ODR settings. If it is latched the value is set until you read the INT1_SRC register.

 

 

 
2) If you set AOI, 6D = 00. The OR condition is used between the other bits settings.

 

If you set AOI, 6D = 10. The AND condition is used between the other bits settings.

 

If you want use 6D detection you can set AOI, 6D bits 01 or 11. Other bits in the INT1_CFG register are ignored.

 

Maybe an example will help:

 

INT1_CFG = 00101010b … if acceleration value in X axis OR in Y axis OR in Z axis will be higher than INT1_THS for time defined in INT1_DURATION register the interrupt will be triggered.

INT1_CFG = 10010101b … if acceleration value in X axis AND in Y axis AND in Z axis will be lower than INT1_THS for time defined in INT1_DURATION register the interrupt will be triggered.

3)

 

You don’t have to worry about this sentence. You don’t have to reboot the accelerometer. It is just saying you can’t configure these register during the start-up of the accelerometer. I suppose there is already small delay after power-up so this is not an issue.

 

 
4) By execution “Reboot memory content� command default values from internal non-volatile memory are loaded to working registers. By this you can reset the register settings to default values.

 

 
5) For High pass filter setting please refer to AN3308 for LIS3DH. The settings is very similar to IIS2DH.

Best regards

 

Miroslav

Selected as BestSelected as Best


^ validate_enabled_instances.c

[1]+ Stopped vi /home/ted/projects/zephyr-based/z4-sandbox-kionix-work/zephyr/soc/arm/nordic_nrf/validate_enabled_instances.c ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/hardware-Stage1-firmware-aws-iot-stand-alone/boards$

 20 /*
 21  * In most Nordic SoCs, SPI and TWI peripherals with the same instance number
 22  * share certain resources and therefore cannot be used at the same time (in
 23  * nRF53 and nRF91 Series this limitation concerns UART peripherals as well).
 24  *
 25  * In some SoCs, like nRF52810, there are only single instances of
 26  * these peripherals and they are arranged in a different way, so this
 27  * limitation does not apply.
 28  *
 29  * The build assertions below check if conflicting peripheral instances are not
 30  * enabled simultaneously.
 31  */
 32 
 33 #define CHECK(idx) \
 34         !(I2C_ENABLED(idx) && SPI_ENABLED(idx)) && \
 35         !(I2C_ENABLED(idx) && UART_ENABLED(idx)) && \
 36         !(SPI_ENABLED(idx) && UART_ENABLED(idx))
 37 
 38 #define MSG(idx) \
 39         "Only one of the following peripherals can be enabled: " \
 40         "SPI"#idx", SPIM"#idx", SPIS"#idx", TWI"#idx", TWIM"#idx", TWIS"#idx \
 41         IF_ENABLED(CONFIG_SOC_SERIES_NRF53X, (", UARTE"#idx)) \
 42         IF_ENABLED(CONFIG_SOC_SERIES_NRF91X, (", UARTE"#idx)) \
 43         ". Check nodes with status \"okay\" in zephyr.dts."
 44 
 45 #if (!IS_ENABLED(CONFIG_SOC_NRF52810) &&        \
 46         !IS_ENABLED(CONFIG_SOC_NRF52805) &&     \
 47         !IS_ENABLED(CONFIG_SOC_NRF52811))
 48 BUILD_ASSERT(CHECK(0), MSG(0));
 49 #endif
 50 BUILD_ASSERT(CHECK(1), MSG(1));
 51 BUILD_ASSERT(CHECK(2), MSG(2));
 52 BUILD_ASSERT(CHECK(3), MSG(3));
 53 
 54 #if IS_ENABLED(CONFIG_SOC_NRF52811)


^ edit point

^ edit point