1+ #include <stdio.h>
2+ #include <zephyr/kernel.h>
3+ #include <zephyr/device.h>
4+ #include <zephyr/drivers/gpio.h>
5+ #include <zephyr/drivers/i2c.h>
6+ #include <zephyr/sys/util.h>
7+ #include <zephyr/logging/log.h>
8+
9+ LOG_MODULE_REGISTER (main , LOG_LEVEL_INF );
10+
11+ /* Use DT_ALIAS to get the nodes */
12+ static const struct i2c_dt_spec imu_i2c = I2C_DT_SPEC_GET (DT_ALIAS (imu0 ));
13+ static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET (DT_ALIAS (led0 ), gpios );
14+ static const struct gpio_dt_spec imu_int = GPIO_DT_SPEC_GET (DT_NODELABEL (lsm6ds3tr_c ), irq_gpios );
15+
16+ /* Register addresses */
17+ #define LSM6DS3TR_C_CTRL1_XL 0x10
18+ #define LSM6DS3TR_C_TAP_SRC 0x1C
19+ #define LSM6DS3TR_C_TAP_CFG 0x58
20+ #define LSM6DS3TR_C_TAP_THS_6D 0x59
21+ #define LSM6DS3TR_C_INT_DUR2 0x5A
22+ #define LSM6DS3TR_C_WAKE_UP_THS 0x5B
23+ #define LSM6DS3TR_C_MD1_CFG 0x5E
24+
25+ /* Register bit definitions and configuration values */
26+ #define LSM6DS3TR_C_ACCEL_ODR_104HZ (0x40)
27+
28+ #define LSM6DS3TR_C_TAP_CFG_INT_ENABLE BIT(7)
29+ #define LSM6DS3TR_C_TAP_CFG_TAP_X_EN BIT(3)
30+ #define LSM6DS3TR_C_TAP_CFG_TAP_Y_EN BIT(2)
31+ #define LSM6DS3TR_C_TAP_CFG_TAP_Z_EN BIT(1)
32+ #define LSM6DS3TR_C_TAP_CFG_LATCH_INT BIT(0)
33+
34+ #define LSM6DS3TR_C_TAP_CONFIG (LSM6DS3TR_C_TAP_CFG_INT_ENABLE | \
35+ LSM6DS3TR_C_TAP_CFG_TAP_X_EN | \
36+ LSM6DS3TR_C_TAP_CFG_TAP_Y_EN | \
37+ LSM6DS3TR_C_TAP_CFG_TAP_Z_EN | \
38+ LSM6DS3TR_C_TAP_CFG_LATCH_INT)
39+
40+ #define LSM6DS3TR_C_TAP_THRESHOLD (0x0A) /* Adjust sensitivity as needed */
41+ #define LSM6DS3TR_C_TAP_TIMING (0x80)
42+ #define LSM6DS3TR_C_WAKE_UP_THS_SINGLE_DOUBLE_EN BIT(7)
43+ #define LSM6DS3TR_C_MD1_CFG_INT1_SINGLE_TAP_EN BIT(6)
44+ #define LSM6DS3TR_C_INT1_ROUTING (LSM6DS3TR_C_MD1_CFG_INT1_SINGLE_TAP_EN)
45+
46+ #define DOUBLE_TAP_WINDOW_MS 500
47+
48+ /* Forward declarations */
49+ static void imu_work_handler (struct k_work * work );
50+ static void led_off_work_handler (struct k_work * work );
51+ static void tap_timer_expiry_function (struct k_timer * timer_id );
52+
53+ /* Work items and timers */
54+ static K_WORK_DEFINE (imu_work , imu_work_handler ) ;
55+ static K_WORK_DELAYABLE_DEFINE (led_off_work , led_off_work_handler ) ;
56+ static K_TIMER_DEFINE (tap_timer , tap_timer_expiry_function , NULL) ;
57+
58+ /* GPIO callback struct for the IMU interrupt pin */
59+ static struct gpio_callback imu_cb_data ;
60+
61+ /* Helper to flash the LED */
62+ static void trigger_led_flash (void )
63+ {
64+ gpio_pin_set_dt (& led , 1 );
65+ k_work_schedule (& led_off_work , K_MSEC (150 ));
66+ }
67+
68+ /* Called by timer when the double-tap window expires */
69+ static void tap_timer_expiry_function (struct k_timer * timer_id )
70+ {
71+ LOG_INF ("Single tap event detected!" );
72+ trigger_led_flash ();
73+ }
74+
75+ /* Work handler to process IMU interrupt in thread context */
76+ static void imu_work_handler (struct k_work * work )
77+ {
78+ /* An interrupt means a tap occurred. Check timer to classify it. */
79+ if (k_timer_remaining_get (& tap_timer ) > 0 )
80+ {
81+ /* Timer is running: this is the second tap of a double tap */
82+ k_timer_stop (& tap_timer );
83+ LOG_INF ("Double tap event detected!" );
84+ trigger_led_flash ();
85+ }
86+ else
87+ {
88+ /* Timer is not running: this is the first tap. Start the window. */
89+ k_timer_start (& tap_timer , K_MSEC (DOUBLE_TAP_WINDOW_MS ), K_NO_WAIT );
90+ }
91+
92+ /* Reading TAP_SRC is still good practice to clear the latched interrupt */
93+ uint8_t tap_src ;
94+ i2c_reg_read_byte_dt (& imu_i2c , LSM6DS3TR_C_TAP_SRC , & tap_src );
95+ }
96+
97+ /* ISR: only submits work to a thread. Non-blocking and fast. */
98+ static void gpio_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
99+ gpio_port_pins_t pins )
100+ {
101+ k_work_submit (& imu_work );
102+ }
103+
104+ static void led_off_work_handler (struct k_work * work )
105+ {
106+ gpio_pin_set_dt (& led , 0 );
107+ }
108+
109+ static int setup_gpio_interrupt (void )
110+ {
111+ if (!gpio_is_ready_dt (& imu_int ))
112+ {
113+ LOG_ERR ("IMU interrupt pin not ready." );
114+ return - ENODEV ;
115+ }
116+
117+ int ret = gpio_pin_configure_dt (& imu_int , GPIO_INPUT );
118+ if (ret )
119+ {
120+ LOG_ERR ("Error configuring interrupt pin: %d" , ret );
121+ return ret ;
122+ }
123+
124+ ret = gpio_pin_interrupt_configure_dt (& imu_int , GPIO_INT_EDGE_TO_ACTIVE );
125+ if (ret )
126+ {
127+ LOG_ERR ("Error configuring interrupt: %d" , ret );
128+ return ret ;
129+ }
130+
131+ gpio_init_callback (& imu_cb_data , gpio_interrupt_handler , BIT (imu_int .pin ));
132+ gpio_add_callback (imu_int .port , & imu_cb_data );
133+
134+ LOG_INF ("GPIO interrupt configured on %s, pin %d" , imu_int .port -> name , imu_int .pin );
135+ return 0 ;
136+ }
137+
138+ static int configure_lsm6ds3_tap (void )
139+ {
140+ int ret = 0 ;
141+
142+ /* Enable accelerometer */
143+ ret = i2c_reg_write_byte_dt (& imu_i2c , LSM6DS3TR_C_CTRL1_XL , LSM6DS3TR_C_ACCEL_ODR_104HZ );
144+ if (ret )
145+ {
146+ return ret ;
147+ }
148+ k_msleep (20 );
149+
150+ /* Enable interrupts, latch them, and enable tap on all axes */
151+ ret = i2c_reg_write_byte_dt (& imu_i2c , LSM6DS3TR_C_TAP_CFG , LSM6DS3TR_C_TAP_CONFIG );
152+ if (ret )
153+ {
154+ return ret ;
155+ }
156+
157+ /* Set tap threshold */
158+ ret = i2c_reg_write_byte_dt (& imu_i2c , LSM6DS3TR_C_TAP_THS_6D , LSM6DS3TR_C_TAP_THRESHOLD );
159+ if (ret )
160+ {
161+ return ret ;
162+ }
163+
164+ /* Set tap timing parameters (DUR field is ignored in single-tap only mode) */
165+ ret = i2c_reg_write_byte_dt (& imu_i2c , LSM6DS3TR_C_INT_DUR2 , LSM6DS3TR_C_TAP_TIMING );
166+ if (ret )
167+ {
168+ return ret ;
169+ }
170+
171+ /* Configure for single-tap ONLY by clearing the SINGLE_DOUBLE_TAP bit */
172+ ret = i2c_reg_update_byte_dt (& imu_i2c , LSM6DS3TR_C_WAKE_UP_THS ,
173+ LSM6DS3TR_C_WAKE_UP_THS_SINGLE_DOUBLE_EN ,
174+ 0 );
175+ if (ret )
176+ {
177+ return ret ;
178+ }
179+
180+ /* Route ONLY single tap interrupt to INT1 */
181+ ret = i2c_reg_write_byte_dt (& imu_i2c , LSM6DS3TR_C_MD1_CFG , LSM6DS3TR_C_INT1_ROUTING );
182+ if (ret )
183+ {
184+ return ret ;
185+ }
186+
187+ LOG_INF ("LSM6DS3TR-C tap detection configured for single-tap events." );
188+ return 0 ;
189+ }
190+
191+ int main (void )
192+ {
193+ if (!i2c_is_ready_dt (& imu_i2c ))
194+ {
195+ LOG_ERR ("I2C bus for IMU not ready." );
196+ return 0 ;
197+ }
198+
199+ if (!gpio_is_ready_dt (& led ))
200+ {
201+ LOG_ERR ("LED device not found!" );
202+ return 0 ;
203+ }
204+ gpio_pin_configure_dt (& led , GPIO_OUTPUT_INACTIVE );
205+
206+ LOG_INF ("Blinking LED to indicate startup..." );
207+ gpio_pin_set_dt (& led , 1 );
208+ k_msleep (500 );
209+ gpio_pin_set_dt (& led , 0 );
210+
211+ if (configure_lsm6ds3_tap () != 0 )
212+ {
213+ LOG_ERR ("Failed to configure IMU for tap detection." );
214+ return 0 ;
215+ }
216+
217+ if (setup_gpio_interrupt () != 0 )
218+ {
219+ LOG_ERR ("Failed to set up GPIO interrupt." );
220+ return 0 ;
221+ }
222+
223+ LOG_INF ("Setup complete. Entering sleep mode." );
224+ LOG_INF ("Tap the board to wake it up." );
225+
226+ while (1 )
227+ {
228+ k_sleep (K_FOREVER );
229+ }
230+
231+ return 0 ;
232+ }
0 commit comments